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 enum GString {
25     ForeignOwned(Option<CString>),
26     Borrowed(*const c_char, usize),
27     Owned(*mut c_char, usize),
28 }
29 
30 impl GString {
new(ptr: *mut c_char) -> Self31     pub unsafe fn new(ptr: *mut c_char) -> Self {
32         assert!(!ptr.is_null());
33         GString::Owned(ptr, libc::strlen(ptr))
34     }
35 
new_borrowed(ptr: *const c_char) -> Self36     pub unsafe fn new_borrowed(ptr: *const c_char) -> Self {
37         assert!(!ptr.is_null());
38         GString::Borrowed(ptr, libc::strlen(ptr))
39     }
40 
as_str(&self) -> &str41     pub fn as_str(&self) -> &str {
42         let cstr = match self {
43             GString::Borrowed(ptr, length) => unsafe {
44                 let bytes = slice::from_raw_parts(*ptr as *const u8, length + 1);
45                 CStr::from_bytes_with_nul_unchecked(bytes)
46             },
47             GString::Owned(ptr, length) => unsafe {
48                 let bytes = slice::from_raw_parts(*ptr as *const u8, length + 1);
49                 CStr::from_bytes_with_nul_unchecked(bytes)
50             },
51             GString::ForeignOwned(cstring) => cstring
52                 .as_ref()
53                 .expect("ForeignOwned shouldn't be empty")
54                 .as_c_str(),
55         };
56         cstr.to_str().unwrap()
57     }
58 }
59 
60 impl Drop for GString {
drop(&mut self)61     fn drop(&mut self) {
62         if let GString::Owned(ptr, _len) = self {
63             unsafe {
64                 glib_sys::g_free(*ptr as *mut _);
65             }
66         }
67     }
68 }
69 
70 impl fmt::Display for GString {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result71     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72         write!(f, "{}", self.as_str())
73     }
74 }
75 
76 impl hash::Hash for GString {
hash<H: hash::Hasher>(&self, state: &mut H)77     fn hash<H: hash::Hasher>(&self, state: &mut H) {
78         let bytes = match self {
79             GString::Borrowed(ptr, length) => unsafe {
80                 slice::from_raw_parts(*ptr as *const u8, length + 1)
81             },
82             GString::Owned(ptr, length) => unsafe {
83                 slice::from_raw_parts(*ptr as *const u8, length + 1)
84             },
85             GString::ForeignOwned(cstring) => cstring
86                 .as_ref()
87                 .expect("ForeignOwned shouldn't be empty")
88                 .as_bytes(),
89         };
90         state.write(bytes);
91     }
92 }
93 
94 impl Borrow<str> for GString {
borrow(&self) -> &str95     fn borrow(&self) -> &str {
96         self.as_str()
97     }
98 }
99 
100 impl Ord for GString {
cmp(&self, other: &GString) -> Ordering101     fn cmp(&self, other: &GString) -> Ordering {
102         self.as_str().cmp(other.as_str())
103     }
104 }
105 
106 impl PartialOrd for GString {
partial_cmp(&self, other: &GString) -> Option<Ordering>107     fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
108         Some(self.cmp(other))
109     }
110 }
111 
112 impl PartialEq for GString {
eq(&self, other: &GString) -> bool113     fn eq(&self, other: &GString) -> bool {
114         self.as_str() == other.as_str()
115     }
116 }
117 
118 impl PartialEq<GString> for String {
eq(&self, other: &GString) -> bool119     fn eq(&self, other: &GString) -> bool {
120         self.as_str() == other.as_str()
121     }
122 }
123 
124 impl PartialEq<str> for GString {
eq(&self, other: &str) -> bool125     fn eq(&self, other: &str) -> bool {
126         self.as_str() == other
127     }
128 }
129 
130 impl<'a> PartialEq<&'a str> for GString {
eq(&self, other: &&'a str) -> bool131     fn eq(&self, other: &&'a str) -> bool {
132         self.as_str() == *other
133     }
134 }
135 
136 impl<'a> PartialEq<GString> for &'a str {
eq(&self, other: &GString) -> bool137     fn eq(&self, other: &GString) -> bool {
138         *self == other.as_str()
139     }
140 }
141 
142 impl PartialEq<String> for GString {
eq(&self, other: &String) -> bool143     fn eq(&self, other: &String) -> bool {
144         self.as_str() == other.as_str()
145     }
146 }
147 
148 impl PartialEq<GString> for str {
eq(&self, other: &GString) -> bool149     fn eq(&self, other: &GString) -> bool {
150         self == other.as_str()
151     }
152 }
153 
154 impl PartialOrd<GString> for String {
partial_cmp(&self, other: &GString) -> Option<Ordering>155     fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
156         Some(self.cmp(&String::from(other.as_str())))
157     }
158 }
159 
160 impl PartialOrd<String> for GString {
partial_cmp(&self, other: &String) -> Option<Ordering>161     fn partial_cmp(&self, other: &String) -> Option<Ordering> {
162         Some(self.as_str().cmp(other.as_str()))
163     }
164 }
165 
166 impl PartialOrd<GString> for str {
partial_cmp(&self, other: &GString) -> Option<Ordering>167     fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
168         Some(self.cmp(&other))
169     }
170 }
171 
172 impl PartialOrd<str> for GString {
partial_cmp(&self, other: &str) -> Option<Ordering>173     fn partial_cmp(&self, other: &str) -> Option<Ordering> {
174         Some(self.as_str().cmp(other))
175     }
176 }
177 
178 impl Eq for GString {}
179 
180 impl AsRef<str> for GString {
as_ref(&self) -> &str181     fn as_ref(&self) -> &str {
182         self.as_str()
183     }
184 }
185 
186 impl AsRef<OsStr> for GString {
as_ref(&self) -> &OsStr187     fn as_ref(&self) -> &OsStr {
188         OsStr::new(self.as_str())
189     }
190 }
191 
192 impl Deref for GString {
193     type Target = str;
194 
deref(&self) -> &str195     fn deref(&self) -> &str {
196         self.as_str()
197     }
198 }
199 
200 impl From<GString> for String {
201     #[inline]
from(mut s: GString) -> Self202     fn from(mut s: GString) -> Self {
203         if let GString::ForeignOwned(ref mut cstring) = s {
204             if let Ok(s) = cstring
205                 .take()
206                 .expect("ForeignOwned shouldn't be empty")
207                 .into_string()
208             {
209                 return s;
210             }
211         }
212         String::from(s.as_str())
213     }
214 }
215 
216 impl From<GString> for Box<str> {
217     #[inline]
from(s: GString) -> Self218     fn from(s: GString) -> Self {
219         let st: String = s.into();
220         st.into_boxed_str()
221     }
222 }
223 
224 impl From<String> for GString {
225     #[inline]
from(s: String) -> Self226     fn from(s: String) -> Self {
227         s.into_bytes().into()
228     }
229 }
230 
231 impl From<Box<str>> for GString {
232     #[inline]
from(s: Box<str>) -> Self233     fn from(s: Box<str>) -> Self {
234         s.as_bytes().to_vec().into()
235     }
236 }
237 
238 impl<'a> From<&'a str> for GString {
239     #[inline]
from(s: &'a str) -> Self240     fn from(s: &'a str) -> Self {
241         s.as_bytes().to_vec().into()
242     }
243 }
244 
245 impl From<Vec<u8>> for GString {
246     #[inline]
from(s: Vec<u8>) -> Self247     fn from(s: Vec<u8>) -> Self {
248         let cstring = CString::new(s).expect("CString::new failed");
249         cstring.into()
250     }
251 }
252 
253 impl From<CString> for GString {
254     #[inline]
from(s: CString) -> Self255     fn from(s: CString) -> Self {
256         GString::ForeignOwned(Some(s))
257     }
258 }
259 
260 impl<'a> From<&'a CStr> for GString {
261     #[inline]
from(c: &'a CStr) -> Self262     fn from(c: &'a CStr) -> Self {
263         CString::from(c).into()
264     }
265 }
266 
267 #[doc(hidden)]
268 impl FromGlibPtrFull<*const c_char> for GString {
269     #[inline]
from_glib_full(ptr: *const c_char) -> Self270     unsafe fn from_glib_full(ptr: *const c_char) -> Self {
271         GString::new(ptr as *mut _)
272     }
273 }
274 
275 #[doc(hidden)]
276 impl FromGlibPtrFull<*mut u8> for GString {
277     #[inline]
from_glib_full(ptr: *mut u8) -> Self278     unsafe fn from_glib_full(ptr: *mut u8) -> Self {
279         GString::new(ptr as *mut _)
280     }
281 }
282 
283 #[doc(hidden)]
284 impl FromGlibPtrFull<*mut i8> for GString {
285     #[inline]
from_glib_full(ptr: *mut i8) -> Self286     unsafe fn from_glib_full(ptr: *mut i8) -> Self {
287         GString::new(ptr as *mut _)
288     }
289 }
290 
291 #[doc(hidden)]
292 impl FromGlibPtrNone<*const c_char> for GString {
293     #[inline]
from_glib_none(ptr: *const c_char) -> Self294     unsafe fn from_glib_none(ptr: *const c_char) -> Self {
295         let cstr = CStr::from_ptr(ptr);
296         cstr.into()
297     }
298 }
299 
300 #[doc(hidden)]
301 impl FromGlibPtrNone<*mut u8> for GString {
302     #[inline]
from_glib_none(ptr: *mut u8) -> Self303     unsafe fn from_glib_none(ptr: *mut u8) -> Self {
304         let cstr = CStr::from_ptr(ptr as *mut _);
305         cstr.into()
306     }
307 }
308 
309 #[doc(hidden)]
310 impl FromGlibPtrNone<*mut i8> for GString {
311     #[inline]
from_glib_none(ptr: *mut i8) -> Self312     unsafe fn from_glib_none(ptr: *mut i8) -> Self {
313         let cstr = CStr::from_ptr(ptr as *mut _);
314         cstr.into()
315     }
316 }
317 
318 #[doc(hidden)]
319 impl FromGlibPtrBorrow<*const c_char> for GString {
320     #[inline]
from_glib_borrow(ptr: *const c_char) -> Self321     unsafe fn from_glib_borrow(ptr: *const c_char) -> Self {
322         GString::new_borrowed(ptr)
323     }
324 }
325 
326 #[doc(hidden)]
327 impl FromGlibPtrBorrow<*mut u8> for GString {
328     #[inline]
from_glib_borrow(ptr: *mut u8) -> Self329     unsafe fn from_glib_borrow(ptr: *mut u8) -> Self {
330         GString::new_borrowed(ptr as *const c_char)
331     }
332 }
333 
334 #[doc(hidden)]
335 impl FromGlibPtrBorrow<*mut i8> for GString {
336     #[inline]
from_glib_borrow(ptr: *mut i8) -> Self337     unsafe fn from_glib_borrow(ptr: *mut i8) -> Self {
338         GString::new_borrowed(ptr as *const c_char)
339     }
340 }
341 
342 #[doc(hidden)]
343 impl<'a> ToGlibPtr<'a, *const c_char> for GString {
344     type Storage = &'a Self;
345 
346     #[inline]
to_glib_none(&'a self) -> Stash<'a, *const c_char, Self>347     fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> {
348         Stash(self.as_ptr() as *const _, self)
349     }
350 
351     #[inline]
to_glib_full(&self) -> *const c_char352     fn to_glib_full(&self) -> *const c_char {
353         unsafe {
354             glib_sys::g_strndup(self.as_ptr() as *const c_char, self.len() as libc::size_t)
355                 as *const c_char
356         }
357     }
358 }
359 
360 #[doc(hidden)]
361 impl<'a> ToGlibPtr<'a, *mut c_char> for GString {
362     type Storage = &'a Self;
363 
364     #[inline]
to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self>365     fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> {
366         Stash(self.as_ptr() as *mut _, self)
367     }
368 
369     #[inline]
to_glib_full(&self) -> *mut c_char370     fn to_glib_full(&self) -> *mut c_char {
371         unsafe {
372             glib_sys::g_strndup(self.as_ptr() as *const c_char, self.len() as libc::size_t)
373                 as *mut c_char
374         }
375     }
376 }
377 
378 impl GlibPtrDefault for GString {
379     type GlibType = *const c_char;
380 }
381 
382 impl StaticType for GString {
static_type() -> Type383     fn static_type() -> Type {
384         String::static_type()
385     }
386 }
387 
388 impl StaticType for Vec<GString> {
static_type() -> Type389     fn static_type() -> Type {
390         unsafe { from_glib(glib_sys::g_strv_get_type()) }
391     }
392 }
393 
394 impl<'a> FromValueOptional<'a> for GString {
from_value_optional(value: &'a Value) -> Option<Self>395     unsafe fn from_value_optional(value: &'a Value) -> Option<Self> {
396         let val = value.to_glib_none().0;
397         if val.is_null() {
398             None
399         } else {
400             let ptr = gobject_sys::g_value_dup_string(val);
401             Some(GString::new(ptr))
402         }
403     }
404 }
405 
406 impl SetValue for GString {
set_value(value: &mut Value, this: &Self)407     unsafe fn set_value(value: &mut Value, this: &Self) {
408         gobject_sys::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full())
409     }
410 }
411 
412 impl SetValueOptional for GString {
set_value_optional(value: &mut Value, this: Option<&Self>)413     unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) {
414         gobject_sys::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full())
415     }
416 }
417 
418 impl_from_glib_container_as_vec_string!(GString, *const c_char);
419 impl_from_glib_container_as_vec_string!(GString, *mut c_char);
420 
421 #[cfg(test)]
422 mod tests {
423     use glib_sys;
424     use gstring::GString;
425     use std::ffi::CString;
426 
427     #[test]
test_gstring()428     fn test_gstring() {
429         let data = CString::new("foo").unwrap();
430         let ptr = data.into_raw();
431 
432         unsafe {
433             let ptr_copy = glib_sys::g_strdup(ptr);
434             let gstring = GString::new(ptr_copy);
435             assert_eq!(gstring.as_str(), "foo");
436             let foo: Box<str> = gstring.into();
437             assert_eq!(foo.as_ref(), "foo");
438         }
439     }
440 
441     #[test]
test_owned_glib_string()442     fn test_owned_glib_string() {
443         let data = CString::new("foo").unwrap();
444         let ptr = data.into_raw();
445         unsafe {
446             let ptr_copy = glib_sys::g_strdup(ptr);
447             let gstr = GString::new(ptr_copy);
448             assert_eq!(gstr, "foo");
449         }
450     }
451 
452     #[test]
test_gstring_from_str()453     fn test_gstring_from_str() {
454         let gstring: GString = "foo".into();
455         assert_eq!(gstring.as_str(), "foo");
456         let foo: Box<str> = gstring.into();
457         assert_eq!(foo.as_ref(), "foo");
458     }
459 
460     #[test]
test_gstring_from_cstring()461     fn test_gstring_from_cstring() {
462         let cstr = CString::new("foo").unwrap();
463         let gstring = GString::from(cstr);
464         assert_eq!(gstring.as_str(), "foo");
465         let foo: Box<str> = gstring.into();
466         assert_eq!(foo.as_ref(), "foo");
467     }
468 
469     #[test]
test_string_from_gstring()470     fn test_string_from_gstring() {
471         let cstr = CString::new("foo").unwrap();
472         let gstring = GString::from(cstr);
473         assert_eq!(gstring.as_str(), "foo");
474         let s = String::from(gstring);
475         assert_eq!(s, "foo");
476     }
477 
478     #[test]
test_vec_u8_to_gstring()479     fn test_vec_u8_to_gstring() {
480         let v = "foo".as_bytes();
481         let s: GString = Vec::from(v).into();
482         assert_eq!(s.as_str(), "foo");
483     }
484 
485     #[test]
test_hashmap()486     fn test_hashmap() {
487         use std::collections::HashMap;
488 
489         let cstr = CString::new("foo").unwrap();
490         let gstring = GString::from(cstr);
491         assert_eq!(gstring.as_str(), "foo");
492         let mut h: HashMap<GString, i32> = HashMap::new();
493         h.insert(gstring, 42);
494         let gstring: GString = "foo".into();
495         assert!(h.contains_key(&gstring));
496     }
497 }
498