use std::borrow::Borrow;
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::ffi::CStr;
use std::ptr;
use libc::c_void;
use translate::*;
use types::{StaticType, Type};
use ffi as glib_ffi;
use gobject_ffi;
pub struct Value(gobject_ffi::GValue);
impl Value {
pub fn downcast<'a, T: FromValueOptional<'a> + SetValue>(self) -> Result<TypedValue<T>, Self> {
unsafe {
let ok = from_glib(
gobject_ffi::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 get<'a, T: FromValueOptional<'a>>(&'a self) -> Option<T> {
unsafe {
let ok = from_glib(
gobject_ffi::g_type_check_value_holds(mut_override(self.to_glib_none().0),
T::static_type().to_glib()));
if ok {
T::from_value_optional(self)
}
else {
None
}
}
}
#[inline]
pub fn is<'a, T: FromValueOptional<'a> + SetValue>(&self) -> bool {
self.type_() == 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_ffi::g_value_type_transformable(src.to_glib(), dst.to_glib()))
}
}
#[doc(hidden)]
pub fn into_raw(mut self) -> gobject_ffi::GValue {
unsafe {
let ret = mem::replace(&mut self.0, mem::uninitialized());
mem::forget(self);
ret
}
}
}
impl Clone for Value {
fn clone(&self) -> Self {
unsafe {
let mut ret = Value::uninitialized();
gobject_ffi::g_value_init(ret.to_glib_none_mut().0, self.0.g_type);
gobject_ffi::g_value_copy(self.to_glib_none().0, ret.to_glib_none_mut().0);
ret
}
}
}
impl Drop for Value {
fn drop(&mut self) {
unsafe { gobject_ffi::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: String = from_glib_full(
gobject_ffi::g_strdup_value_contents(self.to_glib_none().0));
write!(f, "Value({})", s)
}
}
}
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 Uninitialized for Value {
unsafe fn uninitialized() -> Value {
Value(mem::zeroed())
}
}
impl<'a> ToGlibPtr<'a, *const gobject_ffi::GValue> for Value {
type Storage = &'a Value;
fn to_glib_none(&'a self) -> Stash<'a, *const gobject_ffi::GValue, Self> {
Stash(&self.0, self)
}
}
impl<'a> ToGlibPtrMut<'a, *mut gobject_ffi::GValue> for Value {
type Storage = &'a mut Value;
fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut gobject_ffi::GValue, Self> {
StashMut(&mut self.0, self)
}
}
impl<'a> ToGlibPtr<'a, *mut gobject_ffi::GValue> for &'a [&'a ToValue] {
type Storage = ValueArray;
fn to_glib_none(&'a self) -> Stash<'a, *mut gobject_ffi::GValue, Self> {
let mut values: Vec<gobject_ffi::GValue> = self.iter()
.map(|v| v.to_value().into_raw())
.collect();
Stash(values.as_mut_ptr(), ValueArray(values))
}
}
impl<'a> ToGlibContainerFromSlice<'a, *mut gobject_ffi::GValue> for &'a Value {
type Storage = &'a [&'a Value];
fn to_glib_none_from_slice(t: &'a [&'a Value]) -> (*mut gobject_ffi::GValue, &'a [&'a Value]) {
(t.as_ptr() as *mut gobject_ffi::GValue, t)
}
fn to_glib_container_from_slice(t: &'a [&'a Value]) -> (*mut gobject_ffi::GValue, &'a [&'a Value]) {
if t.is_empty() {
return (ptr::null_mut(), t);
}
unsafe {
let res = glib_ffi::g_malloc(mem::size_of::<gobject_ffi::GValue>() * t.len()) as *mut gobject_ffi::GValue;
ptr::copy_nonoverlapping(t.as_ptr() as *const gobject_ffi::GValue, res, t.len());
(res, t)
}
}
fn to_glib_full_from_slice(t: &[&'a Value]) -> *mut gobject_ffi::GValue {
if t.is_empty() {
return ptr::null_mut();
}
unsafe {
let res = glib_ffi::g_malloc(mem::size_of::<gobject_ffi::GValue>() * t.len()) as *mut gobject_ffi::GValue;
for (i, v) in t.iter().enumerate() {
gobject_ffi::g_value_init(res.offset(i as isize), v.type_().to_glib());
gobject_ffi::g_value_copy(v.to_glib_none().0, res.offset(i as isize));
}
res
}
}
}
impl<'a> ToGlibContainerFromSlice<'a, *const gobject_ffi::GValue> for &'a Value {
type Storage = &'a [&'a Value];
fn to_glib_none_from_slice(t: &'a [&'a Value]) -> (*const gobject_ffi::GValue, &'a [&'a Value]) {
let (ptr, storage) = ToGlibContainerFromSlice::<'a, *mut gobject_ffi::GValue>::to_glib_none_from_slice(t);
(ptr as *const _, storage)
}
fn to_glib_container_from_slice(_: &'a [&'a Value]) -> (*const gobject_ffi::GValue, &'a [&'a Value]) {
unimplemented!()
}
fn to_glib_full_from_slice(_: &[&'a Value]) -> *const gobject_ffi::GValue {
unimplemented!()
}
}
impl FromGlibPtrNone<*const gobject_ffi::GValue> for Value {
unsafe fn from_glib_none(ptr: *const gobject_ffi::GValue) -> Self {
let mut ret = Value::uninitialized();
gobject_ffi::g_value_init(ret.to_glib_none_mut().0, (*ptr).g_type);
gobject_ffi::g_value_copy(ptr, ret.to_glib_none_mut().0);
ret
}
}
impl FromGlibPtrNone<*mut gobject_ffi::GValue> for Value {
unsafe fn from_glib_none(ptr: *mut gobject_ffi::GValue) -> Self {
from_glib_none(ptr as *const _)
}
}
impl FromGlibPtrFull<*mut gobject_ffi::GValue> for Value {
unsafe fn from_glib_full(ptr: *mut gobject_ffi::GValue) -> Self {
let mut ret = Value::uninitialized();
ptr::swap(&mut ret.0, ptr);
glib_ffi::g_free(ptr as *mut c_void);
ret
}
}
impl FromGlibContainerAsVec<*mut gobject_ffi::GValue, *mut *mut gobject_ffi::GValue> for Value {
unsafe fn from_glib_none_num_as_vec(ptr: *mut *mut gobject_ffi::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.offset(i as isize))));
}
res
}
unsafe fn from_glib_container_num_as_vec(ptr: *mut *mut gobject_ffi::GValue, num: usize) -> Vec<Self> {
let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
glib_ffi::g_free(ptr as *mut _);
res
}
unsafe fn from_glib_full_num_as_vec(ptr: *mut *mut gobject_ffi::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.offset(i as isize))));
}
glib_ffi::g_free(ptr as *mut _);
res
}
}
impl FromGlibPtrArrayContainerAsVec<*mut gobject_ffi::GValue, *mut *mut gobject_ffi::GValue> for Value {
unsafe fn from_glib_none_as_vec(ptr: *mut *mut gobject_ffi::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_ffi::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_ffi::GValue) -> Vec<Self> {
FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, c_ptr_array_len(ptr))
}
}
impl FromGlibContainerAsVec<*mut gobject_ffi::GValue, *const *mut gobject_ffi::GValue> for Value {
unsafe fn from_glib_none_num_as_vec(ptr: *const *mut gobject_ffi::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_ffi::GValue, _: usize) -> Vec<Self> {
unimplemented!()
}
unsafe fn from_glib_full_num_as_vec(_: *const *mut gobject_ffi::GValue, _: usize) -> Vec<Self> {
unimplemented!()
}
}
impl FromGlibPtrArrayContainerAsVec<*mut gobject_ffi::GValue, *const *mut gobject_ffi::GValue> for Value {
unsafe fn from_glib_none_as_vec(ptr: *const *mut gobject_ffi::GValue) -> Vec<Self> {
FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr as *mut *mut _)
}
unsafe fn from_glib_container_as_vec(_: *const *mut gobject_ffi::GValue) -> Vec<Self> {
unimplemented!()
}
unsafe fn from_glib_full_as_vec(_: *const *mut gobject_ffi::GValue) -> Vec<Self> {
unimplemented!()
}
}
pub struct ValueArray(Vec<gobject_ffi::GValue>);
impl Drop for ValueArray {
fn drop(&mut self) {
unsafe {
for value in &mut self.0 {
gobject_ffi::g_value_unset(value);
}
}
}
}
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(self, value) }
}
pub fn set_none(&mut self) where T: SetValueOptional {
unsafe { T::set_value_optional(self, None) }
}
pub fn set_some<U: ?Sized + SetValue>(&mut self, value: &U) where T: Borrow<U> {
unsafe { SetValue::set_value(self, value) }
}
}
impl<T> Clone for TypedValue<T> {
fn clone(&self) -> Self {
TypedValue(self.0.clone(), PhantomData)
}
}
impl<T> fmt::Debug for TypedValue<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "TypedValue({:?})", self.0)
}
}
impl<T> Deref for TypedValue<T> {
type Target = Value;
fn deref(&self) -> &Value {
&self.0
}
}
impl<T> DerefMut for TypedValue<T> {
fn deref_mut(&mut self) -> &mut Value {
&mut self.0
}
}
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)
}
}
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::uninitialized();
gobject_ffi::g_value_init(ret.to_glib_none_mut().0, T::static_type().to_glib());
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::uninitialized();
gobject_ffi::g_value_init(ret.to_glib_none_mut().0, T::static_type().to_glib());
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_()
}
}
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_ffi::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_ffi::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_ffi::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_ffi::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full())
}
}
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.map(|v| *v))
}
}
impl SetValue for String {
unsafe fn set_value(value: &mut Value, this: &Self) {
gobject_ffi::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_ffi::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_ffi::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_ffi::g_value_get_boolean(value.to_glib_none().0))
}
}
impl SetValue for bool {
unsafe fn set_value(value: &mut Value, this: &Self) {
gobject_ffi::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_ffi::$get(value.to_glib_none().0))
}
}
impl<'a> FromValue<'a> for $name {
unsafe fn from_value(value: &'a Value) -> Self {
gobject_ffi::$get(value.to_glib_none().0)
}
}
impl SetValue for $name {
unsafe fn set_value(value: &mut Value, this: &Self) {
gobject_ffi::$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);