use libc::{c_char, c_void};
use std::borrow::Borrow;
use std::error;
use std::ffi::CStr;
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use std::ptr;
use glib_sys;
use gobject_sys;
use gstring::GString;
use translate::*;
use types::{StaticType, Type};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct GetError {
pub actual: Type,
pub requested: Type,
}
impl GetError {
pub fn new_type_mismatch(actual: Type, requested: Type) -> Self {
GetError { actual, requested }
}
}
impl fmt::Display for GetError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"GetError: Value type mismatch. Actual {:?}, requested {:?}",
self.actual, self.requested,
)
}
}
impl error::Error for GetError {
fn description(&self) -> &str {
"GetError: Value type mismatch"
}
}
#[repr(C)]
pub struct Value(pub(crate) gobject_sys::GValue, PhantomData<*const c_void>);
impl Value {
pub fn from_type(type_: Type) -> Self {
unsafe {
assert_eq!(
gobject_sys::g_type_check_is_value_type(type_.to_glib()),
glib_sys::GTRUE
);
let mut value = Value::uninitialized();
gobject_sys::g_value_init(value.to_glib_none_mut().0, type_.to_glib());
value
}
}
pub fn downcast<'a, T: FromValueOptional<'a> + SetValue>(self) -> Result<TypedValue<T>, Self> {
unsafe {
let ok = from_glib(gobject_sys::g_type_check_value_holds(
mut_override(self.to_glib_none().0),
T::static_type().to_glib(),
));
if ok {
Ok(TypedValue(self, PhantomData))
} else {
Err(self)
}
}
}
pub fn downcast_ref<'a, T: FromValueOptional<'a> + SetValue>(&self) -> Option<&TypedValue<T>> {
unsafe {
let ok = from_glib(gobject_sys::g_type_check_value_holds(
mut_override(self.to_glib_none().0),
T::static_type().to_glib(),
));
if ok {
Some(&*(self as *const Value as *const TypedValue<T>))
} else {
None
}
}
}
pub fn get<'a, T: FromValueOptional<'a>>(&'a self) -> Result<Option<T>, GetError> {
unsafe {
let ok = from_glib(gobject_sys::g_type_check_value_holds(
mut_override(self.to_glib_none().0),
T::static_type().to_glib(),
));
if ok {
Ok(T::from_value_optional(self))
} else {
Err(GetError::new_type_mismatch(self.type_(), T::static_type()))
}
}
}
pub fn get_some<'a, T: FromValue<'a>>(&'a self) -> Result<T, GetError> {
unsafe {
let ok = from_glib(gobject_sys::g_type_check_value_holds(
mut_override(self.to_glib_none().0),
T::static_type().to_glib(),
));
if ok {
Ok(T::from_value(self))
} else {
Err(GetError::new_type_mismatch(self.type_(), T::static_type()))
}
}
}
#[inline]
pub fn is<'a, T: FromValueOptional<'a> + SetValue>(&self) -> bool {
self.type_().is_a(&T::static_type())
}
pub fn type_(&self) -> Type {
from_glib(self.0.g_type)
}
pub fn type_transformable(src: Type, dst: Type) -> bool {
unsafe {
from_glib(gobject_sys::g_value_type_transformable(
src.to_glib(),
dst.to_glib(),
))
}
}
pub fn transform<T: StaticType + SetValue>(&self) -> Option<Value> {
unsafe {
let mut dest = Value::from_type(T::static_type());
if from_glib(gobject_sys::g_value_transform(
self.to_glib_none().0,
dest.to_glib_none_mut().0,
)) {
Some(dest)
} else {
None
}
}
}
#[doc(hidden)]
pub fn into_raw(self) -> gobject_sys::GValue {
unsafe {
let ret = ptr::read(&self.0);
mem::forget(self);
ret
}
}
pub fn try_into_send_value<'a, T: Send + FromValueOptional<'a> + SetValue>(
self,
) -> Result<SendValue, Self> {
self.downcast::<T>().map(TypedValue::into_send_value)
}
}
impl Clone for Value {
fn clone(&self) -> Self {
unsafe {
let mut ret = Value::from_type(from_glib(self.0.g_type));
gobject_sys::g_value_copy(self.to_glib_none().0, ret.to_glib_none_mut().0);
ret
}
}
}
impl Drop for Value {
fn drop(&mut self) {
if self.type_() != Type::Invalid {
unsafe { gobject_sys::g_value_unset(self.to_glib_none_mut().0) }
}
}
}
impl fmt::Debug for Value {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
unsafe {
let s: GString =
from_glib_full(gobject_sys::g_strdup_value_contents(self.to_glib_none().0));
f.debug_tuple("Value").field(&s).finish()
}
}
}
impl<'a, T: ?Sized + SetValueOptional> From<Option<&'a T>> for Value {
#[inline]
fn from(value: Option<&'a T>) -> Self {
value.to_value()
}
}
impl<'a, T: ?Sized + SetValue> From<&'a T> for Value {
#[inline]
fn from(value: &'a T) -> Self {
value.to_value()
}
}
impl<T> From<TypedValue<T>> for Value {
fn from(value: TypedValue<T>) -> Self {
value.0
}
}
impl From<SendValue> for Value {
fn from(value: SendValue) -> Self {
value.0
}
}
impl Uninitialized for Value {
unsafe fn uninitialized() -> Value {
mem::zeroed()
}
}
#[doc(hidden)]
impl<'a> ToGlibPtr<'a, *const gobject_sys::GValue> for Value {
type Storage = &'a Value;
fn to_glib_none(&'a self) -> Stash<'a, *const gobject_sys::GValue, Self> {
Stash(&self.0, self)
}
}
#[doc(hidden)]
impl<'a> ToGlibPtrMut<'a, *mut gobject_sys::GValue> for Value {
type Storage = &'a mut Value;
fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut gobject_sys::GValue, Self> {
StashMut(&mut self.0, self)
}
}
#[doc(hidden)]
impl<'a> ToGlibPtr<'a, *mut gobject_sys::GValue> for &'a [&'a dyn ToValue] {
type Storage = ValueArray;
fn to_glib_none(&'a self) -> Stash<'a, *mut gobject_sys::GValue, Self> {
let mut values: Vec<gobject_sys::GValue> =
self.iter().map(|v| v.to_value().into_raw()).collect();
Stash(values.as_mut_ptr(), ValueArray(values))
}
}
#[doc(hidden)]
impl<'a> ToGlibContainerFromSlice<'a, *mut gobject_sys::GValue> for &'a Value {
type Storage = &'a [&'a Value];
fn to_glib_none_from_slice(t: &'a [&'a Value]) -> (*mut gobject_sys::GValue, &'a [&'a Value]) {
(t.as_ptr() as *mut gobject_sys::GValue, t)
}
fn to_glib_container_from_slice(
t: &'a [&'a Value],
) -> (*mut gobject_sys::GValue, &'a [&'a Value]) {
if t.is_empty() {
return (ptr::null_mut(), t);
}
unsafe {
let res = glib_sys::g_malloc(mem::size_of::<gobject_sys::GValue>() * t.len())
as *mut gobject_sys::GValue;
ptr::copy_nonoverlapping(t.as_ptr() as *const gobject_sys::GValue, res, t.len());
(res, t)
}
}
fn to_glib_full_from_slice(t: &[&'a Value]) -> *mut gobject_sys::GValue {
if t.is_empty() {
return ptr::null_mut();
}
unsafe {
let res = glib_sys::g_malloc(mem::size_of::<gobject_sys::GValue>() * t.len())
as *mut gobject_sys::GValue;
for (i, v) in t.iter().enumerate() {
gobject_sys::g_value_init(res.add(i), v.type_().to_glib());
gobject_sys::g_value_copy(v.to_glib_none().0, res.add(i));
}
res
}
}
}
#[doc(hidden)]
impl<'a> ToGlibContainerFromSlice<'a, *const gobject_sys::GValue> for &'a Value {
type Storage = &'a [&'a Value];
fn to_glib_none_from_slice(
t: &'a [&'a Value],
) -> (*const gobject_sys::GValue, &'a [&'a Value]) {
let (ptr, storage) =
ToGlibContainerFromSlice::<'a, *mut gobject_sys::GValue>::to_glib_none_from_slice(t);
(ptr as *const _, storage)
}
fn to_glib_container_from_slice(
_: &'a [&'a Value],
) -> (*const gobject_sys::GValue, &'a [&'a Value]) {
unimplemented!()
}
fn to_glib_full_from_slice(_: &[&'a Value]) -> *const gobject_sys::GValue {
unimplemented!()
}
}
macro_rules! from_glib {
($name:ident, $wrap:expr) => {
impl FromGlibPtrNone<*const gobject_sys::GValue> for $name {
unsafe fn from_glib_none(ptr: *const gobject_sys::GValue) -> Self {
let mut ret = Value::from_type(from_glib((*ptr).g_type));
gobject_sys::g_value_copy(ptr, ret.to_glib_none_mut().0);
$wrap(ret)
}
}
impl FromGlibPtrNone<*mut gobject_sys::GValue> for $name {
unsafe fn from_glib_none(ptr: *mut gobject_sys::GValue) -> Self {
from_glib_none(ptr as *const _)
}
}
impl FromGlibPtrFull<*mut gobject_sys::GValue> for $name {
unsafe fn from_glib_full(ptr: *mut gobject_sys::GValue) -> Self {
let mut ret = Value::uninitialized();
ptr::swap(&mut ret.0, ptr);
glib_sys::g_free(ptr as *mut c_void);
$wrap(ret)
}
}
impl FromGlibContainerAsVec<*mut gobject_sys::GValue, *mut *mut gobject_sys::GValue>
for $name
{
unsafe fn from_glib_none_num_as_vec(
ptr: *mut *mut gobject_sys::GValue,
num: usize,
) -> Vec<Self> {
if num == 0 || ptr.is_null() {
return Vec::new();
}
let mut res = Vec::with_capacity(num);
for i in 0..num {
res.push(from_glib_none(ptr::read(ptr.add(i))));
}
res
}
unsafe fn from_glib_container_num_as_vec(
ptr: *mut *mut gobject_sys::GValue,
num: usize,
) -> Vec<Self> {
let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
glib_sys::g_free(ptr as *mut _);
res
}
unsafe fn from_glib_full_num_as_vec(
ptr: *mut *mut gobject_sys::GValue,
num: usize,
) -> Vec<Self> {
if num == 0 || ptr.is_null() {
return Vec::new();
}
let mut res = Vec::with_capacity(num);
for i in 0..num {
res.push(from_glib_full(ptr::read(ptr.add(i))));
}
glib_sys::g_free(ptr as *mut _);
res
}
}
impl FromGlibPtrArrayContainerAsVec<*mut gobject_sys::GValue, *mut *mut gobject_sys::GValue>
for $name
{
unsafe fn from_glib_none_as_vec(ptr: *mut *mut gobject_sys::GValue) -> Vec<Self> {
FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, c_ptr_array_len(ptr))
}
unsafe fn from_glib_container_as_vec(ptr: *mut *mut gobject_sys::GValue) -> Vec<Self> {
FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, c_ptr_array_len(ptr))
}
unsafe fn from_glib_full_as_vec(ptr: *mut *mut gobject_sys::GValue) -> Vec<Self> {
FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, c_ptr_array_len(ptr))
}
}
impl FromGlibContainerAsVec<*mut gobject_sys::GValue, *const *mut gobject_sys::GValue>
for $name
{
unsafe fn from_glib_none_num_as_vec(
ptr: *const *mut gobject_sys::GValue,
num: usize,
) -> Vec<Self> {
FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *mut *mut _, num)
}
unsafe fn from_glib_container_num_as_vec(
_: *const *mut gobject_sys::GValue,
_: usize,
) -> Vec<Self> {
unimplemented!()
}
unsafe fn from_glib_full_num_as_vec(
_: *const *mut gobject_sys::GValue,
_: usize,
) -> Vec<Self> {
unimplemented!()
}
}
impl
FromGlibPtrArrayContainerAsVec<
*mut gobject_sys::GValue,
*const *mut gobject_sys::GValue,
> for $name
{
unsafe fn from_glib_none_as_vec(ptr: *const *mut gobject_sys::GValue) -> Vec<Self> {
FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr as *mut *mut _)
}
unsafe fn from_glib_container_as_vec(_: *const *mut gobject_sys::GValue) -> Vec<Self> {
unimplemented!()
}
unsafe fn from_glib_full_as_vec(_: *const *mut gobject_sys::GValue) -> Vec<Self> {
unimplemented!()
}
}
};
}
from_glib!(Value, |v| v);
pub struct ValueArray(Vec<gobject_sys::GValue>);
impl Drop for ValueArray {
fn drop(&mut self) {
unsafe {
for value in &mut self.0 {
if value.g_type != gobject_sys::G_TYPE_INVALID {
gobject_sys::g_value_unset(value);
}
}
}
}
}
#[derive(Clone)]
#[repr(C)]
pub struct TypedValue<T>(Value, PhantomData<*const T>);
impl<'a, T: FromValueOptional<'a> + SetValue> TypedValue<T> {
pub fn get(&'a self) -> Option<T> {
unsafe { T::from_value_optional(self) }
}
pub fn get_some(&'a self) -> T
where
T: FromValue<'a>,
{
unsafe { T::from_value(self) }
}
pub fn set<U: ?Sized + SetValueOptional>(&mut self, value: Option<&U>)
where
T: Borrow<U>,
{
unsafe { SetValueOptional::set_value_optional(&mut self.0, value) }
}
pub fn set_none(&mut self)
where
T: SetValueOptional,
{
unsafe { T::set_value_optional(&mut self.0, None) }
}
pub fn set_some<U: ?Sized + SetValue>(&mut self, value: &U)
where
T: Borrow<U>,
{
unsafe { SetValue::set_value(&mut self.0, value) }
}
}
impl<T> fmt::Debug for TypedValue<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.debug_tuple("TypedValue").field(&self.0).finish()
}
}
impl<'a, T: FromValueOptional<'a> + SetValue + Send> TypedValue<T> {
pub fn into_send_value(self) -> SendValue {
SendValue(self.0)
}
}
impl<T> Deref for TypedValue<T> {
type Target = Value;
fn deref(&self) -> &Value {
&self.0
}
}
unsafe impl<T: Send> Send for TypedValue<T> {}
unsafe impl<T: Sync> Sync for TypedValue<T> {}
impl<'a, T: FromValueOptional<'a> + SetValueOptional> From<Option<&'a T>> for TypedValue<T> {
fn from(value: Option<&'a T>) -> Self {
TypedValue(Value::from(value), PhantomData)
}
}
impl<'a, T: FromValueOptional<'a> + SetValue> From<&'a T> for TypedValue<T> {
fn from(value: &'a T) -> Self {
TypedValue(Value::from(value), PhantomData)
}
}
impl<'a> From<Option<&'a str>> for TypedValue<String> {
fn from(value: Option<&'a str>) -> Self {
TypedValue(Value::from(value), PhantomData)
}
}
impl<'a> From<&'a str> for TypedValue<String> {
fn from(value: &'a str) -> Self {
TypedValue(Value::from(value), PhantomData)
}
}
impl<'a> From<TypedValue<&'a str>> for TypedValue<String> {
fn from(value: TypedValue<&str>) -> Self {
TypedValue(value.0, PhantomData)
}
}
impl<'a> From<TypedValue<String>> for TypedValue<&'a str> {
fn from(value: TypedValue<String>) -> Self {
TypedValue(value.0, PhantomData)
}
}
#[doc(hidden)]
impl<'a, T: 'a> ToGlibPtrMut<'a, *mut gobject_sys::GValue> for TypedValue<T> {
type Storage = &'a mut TypedValue<T>;
fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut gobject_sys::GValue, Self> {
StashMut(&mut (self.0).0, self)
}
}
pub trait ToValue {
fn to_value(&self) -> Value;
fn to_value_type(&self) -> Type;
}
impl<T: SetValueOptional> ToValue for Option<T> {
fn to_value(&self) -> Value {
unsafe {
let mut ret = Value::from_type(T::static_type());
T::set_value_optional(&mut ret, self.as_ref());
ret
}
}
#[inline]
fn to_value_type(&self) -> Type {
T::static_type()
}
}
impl<T: ?Sized + SetValue> ToValue for T {
fn to_value(&self) -> Value {
unsafe {
let mut ret = Value::from_type(T::static_type());
T::set_value(&mut ret, self);
ret
}
}
#[inline]
fn to_value_type(&self) -> Type {
T::static_type()
}
}
impl ToValue for Value {
fn to_value(&self) -> Value {
self.clone()
}
fn to_value_type(&self) -> Type {
self.type_()
}
}
#[derive(Clone)]
#[repr(C)]
pub struct SendValue(Value);
unsafe impl Send for SendValue {}
impl SendValue {
pub fn downcast<'a, T: FromValueOptional<'a> + SetValue + Send>(
self,
) -> Result<TypedValue<T>, Self> {
self.0.downcast().map_err(SendValue)
}
pub fn downcast_ref<'a, T: FromValueOptional<'a> + SetValue>(&self) -> Option<&TypedValue<T>> {
unsafe {
let ok = from_glib(gobject_sys::g_type_check_value_holds(
mut_override(self.to_glib_none().0),
T::static_type().to_glib(),
));
if ok {
Some(&*(self as *const SendValue as *const TypedValue<T>))
} else {
None
}
}
}
#[doc(hidden)]
pub fn into_raw(self) -> gobject_sys::GValue {
self.0.into_raw()
}
}
impl fmt::Debug for SendValue {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.debug_tuple("SendValue").field(&self.0).finish()
}
}
impl Deref for SendValue {
type Target = Value;
fn deref(&self) -> &Value {
&self.0
}
}
impl<'a, T: ?Sized + SetValueOptional + Send> From<Option<&'a T>> for SendValue {
#[inline]
fn from(value: Option<&'a T>) -> Self {
SendValue(value.to_value())
}
}
impl<'a, T: ?Sized + SetValue + Send> From<&'a T> for SendValue {
#[inline]
fn from(value: &'a T) -> Self {
SendValue(value.to_value())
}
}
impl<T: Send> From<TypedValue<T>> for SendValue {
fn from(value: TypedValue<T>) -> Self {
SendValue(value.0)
}
}
from_glib!(SendValue, SendValue);
#[doc(hidden)]
impl<'a> ToGlibPtrMut<'a, *mut gobject_sys::GValue> for SendValue {
type Storage = &'a mut SendValue;
fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut gobject_sys::GValue, Self> {
StashMut(&mut (self.0).0, self)
}
}
pub trait ToSendValue: Send + ToValue {
fn to_send_value(&self) -> SendValue;
}
impl<T: SetValueOptional + Send + ToValue> ToSendValue for Option<T> {
fn to_send_value(&self) -> SendValue {
SendValue(self.to_value())
}
}
impl<T: ?Sized + SetValue + Send + ToValue> ToSendValue for T {
fn to_send_value(&self) -> SendValue {
SendValue(self.to_value())
}
}
impl ToSendValue for SendValue {
fn to_send_value(&self) -> SendValue {
self.clone()
}
}
impl ToValue for SendValue {
fn to_value(&self) -> Value {
self.0.clone()
}
fn to_value_type(&self) -> Type {
self.type_()
}
}
pub trait FromValueOptional<'a>: StaticType + Sized {
unsafe fn from_value_optional(&'a Value) -> Option<Self>;
}
pub trait FromValue<'a>: FromValueOptional<'a> {
unsafe fn from_value(&'a Value) -> Self;
}
pub trait SetValueOptional: SetValue {
unsafe fn set_value_optional(&mut Value, Option<&Self>);
}
pub trait SetValue: StaticType {
unsafe fn set_value(&mut Value, &Self);
}
impl<'a> FromValueOptional<'a> for String {
unsafe fn from_value_optional(value: &'a Value) -> Option<Self> {
from_glib_none(gobject_sys::g_value_get_string(value.to_glib_none().0))
}
}
impl<'a> FromValueOptional<'a> for &'a str {
unsafe fn from_value_optional(value: &'a Value) -> Option<Self> {
let cstr = gobject_sys::g_value_get_string(value.to_glib_none().0);
if cstr.is_null() {
None
} else {
CStr::from_ptr(cstr).to_str().ok()
}
}
}
impl SetValue for str {
unsafe fn set_value(value: &mut Value, this: &Self) {
gobject_sys::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full())
}
}
impl SetValueOptional for str {
unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) {
gobject_sys::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full())
}
}
impl<'a> FromValueOptional<'a> for Vec<String> {
unsafe fn from_value_optional(value: &'a Value) -> Option<Self> {
Some(<Vec<String> as FromValue>::from_value(value))
}
}
impl<'a> FromValue<'a> for Vec<String> {
unsafe fn from_value(value: &'a Value) -> Self {
let ptr = gobject_sys::g_value_get_boxed(value.to_glib_none().0) as *const *const c_char;
FromGlibPtrContainer::from_glib_none(ptr)
}
}
impl<'a> FromValueOptional<'a> for Vec<GString> {
unsafe fn from_value_optional(value: &'a Value) -> Option<Self> {
Some(<Vec<GString> as FromValue>::from_value(value))
}
}
impl<'a> FromValue<'a> for Vec<GString> {
unsafe fn from_value(value: &'a Value) -> Self {
let ptr = gobject_sys::g_value_get_boxed(value.to_glib_none().0) as *const *const c_char;
FromGlibPtrContainer::from_glib_none(ptr)
}
}
impl<'a> SetValue for [&'a str] {
unsafe fn set_value(value: &mut Value, this: &Self) {
let ptr: *mut *mut c_char = this.to_glib_full();
gobject_sys::g_value_take_boxed(value.to_glib_none_mut().0, ptr as *const c_void)
}
}
impl<'a> SetValueOptional for [&'a str] {
unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) {
let ptr: *mut *mut c_char = this.to_glib_full();
gobject_sys::g_value_take_boxed(value.to_glib_none_mut().0, ptr as *const c_void)
}
}
impl SetValue for Vec<String> {
unsafe fn set_value(value: &mut Value, this: &Self) {
let ptr: *mut *mut c_char = this.to_glib_full();
gobject_sys::g_value_take_boxed(value.to_glib_none_mut().0, ptr as *const c_void)
}
}
impl SetValueOptional for Vec<String> {
#[allow(clippy::redundant_closure)]
unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) {
let ptr: *mut *mut c_char = this.map(|v| v.to_glib_full()).unwrap_or(ptr::null_mut());
gobject_sys::g_value_take_boxed(value.to_glib_none_mut().0, ptr as *const c_void)
}
}
impl<'a, T: ?Sized + SetValue> SetValue for &'a T {
unsafe fn set_value(value: &mut Value, this: &Self) {
SetValue::set_value(value, *this)
}
}
impl<'a, T: ?Sized + SetValueOptional> SetValueOptional for &'a T {
unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) {
SetValueOptional::set_value_optional(value, this.cloned())
}
}
impl SetValue for String {
unsafe fn set_value(value: &mut Value, this: &Self) {
gobject_sys::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full())
}
}
impl SetValueOptional for String {
unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) {
gobject_sys::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full())
}
}
impl<'a> FromValueOptional<'a> for bool {
unsafe fn from_value_optional(value: &'a Value) -> Option<Self> {
Some(from_glib(gobject_sys::g_value_get_boolean(
value.to_glib_none().0,
)))
}
}
impl<'a> FromValue<'a> for bool {
unsafe fn from_value(value: &'a Value) -> Self {
from_glib(gobject_sys::g_value_get_boolean(value.to_glib_none().0))
}
}
impl SetValue for bool {
unsafe fn set_value(value: &mut Value, this: &Self) {
gobject_sys::g_value_set_boolean(value.to_glib_none_mut().0, this.to_glib())
}
}
macro_rules! numeric {
($name:ident, $get:ident, $set:ident) => {
impl<'a> FromValueOptional<'a> for $name {
unsafe fn from_value_optional(value: &'a Value) -> Option<Self> {
Some(gobject_sys::$get(value.to_glib_none().0))
}
}
impl<'a> FromValue<'a> for $name {
unsafe fn from_value(value: &'a Value) -> Self {
gobject_sys::$get(value.to_glib_none().0)
}
}
impl SetValue for $name {
unsafe fn set_value(value: &mut Value, this: &Self) {
gobject_sys::$set(value.to_glib_none_mut().0, *this)
}
}
};
}
numeric!(i8, g_value_get_schar, g_value_set_schar);
numeric!(u8, g_value_get_uchar, g_value_set_uchar);
numeric!(i32, g_value_get_int, g_value_set_int);
numeric!(u32, g_value_get_uint, g_value_set_uint);
numeric!(i64, g_value_get_int64, g_value_set_int64);
numeric!(u64, g_value_get_uint64, g_value_set_uint64);
numeric!(f32, g_value_get_float, g_value_set_float);
numeric!(f64, g_value_get_double, g_value_set_double);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_send_value() {
use std::thread;
let v = SendValue::from(&1i32);
thread::spawn(move || drop(v)).join().unwrap();
}
#[test]
fn test_strv() {
let v = vec!["123", "456"].to_value();
assert_eq!(
v.get::<Vec<GString>>(),
Ok(Some(vec![GString::from("123"), GString::from("456")]))
);
let v = vec![String::from("123"), String::from("456")].to_value();
assert_eq!(
v.get::<Vec<GString>>(),
Ok(Some(vec![GString::from("123"), GString::from("456")]))
);
}
#[test]
fn test_get() {
let v = 123.to_value();
assert_eq!(v.get(), Ok(Some(123)));
assert_eq!(v.get_some::<i32>(), Ok(123));
assert_eq!(
v.get::<&str>(),
Err(GetError::new_type_mismatch(Type::I32, Type::String))
);
assert_eq!(
v.get_some::<bool>(),
Err(GetError::new_type_mismatch(Type::I32, Type::Bool))
);
let some_v = Some("test").to_value();
assert_eq!(some_v.get::<&str>(), Ok(Some("test")));
assert_eq!(some_v.get::<&str>(), Ok(Some("test")));
assert_eq!(
some_v.get::<i32>(),
Err(GetError::new_type_mismatch(Type::String, Type::I32))
);
let none_str: Option<&str> = None;
let none_v = none_str.to_value();
assert_eq!(none_v.get::<&str>(), Ok(None));
assert_eq!(
none_v.get::<i32>(),
Err(GetError::new_type_mismatch(Type::String, Type::I32))
);
}
#[test]
fn test_transform() {
let v = 123.to_value();
let v2 = v
.transform::<String>()
.expect("Failed to transform to string");
assert_eq!(v2.get::<&str>(), Ok(Some("123")));
}
}