1 // Take a look at the license at the top of the repository in the LICENSE file.
2 
3 use crate::translate::*;
4 use crate::types::{StaticType, Type};
5 use std::borrow::Borrow;
6 use std::cmp::Ordering;
7 use std::ffi::{CStr, CString, OsStr};
8 use std::fmt;
9 use std::hash;
10 use std::ops::Deref;
11 use std::os::raw::{c_char, c_void};
12 use std::ptr;
13 use std::slice;
14 use std::string::String;
15 
16 pub struct GString(Inner);
17 
18 enum Inner {
19     Native(Option<CString>),
20     Foreign(ptr::NonNull<c_char>, usize),
21 }
22 
23 unsafe impl Send for GString {}
24 unsafe impl Sync for GString {}
25 
26 impl GString {
27     /// Create a new GString from a glib-originated string, taking ownership.
28     ///
29     /// # Safety
30     ///
31     /// The provided string must be a valid C string (i.e. `'0'` terminated).
32     ///
33     /// The provided pointer must be allocated by glib such that `g_free(ptr)`
34     /// is valid, as the `GString` will call `g_free(ptr)` on drop.
35     ///
36     /// It is essential that noone else free this pointer as it owned by the
37     /// returned `GString`.
38     ///
39     /// The underlying string must not be mutated, in particular in terms of
40     /// length, underneath the `GString` instance.
new(ptr: *mut c_char) -> Self41     unsafe fn new(ptr: *mut c_char) -> Self {
42         assert!(!ptr.is_null());
43         Self(Inner::Foreign(
44             ptr::NonNull::new_unchecked(ptr),
45             libc::strlen(ptr),
46         ))
47     }
48 
49     /// Create a new GString from a glib-originated string, borrowing it rather
50     /// than taking ownership.
51     ///
52     /// # Safety
53     ///
54     /// The provided string must be a valid C string (i.e. `'0'` terminated).
55     ///
56     /// It is essential that noone else free this pointer as it owned by the
57     /// returned `GString` until the borrow is dropped.
58     ///
59     /// The underlying string must not be mutated, in particular in terms of
60     /// length, underneath the `GString` instance for the duration of the borrow.
new_borrowed(ptr: *const c_char) -> Borrowed<Self>61     unsafe fn new_borrowed(ptr: *const c_char) -> Borrowed<Self> {
62         assert!(!ptr.is_null());
63         Borrowed::new(GString(Inner::Foreign(
64             ptr::NonNull::new_unchecked(ptr as *mut _),
65             libc::strlen(ptr),
66         )))
67     }
68 
as_str(&self) -> &str69     pub fn as_str(&self) -> &str {
70         let cstr = match self {
71             GString(Inner::Foreign(ptr, length)) => unsafe {
72                 let bytes = slice::from_raw_parts(ptr.as_ptr() as *const u8, length + 1);
73                 CStr::from_bytes_with_nul_unchecked(bytes)
74             },
75             GString(Inner::Native(cstring)) => cstring
76                 .as_ref()
77                 .expect("Native shouldn't be empty")
78                 .as_c_str(),
79         };
80         cstr.to_str().unwrap()
81     }
82 }
83 
84 impl Clone for GString {
clone(&self) -> GString85     fn clone(&self) -> GString {
86         let cstring = CString::new(self.as_str().to_string()).expect("CString::new failed");
87 
88         GString(Inner::Native(Some(cstring)))
89     }
90 }
91 
92 impl fmt::Debug for GString {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result93     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94         <&str as fmt::Debug>::fmt(&self.as_str(), f)
95     }
96 }
97 
98 impl Drop for GString {
drop(&mut self)99     fn drop(&mut self) {
100         if let GString(Inner::Foreign(ptr, _len)) = self {
101             unsafe {
102                 ffi::g_free(ptr.as_ptr() as *mut _);
103             }
104         }
105     }
106 }
107 
108 impl fmt::Display for GString {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result109     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
110         f.write_str(self.as_str())
111     }
112 }
113 
114 impl hash::Hash for GString {
hash<H: hash::Hasher>(&self, state: &mut H)115     fn hash<H: hash::Hasher>(&self, state: &mut H) {
116         let bytes = match self {
117             GString(Inner::Foreign(ptr, length)) => unsafe {
118                 slice::from_raw_parts(ptr.as_ptr() as *const u8, length + 1)
119             },
120             GString(Inner::Native(cstring)) => cstring
121                 .as_ref()
122                 .expect("Native shouldn't be empty")
123                 .as_bytes(),
124         };
125         state.write(bytes);
126     }
127 }
128 
129 impl Borrow<str> for GString {
borrow(&self) -> &str130     fn borrow(&self) -> &str {
131         self.as_str()
132     }
133 }
134 
135 impl Ord for GString {
cmp(&self, other: &GString) -> Ordering136     fn cmp(&self, other: &GString) -> Ordering {
137         self.as_str().cmp(other.as_str())
138     }
139 }
140 
141 impl PartialOrd for GString {
partial_cmp(&self, other: &GString) -> Option<Ordering>142     fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
143         Some(self.cmp(other))
144     }
145 }
146 
147 impl PartialEq for GString {
eq(&self, other: &GString) -> bool148     fn eq(&self, other: &GString) -> bool {
149         self.as_str() == other.as_str()
150     }
151 }
152 
153 impl PartialEq<GString> for String {
eq(&self, other: &GString) -> bool154     fn eq(&self, other: &GString) -> bool {
155         self.as_str() == other.as_str()
156     }
157 }
158 
159 impl PartialEq<str> for GString {
eq(&self, other: &str) -> bool160     fn eq(&self, other: &str) -> bool {
161         self.as_str() == other
162     }
163 }
164 
165 impl<'a> PartialEq<&'a str> for GString {
eq(&self, other: &&'a str) -> bool166     fn eq(&self, other: &&'a str) -> bool {
167         self.as_str() == *other
168     }
169 }
170 
171 impl<'a> PartialEq<GString> for &'a str {
eq(&self, other: &GString) -> bool172     fn eq(&self, other: &GString) -> bool {
173         *self == other.as_str()
174     }
175 }
176 
177 impl PartialEq<String> for GString {
eq(&self, other: &String) -> bool178     fn eq(&self, other: &String) -> bool {
179         self.as_str() == other.as_str()
180     }
181 }
182 
183 impl PartialEq<GString> for str {
eq(&self, other: &GString) -> bool184     fn eq(&self, other: &GString) -> bool {
185         self == other.as_str()
186     }
187 }
188 
189 impl PartialOrd<GString> for String {
partial_cmp(&self, other: &GString) -> Option<Ordering>190     fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
191         Some(self.cmp(&String::from(other.as_str())))
192     }
193 }
194 
195 impl PartialOrd<String> for GString {
partial_cmp(&self, other: &String) -> Option<Ordering>196     fn partial_cmp(&self, other: &String) -> Option<Ordering> {
197         Some(self.as_str().cmp(other.as_str()))
198     }
199 }
200 
201 impl PartialOrd<GString> for str {
partial_cmp(&self, other: &GString) -> Option<Ordering>202     fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
203         Some(self.cmp(other))
204     }
205 }
206 
207 impl PartialOrd<str> for GString {
partial_cmp(&self, other: &str) -> Option<Ordering>208     fn partial_cmp(&self, other: &str) -> Option<Ordering> {
209         Some(self.as_str().cmp(other))
210     }
211 }
212 
213 impl Eq for GString {}
214 
215 impl AsRef<str> for GString {
as_ref(&self) -> &str216     fn as_ref(&self) -> &str {
217         self.as_str()
218     }
219 }
220 
221 impl AsRef<OsStr> for GString {
as_ref(&self) -> &OsStr222     fn as_ref(&self) -> &OsStr {
223         OsStr::new(self.as_str())
224     }
225 }
226 
227 impl Deref for GString {
228     type Target = str;
229 
deref(&self) -> &str230     fn deref(&self) -> &str {
231         self.as_str()
232     }
233 }
234 
235 impl From<GString> for String {
236     #[inline]
from(mut s: GString) -> Self237     fn from(mut s: GString) -> Self {
238         if let GString(Inner::Native(ref mut cstring)) = s {
239             if let Ok(s) = cstring
240                 .take()
241                 .expect("Native shouldn't be empty")
242                 .into_string()
243             {
244                 return s;
245             }
246         }
247         Self::from(s.as_str())
248     }
249 }
250 
251 impl From<GString> for Box<str> {
252     #[inline]
from(s: GString) -> Self253     fn from(s: GString) -> Self {
254         let st: String = s.into();
255         st.into_boxed_str()
256     }
257 }
258 
259 impl From<String> for GString {
260     #[inline]
from(s: String) -> Self261     fn from(s: String) -> Self {
262         s.into_bytes().into()
263     }
264 }
265 
266 impl From<Box<str>> for GString {
267     #[inline]
from(s: Box<str>) -> Self268     fn from(s: Box<str>) -> Self {
269         s.as_bytes().to_vec().into()
270     }
271 }
272 
273 impl<'a> From<&'a str> for GString {
274     #[inline]
from(s: &'a str) -> Self275     fn from(s: &'a str) -> Self {
276         s.as_bytes().to_vec().into()
277     }
278 }
279 
280 impl From<Vec<u8>> for GString {
281     #[inline]
from(s: Vec<u8>) -> Self282     fn from(s: Vec<u8>) -> Self {
283         let cstring = CString::new(s).expect("CString::new failed");
284         cstring.into()
285     }
286 }
287 
288 impl From<CString> for GString {
289     #[inline]
from(s: CString) -> Self290     fn from(s: CString) -> Self {
291         Self(Inner::Native(Some(s)))
292     }
293 }
294 
295 impl<'a> From<&'a CStr> for GString {
296     #[inline]
from(c: &'a CStr) -> Self297     fn from(c: &'a CStr) -> Self {
298         CString::from(c).into()
299     }
300 }
301 
302 #[doc(hidden)]
303 impl FromGlibPtrFull<*const c_char> for GString {
304     #[inline]
from_glib_full(ptr: *const c_char) -> Self305     unsafe fn from_glib_full(ptr: *const c_char) -> Self {
306         Self::new(ptr as *mut _)
307     }
308 }
309 
310 #[doc(hidden)]
311 impl FromGlibPtrFull<*mut u8> for GString {
312     #[inline]
from_glib_full(ptr: *mut u8) -> Self313     unsafe fn from_glib_full(ptr: *mut u8) -> Self {
314         Self::new(ptr as *mut _)
315     }
316 }
317 
318 #[doc(hidden)]
319 impl FromGlibPtrFull<*mut i8> for GString {
320     #[inline]
from_glib_full(ptr: *mut i8) -> Self321     unsafe fn from_glib_full(ptr: *mut i8) -> Self {
322         Self::new(ptr as *mut _)
323     }
324 }
325 
326 #[doc(hidden)]
327 impl FromGlibPtrNone<*const c_char> for GString {
328     #[inline]
from_glib_none(ptr: *const c_char) -> Self329     unsafe fn from_glib_none(ptr: *const c_char) -> Self {
330         assert!(!ptr.is_null());
331         let cstr = CStr::from_ptr(ptr);
332         cstr.into()
333     }
334 }
335 
336 #[doc(hidden)]
337 impl FromGlibPtrNone<*mut u8> for GString {
338     #[inline]
from_glib_none(ptr: *mut u8) -> Self339     unsafe fn from_glib_none(ptr: *mut u8) -> Self {
340         assert!(!ptr.is_null());
341         let cstr = CStr::from_ptr(ptr as *mut _);
342         cstr.into()
343     }
344 }
345 
346 #[doc(hidden)]
347 impl FromGlibPtrNone<*mut i8> for GString {
348     #[inline]
from_glib_none(ptr: *mut i8) -> Self349     unsafe fn from_glib_none(ptr: *mut i8) -> Self {
350         assert!(!ptr.is_null());
351         let cstr = CStr::from_ptr(ptr as *mut _);
352         cstr.into()
353     }
354 }
355 
356 #[doc(hidden)]
357 impl FromGlibPtrBorrow<*const c_char> for GString {
358     #[inline]
from_glib_borrow(ptr: *const c_char) -> Borrowed<Self>359     unsafe fn from_glib_borrow(ptr: *const c_char) -> Borrowed<Self> {
360         Self::new_borrowed(ptr)
361     }
362 }
363 
364 #[doc(hidden)]
365 impl FromGlibPtrBorrow<*mut u8> for GString {
366     #[inline]
from_glib_borrow(ptr: *mut u8) -> Borrowed<Self>367     unsafe fn from_glib_borrow(ptr: *mut u8) -> Borrowed<Self> {
368         Self::new_borrowed(ptr as *const c_char)
369     }
370 }
371 
372 #[doc(hidden)]
373 impl FromGlibPtrBorrow<*mut i8> for GString {
374     #[inline]
from_glib_borrow(ptr: *mut i8) -> Borrowed<Self>375     unsafe fn from_glib_borrow(ptr: *mut i8) -> Borrowed<Self> {
376         Self::new_borrowed(ptr as *const c_char)
377     }
378 }
379 
380 #[doc(hidden)]
381 impl<'a> ToGlibPtr<'a, *const c_char> for GString {
382     type Storage = &'a Self;
383 
384     #[inline]
to_glib_none(&'a self) -> Stash<'a, *const c_char, Self>385     fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> {
386         Stash(self.as_ptr() as *const _, self)
387     }
388 
389     #[inline]
to_glib_full(&self) -> *const c_char390     fn to_glib_full(&self) -> *const c_char {
391         unsafe {
392             ffi::g_strndup(self.as_ptr() as *const c_char, self.len() as libc::size_t)
393                 as *const c_char
394         }
395     }
396 }
397 
398 #[doc(hidden)]
399 impl<'a> ToGlibPtr<'a, *mut c_char> for GString {
400     type Storage = &'a Self;
401 
402     #[inline]
to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self>403     fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> {
404         Stash(self.as_ptr() as *mut _, self)
405     }
406 
407     #[inline]
to_glib_full(&self) -> *mut c_char408     fn to_glib_full(&self) -> *mut c_char {
409         unsafe {
410             ffi::g_strndup(self.as_ptr() as *const c_char, self.len() as libc::size_t)
411                 as *mut c_char
412         }
413     }
414 }
415 
416 #[doc(hidden)]
417 impl<'a> FromGlibContainer<*const c_char, *const i8> for GString {
from_glib_none_num(ptr: *const i8, num: usize) -> Self418     unsafe fn from_glib_none_num(ptr: *const i8, num: usize) -> Self {
419         if num == 0 || ptr.is_null() {
420             return Self::from("");
421         }
422         let mut bytes = Vec::with_capacity(num + 1);
423         let slice = slice::from_raw_parts(ptr as *const u8, num);
424         bytes.extend_from_slice(slice);
425         bytes.push(0);
426 
427         CStr::from_bytes_with_nul_unchecked(bytes.as_slice()).into()
428     }
429 
from_glib_container_num(ptr: *const i8, num: usize) -> Self430     unsafe fn from_glib_container_num(ptr: *const i8, num: usize) -> Self {
431         if num == 0 || ptr.is_null() {
432             return Self::from("");
433         }
434         GString(Inner::Foreign(
435             ptr::NonNull::new_unchecked(ptr as *mut _),
436             num,
437         ))
438     }
439 
from_glib_full_num(ptr: *const i8, num: usize) -> Self440     unsafe fn from_glib_full_num(ptr: *const i8, num: usize) -> Self {
441         if num == 0 || ptr.is_null() {
442             return Self::from("");
443         }
444         GString(Inner::Foreign(
445             ptr::NonNull::new_unchecked(ptr as *mut _),
446             num,
447         ))
448     }
449 }
450 
451 #[doc(hidden)]
452 impl<'a> FromGlibContainer<*const c_char, *mut i8> for GString {
from_glib_none_num(ptr: *mut i8, num: usize) -> Self453     unsafe fn from_glib_none_num(ptr: *mut i8, num: usize) -> Self {
454         FromGlibContainer::from_glib_none_num(ptr as *const i8, num)
455     }
456 
from_glib_container_num(ptr: *mut i8, num: usize) -> Self457     unsafe fn from_glib_container_num(ptr: *mut i8, num: usize) -> Self {
458         FromGlibContainer::from_glib_container_num(ptr as *const i8, num)
459     }
460 
from_glib_full_num(ptr: *mut i8, num: usize) -> Self461     unsafe fn from_glib_full_num(ptr: *mut i8, num: usize) -> Self {
462         FromGlibContainer::from_glib_full_num(ptr as *const i8, num)
463     }
464 }
465 
466 #[doc(hidden)]
467 impl<'a> FromGlibContainer<*const c_char, *const u8> for GString {
from_glib_none_num(ptr: *const u8, num: usize) -> Self468     unsafe fn from_glib_none_num(ptr: *const u8, num: usize) -> Self {
469         FromGlibContainer::from_glib_none_num(ptr as *const i8, num)
470     }
471 
from_glib_container_num(ptr: *const u8, num: usize) -> Self472     unsafe fn from_glib_container_num(ptr: *const u8, num: usize) -> Self {
473         FromGlibContainer::from_glib_container_num(ptr as *const i8, num)
474     }
475 
from_glib_full_num(ptr: *const u8, num: usize) -> Self476     unsafe fn from_glib_full_num(ptr: *const u8, num: usize) -> Self {
477         FromGlibContainer::from_glib_full_num(ptr as *const i8, num)
478     }
479 }
480 
481 #[doc(hidden)]
482 impl<'a> FromGlibContainer<*const c_char, *mut u8> for GString {
from_glib_none_num(ptr: *mut u8, num: usize) -> Self483     unsafe fn from_glib_none_num(ptr: *mut u8, num: usize) -> Self {
484         FromGlibContainer::from_glib_none_num(ptr as *const i8, num)
485     }
486 
from_glib_container_num(ptr: *mut u8, num: usize) -> Self487     unsafe fn from_glib_container_num(ptr: *mut u8, num: usize) -> Self {
488         FromGlibContainer::from_glib_container_num(ptr as *const i8, num)
489     }
490 
from_glib_full_num(ptr: *mut u8, num: usize) -> Self491     unsafe fn from_glib_full_num(ptr: *mut u8, num: usize) -> Self {
492         FromGlibContainer::from_glib_full_num(ptr as *const i8, num)
493     }
494 }
495 
496 impl GlibPtrDefault for GString {
497     type GlibType = *const c_char;
498 }
499 
500 impl StaticType for GString {
static_type() -> Type501     fn static_type() -> Type {
502         String::static_type()
503     }
504 }
505 
506 impl crate::value::ValueType for GString {
507     type Type = String;
508 }
509 
510 unsafe impl<'a> crate::value::FromValue<'a> for GString {
511     type Checker = crate::value::GenericValueTypeOrNoneChecker<Self>;
512 
from_value(value: &'a crate::Value) -> Self513     unsafe fn from_value(value: &'a crate::Value) -> Self {
514         Self::from(<&str>::from_value(value))
515     }
516 }
517 
518 impl crate::value::ToValue for GString {
to_value(&self) -> crate::Value519     fn to_value(&self) -> crate::Value {
520         <&str>::to_value(&self.as_str())
521     }
522 
value_type(&self) -> Type523     fn value_type(&self) -> Type {
524         String::static_type()
525     }
526 }
527 
528 impl crate::value::ToValueOptional for GString {
to_value_optional(s: Option<&Self>) -> crate::Value529     fn to_value_optional(s: Option<&Self>) -> crate::Value {
530         <str>::to_value_optional(s.as_ref().map(|s| s.as_str()))
531     }
532 }
533 
534 impl StaticType for Vec<GString> {
static_type() -> Type535     fn static_type() -> Type {
536         <Vec<String>>::static_type()
537     }
538 }
539 
540 impl crate::value::ValueType for Vec<GString> {
541     type Type = Vec<GString>;
542 }
543 
544 unsafe impl<'a> crate::value::FromValue<'a> for Vec<GString> {
545     type Checker = crate::value::GenericValueTypeChecker<Self>;
546 
from_value(value: &'a crate::value::Value) -> Self547     unsafe fn from_value(value: &'a crate::value::Value) -> Self {
548         let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const *const c_char;
549         FromGlibPtrContainer::from_glib_none(ptr)
550     }
551 }
552 
553 impl crate::value::ToValue for Vec<GString> {
to_value(&self) -> crate::value::Value554     fn to_value(&self) -> crate::value::Value {
555         unsafe {
556             let mut value = crate::value::Value::for_value_type::<Self>();
557             let ptr: *mut *mut c_char = self.to_glib_full();
558             gobject_ffi::g_value_take_boxed(value.to_glib_none_mut().0, ptr as *const c_void);
559             value
560         }
561     }
562 
value_type(&self) -> Type563     fn value_type(&self) -> Type {
564         <Vec<GString>>::static_type()
565     }
566 }
567 
568 impl_from_glib_container_as_vec_string!(GString, *const c_char);
569 impl_from_glib_container_as_vec_string!(GString, *mut c_char);
570 
571 #[cfg(test)]
572 #[allow(clippy::blacklisted_name)]
573 mod tests {
574     use super::{FromGlibContainer, GString};
575     use std::ffi::CString;
576 
577     #[test]
test_gstring()578     fn test_gstring() {
579         let data = CString::new("foo").unwrap();
580         let ptr = data.as_ptr();
581 
582         unsafe {
583             let ptr_copy = ffi::g_strdup(ptr);
584             let gstring = GString::new(ptr_copy);
585             assert_eq!(gstring.as_str(), "foo");
586             let foo: Box<str> = gstring.into();
587             assert_eq!(foo.as_ref(), "foo");
588         }
589     }
590 
591     #[test]
test_owned_glib_string()592     fn test_owned_glib_string() {
593         let data = CString::new("foo").unwrap();
594         let ptr = data.as_ptr();
595         unsafe {
596             let ptr_copy = ffi::g_strdup(ptr);
597             let gstr = GString::new(ptr_copy);
598             assert_eq!(gstr, "foo");
599         }
600     }
601 
602     #[test]
test_gstring_from_str()603     fn test_gstring_from_str() {
604         let gstring: GString = "foo".into();
605         assert_eq!(gstring.as_str(), "foo");
606         let foo: Box<str> = gstring.into();
607         assert_eq!(foo.as_ref(), "foo");
608     }
609 
610     #[test]
test_gstring_from_cstring()611     fn test_gstring_from_cstring() {
612         let cstr = CString::new("foo").unwrap();
613         let gstring = GString::from(cstr);
614         assert_eq!(gstring.as_str(), "foo");
615         let foo: Box<str> = gstring.into();
616         assert_eq!(foo.as_ref(), "foo");
617     }
618 
619     #[test]
test_string_from_gstring()620     fn test_string_from_gstring() {
621         let cstr = CString::new("foo").unwrap();
622         let gstring = GString::from(cstr);
623         assert_eq!(gstring.as_str(), "foo");
624         let s = String::from(gstring);
625         assert_eq!(s, "foo");
626     }
627 
628     #[test]
test_vec_u8_to_gstring()629     fn test_vec_u8_to_gstring() {
630         let v: &[u8] = b"foo";
631         let s: GString = Vec::from(v).into();
632         assert_eq!(s.as_str(), "foo");
633     }
634 
635     #[test]
test_from_glib_container()636     fn test_from_glib_container() {
637         unsafe {
638             let test_a: GString = FromGlibContainer::from_glib_container_num(
639                 ffi::g_strdup("hello_world".as_ptr() as *const _),
640                 5,
641             );
642             assert_eq!("hello", test_a.as_str());
643 
644             let test_b: GString = FromGlibContainer::from_glib_none_num("hello_world".as_ptr(), 5);
645             assert_eq!("hello", test_b.as_str());
646 
647             let test_c: GString =
648                 FromGlibContainer::from_glib_none_num(std::ptr::null::<std::os::raw::c_char>(), 0);
649             assert_eq!("", test_c.as_str());
650 
651             let test_d: GString = FromGlibContainer::from_glib_none_num("".as_ptr(), 0);
652             assert_eq!("", test_d.as_str());
653 
654             let test_e: GString =
655                 FromGlibContainer::from_glib_container_num(ffi::g_strdup(std::ptr::null()), 0);
656             assert_eq!("", test_e.as_str());
657         }
658     }
659 
660     #[test]
test_hashmap()661     fn test_hashmap() {
662         use std::collections::HashMap;
663 
664         let cstr = CString::new("foo").unwrap();
665         let gstring = GString::from(cstr);
666         assert_eq!(gstring.as_str(), "foo");
667         let mut h: HashMap<GString, i32> = HashMap::new();
668         h.insert(gstring, 42);
669         let gstring: GString = "foo".into();
670         assert!(h.contains_key(&gstring));
671     }
672 }
673