Skip to content

Commit c0f177b

Browse files
committed
glib: Use TryFrom for GString conversions
1 parent 6d59895 commit c0f177b

File tree

6 files changed

+71
-66
lines changed

6 files changed

+71
-66
lines changed

gio/src/file.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ impl<O: IsA<File>> FileExtManual for O {
237237
+ 'static,
238238
>,
239239
> {
240-
let etag = etag.map(glib::GString::from);
240+
let etag = etag.map(|e| glib::GString::try_from(e).unwrap());
241241
Box::pin(crate::GioFuture::new(
242242
self,
243243
move |obj, cancellable, send| {

glib/src/gstring.rs

Lines changed: 51 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ impl GString {
426426

427427
impl Clone for GString {
428428
fn clone(&self) -> GString {
429-
self.as_str().into()
429+
self.as_gstr().to_owned()
430430
}
431431
}
432432

@@ -651,23 +651,23 @@ impl From<GString> for Box<str> {
651651
}
652652
}
653653

654-
impl From<String> for GString {
654+
impl TryFrom<String> for GString {
655+
type Error = std::ffi::NulError;
655656
#[inline]
656-
fn from(s: String) -> Self {
657+
fn try_from(s: String) -> Result<Self, Self::Error> {
657658
// Moves the content of the String
658-
unsafe {
659-
// No check for valid UTF-8 here
660-
let cstr = CString::from_vec_unchecked(s.into_bytes());
661-
GString(Inner::Native(Some(cstr)))
662-
}
659+
// Check for interior nul bytes
660+
let cstr = CString::new(s.into_bytes())?;
661+
Ok(GString(Inner::Native(Some(cstr))))
663662
}
664663
}
665664

666-
impl From<Box<str>> for GString {
665+
impl TryFrom<Box<str>> for GString {
666+
type Error = std::ffi::NulError;
667667
#[inline]
668-
fn from(s: Box<str>) -> Self {
668+
fn try_from(s: Box<str>) -> Result<Self, Self::Error> {
669669
// Moves the content of the String
670-
s.into_string().into()
670+
s.into_string().try_into()
671671
}
672672
}
673673

@@ -678,50 +678,48 @@ impl From<&GStr> for GString {
678678
}
679679
}
680680

681-
impl From<&str> for GString {
681+
impl TryFrom<&str> for GString {
682+
type Error = std::ffi::NulError;
682683
#[inline]
683-
fn from(s: &str) -> Self {
684-
// Allocates with the GLib allocator
685-
unsafe {
686-
// No check for valid UTF-8 here
687-
let copy = ffi::g_malloc(s.len() + 1) as *mut c_char;
688-
ptr::copy_nonoverlapping(s.as_ptr() as *const c_char, copy, s.len() + 1);
689-
ptr::write(copy.add(s.len()), 0);
690-
691-
GString(Inner::Foreign {
692-
ptr: ptr::NonNull::new_unchecked(copy),
693-
len: s.len(),
694-
})
695-
}
684+
fn try_from(s: &str) -> Result<Self, Self::Error> {
685+
s.to_owned().try_into()
696686
}
697687
}
698688

699-
impl From<Vec<u8>> for GString {
689+
#[derive(thiserror::Error, Debug)]
690+
pub enum GStringError {
691+
#[error("invalid UTF-8")]
692+
Utf8(#[from] std::str::Utf8Error),
693+
#[error("interior nul bytes")]
694+
Nul(#[from] std::ffi::NulError),
695+
}
696+
697+
impl TryFrom<Vec<u8>> for GString {
698+
type Error = GStringError;
700699
#[inline]
701-
fn from(s: Vec<u8>) -> Self {
700+
fn try_from(s: Vec<u8>) -> Result<Self, Self::Error> {
702701
// Moves the content of the Vec
703-
// Also check if it's valid UTF-8
704-
let cstring = CString::new(s).expect("CString::new failed");
705-
cstring.into()
702+
// Also check if it's valid UTF-8 and has no interior nuls
703+
let cstring = CString::new(s)?;
704+
Ok(cstring.try_into()?)
706705
}
707706
}
708707

709-
impl From<CString> for GString {
710-
#[inline]
711-
fn from(s: CString) -> Self {
708+
impl TryFrom<CString> for GString {
709+
type Error = std::str::Utf8Error;
710+
fn try_from(s: CString) -> Result<Self, Self::Error> {
712711
// Moves the content of the CString
713712
// Also check if it's valid UTF-8
714-
assert!(s.to_str().is_ok());
715-
Self(Inner::Native(Some(s)))
713+
s.to_str()?;
714+
Ok(Self(Inner::Native(Some(s))))
716715
}
717716
}
718717

719-
impl From<&CStr> for GString {
718+
impl TryFrom<&CStr> for GString {
719+
type Error = std::str::Utf8Error;
720720
#[inline]
721-
fn from(c: &CStr) -> Self {
722-
// Creates a copy with the GLib allocator
723-
// Also check if it's valid UTF-8
724-
c.to_str().unwrap().into()
721+
fn try_from(c: &CStr) -> Result<Self, Self::Error> {
722+
c.to_owned().try_into()
725723
}
726724
}
727725

@@ -772,7 +770,7 @@ impl FromGlibPtrNone<*const u8> for GString {
772770
assert!(!ptr.is_null());
773771
let cstr = CStr::from_ptr(ptr as *const _);
774772
// Also check if it's valid UTF-8
775-
cstr.to_str().unwrap().into()
773+
cstr.try_into().unwrap()
776774
}
777775
}
778776

@@ -904,16 +902,16 @@ impl<'a> ToGlibPtr<'a, *mut i8> for GString {
904902
impl<'a> FromGlibContainer<*const c_char, *const i8> for GString {
905903
unsafe fn from_glib_none_num(ptr: *const i8, num: usize) -> Self {
906904
if num == 0 || ptr.is_null() {
907-
return Self::from("");
905+
return Self::try_from("").unwrap();
908906
}
909907
let slice = slice::from_raw_parts(ptr as *const u8, num);
910908
// Also check if it's valid UTF-8
911-
std::str::from_utf8(slice).unwrap().into()
909+
std::str::from_utf8(slice).unwrap().try_into().unwrap()
912910
}
913911

914912
unsafe fn from_glib_container_num(ptr: *const i8, num: usize) -> Self {
915913
if num == 0 || ptr.is_null() {
916-
return Self::from("");
914+
return Self::try_from("").unwrap();
917915
}
918916

919917
// Check if it's valid UTF-8
@@ -928,7 +926,7 @@ impl<'a> FromGlibContainer<*const c_char, *const i8> for GString {
928926

929927
unsafe fn from_glib_full_num(ptr: *const i8, num: usize) -> Self {
930928
if num == 0 || ptr.is_null() {
931-
return Self::from("");
929+
return Self::try_from("").unwrap();
932930
}
933931

934932
// Check if it's valid UTF-8
@@ -1007,7 +1005,7 @@ unsafe impl<'a> crate::value::FromValue<'a> for GString {
10071005
type Checker = crate::value::GenericValueTypeOrNoneChecker<Self>;
10081006

10091007
unsafe fn from_value(value: &'a crate::Value) -> Self {
1010-
Self::from(<&str>::from_value(value))
1008+
Self::try_from(<&str>::from_value(value)).unwrap()
10111009
}
10121010
}
10131011

@@ -1097,15 +1095,15 @@ mod tests {
10971095

10981096
#[test]
10991097
fn test_gstring_from_str() {
1100-
let gstring: GString = "foo".into();
1098+
let gstring: GString = "foo".try_into().unwrap();
11011099
assert_eq!(gstring.as_str(), "foo");
11021100
let foo: Box<str> = gstring.into();
11031101
assert_eq!(foo.as_ref(), "foo");
11041102
}
11051103

11061104
#[test]
11071105
fn test_string_from_gstring() {
1108-
let gstring = GString::from("foo");
1106+
let gstring = GString::try_from("foo").unwrap();
11091107
assert_eq!(gstring.as_str(), "foo");
11101108
let s = String::from(gstring);
11111109
assert_eq!(s, "foo");
@@ -1114,7 +1112,7 @@ mod tests {
11141112
#[test]
11151113
fn test_gstring_from_cstring() {
11161114
let cstr = CString::new("foo").unwrap();
1117-
let gstring = GString::from(cstr);
1115+
let gstring = GString::try_from(cstr).unwrap();
11181116
assert_eq!(gstring.as_str(), "foo");
11191117
let foo: Box<str> = gstring.into();
11201118
assert_eq!(foo.as_ref(), "foo");
@@ -1123,7 +1121,7 @@ mod tests {
11231121
#[test]
11241122
fn test_string_from_gstring_from_cstring() {
11251123
let cstr = CString::new("foo").unwrap();
1126-
let gstring = GString::from(cstr);
1124+
let gstring = GString::try_from(cstr).unwrap();
11271125
assert_eq!(gstring.as_str(), "foo");
11281126
let s = String::from(gstring);
11291127
assert_eq!(s, "foo");
@@ -1132,7 +1130,7 @@ mod tests {
11321130
#[test]
11331131
fn test_vec_u8_to_gstring() {
11341132
let v: &[u8] = b"foo";
1135-
let s: GString = Vec::from(v).into();
1133+
let s: GString = Vec::from(v).try_into().unwrap();
11361134
assert_eq!(s.as_str(), "foo");
11371135
}
11381136

@@ -1165,11 +1163,11 @@ mod tests {
11651163
fn test_hashmap() {
11661164
use std::collections::HashMap;
11671165

1168-
let gstring = GString::from("foo");
1166+
let gstring = GString::try_from("foo").unwrap();
11691167
assert_eq!(gstring.as_str(), "foo");
11701168
let mut h: HashMap<GString, i32> = HashMap::new();
11711169
h.insert(gstring, 42);
1172-
let gstring: GString = "foo".into();
1170+
let gstring: GString = "foo".try_into().unwrap();
11731171
assert!(h.contains_key(&gstring));
11741172
}
11751173
}

glib/src/log.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -859,8 +859,8 @@ macro_rules! g_printerr {
859859
/// "MY_FIELD2" => "abc {}", "def";
860860
/// // single argument can be a &str or a &[u8] or anything else satsfying AsRef<[u8]>
861861
/// "MY_FIELD3" => CString::new("my string").unwrap().to_bytes();
862-
/// // field names can also be dynamic
863-
/// GString::from("MY_FIELD4") => b"a binary string".to_owned();
862+
/// // field names can also be dynamic, satisfying AsRef<GStr>
863+
/// GString::try_from("MY_FIELD4").unwrap() => b"a binary string".to_owned();
864864
/// // the main log message goes in the MESSAGE field
865865
/// "MESSAGE" => "test: {} {}", 1, 2, ;
866866
/// }

glib/src/utils.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -336,18 +336,18 @@ mod tests {
336336
fn test_filename_from_uri() {
337337
use crate::GString;
338338
use std::path::PathBuf;
339-
let uri: GString = "file:///foo/bar.txt".into();
339+
let uri: GString = "file:///foo/bar.txt".try_into().unwrap();
340340
if let Ok((filename, hostname)) = crate::filename_from_uri(&uri) {
341341
assert_eq!(filename, PathBuf::from(r"/foo/bar.txt"));
342342
assert_eq!(hostname, None);
343343
} else {
344344
unreachable!();
345345
}
346346

347-
let uri: GString = "file://host/foo/bar.txt".into();
347+
let uri: GString = "file://host/foo/bar.txt".try_into().unwrap();
348348
if let Ok((filename, hostname)) = crate::filename_from_uri(&uri) {
349349
assert_eq!(filename, PathBuf::from(r"/foo/bar.txt"));
350-
assert_eq!(hostname, Some(GString::from("host")));
350+
assert_eq!(hostname, Some(GString::try_from("host").unwrap()));
351351
} else {
352352
unreachable!();
353353
}
@@ -358,19 +358,19 @@ mod tests {
358358
use crate::GString;
359359
assert_eq!(
360360
crate::uri_parse_scheme("foo://bar"),
361-
Some(GString::from("foo"))
361+
Some(GString::try_from("foo").unwrap())
362362
);
363363
assert_eq!(crate::uri_parse_scheme("foo"), None);
364364

365365
let escaped = crate::uri_escape_string("&foo", None, true);
366-
assert_eq!(escaped, GString::from("%26foo"));
366+
assert_eq!(escaped, GString::try_from("%26foo").unwrap());
367367

368368
let unescaped = crate::uri_unescape_string(escaped.as_str(), None);
369-
assert_eq!(unescaped, Some(GString::from("&foo")));
369+
assert_eq!(unescaped, Some(GString::try_from("&foo").unwrap()));
370370

371371
assert_eq!(
372372
crate::uri_unescape_segment(Some("/foo"), None, None),
373-
Some(GString::from("/foo"))
373+
Some(GString::try_from("/foo").unwrap())
374374
);
375375
assert_eq!(crate::uri_unescape_segment(Some("/foo%"), None, None), None);
376376
}

glib/src/value.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,13 +1152,19 @@ mod tests {
11521152
let v = vec!["123", "456"].to_value();
11531153
assert_eq!(
11541154
v.get::<Vec<GString>>(),
1155-
Ok(vec![GString::from("123"), GString::from("456")])
1155+
Ok(vec![
1156+
GString::try_from("123").unwrap(),
1157+
GString::try_from("456").unwrap()
1158+
])
11561159
);
11571160

11581161
let v = vec![String::from("123"), String::from("456")].to_value();
11591162
assert_eq!(
11601163
v.get::<Vec<GString>>(),
1161-
Ok(vec![GString::from("123"), GString::from("456")])
1164+
Ok(vec![
1165+
GString::try_from("123").unwrap(),
1166+
GString::try_from("456").unwrap()
1167+
])
11621168
);
11631169
}
11641170

glib/tests/structured_log.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ fn structured_log() {
3535
}
3636
);
3737

38+
let my_meta3 = GString::try_from("MY_META3").unwrap();
3839
log_structured!(
3940
None,
4041
LogLevel::Message,
@@ -43,7 +44,7 @@ fn structured_log() {
4344
"MESSAGE" => "formatted with meta: {} {}", 123, 456.0;
4445
"MY_META2" => "def{}", "ghi";
4546
"EMPTY" => b"";
46-
GString::from("MY_META3") => b"bstring".to_owned();
47+
my_meta3 => b"bstring".to_owned();
4748
}
4849
);
4950
log_structured_array(

0 commit comments

Comments
 (0)