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