1 // Copyright 2018, The Gtk-rs Project Developers.
2 // See the COPYRIGHT file at the top-level directory of this distribution.
3 // Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>
4 
5 use libc;
6 use std::borrow::Borrow;
7 use std::cmp::Ordering;
8 use std::ffi::{CStr, CString, OsStr};
9 use std::fmt;
10 use std::hash;
11 use std::ops::Deref;
12 use std::os::raw::c_char;
13 use std::ptr;
14 use std::slice;
15 use std::string::String;
16 use translate::*;
17 use types::{StaticType, Type};
18 
19 use glib_sys;
20 use gobject_sys;
21 use value::{FromValueOptional, SetValue, SetValueOptional, Value};
22 
23 #[derive(Debug)]
24 pub struct GString(Inner);
25 
26 #[derive(Debug)]
27 enum Inner {
28     Native(Option<CString>),
29     Foreign(*mut c_char, usize),
30 }
31 
32 unsafe impl Send for GString {}
33 unsafe impl Sync for GString {}
34 
35 impl GString {
36     /// Create a new GString from a glib-originated string, taking ownership.
37     ///
38     /// # Safety
39     ///
40     /// The provided string must be a valid C string (i.e. `'0'` terminated).
41     ///
42     /// The provided pointer must be allocated by glib such that `g_free(ptr)`
43     /// is valid, as the `GString` will call `g_free(ptr)` on drop.
44     ///
45     /// It is essential that noone else free this pointer as it owned by the
46     /// returned `GString`.
47     ///
48     /// The underlying string must not be mutated, in particular in terms of
49     /// length, underneath the `GString` instance.
new(ptr: *mut c_char) -> Self50     unsafe fn new(ptr: *mut c_char) -> Self {
51         assert!(!ptr.is_null());
52         GString(Inner::Foreign(ptr, libc::strlen(ptr)))
53     }
54 
55     /// Create a new GString from a glib-originated string, borrowing it rather
56     /// than taking ownership.
57     ///
58     /// # Safety
59     ///
60     /// The provided string must be a valid C string (i.e. `'0'` terminated).
61     ///
62     /// It is essential that noone else free this pointer as it owned by the
63     /// returned `GString` until the borrow is dropped.
64     ///
65     /// The underlying string must not be mutated, in particular in terms of
66     /// length, underneath the `GString` instance for the duration of the borrow.
new_borrowed(ptr: *const c_char) -> Borrowed<Self>67     unsafe fn new_borrowed(ptr: *const c_char) -> Borrowed<Self> {
68         assert!(!ptr.is_null());
69         Borrowed::new(GString(Inner::Foreign(ptr as *mut _, libc::strlen(ptr))))
70     }
71 
as_str(&self) -> &str72     pub fn as_str(&self) -> &str {
73         let cstr = match self {
74             GString(Inner::Foreign(ptr, length)) => unsafe {
75                 let bytes = slice::from_raw_parts(*ptr as *const u8, length + 1);
76                 CStr::from_bytes_with_nul_unchecked(bytes)
77             },
78             GString(Inner::Native(cstring)) => cstring
79                 .as_ref()
80                 .expect("Native shouldn't be empty")
81                 .as_c_str(),
82         };
83         cstr.to_str().unwrap()
84     }
85 }
86 
87 impl Drop for GString {
drop(&mut self)88     fn drop(&mut self) {
89         if let GString(Inner::Foreign(ptr, _len)) = self {
90             unsafe {
91                 glib_sys::g_free(*ptr as *mut _);
92             }
93         }
94     }
95 }
96 
97 impl fmt::Display for GString {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result98     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
99         write!(f, "{}", self.as_str())
100     }
101 }
102 
103 impl hash::Hash for GString {
hash<H: hash::Hasher>(&self, state: &mut H)104     fn hash<H: hash::Hasher>(&self, state: &mut H) {
105         let bytes = match self {
106             GString(Inner::Foreign(ptr, length)) => unsafe {
107                 slice::from_raw_parts(*ptr as *const u8, length + 1)
108             },
109             GString(Inner::Native(cstring)) => cstring
110                 .as_ref()
111                 .expect("Native shouldn't be empty")
112                 .as_bytes(),
113         };
114         state.write(bytes);
115     }
116 }
117 
118 impl Borrow<str> for GString {
borrow(&self) -> &str119     fn borrow(&self) -> &str {
120         self.as_str()
121     }
122 }
123 
124 impl Ord for GString {
cmp(&self, other: &GString) -> Ordering125     fn cmp(&self, other: &GString) -> Ordering {
126         self.as_str().cmp(other.as_str())
127     }
128 }
129 
130 impl PartialOrd for GString {
partial_cmp(&self, other: &GString) -> Option<Ordering>131     fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
132         Some(self.cmp(other))
133     }
134 }
135 
136 impl PartialEq for GString {
eq(&self, other: &GString) -> bool137     fn eq(&self, other: &GString) -> bool {
138         self.as_str() == other.as_str()
139     }
140 }
141 
142 impl PartialEq<GString> for String {
eq(&self, other: &GString) -> bool143     fn eq(&self, other: &GString) -> bool {
144         self.as_str() == other.as_str()
145     }
146 }
147 
148 impl PartialEq<str> for GString {
eq(&self, other: &str) -> bool149     fn eq(&self, other: &str) -> bool {
150         self.as_str() == other
151     }
152 }
153 
154 impl<'a> PartialEq<&'a str> for GString {
eq(&self, other: &&'a str) -> bool155     fn eq(&self, other: &&'a str) -> bool {
156         self.as_str() == *other
157     }
158 }
159 
160 impl<'a> PartialEq<GString> for &'a str {
eq(&self, other: &GString) -> bool161     fn eq(&self, other: &GString) -> bool {
162         *self == other.as_str()
163     }
164 }
165 
166 impl PartialEq<String> for GString {
eq(&self, other: &String) -> bool167     fn eq(&self, other: &String) -> bool {
168         self.as_str() == other.as_str()
169     }
170 }
171 
172 impl PartialEq<GString> for str {
eq(&self, other: &GString) -> bool173     fn eq(&self, other: &GString) -> bool {
174         self == other.as_str()
175     }
176 }
177 
178 impl PartialOrd<GString> for String {
partial_cmp(&self, other: &GString) -> Option<Ordering>179     fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
180         Some(self.cmp(&String::from(other.as_str())))
181     }
182 }
183 
184 impl PartialOrd<String> for GString {
partial_cmp(&self, other: &String) -> Option<Ordering>185     fn partial_cmp(&self, other: &String) -> Option<Ordering> {
186         Some(self.as_str().cmp(other.as_str()))
187     }
188 }
189 
190 impl PartialOrd<GString> for str {
partial_cmp(&self, other: &GString) -> Option<Ordering>191     fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
192         Some(self.cmp(&other))
193     }
194 }
195 
196 impl PartialOrd<str> for GString {
partial_cmp(&self, other: &str) -> Option<Ordering>197     fn partial_cmp(&self, other: &str) -> Option<Ordering> {
198         Some(self.as_str().cmp(other))
199     }
200 }
201 
202 impl Eq for GString {}
203 
204 impl AsRef<str> for GString {
as_ref(&self) -> &str205     fn as_ref(&self) -> &str {
206         self.as_str()
207     }
208 }
209 
210 impl AsRef<OsStr> for GString {
as_ref(&self) -> &OsStr211     fn as_ref(&self) -> &OsStr {
212         OsStr::new(self.as_str())
213     }
214 }
215 
216 impl Deref for GString {
217     type Target = str;
218 
deref(&self) -> &str219     fn deref(&self) -> &str {
220         self.as_str()
221     }
222 }
223 
224 impl From<GString> for String {
225     #[inline]
from(mut s: GString) -> Self226     fn from(mut s: GString) -> Self {
227         if let GString(Inner::Native(ref mut cstring)) = s {
228             if let Ok(s) = cstring
229                 .take()
230                 .expect("Native shouldn't be empty")
231                 .into_string()
232             {
233                 return s;
234             }
235         }
236         String::from(s.as_str())
237     }
238 }
239 
240 impl From<GString> for Box<str> {
241     #[inline]
from(s: GString) -> Self242     fn from(s: GString) -> Self {
243         let st: String = s.into();
244         st.into_boxed_str()
245     }
246 }
247 
248 impl From<String> for GString {
249     #[inline]
from(s: String) -> Self250     fn from(s: String) -> Self {
251         s.into_bytes().into()
252     }
253 }
254 
255 impl From<Box<str>> for GString {
256     #[inline]
from(s: Box<str>) -> Self257     fn from(s: Box<str>) -> Self {
258         s.as_bytes().to_vec().into()
259     }
260 }
261 
262 impl<'a> From<&'a str> for GString {
263     #[inline]
from(s: &'a str) -> Self264     fn from(s: &'a str) -> Self {
265         s.as_bytes().to_vec().into()
266     }
267 }
268 
269 impl From<Vec<u8>> for GString {
270     #[inline]
from(s: Vec<u8>) -> Self271     fn from(s: Vec<u8>) -> Self {
272         let cstring = CString::new(s).expect("CString::new failed");
273         cstring.into()
274     }
275 }
276 
277 impl From<CString> for GString {
278     #[inline]
from(s: CString) -> Self279     fn from(s: CString) -> Self {
280         GString(Inner::Native(Some(s)))
281     }
282 }
283 
284 impl<'a> From<&'a CStr> for GString {
285     #[inline]
from(c: &'a CStr) -> Self286     fn from(c: &'a CStr) -> Self {
287         CString::from(c).into()
288     }
289 }
290 
291 #[doc(hidden)]
292 impl FromGlibPtrFull<*const c_char> for GString {
293     #[inline]
from_glib_full(ptr: *const c_char) -> Self294     unsafe fn from_glib_full(ptr: *const c_char) -> Self {
295         GString::new(ptr as *mut _)
296     }
297 }
298 
299 #[doc(hidden)]
300 impl FromGlibPtrFull<*mut u8> for GString {
301     #[inline]
from_glib_full(ptr: *mut u8) -> Self302     unsafe fn from_glib_full(ptr: *mut u8) -> Self {
303         GString::new(ptr as *mut _)
304     }
305 }
306 
307 #[doc(hidden)]
308 impl FromGlibPtrFull<*mut i8> for GString {
309     #[inline]
from_glib_full(ptr: *mut i8) -> Self310     unsafe fn from_glib_full(ptr: *mut i8) -> Self {
311         GString::new(ptr as *mut _)
312     }
313 }
314 
315 #[doc(hidden)]
316 impl FromGlibPtrNone<*const c_char> for GString {
317     #[inline]
from_glib_none(ptr: *const c_char) -> Self318     unsafe fn from_glib_none(ptr: *const c_char) -> Self {
319         let cstr = CStr::from_ptr(ptr);
320         cstr.into()
321     }
322 }
323 
324 #[doc(hidden)]
325 impl FromGlibPtrNone<*mut u8> for GString {
326     #[inline]
from_glib_none(ptr: *mut u8) -> Self327     unsafe fn from_glib_none(ptr: *mut u8) -> Self {
328         let cstr = CStr::from_ptr(ptr as *mut _);
329         cstr.into()
330     }
331 }
332 
333 #[doc(hidden)]
334 impl FromGlibPtrNone<*mut i8> for GString {
335     #[inline]
from_glib_none(ptr: *mut i8) -> Self336     unsafe fn from_glib_none(ptr: *mut i8) -> Self {
337         let cstr = CStr::from_ptr(ptr as *mut _);
338         cstr.into()
339     }
340 }
341 
342 #[doc(hidden)]
343 impl FromGlibPtrBorrow<*const c_char> for GString {
344     #[inline]
from_glib_borrow(ptr: *const c_char) -> Borrowed<Self>345     unsafe fn from_glib_borrow(ptr: *const c_char) -> Borrowed<Self> {
346         GString::new_borrowed(ptr)
347     }
348 }
349 
350 #[doc(hidden)]
351 impl FromGlibPtrBorrow<*mut u8> for GString {
352     #[inline]
from_glib_borrow(ptr: *mut u8) -> Borrowed<Self>353     unsafe fn from_glib_borrow(ptr: *mut u8) -> Borrowed<Self> {
354         GString::new_borrowed(ptr as *const c_char)
355     }
356 }
357 
358 #[doc(hidden)]
359 impl FromGlibPtrBorrow<*mut i8> for GString {
360     #[inline]
from_glib_borrow(ptr: *mut i8) -> Borrowed<Self>361     unsafe fn from_glib_borrow(ptr: *mut i8) -> Borrowed<Self> {
362         GString::new_borrowed(ptr as *const c_char)
363     }
364 }
365 
366 #[doc(hidden)]
367 impl<'a> ToGlibPtr<'a, *const c_char> for GString {
368     type Storage = &'a Self;
369 
370     #[inline]
to_glib_none(&'a self) -> Stash<'a, *const c_char, Self>371     fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> {
372         Stash(self.as_ptr() as *const _, self)
373     }
374 
375     #[inline]
to_glib_full(&self) -> *const c_char376     fn to_glib_full(&self) -> *const c_char {
377         unsafe {
378             glib_sys::g_strndup(self.as_ptr() as *const c_char, self.len() as libc::size_t)
379                 as *const c_char
380         }
381     }
382 }
383 
384 #[doc(hidden)]
385 impl<'a> ToGlibPtr<'a, *mut c_char> for GString {
386     type Storage = &'a Self;
387 
388     #[inline]
to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self>389     fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> {
390         Stash(self.as_ptr() as *mut _, self)
391     }
392 
393     #[inline]
to_glib_full(&self) -> *mut c_char394     fn to_glib_full(&self) -> *mut c_char {
395         unsafe {
396             glib_sys::g_strndup(self.as_ptr() as *const c_char, self.len() as libc::size_t)
397                 as *mut c_char
398         }
399     }
400 }
401 
402 impl GlibPtrDefault for GString {
403     type GlibType = *const c_char;
404 }
405 
406 impl StaticType for GString {
static_type() -> Type407     fn static_type() -> Type {
408         String::static_type()
409     }
410 }
411 
412 impl StaticType for Vec<GString> {
static_type() -> Type413     fn static_type() -> Type {
414         unsafe { from_glib(glib_sys::g_strv_get_type()) }
415     }
416 }
417 
418 impl<'a> FromValueOptional<'a> for GString {
from_value_optional(value: &'a Value) -> Option<Self>419     unsafe fn from_value_optional(value: &'a Value) -> Option<Self> {
420         let val = value.to_glib_none().0;
421         if val.is_null() {
422             None
423         } else {
424             let ptr = gobject_sys::g_value_dup_string(val);
425             Some(GString::new(ptr))
426         }
427     }
428 }
429 
430 impl SetValue for GString {
set_value(value: &mut Value, this: &Self)431     unsafe fn set_value(value: &mut Value, this: &Self) {
432         gobject_sys::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full())
433     }
434 }
435 
436 impl SetValueOptional for GString {
set_value_optional(value: &mut Value, this: Option<&Self>)437     unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) {
438         gobject_sys::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full())
439     }
440 }
441 
442 impl_from_glib_container_as_vec_string!(GString, *const c_char);
443 impl_from_glib_container_as_vec_string!(GString, *mut c_char);
444 
445 #[cfg(test)]
446 #[allow(clippy::blacklisted_name)]
447 mod tests {
448     use glib_sys;
449     use gstring::GString;
450     use std::ffi::CString;
451 
452     #[test]
test_gstring()453     fn test_gstring() {
454         let data = CString::new("foo").unwrap();
455         let ptr = data.as_ptr();
456 
457         unsafe {
458             let ptr_copy = glib_sys::g_strdup(ptr);
459             let gstring = GString::new(ptr_copy);
460             assert_eq!(gstring.as_str(), "foo");
461             let foo: Box<str> = gstring.into();
462             assert_eq!(foo.as_ref(), "foo");
463         }
464     }
465 
466     #[test]
test_owned_glib_string()467     fn test_owned_glib_string() {
468         let data = CString::new("foo").unwrap();
469         let ptr = data.as_ptr();
470         unsafe {
471             let ptr_copy = glib_sys::g_strdup(ptr);
472             let gstr = GString::new(ptr_copy);
473             assert_eq!(gstr, "foo");
474         }
475     }
476 
477     #[test]
test_gstring_from_str()478     fn test_gstring_from_str() {
479         let gstring: GString = "foo".into();
480         assert_eq!(gstring.as_str(), "foo");
481         let foo: Box<str> = gstring.into();
482         assert_eq!(foo.as_ref(), "foo");
483     }
484 
485     #[test]
test_gstring_from_cstring()486     fn test_gstring_from_cstring() {
487         let cstr = CString::new("foo").unwrap();
488         let gstring = GString::from(cstr);
489         assert_eq!(gstring.as_str(), "foo");
490         let foo: Box<str> = gstring.into();
491         assert_eq!(foo.as_ref(), "foo");
492     }
493 
494     #[test]
test_string_from_gstring()495     fn test_string_from_gstring() {
496         let cstr = CString::new("foo").unwrap();
497         let gstring = GString::from(cstr);
498         assert_eq!(gstring.as_str(), "foo");
499         let s = String::from(gstring);
500         assert_eq!(s, "foo");
501     }
502 
503     #[test]
test_vec_u8_to_gstring()504     fn test_vec_u8_to_gstring() {
505         let v: &[u8] = b"foo";
506         let s: GString = Vec::from(v).into();
507         assert_eq!(s.as_str(), "foo");
508     }
509 
510     #[test]
test_hashmap()511     fn test_hashmap() {
512         use std::collections::HashMap;
513 
514         let cstr = CString::new("foo").unwrap();
515         let gstring = GString::from(cstr);
516         assert_eq!(gstring.as_str(), "foo");
517         let mut h: HashMap<GString, i32> = HashMap::new();
518         h.insert(gstring, 42);
519         let gstring: GString = "foo".into();
520         assert!(h.contains_key(&gstring));
521     }
522 }
523