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