use crate::translate::*;
use crate::types::{StaticType, Type};
use std::borrow::{Borrow, Cow};
use std::cmp::Ordering;
use std::ffi::{CStr, CString, OsStr};
use std::fmt;
use std::hash;
use std::mem;
use std::ops::Deref;
use std::os::raw::{c_char, c_void};
use std::path::Path;
use std::ptr;
use std::slice;
use std::string::String;
#[derive(Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct GStr(str);
impl GStr {
pub fn from_str_with_nul(s: &str) -> Result<&Self, std::ffi::FromBytesWithNulError> {
let bytes = s.as_bytes();
CStr::from_bytes_with_nul(bytes)?;
Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
}
#[inline]
pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &Self {
debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0);
mem::transmute(bytes)
}
#[inline]
pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a Self {
let cstr = CStr::from_ptr(ptr);
Self::from_bytes_with_nul_unchecked(cstr.to_bytes_with_nul())
}
#[inline]
pub fn to_bytes_with_nul(&self) -> &[u8] {
self.0.as_bytes()
}
#[inline]
pub fn to_bytes(&self) -> &[u8] {
self.as_str().as_bytes()
}
#[inline]
pub fn as_ptr(&self) -> *const c_char {
self.0.as_ptr() as *const _
}
#[inline]
pub fn as_str(&self) -> &str {
&self.0[0..self.0.len() - 1]
}
#[inline]
pub fn as_c_str(&self) -> &CStr {
unsafe { CStr::from_bytes_with_nul_unchecked(self.to_bytes_with_nul()) }
}
}
#[macro_export]
macro_rules! gstr {
($s:literal) => {
unsafe { $crate::GStr::from_bytes_with_nul_unchecked($crate::cstr_bytes!($s)) }
};
}
impl Default for &GStr {
fn default() -> Self {
const SLICE: &[c_char] = &[0];
unsafe { GStr::from_ptr(SLICE.as_ptr()) }
}
}
impl<'a> TryFrom<&'a CStr> for &'a GStr {
type Error = std::str::Utf8Error;
#[inline]
fn try_from(s: &'a CStr) -> Result<Self, Self::Error> {
s.to_str()?;
Ok(unsafe { GStr::from_bytes_with_nul_unchecked(s.to_bytes_with_nul()) })
}
}
impl PartialEq<GStr> for String {
fn eq(&self, other: &GStr) -> bool {
self.as_str() == other.as_str()
}
}
impl PartialEq<str> for GStr {
fn eq(&self, other: &str) -> bool {
self.as_str() == other
}
}
impl<'a> PartialEq<&'a str> for GStr {
fn eq(&self, other: &&'a str) -> bool {
self.as_str() == *other
}
}
impl<'a> PartialEq<GStr> for &'a str {
fn eq(&self, other: &GStr) -> bool {
*self == other.as_str()
}
}
impl PartialEq<String> for GStr {
fn eq(&self, other: &String) -> bool {
self.as_str() == other.as_str()
}
}
impl PartialEq<GStr> for str {
fn eq(&self, other: &GStr) -> bool {
self == other.as_str()
}
}
impl PartialOrd<GStr> for String {
fn partial_cmp(&self, other: &GStr) -> Option<Ordering> {
Some(self.cmp(&String::from(other.as_str())))
}
}
impl PartialOrd<String> for GStr {
fn partial_cmp(&self, other: &String) -> Option<Ordering> {
Some(self.as_str().cmp(other.as_str()))
}
}
impl PartialOrd<GStr> for str {
fn partial_cmp(&self, other: &GStr) -> Option<Ordering> {
Some(self.cmp(other.as_str()))
}
}
impl PartialOrd<str> for GStr {
fn partial_cmp(&self, other: &str) -> Option<Ordering> {
Some(self.as_str().cmp(other))
}
}
impl AsRef<GStr> for GStr {
fn as_ref(&self) -> &GStr {
self
}
}
impl AsRef<str> for GStr {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl AsRef<CStr> for GStr {
fn as_ref(&self) -> &CStr {
self.as_c_str()
}
}
impl AsRef<OsStr> for GStr {
fn as_ref(&self) -> &OsStr {
OsStr::new(self.as_str())
}
}
impl AsRef<Path> for GStr {
fn as_ref(&self) -> &Path {
Path::new(self.as_str())
}
}
impl AsRef<[u8]> for GStr {
fn as_ref(&self) -> &[u8] {
self.to_bytes()
}
}
impl Deref for GStr {
type Target = str;
fn deref(&self) -> &str {
self.as_str()
}
}
impl ToOwned for GStr {
type Owned = GString;
#[inline]
fn to_owned(&self) -> Self::Owned {
GString(Inner::Native(Some(self.as_c_str().to_owned())))
}
}
impl GlibPtrDefault for GStr {
type GlibType = *mut c_char;
}
impl StaticType for GStr {
fn static_type() -> Type {
str::static_type()
}
}
unsafe impl<'a> crate::value::FromValue<'a> for &'a GStr {
type Checker = crate::value::GenericValueTypeOrNoneChecker<Self>;
unsafe fn from_value(value: &'a crate::Value) -> Self {
let ptr = gobject_ffi::g_value_get_string(value.to_glib_none().0);
let cstr = CStr::from_ptr(ptr);
assert!(cstr.to_str().is_ok());
GStr::from_bytes_with_nul_unchecked(cstr.to_bytes_with_nul())
}
}
impl crate::value::ToValue for GStr {
#[inline]
fn to_value(&self) -> crate::Value {
self.as_str().to_value()
}
#[inline]
fn value_type(&self) -> Type {
str::static_type()
}
}
impl crate::value::ToValue for &GStr {
#[inline]
fn to_value(&self) -> crate::Value {
(*self).to_value()
}
#[inline]
fn value_type(&self) -> Type {
str::static_type()
}
}
impl crate::value::ToValueOptional for GStr {
#[inline]
fn to_value_optional(s: Option<&Self>) -> crate::Value {
crate::value::ToValueOptional::to_value_optional(s.map(|s| s.as_str()))
}
}
#[doc(hidden)]
impl<'a> ToGlibPtr<'a, *const c_char> for GStr {
type Storage = GString;
#[inline]
fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> {
let tmp = self.to_owned();
Stash(self.as_ptr(), tmp)
}
#[inline]
fn to_glib_full(&self) -> *const c_char {
self.as_str().to_glib_full()
}
}
#[doc(hidden)]
impl<'a> ToGlibPtr<'a, *mut c_char> for GStr {
type Storage = GString;
#[inline]
fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> {
let tmp = self.to_owned();
Stash(tmp.as_ptr() as *mut c_char, tmp)
}
#[inline]
fn to_glib_full(&self) -> *mut c_char {
self.as_str().to_glib_full()
}
}
pub struct GString(Inner);
enum Inner {
Native(Option<CString>),
Foreign {
ptr: ptr::NonNull<c_char>,
len: usize,
},
}
unsafe impl Send for GString {}
unsafe impl Sync for GString {}
impl GString {
pub fn as_str(&self) -> &str {
unsafe {
let (ptr, len) = match self.0 {
Inner::Native(ref cstr) => {
let cstr = cstr.as_ref().unwrap();
(cstr.as_ptr() as *const u8, cstr.to_bytes().len())
}
Inner::Foreign { ptr, len } => (ptr.as_ptr() as *const u8, len),
};
if len == 0 {
""
} else {
let slice = slice::from_raw_parts(ptr, len);
std::str::from_utf8_unchecked(slice)
}
}
}
pub fn as_gstr(&self) -> &GStr {
let bytes = match self.0 {
Inner::Native(ref cstr) => cstr.as_ref().unwrap().to_bytes_with_nul(),
Inner::Foreign { len, .. } if len == 0 => &[0],
Inner::Foreign { ptr, len } => unsafe {
slice::from_raw_parts(ptr.as_ptr() as *const _, len + 1)
},
};
unsafe { GStr::from_bytes_with_nul_unchecked(bytes) }
}
pub fn as_ptr(&self) -> *const c_char {
match self.0 {
Inner::Native(ref cstr) => cstr.as_ref().unwrap().as_ptr() as *const _,
Inner::Foreign { ptr, .. } => ptr.as_ptr(),
}
}
}
impl IntoGlibPtr<*mut c_char> for GString {
unsafe fn into_glib_ptr(self) -> *mut c_char {
match self.0 {
Inner::Native(ref cstr) => {
let cstr = cstr.as_ref().unwrap();
let ptr = cstr.as_ptr();
let len = cstr.to_bytes().len();
let copy = ffi::g_malloc(len + 1) as *mut c_char;
ptr::copy_nonoverlapping(ptr as *const c_char, copy, len + 1);
ptr::write(copy.add(len), 0);
copy
}
Inner::Foreign { ptr, .. } => {
let _s = mem::ManuallyDrop::new(self);
ptr.as_ptr()
}
}
}
}
impl Clone for GString {
fn clone(&self) -> GString {
self.as_str().into()
}
}
impl fmt::Debug for GString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<&str as fmt::Debug>::fmt(&self.as_str(), f)
}
}
impl Drop for GString {
fn drop(&mut self) {
if let Inner::Foreign { ptr, .. } = self.0 {
unsafe {
ffi::g_free(ptr.as_ptr() as *mut _);
}
}
}
}
impl fmt::Display for GString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl hash::Hash for GString {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.as_str().hash(state)
}
}
impl Borrow<GStr> for GString {
fn borrow(&self) -> &GStr {
self.as_gstr()
}
}
impl Borrow<str> for GString {
fn borrow(&self) -> &str {
self.as_str()
}
}
impl Ord for GString {
fn cmp(&self, other: &GString) -> Ordering {
self.as_str().cmp(other.as_str())
}
}
impl PartialOrd for GString {
fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for GString {
fn eq(&self, other: &GString) -> bool {
self.as_str() == other.as_str()
}
}
impl PartialEq<GString> for String {
fn eq(&self, other: &GString) -> bool {
self.as_str() == other.as_str()
}
}
impl PartialEq<GStr> for GString {
fn eq(&self, other: &GStr) -> bool {
self.as_str() == other.as_str()
}
}
impl PartialEq<&GStr> for GString {
fn eq(&self, other: &&GStr) -> bool {
self.as_str() == other.as_str()
}
}
impl PartialEq<str> for GString {
fn eq(&self, other: &str) -> bool {
self.as_str() == other
}
}
impl PartialEq<&str> for GString {
fn eq(&self, other: &&str) -> bool {
self.as_str() == *other
}
}
impl PartialEq<GString> for &GStr {
fn eq(&self, other: &GString) -> bool {
self.as_str() == other.as_str()
}
}
impl PartialEq<GString> for &str {
fn eq(&self, other: &GString) -> bool {
*self == other.as_str()
}
}
impl PartialEq<String> for GString {
fn eq(&self, other: &String) -> bool {
self.as_str() == other.as_str()
}
}
impl PartialEq<GString> for str {
fn eq(&self, other: &GString) -> bool {
self == other.as_str()
}
}
impl PartialEq<GString> for GStr {
fn eq(&self, other: &GString) -> bool {
self.as_str() == other.as_str()
}
}
impl PartialOrd<GString> for String {
fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
Some(self.cmp(&String::from(other.as_str())))
}
}
impl PartialOrd<String> for GString {
fn partial_cmp(&self, other: &String) -> Option<Ordering> {
Some(self.as_str().cmp(other.as_str()))
}
}
impl PartialOrd<GString> for GStr {
fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
Some(self.as_str().cmp(other))
}
}
impl PartialOrd<GStr> for GString {
fn partial_cmp(&self, other: &GStr) -> Option<Ordering> {
Some(self.as_str().cmp(other.as_str()))
}
}
impl PartialOrd<GString> for str {
fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialOrd<str> for GString {
fn partial_cmp(&self, other: &str) -> Option<Ordering> {
Some(self.as_str().cmp(other))
}
}
impl Eq for GString {}
impl AsRef<GStr> for GString {
fn as_ref(&self) -> &GStr {
self.as_gstr()
}
}
impl AsRef<str> for GString {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl AsRef<CStr> for GString {
fn as_ref(&self) -> &CStr {
self.as_gstr().as_c_str()
}
}
impl AsRef<OsStr> for GString {
fn as_ref(&self) -> &OsStr {
OsStr::new(self.as_str())
}
}
impl AsRef<Path> for GString {
fn as_ref(&self) -> &Path {
Path::new(self.as_str())
}
}
impl AsRef<[u8]> for GString {
fn as_ref(&self) -> &[u8] {
self.as_str().as_bytes()
}
}
impl Deref for GString {
type Target = str;
fn deref(&self) -> &str {
self.as_str()
}
}
impl From<GString> for String {
#[inline]
fn from(mut s: GString) -> Self {
match s.0 {
Inner::Foreign { len, .. } if len == 0 => String::new(),
Inner::Foreign { ptr, len } => unsafe {
let slice = slice::from_raw_parts(ptr.as_ptr() as *const u8, len);
std::str::from_utf8_unchecked(slice).into()
},
Inner::Native(ref mut cstr) => {
cstr.take().unwrap().into_string().unwrap()
}
}
}
}
impl From<GString> for Box<str> {
#[inline]
fn from(s: GString) -> Self {
let st: String = s.into();
st.into_boxed_str()
}
}
impl From<String> for GString {
#[inline]
fn from(s: String) -> Self {
unsafe {
let cstr = CString::from_vec_unchecked(s.into_bytes());
GString(Inner::Native(Some(cstr)))
}
}
}
impl From<Box<str>> for GString {
#[inline]
fn from(s: Box<str>) -> Self {
s.into_string().into()
}
}
impl From<&GStr> for GString {
#[inline]
fn from(s: &GStr) -> GString {
s.to_owned()
}
}
impl From<&str> for GString {
#[inline]
fn from(s: &str) -> Self {
unsafe {
let copy = ffi::g_malloc(s.len() + 1) as *mut c_char;
ptr::copy_nonoverlapping(s.as_ptr() as *const c_char, copy, s.len());
ptr::write(copy.add(s.len()), 0);
GString(Inner::Foreign {
ptr: ptr::NonNull::new_unchecked(copy),
len: s.len(),
})
}
}
}
impl From<Vec<u8>> for GString {
#[inline]
fn from(s: Vec<u8>) -> Self {
let cstring = CString::new(s).expect("CString::new failed");
cstring.into()
}
}
impl From<CString> for GString {
#[inline]
fn from(s: CString) -> Self {
assert!(s.to_str().is_ok());
Self(Inner::Native(Some(s)))
}
}
impl From<&CStr> for GString {
#[inline]
fn from(c: &CStr) -> Self {
c.to_str().unwrap().into()
}
}
impl<'a> From<GString> for Cow<'a, GStr> {
fn from(v: GString) -> Self {
Cow::Owned(v)
}
}
impl<'a> From<&'a GStr> for Cow<'a, GStr> {
fn from(v: &'a GStr) -> Self {
Cow::Borrowed(v)
}
}
#[doc(hidden)]
impl FromGlibPtrFull<*mut u8> for GString {
#[inline]
unsafe fn from_glib_full(ptr: *mut u8) -> Self {
assert!(!ptr.is_null());
let cstr = CStr::from_ptr(ptr as *const _);
assert!(cstr.to_str().is_ok());
GString(Inner::Foreign {
ptr: ptr::NonNull::new_unchecked(ptr as *mut _),
len: cstr.to_bytes().len(),
})
}
}
#[doc(hidden)]
impl FromGlibPtrFull<*mut i8> for GString {
#[inline]
unsafe fn from_glib_full(ptr: *mut i8) -> Self {
from_glib_full(ptr as *mut u8)
}
}
#[doc(hidden)]
impl FromGlibPtrFull<*const u8> for GString {
#[inline]
unsafe fn from_glib_full(ptr: *const u8) -> Self {
from_glib_full(ptr as *mut u8)
}
}
#[doc(hidden)]
impl FromGlibPtrFull<*const i8> for GString {
#[inline]
unsafe fn from_glib_full(ptr: *const i8) -> Self {
from_glib_full(ptr as *mut u8)
}
}
#[doc(hidden)]
impl FromGlibPtrNone<*const u8> for GString {
#[inline]
unsafe fn from_glib_none(ptr: *const u8) -> Self {
assert!(!ptr.is_null());
let cstr = CStr::from_ptr(ptr as *const _);
cstr.to_str().unwrap().into()
}
}
#[doc(hidden)]
impl FromGlibPtrNone<*const i8> for GString {
#[inline]
unsafe fn from_glib_none(ptr: *const i8) -> Self {
from_glib_none(ptr as *const u8)
}
}
#[doc(hidden)]
impl FromGlibPtrNone<*mut u8> for GString {
#[inline]
unsafe fn from_glib_none(ptr: *mut u8) -> Self {
from_glib_none(ptr as *const u8)
}
}
#[doc(hidden)]
impl FromGlibPtrNone<*mut i8> for GString {
#[inline]
unsafe fn from_glib_none(ptr: *mut i8) -> Self {
from_glib_none(ptr as *const u8)
}
}
#[doc(hidden)]
impl FromGlibPtrBorrow<*const u8> for GString {
#[inline]
unsafe fn from_glib_borrow(ptr: *const u8) -> Borrowed<Self> {
assert!(!ptr.is_null());
let cstr = CStr::from_ptr(ptr as *const _);
assert!(cstr.to_str().is_ok());
Borrowed::new(GString(Inner::Foreign {
ptr: ptr::NonNull::new_unchecked(ptr as *mut _),
len: cstr.to_bytes().len(),
}))
}
}
#[doc(hidden)]
impl FromGlibPtrBorrow<*const i8> for GString {
#[inline]
unsafe fn from_glib_borrow(ptr: *const i8) -> Borrowed<Self> {
from_glib_borrow(ptr as *const u8)
}
}
#[doc(hidden)]
impl FromGlibPtrBorrow<*mut u8> for GString {
#[inline]
unsafe fn from_glib_borrow(ptr: *mut u8) -> Borrowed<Self> {
from_glib_borrow(ptr as *const u8)
}
}
#[doc(hidden)]
impl FromGlibPtrBorrow<*mut i8> for GString {
#[inline]
unsafe fn from_glib_borrow(ptr: *mut i8) -> Borrowed<Self> {
from_glib_borrow(ptr as *const u8)
}
}
#[doc(hidden)]
impl<'a> ToGlibPtr<'a, *const u8> for GString {
type Storage = &'a Self;
#[inline]
fn to_glib_none(&'a self) -> Stash<'a, *const u8, Self> {
Stash(self.as_ptr() as *const u8, self)
}
#[inline]
fn to_glib_full(&self) -> *const u8 {
unsafe { self.clone().into_glib_ptr() as *const u8 }
}
}
#[doc(hidden)]
impl<'a> ToGlibPtr<'a, *const i8> for GString {
type Storage = &'a Self;
#[inline]
fn to_glib_none(&'a self) -> Stash<'a, *const i8, Self> {
Stash(self.as_ptr() as *const i8, self)
}
#[inline]
fn to_glib_full(&self) -> *const i8 {
unsafe { self.clone().into_glib_ptr() as *const i8 }
}
}
#[doc(hidden)]
impl<'a> ToGlibPtr<'a, *mut u8> for GString {
type Storage = &'a Self;
#[inline]
fn to_glib_none(&'a self) -> Stash<'a, *mut u8, Self> {
Stash(self.as_ptr() as *mut u8, self)
}
#[inline]
fn to_glib_full(&self) -> *mut u8 {
unsafe { self.clone().into_glib_ptr() as *mut u8 }
}
}
#[doc(hidden)]
impl<'a> ToGlibPtr<'a, *mut i8> for GString {
type Storage = &'a Self;
#[inline]
fn to_glib_none(&'a self) -> Stash<'a, *mut i8, Self> {
Stash(self.as_ptr() as *mut i8, self)
}
#[inline]
fn to_glib_full(&self) -> *mut i8 {
unsafe { self.clone().into_glib_ptr() as *mut i8 }
}
}
#[doc(hidden)]
impl FromGlibContainer<*const c_char, *const i8> for GString {
unsafe fn from_glib_none_num(ptr: *const i8, num: usize) -> Self {
if num == 0 || ptr.is_null() {
return Self::from("");
}
let slice = slice::from_raw_parts(ptr as *const u8, num);
std::str::from_utf8(slice).unwrap().into()
}
unsafe fn from_glib_container_num(ptr: *const i8, num: usize) -> Self {
if num == 0 || ptr.is_null() {
return Self::from("");
}
let slice = slice::from_raw_parts(ptr as *const u8, num);
std::str::from_utf8(slice).unwrap();
GString(Inner::Foreign {
ptr: ptr::NonNull::new_unchecked(ptr as *mut _),
len: num,
})
}
unsafe fn from_glib_full_num(ptr: *const i8, num: usize) -> Self {
if num == 0 || ptr.is_null() {
return Self::from("");
}
let slice = slice::from_raw_parts(ptr as *const u8, num);
std::str::from_utf8(slice).unwrap();
GString(Inner::Foreign {
ptr: ptr::NonNull::new_unchecked(ptr as *mut _),
len: num,
})
}
}
#[doc(hidden)]
impl FromGlibContainer<*const c_char, *mut i8> for GString {
unsafe fn from_glib_none_num(ptr: *mut i8, num: usize) -> Self {
FromGlibContainer::from_glib_none_num(ptr as *const i8, num)
}
unsafe fn from_glib_container_num(ptr: *mut i8, num: usize) -> Self {
FromGlibContainer::from_glib_container_num(ptr as *const i8, num)
}
unsafe fn from_glib_full_num(ptr: *mut i8, num: usize) -> Self {
FromGlibContainer::from_glib_full_num(ptr as *const i8, num)
}
}
#[doc(hidden)]
impl FromGlibContainer<*const c_char, *const u8> for GString {
unsafe fn from_glib_none_num(ptr: *const u8, num: usize) -> Self {
FromGlibContainer::from_glib_none_num(ptr as *const i8, num)
}
unsafe fn from_glib_container_num(ptr: *const u8, num: usize) -> Self {
FromGlibContainer::from_glib_container_num(ptr as *const i8, num)
}
unsafe fn from_glib_full_num(ptr: *const u8, num: usize) -> Self {
FromGlibContainer::from_glib_full_num(ptr as *const i8, num)
}
}
#[doc(hidden)]
impl FromGlibContainer<*const c_char, *mut u8> for GString {
unsafe fn from_glib_none_num(ptr: *mut u8, num: usize) -> Self {
FromGlibContainer::from_glib_none_num(ptr as *const i8, num)
}
unsafe fn from_glib_container_num(ptr: *mut u8, num: usize) -> Self {
FromGlibContainer::from_glib_container_num(ptr as *const i8, num)
}
unsafe fn from_glib_full_num(ptr: *mut u8, num: usize) -> Self {
FromGlibContainer::from_glib_full_num(ptr as *const i8, num)
}
}
impl GlibPtrDefault for GString {
type GlibType = *const c_char;
}
impl StaticType for GString {
fn static_type() -> Type {
String::static_type()
}
}
impl crate::value::ValueType for GString {
type Type = String;
}
impl crate::value::ValueTypeOptional for GString {}
unsafe impl<'a> crate::value::FromValue<'a> for GString {
type Checker = crate::value::GenericValueTypeOrNoneChecker<Self>;
unsafe fn from_value(value: &'a crate::Value) -> Self {
Self::from(<&str>::from_value(value))
}
}
impl crate::value::ToValue for GString {
fn to_value(&self) -> crate::Value {
<&str>::to_value(&self.as_str())
}
fn value_type(&self) -> Type {
String::static_type()
}
}
impl crate::value::ToValueOptional for GString {
fn to_value_optional(s: Option<&Self>) -> crate::Value {
<str>::to_value_optional(s.as_ref().map(|s| s.as_str()))
}
}
impl StaticType for Vec<GString> {
fn static_type() -> Type {
<Vec<String>>::static_type()
}
}
impl crate::value::ValueType for Vec<GString> {
type Type = Vec<GString>;
}
unsafe impl<'a> crate::value::FromValue<'a> for Vec<GString> {
type Checker = crate::value::GenericValueTypeChecker<Self>;
unsafe fn from_value(value: &'a crate::value::Value) -> Self {
let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const *const c_char;
FromGlibPtrContainer::from_glib_none(ptr)
}
}
impl crate::value::ToValue for Vec<GString> {
fn to_value(&self) -> crate::value::Value {
unsafe {
let mut value = crate::value::Value::for_value_type::<Self>();
let ptr: *mut *mut c_char = self.to_glib_full();
gobject_ffi::g_value_take_boxed(value.to_glib_none_mut().0, ptr as *const c_void);
value
}
}
fn value_type(&self) -> Type {
<Vec<GString>>::static_type()
}
}
impl_from_glib_container_as_vec_string!(GString, *const c_char);
impl_from_glib_container_as_vec_string!(GString, *mut c_char);
#[cfg(test)]
#[allow(clippy::disallowed_names)]
mod tests {
use super::*;
use std::ffi::CString;
#[test]
fn test_gstring() {
let data = CString::new("foo").unwrap();
let ptr = data.as_ptr();
unsafe {
let ptr_copy = ffi::g_strdup(ptr);
let gstring = GString::from_glib_full(ptr_copy);
assert_eq!(gstring.as_str(), "foo");
let foo: Box<str> = gstring.into();
assert_eq!(foo.as_ref(), "foo");
}
}
#[test]
fn test_owned_glib_string() {
let data = CString::new("foo").unwrap();
let ptr = data.as_ptr();
unsafe {
let ptr_copy = ffi::g_strdup(ptr);
let gstr = GString::from_glib_full(ptr_copy);
assert_eq!(gstr, "foo");
}
}
#[test]
fn test_gstring_from_str() {
let gstring: GString = "foo".into();
assert_eq!(gstring.as_str(), "foo");
let foo: Box<str> = gstring.into();
assert_eq!(foo.as_ref(), "foo");
}
#[test]
fn test_string_from_gstring() {
let gstring = GString::from("foo");
assert_eq!(gstring.as_str(), "foo");
let s = String::from(gstring);
assert_eq!(s, "foo");
}
#[test]
fn test_gstring_from_cstring() {
let cstr = CString::new("foo").unwrap();
let gstring = GString::from(cstr);
assert_eq!(gstring.as_str(), "foo");
let foo: Box<str> = gstring.into();
assert_eq!(foo.as_ref(), "foo");
}
#[test]
fn test_string_from_gstring_from_cstring() {
let cstr = CString::new("foo").unwrap();
let gstring = GString::from(cstr);
assert_eq!(gstring.as_str(), "foo");
let s = String::from(gstring);
assert_eq!(s, "foo");
}
#[test]
fn test_vec_u8_to_gstring() {
let v: &[u8] = b"foo";
let s: GString = Vec::from(v).into();
assert_eq!(s.as_str(), "foo");
}
#[test]
fn test_as_ref_path() {
fn foo<P: AsRef<Path>>(_path: P) {}
let gstring: GString = "/my/path/".into();
let gstr: &GStr = gstring.as_gstr();
foo(gstr);
foo(gstring);
}
#[test]
fn test_from_glib_container() {
unsafe {
let test_a: GString = FromGlibContainer::from_glib_container_num(
ffi::g_strdup("hello_world\0".as_ptr() as *const _),
5,
);
assert_eq!("hello", test_a.as_str());
let test_b: GString = FromGlibContainer::from_glib_none_num("hello_world".as_ptr(), 5);
assert_eq!("hello", test_b.as_str());
let test_c: GString =
FromGlibContainer::from_glib_none_num(std::ptr::null::<std::os::raw::c_char>(), 0);
assert_eq!("", test_c.as_str());
let test_d: GString = FromGlibContainer::from_glib_none_num("".as_ptr(), 0);
assert_eq!("", test_d.as_str());
let test_e: GString =
FromGlibContainer::from_glib_container_num(ffi::g_strdup(std::ptr::null()), 0);
assert_eq!("", test_e.as_str());
}
}
#[test]
fn test_hashmap() {
use std::collections::HashMap;
let gstring = GString::from("foo");
assert_eq!(gstring.as_str(), "foo");
let mut h: HashMap<GString, i32> = HashMap::new();
h.insert(gstring, 42);
let gstring: GString = "foo".into();
assert!(h.contains_key(&gstring));
}
}