1use libc;
6use std::borrow::Borrow;
7use std::cmp::Ordering;
8use std::ffi::{CStr, CString, OsStr};
9use std::fmt;
10use std::hash;
11use std::ops::Deref;
12use std::os::raw::c_char;
13use std::ptr;
14use std::slice;
15use std::string::String;
16use translate::*;
17use types::{StaticType, Type};
18
19use glib_sys;
20use gobject_sys;
21use value::{FromValueOptional, SetValue, SetValueOptional, Value};
22
23#[derive(Debug)]
24pub enum GString {
25 ForeignOwned(Option<CString>),
26 Borrowed(*const c_char, usize),
27 Owned(*mut c_char, usize),
28}
29
30impl GString {
31 pub unsafe fn new(ptr: *mut c_char) -> Self {
32 assert!(!ptr.is_null());
33 GString::Owned(ptr, libc::strlen(ptr))
34 }
35
36 pub unsafe fn new_borrowed(ptr: *const c_char) -> Self {
37 assert!(!ptr.is_null());
38 GString::Borrowed(ptr, libc::strlen(ptr))
39 }
40
41 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
60impl Drop for GString {
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
70impl fmt::Display for GString {
71 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72 write!(f, "{}", self.as_str())
73 }
74}
75
76impl hash::Hash for GString {
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
94impl Borrow<str> for GString {
95 fn borrow(&self) -> &str {
96 self.as_str()
97 }
98}
99
100impl Ord for GString {
101 fn cmp(&self, other: &GString) -> Ordering {
102 self.as_str().cmp(other.as_str())
103 }
104}
105
106impl PartialOrd for GString {
107 fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
108 Some(self.cmp(other))
109 }
110}
111
112impl PartialEq for GString {
113 fn eq(&self, other: &GString) -> bool {
114 self.as_str() == other.as_str()
115 }
116}
117
118impl PartialEq<GString> for String {
119 fn eq(&self, other: &GString) -> bool {
120 self.as_str() == other.as_str()
121 }
122}
123
124impl PartialEq<str> for GString {
125 fn eq(&self, other: &str) -> bool {
126 self.as_str() == other
127 }
128}
129
130impl<'a> PartialEq<&'a str> for GString {
131 fn eq(&self, other: &&'a str) -> bool {
132 self.as_str() == *other
133 }
134}
135
136impl<'a> PartialEq<GString> for &'a str {
137 fn eq(&self, other: &GString) -> bool {
138 *self == other.as_str()
139 }
140}
141
142impl PartialEq<String> for GString {
143 fn eq(&self, other: &String) -> bool {
144 self.as_str() == other.as_str()
145 }
146}
147
148impl PartialEq<GString> for str {
149 fn eq(&self, other: &GString) -> bool {
150 self == other.as_str()
151 }
152}
153
154impl PartialOrd<GString> for String {
155 fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
156 Some(self.cmp(&String::from(other.as_str())))
157 }
158}
159
160impl PartialOrd<String> for GString {
161 fn partial_cmp(&self, other: &String) -> Option<Ordering> {
162 Some(self.as_str().cmp(other.as_str()))
163 }
164}
165
166impl PartialOrd<GString> for str {
167 fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
168 Some(self.cmp(&other))
169 }
170}
171
172impl PartialOrd<str> for GString {
173 fn partial_cmp(&self, other: &str) -> Option<Ordering> {
174 Some(self.as_str().cmp(other))
175 }
176}
177
178impl Eq for GString {}
179
180impl AsRef<str> for GString {
181 fn as_ref(&self) -> &str {
182 self.as_str()
183 }
184}
185
186impl AsRef<OsStr> for GString {
187 fn as_ref(&self) -> &OsStr {
188 OsStr::new(self.as_str())
189 }
190}
191
192impl Deref for GString {
193 type Target = str;
194
195 fn deref(&self) -> &str {
196 self.as_str()
197 }
198}
199
200impl From<GString> for String {
201 #[inline]
202 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
216impl From<GString> for Box<str> {
217 #[inline]
218 fn from(s: GString) -> Self {
219 let st: String = s.into();
220 st.into_boxed_str()
221 }
222}
223
224impl From<String> for GString {
225 #[inline]
226 fn from(s: String) -> Self {
227 s.into_bytes().into()
228 }
229}
230
231impl From<Box<str>> for GString {
232 #[inline]
233 fn from(s: Box<str>) -> Self {
234 s.as_bytes().to_vec().into()
235 }
236}
237
238impl<'a> From<&'a str> for GString {
239 #[inline]
240 fn from(s: &'a str) -> Self {
241 s.as_bytes().to_vec().into()
242 }
243}
244
245impl From<Vec<u8>> for GString {
246 #[inline]
247 fn from(s: Vec<u8>) -> Self {
248 let cstring = CString::new(s).expect("CString::new failed");
249 cstring.into()
250 }
251}
252
253impl From<CString> for GString {
254 #[inline]
255 fn from(s: CString) -> Self {
256 GString::ForeignOwned(Some(s))
257 }
258}
259
260impl<'a> From<&'a CStr> for GString {
261 #[inline]
262 fn from(c: &'a CStr) -> Self {
263 CString::from(c).into()
264 }
265}
266
267#[doc(hidden)]
268impl FromGlibPtrFull<*const c_char> for GString {
269 #[inline]
270 unsafe fn from_glib_full(ptr: *const c_char) -> Self {
271 GString::new(ptr as *mut _)
272 }
273}
274
275#[doc(hidden)]
276impl FromGlibPtrFull<*mut u8> for GString {
277 #[inline]
278 unsafe fn from_glib_full(ptr: *mut u8) -> Self {
279 GString::new(ptr as *mut _)
280 }
281}
282
283#[doc(hidden)]
284impl FromGlibPtrFull<*mut i8> for GString {
285 #[inline]
286 unsafe fn from_glib_full(ptr: *mut i8) -> Self {
287 GString::new(ptr as *mut _)
288 }
289}
290
291#[doc(hidden)]
292impl FromGlibPtrNone<*const c_char> for GString {
293 #[inline]
294 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)]
301impl FromGlibPtrNone<*mut u8> for GString {
302 #[inline]
303 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)]
310impl FromGlibPtrNone<*mut i8> for GString {
311 #[inline]
312 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)]
319impl FromGlibPtrBorrow<*const c_char> for GString {
320 #[inline]
321 unsafe fn from_glib_borrow(ptr: *const c_char) -> Self {
322 GString::new_borrowed(ptr)
323 }
324}
325
326#[doc(hidden)]
327impl FromGlibPtrBorrow<*mut u8> for GString {
328 #[inline]
329 unsafe fn from_glib_borrow(ptr: *mut u8) -> Self {
330 GString::new_borrowed(ptr as *const c_char)
331 }
332}
333
334#[doc(hidden)]
335impl FromGlibPtrBorrow<*mut i8> for GString {
336 #[inline]
337 unsafe fn from_glib_borrow(ptr: *mut i8) -> Self {
338 GString::new_borrowed(ptr as *const c_char)
339 }
340}
341
342#[doc(hidden)]
343impl<'a> ToGlibPtr<'a, *const c_char> for GString {
344 type Storage = &'a Self;
345
346 #[inline]
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]
352 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)]
361impl<'a> ToGlibPtr<'a, *mut c_char> for GString {
362 type Storage = &'a Self;
363
364 #[inline]
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]
370 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
378impl GlibPtrDefault for GString {
379 type GlibType = *const c_char;
380}
381
382impl StaticType for GString {
383 fn static_type() -> Type {
384 String::static_type()
385 }
386}
387
388impl StaticType for Vec<GString> {
389 fn static_type() -> Type {
390 unsafe { from_glib(glib_sys::g_strv_get_type()) }
391 }
392}
393
394impl<'a> FromValueOptional<'a> for GString {
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
406impl SetValue for GString {
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
412impl SetValueOptional for GString {
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
418impl_from_glib_container_as_vec_string!(GString, *const c_char);
419impl_from_glib_container_as_vec_string!(GString, *mut c_char);
420
421#[cfg(test)]
422mod tests {
423 use glib_sys;
424 use gstring::GString;
425 use std::ffi::CString;
426
427 #[test]
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]
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]
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]
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]
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]
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]
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}