use std::{marker, mem};
use super::{InitializingType, Signal};
use crate::{prelude::*, translate::*, Object, ParamSpec, Type};
pub trait PrerequisiteList {
fn types() -> Vec<ffi::GType>;
}
impl PrerequisiteList for () {
fn types() -> Vec<ffi::GType> {
vec![]
}
}
impl<T: crate::ObjectType> PrerequisiteList for (T,) {
fn types() -> Vec<ffi::GType> {
vec![T::static_type().into_glib()]
}
}
macro_rules! prerequisite_list_trait(
($name1:ident, $name2: ident, $($name:ident),*) => (
prerequisite_list_trait!(__impl $name1, $name2; $($name),*);
);
(__impl $($name:ident),+; $name1:ident, $($name2:ident),*) => (
prerequisite_list_trait_impl!($($name),+);
prerequisite_list_trait!(__impl $($name),+ , $name1; $($name2),*);
);
(__impl $($name:ident),+; $name1:ident) => (
prerequisite_list_trait_impl!($($name),+);
prerequisite_list_trait_impl!($($name),+, $name1);
);
);
macro_rules! prerequisite_list_trait_impl(
($($name:ident),+) => (
impl<$($name: crate::ObjectType),+> PrerequisiteList for ( $($name),+ ) {
fn types() -> Vec<ffi::GType> {
vec![$($name::static_type().into_glib()),+]
}
}
);
);
prerequisite_list_trait!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);
pub unsafe trait ObjectInterfaceType {
#[doc(alias = "get_type")]
fn type_() -> Type;
}
pub unsafe trait ObjectInterface: ObjectInterfaceType + Sized + 'static {
const NAME: &'static str;
type Prerequisites: PrerequisiteList;
fn type_init(_type_: &mut InitializingType<Self>) {}
fn interface_init(&mut self) {}
fn properties() -> &'static [ParamSpec] {
&[]
}
fn signals() -> &'static [Signal] {
&[]
}
}
pub trait ObjectInterfaceExt: ObjectInterface {
#[inline]
#[deprecated = "Use from_obj() instead"]
fn from_instance<T: IsA<Object>>(obj: &T) -> &Self {
Self::from_obj(obj)
}
#[inline]
fn from_obj<T: IsA<Object>>(obj: &T) -> &Self {
assert!(obj.as_ref().type_().is_a(Self::type_()));
unsafe {
let klass = (*(obj.as_ptr() as *const gobject_ffi::GTypeInstance)).g_class;
let interface =
gobject_ffi::g_type_interface_peek(klass as *mut _, Self::type_().into_glib());
debug_assert!(!interface.is_null());
&*(interface as *const Self)
}
}
}
impl<T: ObjectInterface> ObjectInterfaceExt for T {}
unsafe extern "C" fn interface_init<T: ObjectInterface>(
klass: ffi::gpointer,
_klass_data: ffi::gpointer,
) {
let iface = &mut *(klass as *mut T);
let pspecs = <T as ObjectInterface>::properties();
for pspec in pspecs {
gobject_ffi::g_object_interface_install_property(
iface as *mut T as *mut _,
pspec.to_glib_none().0,
);
}
let type_ = T::type_();
let signals = <T as ObjectInterface>::signals();
for signal in signals {
signal.register(type_);
}
iface.interface_init();
}
pub fn register_interface<T: ObjectInterface>() -> Type {
unsafe {
use std::ffi::CString;
let type_name = CString::new(T::NAME).unwrap();
assert_eq!(
gobject_ffi::g_type_from_name(type_name.as_ptr()),
gobject_ffi::G_TYPE_INVALID
);
let type_ = gobject_ffi::g_type_register_static_simple(
Type::INTERFACE.into_glib(),
type_name.as_ptr(),
mem::size_of::<T>() as u32,
Some(interface_init::<T>),
0,
None,
0,
);
let prerequisites = T::Prerequisites::types();
for prerequisite in prerequisites {
gobject_ffi::g_type_interface_add_prerequisite(type_, prerequisite);
}
let type_ = Type::from_glib(type_);
assert!(type_.is_valid());
T::type_init(&mut InitializingType::<T>(type_, marker::PhantomData));
type_
}
}