use glib_sys;
use gobject_sys;
use translate::{
from_glib, from_glib_none, FromGlib, FromGlibContainerAsVec, ToGlib, ToGlibContainerFromSlice,
ToGlibPtr, ToGlibPtrMut,
};
use value::{FromValue, FromValueOptional, SetValue, Value};
use std::fmt;
use std::mem;
use std::ptr;
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Type {
Invalid,
Unit,
I8,
U8,
Bool,
I32,
U32,
ILong,
ULong,
I64,
U64,
F32,
F64,
String,
Pointer,
Variant,
BaseInterface,
BaseEnum,
BaseFlags,
BaseBoxed,
BaseParamSpec,
BaseObject,
Other(usize),
}
impl Type {
pub fn name(&self) -> String {
match self {
Type::Invalid => "<invalid>".to_string(),
_ => unsafe { from_glib_none(gobject_sys::g_type_name(self.to_glib())) },
}
}
pub fn qname(&self) -> ::Quark {
match self {
Type::Invalid => ::Quark::from_string("<invalid>"),
_ => unsafe { from_glib(gobject_sys::g_type_qname(self.to_glib())) },
}
}
pub fn is_a(&self, other: &Type) -> bool {
unsafe { from_glib(gobject_sys::g_type_is_a(self.to_glib(), other.to_glib())) }
}
pub fn parent(&self) -> Option<Self> {
unsafe {
let parent = gobject_sys::g_type_parent(self.to_glib());
if parent == gobject_sys::G_TYPE_INVALID {
None
} else {
Some(from_glib(parent))
}
}
}
pub fn children(&self) -> Vec<Self> {
unsafe {
let mut n_children = 0u32;
let children = gobject_sys::g_type_children(self.to_glib(), &mut n_children);
FromGlibContainerAsVec::from_glib_full_num_as_vec(children, n_children as usize)
}
}
pub fn interfaces(&self) -> Vec<Self> {
unsafe {
let mut n_interfaces = 0u32;
let interfaces = gobject_sys::g_type_interfaces(self.to_glib(), &mut n_interfaces);
FromGlibContainerAsVec::from_glib_full_num_as_vec(interfaces, n_interfaces as usize)
}
}
pub fn interface_prerequisites(&self) -> Vec<Self> {
match self {
t if !t.is_a(&Type::BaseInterface) => vec![],
_ => unsafe {
let mut n_prereqs = 0u32;
let prereqs =
gobject_sys::g_type_interface_prerequisites(self.to_glib(), &mut n_prereqs);
FromGlibContainerAsVec::from_glib_full_num_as_vec(prereqs, n_prereqs as usize)
},
}
}
pub fn from_name<'a, P: Into<&'a str>>(name: P) -> Option<Self> {
unsafe {
let type_ = gobject_sys::g_type_from_name(name.into().to_glib_none().0);
if type_ == gobject_sys::G_TYPE_INVALID {
None
} else {
Some(from_glib(type_))
}
}
}
}
impl fmt::Debug for Type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.name())
}
}
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.name())
}
}
pub trait StaticType {
fn static_type() -> Type;
}
impl StaticType for Type {
fn static_type() -> Type {
unsafe { from_glib(gobject_sys::g_gtype_get_type()) }
}
}
impl<'a> FromValueOptional<'a> for Type {
unsafe fn from_value_optional(value: &'a Value) -> Option<Self> {
Some(from_glib(gobject_sys::g_value_get_gtype(
value.to_glib_none().0,
)))
}
}
impl<'a> FromValue<'a> for Type {
unsafe fn from_value(value: &'a Value) -> Self {
from_glib(gobject_sys::g_value_get_gtype(value.to_glib_none().0))
}
}
impl SetValue for Type {
unsafe fn set_value(value: &mut Value, this: &Self) {
gobject_sys::g_value_set_gtype(value.to_glib_none_mut().0, this.to_glib())
}
}
impl<'a, T: ?Sized + StaticType> StaticType for &'a T {
fn static_type() -> Type {
T::static_type()
}
}
impl<'a, T: ?Sized + StaticType> StaticType for &'a mut T {
fn static_type() -> Type {
T::static_type()
}
}
macro_rules! builtin {
($name:ident, $val:ident) => {
impl StaticType for $name {
fn static_type() -> Type {
Type::$val
}
}
};
}
builtin!(bool, Bool);
builtin!(i8, I8);
builtin!(u8, U8);
builtin!(i32, I32);
builtin!(u32, U32);
builtin!(i64, I64);
builtin!(u64, U64);
builtin!(f32, F32);
builtin!(f64, F64);
builtin!(str, String);
builtin!(String, String);
impl<'a> StaticType for [&'a str] {
fn static_type() -> Type {
unsafe { from_glib(glib_sys::g_strv_get_type()) }
}
}
impl StaticType for Vec<String> {
fn static_type() -> Type {
unsafe { from_glib(glib_sys::g_strv_get_type()) }
}
}
#[inline]
#[allow(clippy::missing_safety_doc)]
pub unsafe fn instance_of<C: StaticType>(ptr: glib_sys::gconstpointer) -> bool {
from_glib(gobject_sys::g_type_check_instance_is_a(
ptr as *mut _,
<C as StaticType>::static_type().to_glib(),
))
}
impl FromGlib<glib_sys::GType> for Type {
#[inline]
fn from_glib(val: glib_sys::GType) -> Type {
use self::Type::*;
match val {
gobject_sys::G_TYPE_INVALID => Invalid,
gobject_sys::G_TYPE_NONE => Unit,
gobject_sys::G_TYPE_INTERFACE => BaseInterface,
gobject_sys::G_TYPE_CHAR => I8,
gobject_sys::G_TYPE_UCHAR => U8,
gobject_sys::G_TYPE_BOOLEAN => Bool,
gobject_sys::G_TYPE_INT => I32,
gobject_sys::G_TYPE_UINT => U32,
gobject_sys::G_TYPE_LONG => ILong,
gobject_sys::G_TYPE_ULONG => ULong,
gobject_sys::G_TYPE_INT64 => I64,
gobject_sys::G_TYPE_UINT64 => U64,
gobject_sys::G_TYPE_ENUM => BaseEnum,
gobject_sys::G_TYPE_FLAGS => BaseFlags,
gobject_sys::G_TYPE_FLOAT => F32,
gobject_sys::G_TYPE_DOUBLE => F64,
gobject_sys::G_TYPE_STRING => String,
gobject_sys::G_TYPE_POINTER => Pointer,
gobject_sys::G_TYPE_BOXED => BaseBoxed,
gobject_sys::G_TYPE_PARAM => BaseParamSpec,
gobject_sys::G_TYPE_OBJECT => BaseObject,
gobject_sys::G_TYPE_VARIANT => Variant,
x => Other(x as usize),
}
}
}
impl ToGlib for Type {
type GlibType = glib_sys::GType;
fn to_glib(&self) -> glib_sys::GType {
use self::Type::*;
match *self {
Invalid => gobject_sys::G_TYPE_INVALID,
Unit => gobject_sys::G_TYPE_NONE,
BaseInterface => gobject_sys::G_TYPE_INTERFACE,
I8 => gobject_sys::G_TYPE_CHAR,
U8 => gobject_sys::G_TYPE_UCHAR,
Bool => gobject_sys::G_TYPE_BOOLEAN,
I32 => gobject_sys::G_TYPE_INT,
U32 => gobject_sys::G_TYPE_UINT,
ILong => gobject_sys::G_TYPE_LONG,
ULong => gobject_sys::G_TYPE_ULONG,
I64 => gobject_sys::G_TYPE_INT64,
U64 => gobject_sys::G_TYPE_UINT64,
BaseEnum => gobject_sys::G_TYPE_ENUM,
BaseFlags => gobject_sys::G_TYPE_FLAGS,
F32 => gobject_sys::G_TYPE_FLOAT,
F64 => gobject_sys::G_TYPE_DOUBLE,
String => gobject_sys::G_TYPE_STRING,
Pointer => gobject_sys::G_TYPE_POINTER,
BaseBoxed => gobject_sys::G_TYPE_BOXED,
BaseParamSpec => gobject_sys::G_TYPE_PARAM,
BaseObject => gobject_sys::G_TYPE_OBJECT,
Variant => gobject_sys::G_TYPE_VARIANT,
Other(x) => x as glib_sys::GType,
}
}
}
impl<'a> ToGlibContainerFromSlice<'a, *mut glib_sys::GType> for Type {
type Storage = Option<Vec<glib_sys::GType>>;
fn to_glib_none_from_slice(t: &'a [Type]) -> (*mut glib_sys::GType, Self::Storage) {
let mut vec = t.iter().map(ToGlib::to_glib).collect::<Vec<_>>();
(vec.as_mut_ptr(), Some(vec))
}
fn to_glib_container_from_slice(t: &'a [Type]) -> (*mut glib_sys::GType, Self::Storage) {
(Self::to_glib_full_from_slice(t), None)
}
fn to_glib_full_from_slice(t: &[Type]) -> *mut glib_sys::GType {
if t.is_empty() {
return ptr::null_mut();
}
unsafe {
let res = glib_sys::g_malloc0(mem::size_of::<glib_sys::GType>() * (t.len() + 1))
as *mut glib_sys::GType;
for (i, v) in t.iter().enumerate() {
*res.add(i) = v.to_glib();
}
res
}
}
}
impl FromGlibContainerAsVec<Type, *const glib_sys::GType> for Type {
unsafe fn from_glib_none_num_as_vec(ptr: *const glib_sys::GType, 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(*ptr.add(i)));
}
res
}
unsafe fn from_glib_container_num_as_vec(_: *const glib_sys::GType, _: usize) -> Vec<Self> {
unimplemented!();
}
unsafe fn from_glib_full_num_as_vec(_: *const glib_sys::GType, _: usize) -> Vec<Self> {
unimplemented!();
}
}
impl FromGlibContainerAsVec<Type, *mut glib_sys::GType> for Type {
unsafe fn from_glib_none_num_as_vec(ptr: *mut glib_sys::GType, num: usize) -> Vec<Self> {
FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num)
}
unsafe fn from_glib_container_num_as_vec(ptr: *mut glib_sys::GType, 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 glib_sys::GType, num: usize) -> Vec<Self> {
FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn invalid() {
let invalid = Type::Invalid;
assert_eq!(invalid.name(), "<invalid>");
assert_eq!(invalid.qname(), ::Quark::from_string("<invalid>"));
assert!(invalid.is_a(&Type::Invalid));
assert!(!invalid.is_a(&Type::String));
assert_eq!(invalid.parent(), None);
assert_eq!(invalid.children(), vec![]);
assert_eq!(invalid.interfaces(), vec![]);
assert_eq!(invalid.interface_prerequisites(), vec![]);
dbg!(&invalid);
}
}