@@ -4,7 +4,7 @@ use crate::translate::*;
4
4
use crate :: types:: { StaticType , Type } ;
5
5
use crate :: value:: { FromValue , ToValue } ;
6
6
use crate :: Value ;
7
- use std:: borrow:: Borrow ;
7
+ use std:: borrow:: { Borrow , Cow } ;
8
8
use std:: cmp:: Ordering ;
9
9
use std:: ffi:: { CStr , CString , OsStr } ;
10
10
use std:: fmt;
@@ -18,7 +18,7 @@ use std::slice;
18
18
use std:: string:: String ;
19
19
20
20
// rustdoc-stripper-ignore-next
21
- /// Representaion of a borrowed [`GString`].
21
+ /// Representation of a borrowed [`GString`].
22
22
///
23
23
/// This type is very similar to [`std::ffi::CStr`], but with one added constraint: the string
24
24
/// must also be valid UTF-8.
@@ -59,6 +59,27 @@ impl GStr {
59
59
Self :: from_bytes_with_nul_unchecked ( cstr. to_bytes_with_nul ( ) )
60
60
}
61
61
// rustdoc-stripper-ignore-next
62
+ /// Wraps a raw C string with a safe GLib string wrapper. The provided C string **must** be
63
+ /// nul-terminated. All constraints from [`std::ffi::CStr::from_ptr`] also apply here.
64
+ ///
65
+ /// If the string is valid UTF-8 then it is directly returned otherwise a copy is created with
66
+ /// every invalid character replaced by the Unicode replacement character (U+FFFD).
67
+ #[ inline]
68
+ pub unsafe fn from_ptr_lossy < ' a > ( ptr : * const c_char ) -> Cow < ' a , Self > {
69
+ let mut end_ptr = ptr:: null ( ) ;
70
+ if ffi:: g_utf8_validate ( ptr as * const _ , -1 , & mut end_ptr) != ffi:: GFALSE {
71
+ Cow :: Borrowed ( Self :: from_bytes_with_nul_unchecked ( slice:: from_raw_parts (
72
+ ptr as * const u8 ,
73
+ end_ptr. offset_from ( ptr) as usize + 1 ,
74
+ ) ) )
75
+ } else {
76
+ Cow :: Owned ( GString :: from_glib_full ( ffi:: g_utf8_make_valid (
77
+ ptr as * const _ ,
78
+ -1 ,
79
+ ) ) )
80
+ }
81
+ }
82
+ // rustdoc-stripper-ignore-next
62
83
/// Converts this GLib string to a byte slice containing the trailing 0 byte.
63
84
///
64
85
/// This function is the equivalent of [`GStr::to_bytes`] except that it will retain the
@@ -408,6 +429,17 @@ impl GString {
408
429
Inner :: Foreign { ptr, .. } => ptr. as_ptr ( ) ,
409
430
}
410
431
}
432
+
433
+ // rustdoc-stripper-ignore-next
434
+ /// Wraps a raw C string with a safe GLib string wrapper. The provided C string **must** be
435
+ /// nul-terminated. All constraints from [`std::ffi::CStr::from_ptr`] also apply here.
436
+ ///
437
+ /// If the string is valid UTF-8 then it is directly returned otherwise a copy is created with
438
+ /// every invalid character replaced by the Unicode replacement character (U+FFFD).
439
+ #[ inline]
440
+ pub unsafe fn from_ptr_lossy < ' a > ( ptr : * const c_char ) -> Cow < ' a , GStr > {
441
+ GStr :: from_ptr_lossy ( ptr)
442
+ }
411
443
}
412
444
413
445
impl IntoGlibPtr < * mut c_char > for GString {
@@ -742,6 +774,18 @@ impl From<&CStr> for GString {
742
774
}
743
775
}
744
776
777
+ impl < ' a > From < GString > for Cow < ' a , GStr > {
778
+ fn from ( v : GString ) -> Self {
779
+ Cow :: Owned ( v)
780
+ }
781
+ }
782
+
783
+ impl < ' a > From < & ' a GStr > for Cow < ' a , GStr > {
784
+ fn from ( v : & ' a GStr ) -> Self {
785
+ Cow :: Borrowed ( v)
786
+ }
787
+ }
788
+
745
789
#[ doc( hidden) ]
746
790
impl FromGlibPtrFull < * mut u8 > for GString {
747
791
#[ inline]
@@ -1224,4 +1268,25 @@ mod tests {
1224
1268
let gstring: GString = "foo" . into ( ) ;
1225
1269
assert ! ( h. contains_key( & gstring) ) ;
1226
1270
}
1271
+
1272
+ #[ test]
1273
+ fn test_gstring_from_ptr_lossy ( ) {
1274
+ let data = CString :: new ( "foo" ) . unwrap ( ) ;
1275
+ let ptr = data. as_ptr ( ) ;
1276
+
1277
+ unsafe {
1278
+ let gstring = GString :: from_ptr_lossy ( ptr) ;
1279
+ assert_eq ! ( gstring. as_str( ) , "foo" ) ;
1280
+ assert_eq ! ( ptr, gstring. as_ptr( ) ) ;
1281
+ }
1282
+
1283
+ let data = b"foo\xF0 \x90 \x80 bar\0 " ;
1284
+ let ptr = data. as_ptr ( ) ;
1285
+
1286
+ unsafe {
1287
+ let gstring = GString :: from_ptr_lossy ( ptr as * const _ ) ;
1288
+ assert_eq ! ( gstring. as_str( ) , "foo���bar" ) ;
1289
+ assert_ne ! ( ptr, gstring. as_ptr( ) as * const _) ;
1290
+ }
1291
+ }
1227
1292
}
0 commit comments