1 // Take a look at the license at the top of the repository in the LICENSE file. 2 3 use crate::translate::*; 4 use std::borrow; 5 use std::cmp; 6 use std::convert; 7 use std::fmt; 8 use std::hash; 9 use std::ops; 10 use std::ptr; 11 use std::slice; 12 use std::str; 13 14 wrapper! { 15 /// A mutable text buffer that grows automatically. 16 #[doc(alias = "GString")] 17 pub struct String(Boxed<ffi::GString>); 18 19 match fn { 20 copy => |ptr| gobject_ffi::g_boxed_copy(ffi::g_gstring_get_type(), ptr as *mut _) as *mut ffi::GString, 21 free => |ptr| gobject_ffi::g_boxed_free(ffi::g_gstring_get_type(), ptr as *mut _), 22 type_ => || ffi::g_gstring_get_type(), 23 } 24 } 25 26 unsafe impl Send for String {} 27 unsafe impl Sync for String {} 28 29 impl String { 30 #[doc(alias = "g_string_new_len")] new<T: AsRef<[u8]>>(data: T) -> String31 pub fn new<T: AsRef<[u8]>>(data: T) -> String { 32 let bytes = data.as_ref(); 33 unsafe { 34 from_glib_full(ffi::g_string_new_len( 35 bytes.as_ptr() as *const _, 36 bytes.len() as isize, 37 )) 38 } 39 } 40 41 #[doc(alias = "g_string_append_len")] append(&mut self, val: &str) -> &mut Self42 pub fn append(&mut self, val: &str) -> &mut Self { 43 unsafe { 44 ffi::g_string_append_len( 45 self.to_glib_none_mut().0, 46 val.to_glib_none().0, 47 val.len() as isize, 48 ); 49 } 50 self 51 } 52 53 #[doc(alias = "g_string_insert_len")] insert(&mut self, pos: isize, val: &str) -> &mut Self54 pub fn insert(&mut self, pos: isize, val: &str) -> &mut Self { 55 unsafe { 56 ffi::g_string_insert_len( 57 self.to_glib_none_mut().0, 58 pos, 59 val.to_glib_none().0, 60 val.len() as isize, 61 ); 62 } 63 self 64 } 65 66 #[doc(alias = "g_string_overwrite_len")] overwrite(&mut self, pos: usize, val: &str) -> &mut Self67 pub fn overwrite(&mut self, pos: usize, val: &str) -> &mut Self { 68 unsafe { 69 ffi::g_string_overwrite_len( 70 self.to_glib_none_mut().0, 71 pos, 72 val.to_glib_none().0, 73 val.len() as isize, 74 ); 75 } 76 self 77 } 78 79 #[doc(alias = "g_string_prepend_len")] prepend(&mut self, val: &str) -> &mut Self80 pub fn prepend(&mut self, val: &str) -> &mut Self { 81 unsafe { 82 ffi::g_string_prepend_len( 83 self.to_glib_none_mut().0, 84 val.to_glib_none().0, 85 val.len() as isize, 86 ); 87 } 88 self 89 } 90 91 #[doc(alias = "g_string_truncate")] truncate(&mut self, len: usize) -> &mut Self92 pub fn truncate(&mut self, len: usize) -> &mut Self { 93 unsafe { 94 ffi::g_string_truncate(self.to_glib_none_mut().0, len); 95 } 96 self 97 } 98 99 /// Returns `&str` slice when contained data is valid UTF-8 string, or an error otherwise. to_str(&self) -> Result<&str, str::Utf8Error>100 pub fn to_str(&self) -> Result<&str, str::Utf8Error> { 101 str::from_utf8(self.as_ref()) 102 } 103 104 /// Returns `Cow<str>` containing UTF-8 data. Invalid UTF-8 sequences are replaced with 105 /// replacement character. to_string_lossy(&self) -> borrow::Cow<str>106 pub fn to_string_lossy(&self) -> borrow::Cow<str> { 107 std::string::String::from_utf8_lossy(self.as_ref()) 108 } 109 } 110 111 impl Default for String { 112 /// Creates a new empty string. default() -> Self113 fn default() -> Self { 114 unsafe { from_glib_full(ffi::g_string_new(ptr::null())) } 115 } 116 } 117 118 impl fmt::Debug for String { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result119 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 120 f.write_str(&self.to_string_lossy()) 121 } 122 } 123 124 impl fmt::Display for String { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result125 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 126 f.write_str(&self.to_string_lossy()) 127 } 128 } 129 130 impl PartialEq for String { 131 #[doc(alias = "g_string_equal")] eq(&self, other: &Self) -> bool132 fn eq(&self, other: &Self) -> bool { 133 unsafe { 134 from_glib(ffi::g_string_equal( 135 self.to_glib_none().0, 136 other.to_glib_none().0, 137 )) 138 } 139 } 140 } 141 142 impl Eq for String {} 143 144 impl cmp::PartialOrd for String { partial_cmp(&self, other: &Self) -> Option<cmp::Ordering>145 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { 146 Some(self.cmp(other)) 147 } 148 } 149 150 impl cmp::Ord for String { cmp(&self, other: &Self) -> cmp::Ordering151 fn cmp(&self, other: &Self) -> cmp::Ordering { 152 self.as_ref().cmp(other.as_ref()) 153 } 154 } 155 156 impl hash::Hash for String { hash<H>(&self, state: &mut H) where H: hash::Hasher,157 fn hash<H>(&self, state: &mut H) 158 where 159 H: hash::Hasher, 160 { 161 hash::Hash::hash_slice(self.as_ref(), state) 162 } 163 } 164 165 impl convert::AsRef<[u8]> for String { as_ref(&self) -> &[u8]166 fn as_ref(&self) -> &[u8] { 167 let ptr: *const u8 = (*self.0).str as _; 168 let len: usize = (*self.0).len; 169 unsafe { slice::from_raw_parts(ptr, len) } 170 } 171 } 172 173 impl ops::Deref for String { 174 type Target = [u8]; 175 deref(&self) -> &[u8]176 fn deref(&self) -> &[u8] { 177 let ptr: *const u8 = (*self.0).str as _; 178 let len: usize = (*self.0).len; 179 unsafe { slice::from_raw_parts(ptr, len) } 180 } 181 } 182 183 #[cfg(test)] 184 mod tests { 185 #[test] append()186 fn append() { 187 let mut s = crate::String::new(""); 188 s.append("Hello").append(" ").append("there!"); 189 assert_eq!(&*s, b"Hello there!"); 190 } 191 192 #[test] insert()193 fn insert() { 194 let mut s = crate::String::new("foobaz"); 195 s.insert(3, "bar"); 196 assert_eq!(&*s, b"foobarbaz"); 197 } 198 199 #[test] overwrite()200 fn overwrite() { 201 let mut s = crate::String::new("abc"); 202 s.overwrite(2, "de"); 203 assert_eq!(&*s, b"abde"); 204 } 205 206 #[test] prepend()207 fn prepend() { 208 let mut s = crate::String::new("456"); 209 s.prepend("123"); 210 assert_eq!(&*s, b"123456"); 211 } 212 213 #[test] truncate()214 fn truncate() { 215 let mut s = crate::String::new("12345"); 216 s.truncate(10); 217 assert_eq!(&*s, b"12345"); 218 s.truncate(2); 219 assert_eq!(&*s, b"12"); 220 } 221 222 #[test] default()223 fn default() { 224 let s1: crate::String = Default::default(); 225 assert_eq!(&*s1, b""); 226 } 227 228 #[test] display()229 fn display() { 230 let s: crate::String = crate::String::new("This is a string."); 231 assert_eq!(&format!("{}", s), "This is a string."); 232 } 233 234 #[test] eq()235 fn eq() { 236 let a1 = crate::String::new("a"); 237 let a2 = crate::String::new("a"); 238 let b = crate::String::new("b"); 239 assert_eq!(a1, a2); 240 assert_ne!(a1, b); 241 assert_ne!(a2, b); 242 } 243 244 #[test] invalid_utf8()245 fn invalid_utf8() { 246 let s = crate::String::new(b"Hello \xF0\x90\x80World"); 247 assert!(s.to_str().is_err()); 248 assert_eq!(s.to_string_lossy(), "Hello �World"); 249 } 250 } 251