diff --git a/gio/src/file.rs b/gio/src/file.rs index a5324fb88eb6..d9fdf233845c 100644 --- a/gio/src/file.rs +++ b/gio/src/file.rs @@ -237,7 +237,7 @@ impl> FileExtManual for O { + 'static, >, > { - let etag = etag.map(glib::GString::from); + let etag = etag.map(|e| glib::GString::try_from(e).unwrap()); Box::pin(crate::GioFuture::new( self, move |obj, cancellable, send| { diff --git a/glib/src/gstring.rs b/glib/src/gstring.rs index 46498fd51d26..19cd2fc28af1 100644 --- a/glib/src/gstring.rs +++ b/glib/src/gstring.rs @@ -82,7 +82,7 @@ impl GString { impl Clone for GString { fn clone(&self) -> GString { - self.as_str().into() + self.as_str().try_into().unwrap() } } @@ -247,70 +247,68 @@ impl From for Box { } } -impl From for GString { +impl TryFrom for GString { + type Error = std::ffi::NulError; #[inline] - fn from(s: String) -> Self { + fn try_from(s: String) -> Result { // Moves the content of the String - unsafe { - // No check for valid UTF-8 here - let cstr = CString::from_vec_unchecked(s.into_bytes()); - GString(Inner::Native(Some(cstr))) - } + // Check for interior nul bytes + let cstr = CString::new(s.into_bytes())?; + Ok(GString(Inner::Native(Some(cstr)))) } } -impl From> for GString { +impl TryFrom> for GString { + type Error = std::ffi::NulError; #[inline] - fn from(s: Box) -> Self { + fn try_from(s: Box) -> Result { // Moves the content of the String - s.into_string().into() + s.into_string().try_into() } } -impl<'a> From<&'a str> for GString { +impl TryFrom<&str> for GString { + type Error = std::ffi::NulError; #[inline] - fn from(s: &'a str) -> Self { - // Allocates with the GLib allocator - unsafe { - // No check for valid UTF-8 here - let copy = ffi::g_malloc(s.len() + 1) as *mut c_char; - ptr::copy_nonoverlapping(s.as_ptr() as *const c_char, copy, s.len() + 1); - ptr::write(copy.add(s.len()), 0); - - GString(Inner::Foreign { - ptr: ptr::NonNull::new_unchecked(copy), - len: s.len(), - }) - } + fn try_from(s: &str) -> Result { + s.to_owned().try_into() } } -impl From> for GString { +#[derive(thiserror::Error, Debug)] +pub enum GStringError { + #[error("invalid UTF-8")] + Utf8(#[from] std::str::Utf8Error), + #[error("interior nul bytes")] + Nul(#[from] std::ffi::NulError), +} + +impl TryFrom> for GString { + type Error = GStringError; #[inline] - fn from(s: Vec) -> Self { + fn try_from(s: Vec) -> Result { // Moves the content of the Vec // Also check if it's valid UTF-8 - let cstring = CString::new(s).expect("CString::new failed"); - cstring.into() + let cstring = CString::new(s)?; + Ok(cstring.try_into()?) } } -impl From for GString { - #[inline] - fn from(s: CString) -> Self { +impl TryFrom for GString { + type Error = std::str::Utf8Error; + fn try_from(s: CString) -> Result { // Moves the content of the CString // Also check if it's valid UTF-8 - assert!(s.to_str().is_ok()); - Self(Inner::Native(Some(s))) + s.to_str()?; + Ok(Self(Inner::Native(Some(s)))) } } -impl<'a> From<&'a CStr> for GString { +impl TryFrom<&CStr> for GString { + type Error = std::str::Utf8Error; #[inline] - fn from(c: &'a CStr) -> Self { - // Creates a copy with the GLib allocator - // Also check if it's valid UTF-8 - c.to_str().unwrap().into() + fn try_from(c: &CStr) -> Result { + c.to_owned().try_into() } } @@ -361,7 +359,7 @@ impl FromGlibPtrNone<*const u8> for GString { assert!(!ptr.is_null()); let cstr = CStr::from_ptr(ptr as *const _); // Also check if it's valid UTF-8 - cstr.to_str().unwrap().into() + cstr.try_into().unwrap() } } @@ -493,16 +491,16 @@ impl<'a> ToGlibPtr<'a, *mut i8> for GString { impl<'a> FromGlibContainer<*const c_char, *const i8> for GString { unsafe fn from_glib_none_num(ptr: *const i8, num: usize) -> Self { if num == 0 || ptr.is_null() { - return Self::from(""); + return Self::try_from("").unwrap(); } let slice = slice::from_raw_parts(ptr as *const u8, num); // Also check if it's valid UTF-8 - std::str::from_utf8(slice).unwrap().into() + std::str::from_utf8(slice).unwrap().try_into().unwrap() } unsafe fn from_glib_container_num(ptr: *const i8, num: usize) -> Self { if num == 0 || ptr.is_null() { - return Self::from(""); + return Self::try_from("").unwrap(); } // Check if it's valid UTF-8 @@ -517,7 +515,7 @@ impl<'a> FromGlibContainer<*const c_char, *const i8> for GString { unsafe fn from_glib_full_num(ptr: *const i8, num: usize) -> Self { if num == 0 || ptr.is_null() { - return Self::from(""); + return Self::try_from("").unwrap(); } // Check if it's valid UTF-8 @@ -596,7 +594,7 @@ unsafe impl<'a> crate::value::FromValue<'a> for GString { type Checker = crate::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a crate::Value) -> Self { - Self::from(<&str>::from_value(value)) + Self::try_from(<&str>::from_value(value)).unwrap() } } @@ -686,7 +684,7 @@ mod tests { #[test] fn test_gstring_from_str() { - let gstring: GString = "foo".into(); + let gstring: GString = "foo".try_into().unwrap(); assert_eq!(gstring.as_str(), "foo"); let foo: Box = gstring.into(); assert_eq!(foo.as_ref(), "foo"); @@ -694,7 +692,7 @@ mod tests { #[test] fn test_string_from_gstring() { - let gstring = GString::from("foo"); + let gstring = GString::try_from("foo").unwrap(); assert_eq!(gstring.as_str(), "foo"); let s = String::from(gstring); assert_eq!(s, "foo"); @@ -703,7 +701,7 @@ mod tests { #[test] fn test_gstring_from_cstring() { let cstr = CString::new("foo").unwrap(); - let gstring = GString::from(cstr); + let gstring = GString::try_from(cstr).unwrap(); assert_eq!(gstring.as_str(), "foo"); let foo: Box = gstring.into(); assert_eq!(foo.as_ref(), "foo"); @@ -712,7 +710,7 @@ mod tests { #[test] fn test_string_from_gstring_from_cstring() { let cstr = CString::new("foo").unwrap(); - let gstring = GString::from(cstr); + let gstring = GString::try_from(cstr).unwrap(); assert_eq!(gstring.as_str(), "foo"); let s = String::from(gstring); assert_eq!(s, "foo"); @@ -721,7 +719,7 @@ mod tests { #[test] fn test_vec_u8_to_gstring() { let v: &[u8] = b"foo"; - let s: GString = Vec::from(v).into(); + let s: GString = Vec::from(v).try_into().unwrap(); assert_eq!(s.as_str(), "foo"); } @@ -754,11 +752,11 @@ mod tests { fn test_hashmap() { use std::collections::HashMap; - let gstring = GString::from("foo"); + let gstring = GString::try_from("foo").unwrap(); assert_eq!(gstring.as_str(), "foo"); let mut h: HashMap = HashMap::new(); h.insert(gstring, 42); - let gstring: GString = "foo".into(); + let gstring: GString = "foo".try_into().unwrap(); assert!(h.contains_key(&gstring)); } } diff --git a/glib/src/utils.rs b/glib/src/utils.rs index 65c8f669de9a..99e5f9753419 100644 --- a/glib/src/utils.rs +++ b/glib/src/utils.rs @@ -336,7 +336,7 @@ mod tests { fn test_filename_from_uri() { use crate::GString; use std::path::PathBuf; - let uri: GString = "file:///foo/bar.txt".into(); + let uri: GString = "file:///foo/bar.txt".try_into().unwrap(); if let Ok((filename, hostname)) = crate::filename_from_uri(&uri) { assert_eq!(filename, PathBuf::from(r"/foo/bar.txt")); assert_eq!(hostname, None); @@ -344,10 +344,10 @@ mod tests { unreachable!(); } - let uri: GString = "file://host/foo/bar.txt".into(); + let uri: GString = "file://host/foo/bar.txt".try_into().unwrap(); if let Ok((filename, hostname)) = crate::filename_from_uri(&uri) { assert_eq!(filename, PathBuf::from(r"/foo/bar.txt")); - assert_eq!(hostname, Some(GString::from("host"))); + assert_eq!(hostname, Some(GString::try_from("host").unwrap())); } else { unreachable!(); } @@ -358,19 +358,19 @@ mod tests { use crate::GString; assert_eq!( crate::uri_parse_scheme("foo://bar"), - Some(GString::from("foo")) + Some(GString::try_from("foo").unwrap()) ); assert_eq!(crate::uri_parse_scheme("foo"), None); let escaped = crate::uri_escape_string("&foo", None, true); - assert_eq!(escaped, GString::from("%26foo")); + assert_eq!(escaped, GString::try_from("%26foo").unwrap()); let unescaped = crate::uri_unescape_string(escaped.as_str(), None); - assert_eq!(unescaped, Some(GString::from("&foo"))); + assert_eq!(unescaped, Some(GString::try_from("&foo").unwrap())); assert_eq!( crate::uri_unescape_segment(Some("/foo"), None, None), - Some(GString::from("/foo")) + Some(GString::try_from("/foo").unwrap()) ); assert_eq!(crate::uri_unescape_segment(Some("/foo%"), None, None), None); } diff --git a/glib/src/value.rs b/glib/src/value.rs index 5870c6ed00bf..4755efc6cf9e 100644 --- a/glib/src/value.rs +++ b/glib/src/value.rs @@ -1152,13 +1152,19 @@ mod tests { let v = vec!["123", "456"].to_value(); assert_eq!( v.get::>(), - Ok(vec![GString::from("123"), GString::from("456")]) + Ok(vec![ + GString::try_from("123").unwrap(), + GString::try_from("456").unwrap() + ]) ); let v = vec![String::from("123"), String::from("456")].to_value(); assert_eq!( v.get::>(), - Ok(vec![GString::from("123"), GString::from("456")]) + Ok(vec![ + GString::try_from("123").unwrap(), + GString::try_from("456").unwrap() + ]) ); }