use std::fmt::Debug;
use std::marker::PhantomData;
use libc;
use crate::object::GodotObject;
use crate::user_data::UserData;
use crate::FromVariant;
use crate::Map;
use crate::MapMut;
use crate::NativeClass;
use crate::ToVariant;
use crate::Variant;
mod invalid;
pub use self::invalid::{InvalidGetter, InvalidSetter};
pub unsafe trait RawSetter<C, T> {
unsafe fn as_godot_function(self) -> sys::godot_property_set_func;
}
pub unsafe trait RawGetter<C, T> {
unsafe fn as_godot_function(self) -> sys::godot_property_get_func;
}
#[derive(Debug)]
pub struct Setter<SelfArg, F> {
func: F,
_self_arg: PhantomData<SelfArg>,
}
impl<SelfArg, F> Setter<SelfArg, F> {
pub fn new(func: F) -> Self {
Setter {
func,
_self_arg: PhantomData,
}
}
}
#[derive(Debug)]
pub struct Getter<SelfArg, RetKind, F> {
func: F,
_self_arg: PhantomData<SelfArg>,
_ret_kind: PhantomData<RetKind>,
}
impl<SelfArg, RetKind, F> Getter<SelfArg, RetKind, F> {
pub fn new(func: F) -> Self {
Getter {
func,
_self_arg: PhantomData,
_ret_kind: PhantomData,
}
}
}
pub struct Shr;
pub struct Mut;
pub trait MapSet<C: NativeClass, F, T> {
type Err: Debug;
fn map_set(user_data: &C::UserData, op: &F, owner: C::Base, value: T) -> Result<(), Self::Err>;
}
impl<C, F, T> MapSet<C, F, T> for Shr
where
C: NativeClass,
C::UserData: Map,
F: 'static + Fn(&C, C::Base, T),
{
type Err = <C::UserData as Map>::Err;
fn map_set(user_data: &C::UserData, op: &F, owner: C::Base, value: T) -> Result<(), Self::Err> {
user_data.map(|rust_ty| op(rust_ty, owner, value))
}
}
impl<C, F, T> MapSet<C, F, T> for Mut
where
C: NativeClass,
C::UserData: MapMut,
F: 'static + Fn(&mut C, C::Base, T),
{
type Err = <C::UserData as MapMut>::Err;
fn map_set(user_data: &C::UserData, op: &F, owner: C::Base, value: T) -> Result<(), Self::Err> {
user_data.map_mut(|rust_ty| op(rust_ty, owner, value))
}
}
pub struct Owned;
pub struct Ref;
pub trait MapGet<C: NativeClass, F, T> {
type Err: Debug;
fn map_get(user_data: &C::UserData, op: &F, owner: C::Base) -> Result<Variant, Self::Err>;
}
impl<C, F, T> MapGet<C, F, T> for (Shr, Owned)
where
C: NativeClass,
C::UserData: Map,
T: ToVariant,
F: 'static + Fn(&C, C::Base) -> T,
{
type Err = <C::UserData as Map>::Err;
fn map_get(user_data: &C::UserData, op: &F, owner: C::Base) -> Result<Variant, Self::Err> {
user_data.map(|rust_ty| op(rust_ty, owner).to_variant())
}
}
impl<C, F, T> MapGet<C, F, T> for (Shr, Ref)
where
C: NativeClass,
C::UserData: Map,
T: ToVariant,
F: 'static + Fn(&C, C::Base) -> &T,
{
type Err = <C::UserData as Map>::Err;
fn map_get(user_data: &C::UserData, op: &F, owner: C::Base) -> Result<Variant, Self::Err> {
user_data.map(|rust_ty| op(rust_ty, owner).to_variant())
}
}
impl<C, F, T> MapGet<C, F, T> for (Mut, Owned)
where
C: NativeClass,
C::UserData: MapMut,
T: ToVariant,
F: 'static + Fn(&mut C, C::Base) -> T,
{
type Err = <C::UserData as MapMut>::Err;
fn map_get(user_data: &C::UserData, op: &F, owner: C::Base) -> Result<Variant, Self::Err> {
user_data.map_mut(|rust_ty| op(rust_ty, owner).to_variant())
}
}
impl<C, F, T> MapGet<C, F, T> for (Mut, Ref)
where
C: NativeClass,
C::UserData: MapMut,
T: ToVariant,
F: 'static + Fn(&mut C, C::Base) -> &T,
{
type Err = <C::UserData as MapMut>::Err;
fn map_get(user_data: &C::UserData, op: &F, owner: C::Base) -> Result<Variant, Self::Err> {
user_data.map_mut(|rust_ty| op(rust_ty, owner).to_variant())
}
}
unsafe impl<SelfArg, F, C, T> RawSetter<C, T> for Setter<SelfArg, F>
where
C: NativeClass,
T: FromVariant,
SelfArg: MapSet<C, F, T>,
{
unsafe fn as_godot_function(self) -> sys::godot_property_set_func {
let mut set = sys::godot_property_set_func::default();
let data = Box::new(self.func);
set.method_data = Box::into_raw(data) as *mut _;
extern "C" fn invoke<SelfArg, C, F, T>(
this: *mut sys::godot_object,
method: *mut libc::c_void,
class: *mut libc::c_void,
val: *mut sys::godot_variant,
) where
C: NativeClass,
T: FromVariant,
SelfArg: MapSet<C, F, T>,
{
unsafe {
let user_data = C::UserData::clone_from_user_data_unchecked(class as *const _);
let owner = C::Base::from_sys(this);
let func = &*(method as *const F);
match T::from_variant(Variant::cast_ref(val)) {
Ok(val) => {
if let Err(err) = SelfArg::map_set(&user_data, func, owner, val) {
godot_error!("gdnative-core: cannot call property setter: {:?}", err);
}
}
Err(err) => {
godot_error!("Incorrect type passed to property: {}", err);
}
}
}
}
set.set_func = Some(invoke::<SelfArg, C, F, T>);
extern "C" fn free_func<F>(data: *mut libc::c_void) {
unsafe {
drop(Box::from_raw(data as *mut F));
}
}
set.free_func = Some(free_func::<F>);
set
}
}
unsafe impl<SelfArg, RetKind, F, C, T> RawGetter<C, T> for Getter<SelfArg, RetKind, F>
where
C: NativeClass,
T: ToVariant,
(SelfArg, RetKind): MapGet<C, F, T>,
{
unsafe fn as_godot_function(self) -> sys::godot_property_get_func {
let mut get = sys::godot_property_get_func::default();
let data = Box::new(self.func);
get.method_data = Box::into_raw(data) as *mut _;
extern "C" fn invoke<SelfArg, RetKind, C, F, T>(
this: *mut sys::godot_object,
method: *mut libc::c_void,
class: *mut libc::c_void,
) -> sys::godot_variant
where
C: NativeClass,
T: ToVariant,
(SelfArg, RetKind): MapGet<C, F, T>,
{
unsafe {
let user_data = C::UserData::clone_from_user_data_unchecked(class as *const _);
let owner = C::Base::from_sys(this);
let func = &*(method as *const F);
match <(SelfArg, RetKind)>::map_get(&user_data, func, owner) {
Ok(variant) => variant.forget(),
Err(err) => {
godot_error!("gdnative-core: cannot call property getter: {:?}", err);
Variant::new().to_sys()
}
}
}
}
get.get_func = Some(invoke::<SelfArg, RetKind, C, F, T>);
extern "C" fn free_func<F>(data: *mut libc::c_void) {
unsafe {
drop(Box::from_raw(data as *mut F));
}
}
get.free_func = Some(free_func::<F>);
get
}
}