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