Skip to content
This repository has been archived by the owner on Jun 8, 2021. It is now read-only.

Commit

Permalink
Merge pull request #260 from sdroege/types
Browse files Browse the repository at this point in the history
Various Type improvements and bugfix for Object::connect()
  • Loading branch information
GuillaumeGomez committed Nov 20, 2017
2 parents 5bb4919 + 8bba5c3 commit 4ba0412
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 28 deletions.
56 changes: 35 additions & 21 deletions src/object.rs
Expand Up @@ -71,7 +71,9 @@ pub trait Cast: IsA<Object> {
/// Returns `true` if the object is an instance of (can be cast to) `T`.
fn is<T>(&self) -> bool
where T: StaticType {
types::instance_of::<T>(self.to_glib_none().0 as *const _)
unsafe {
types::instance_of::<T>(self.to_glib_none().0 as *const _)
}
}

/// Tries to cast to an object of type `T`. This handles upcasting, downcasting
Expand Down Expand Up @@ -146,7 +148,9 @@ pub trait Downcast<T> {
impl<Super: IsA<Super>, Sub: IsA<Super>> Downcast<Sub> for Super {
#[inline]
fn can_downcast(&self) -> bool {
types::instance_of::<Sub>(self.to_glib_none().0 as *const _)
unsafe {
types::instance_of::<Sub>(self.to_glib_none().0 as *const _)
}
}

#[inline]
Expand Down Expand Up @@ -474,15 +478,19 @@ macro_rules! glib_object_wrapper {
fn to_glib_none(&'a self) -> $crate::translate::Stash<'a,
*mut <$super_name as $crate::wrapper::Wrapper>::GlibType, Self> {
let stash = self.0.to_glib_none();
debug_assert!($crate::types::instance_of::<$super_name>(stash.0 as *const _));
unsafe {
debug_assert!($crate::types::instance_of::<$super_name>(stash.0 as *const _));
}
$crate::translate::Stash(stash.0 as *mut _, stash.1)
}

#[inline]
fn to_glib_full(&self)
-> *mut <$super_name as $crate::wrapper::Wrapper>::GlibType {
let ptr = self.0.to_glib_full();
debug_assert!($crate::types::instance_of::<$super_name>(ptr as *const _));
unsafe {
debug_assert!($crate::types::instance_of::<$super_name>(ptr as *const _));
}
ptr as *mut _
}
}
Expand All @@ -499,14 +507,18 @@ macro_rules! glib_object_wrapper {
#[inline]
fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *mut $super_ffi, Self> {
let stash = self.0.to_glib_none();
debug_assert!($crate::types::instance_of::<$super_name>(stash.0 as *const _));
unsafe {
debug_assert!($crate::types::instance_of::<$super_name>(stash.0 as *const _));
}
$crate::translate::Stash(stash.0 as *mut _, stash.1)
}

#[inline]
fn to_glib_full(&self) -> *mut $super_ffi {
let ptr = self.0.to_glib_full();
debug_assert!($crate::types::instance_of::<$super_name>(ptr as *const _));
unsafe {
debug_assert!($crate::types::instance_of::<$super_name>(ptr as *const _));
}
ptr as *mut _
}
}
Expand Down Expand Up @@ -710,26 +722,28 @@ impl<T: IsA<Object> + SetValue> ObjectExt for T {
}

// This is actually G_SIGNAL_TYPE_STATIC_SCOPE
let return_type = details.return_type & (!gobject_ffi::G_TYPE_FLAG_RESERVED_ID_BIT);
let return_type: Type = from_glib(details.return_type & (!gobject_ffi::G_TYPE_FLAG_RESERVED_ID_BIT));
let closure = Closure::new(move |values| {
let ret = callback(values);

if return_type == gobject_ffi::G_TYPE_NONE {
// Silently drop return value, if any
None
} else if let Some(ret) = ret {
if ret.type_().to_glib() == return_type {
Some(ret)
} else {
let mut value = Value::uninitialized();
gobject_ffi::g_value_init(value.to_glib_none_mut().0, return_type);
Some(value)
if return_type == Type::Unit {
if let Some(ret) = ret {
panic!("Signal required no return value but got value of type {}", ret.type_().name());
}
None
} else {
// Silently create empty return value
let mut value = Value::uninitialized();
gobject_ffi::g_value_init(value.to_glib_none_mut().0, return_type);
Some(value)
match ret {
Some(ret) => {
if !ret.type_().is_a(&return_type) {
panic!("Signal required return value of type {} but got {}",
return_type.name(), ret.type_().name());
}
Some(ret)
},
None => {
panic!("Signal required return value of type {} but got None", return_type.name());
},
}
}
});
let handler = gobject_ffi::g_signal_connect_closure_by_id(self.to_glib_none().0, signal_id, signal_detail,
Expand Down
137 changes: 130 additions & 7 deletions src/types.rs
Expand Up @@ -4,11 +4,13 @@

//! Runtime type information.

use translate::{FromGlib, ToGlib, from_glib, from_glib_none};
use translate::{FromGlib, FromGlibContainerAsVec, ToGlib, ToGlibPtr, ToGlibContainerFromSlice, from_glib, from_glib_none};
use ffi as glib_ffi;
use gobject_ffi;

use std::fmt;
use std::mem;
use std::ptr;

/// A GLib or GLib-based library type
#[derive(Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -67,6 +69,60 @@ impl Type {
from_glib_none(gobject_ffi::g_type_name(self.to_glib()))
}
}

pub fn is_a(&self, other: &Type) -> bool {
unsafe {
from_glib(gobject_ffi::g_type_is_a(self.to_glib(), other.to_glib()))
}
}

pub fn parent(&self) -> Option<Self> {
unsafe {
let parent = gobject_ffi::g_type_parent(self.to_glib());
if parent == gobject_ffi::G_TYPE_INVALID {
None
} else {
Some(from_glib(parent))
}
}
}

pub fn children(&self) -> Vec<Self> {
unsafe {
let mut n_children = 0u32;
let children = gobject_ffi::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_ffi::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> {
unsafe {
let mut n_prereqs = 0u32;
let prereqs = gobject_ffi::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_ffi::g_type_from_name(name.into().to_glib_none().0);
if type_ == gobject_ffi::G_TYPE_INVALID {
None
} else {
Some(from_glib(type_))
}
}
}
}

impl fmt::Debug for Type {
Expand Down Expand Up @@ -136,12 +192,10 @@ pub trait InstanceType {
}

#[inline]
pub fn instance_of<C: StaticType>(ptr: glib_ffi::gconstpointer) -> bool {
unsafe {
from_glib(
gobject_ffi::g_type_check_instance_is_a(
ptr as *mut _, <C as StaticType>::static_type().to_glib()))
}
pub unsafe fn instance_of<C: StaticType>(ptr: glib_ffi::gconstpointer) -> bool {
from_glib(
gobject_ffi::g_type_check_instance_is_a(
ptr as *mut _, <C as StaticType>::static_type().to_glib()))
}

impl FromGlib<glib_ffi::GType> for Type {
Expand Down Expand Up @@ -208,3 +262,72 @@ impl ToGlib for Type {
}
}
}

impl<'a> ToGlibContainerFromSlice<'a, *mut glib_ffi::GType> for Type {
type Storage = Option<Vec<glib_ffi::GType>>;

fn to_glib_none_from_slice(t: &'a [Type]) -> (*mut glib_ffi::GType, Self::Storage) {
let mut vec = t.iter().map(|v| v.to_glib()).collect::<Vec<_>>();

(vec.as_mut_ptr(), Some(vec))
}

fn to_glib_container_from_slice(t: &'a [Type]) -> (*mut glib_ffi::GType, Self::Storage) {
(Self::to_glib_full_from_slice(t), None)
}

fn to_glib_full_from_slice(t: &[Type]) -> *mut glib_ffi::GType {
if t.len() == 0 {
return ptr::null_mut();
}

unsafe {
let res = glib_ffi::g_malloc0(mem::size_of::<glib_ffi::GType>() * (t.len() + 1)) as *mut glib_ffi::GType;
for (i, v) in t.iter().enumerate() {
*res.offset(i as isize) = v.to_glib();
}
res
}
}
}


impl FromGlibContainerAsVec<Type, *const glib_ffi::GType> for Type {
unsafe fn from_glib_none_num_as_vec(ptr: *const glib_ffi::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.offset(i as isize)));
}
res
}

unsafe fn from_glib_container_num_as_vec(_: *const glib_ffi::GType, _: usize) -> Vec<Self> {
// Can't really free a *const
unimplemented!();
}

unsafe fn from_glib_full_num_as_vec(_: *const glib_ffi::GType, _: usize) -> Vec<Self> {
// Can't really free a *const
unimplemented!();
}
}

impl FromGlibContainerAsVec<Type, *mut glib_ffi::GType> for Type {
unsafe fn from_glib_none_num_as_vec(ptr: *mut glib_ffi::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_ffi::GType, 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 glib_ffi::GType, num: usize) -> Vec<Self> {
FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num)
}
}

0 comments on commit 4ba0412

Please sign in to comment.