use crate::binds::{MonoDelegate, MonoMethod};
use crate::binds::{MonoException, MonoObject};
use crate::gc::{gc_unsafe_enter, gc_unsafe_exit, GCHandle};
use crate::tupleutilis::{CompareClasses, TupleToPtrs};
#[allow(unused_imports)] use crate::Method;
use crate::ObjectTrait;
use crate::{Class, Domain, Exception, InteropClass, InteropRecive, InteropSend, MString, Object};
use core::ptr::null_mut;
use std::ffi::c_void;
use std::marker::PhantomData;
pub struct Delegate<Args: InteropSend> {
#[cfg(not(feature = "referneced_objects"))]
dptr: *mut MonoDelegate,
#[cfg(feature = "referneced_objects")]
handle: GCHandle,
args_type: PhantomData<Args>,
}
impl<Args: InteropSend> Delegate<Args> {
fn get_ptr(&self) -> *mut MonoDelegate {
#[cfg(not(feature = "referneced_objects"))]
{
self.dptr
}
#[cfg(feature = "referneced_objects")]
{
self.handle.get_target() as *mut MonoDelegate
}
}
pub fn get_param_count(&self) -> u32 {
#[cfg(feature = "referneced_objects")]
let marker = gc_unsafe_enter();
let sig = unsafe { crate::binds::mono_method_signature(self.get_method_ptr()) };
let pcount = unsafe { crate::binds::mono_signature_get_param_count(sig) };
#[cfg(feature = "referneced_objects")]
gc_unsafe_exit(marker);
pcount
}
pub fn get_params(&self) -> Vec<Class> {
#[cfg(feature = "referneced_objects")]
let marker = gc_unsafe_enter();
let sig = unsafe { crate::binds::mono_method_signature(self.get_method_ptr()) };
let mut iter: usize = 0;
let mut res = Vec::with_capacity(self.get_param_count() as usize);
while let Some(class) = unsafe {
Class::from_ptr({
let ptr = crate::binds::mono_signature_get_params(
sig,
&mut iter as *mut usize as *mut *mut c_void,
);
if ptr.is_null() {
null_mut()
} else {
crate::binds::mono_class_from_mono_type(ptr)
}
})
} {
res.push(class);
}
#[cfg(feature = "referneced_objects")]
gc_unsafe_exit(marker);
res
}
pub fn get_param_names(&self) -> Vec<String> {
use std::ffi::CString;
let pcount = self.get_param_count() as usize;
let mut ptrs: Vec<*const i8> = Vec::with_capacity(pcount);
ptrs.resize(pcount, std::ptr::null::<i8>());
#[cfg(feature = "referneced_objects")]
let marker = gc_unsafe_enter();
unsafe {
crate::binds::mono_method_get_param_names(
self.get_method_ptr(),
ptrs.as_ptr() as *mut *const i8,
)
};
let mut res: Vec<String> = Vec::with_capacity(pcount);
for ptr in &ptrs {
let cstr = unsafe { CString::from_raw(*ptr as *mut i8) };
res.push(
cstr.to_str()
.expect("Could not create String from ptr")
.to_owned(),
);
let _ = cstr.into_raw();
}
drop(ptrs);
#[cfg(feature = "referneced_objects")]
gc_unsafe_exit(marker);
res
}
pub fn get_return(&self) -> Class {
let sig = unsafe { crate::binds::mono_method_signature(self.get_method_ptr()) };
let ptr = unsafe { crate::binds::mono_signature_get_return_type(sig) };
unsafe {
Class::from_ptr(crate::binds::mono_class_from_mono_type(ptr)).expect("Got no method return type, but no return type should be signaled by System.Void type!")
}
}
fn get_method_ptr(&self) -> *mut MonoMethod {
unsafe { crate::binds::mono_get_delegate_invoke(self.get_class().get_ptr()) }
}
}
pub trait DelegateTrait<Args: InteropSend> {
unsafe fn from_ptr(ptr: *mut MonoDelegate) -> Option<Self>
where
Self: Sized;
unsafe fn from_ptr_checked(ptr: *mut MonoDelegate) -> Option<Self>
where
Self: Sized;
fn invoke(&self, params: Args) -> Result<Option<Object>, Exception>;
}
impl<Args: InteropSend> DelegateTrait<Args> for Delegate<Args> {
default unsafe fn from_ptr(ptr: *mut MonoDelegate) -> Option<Self> {
if ptr.is_null() {
None
} else {
#[cfg(not(feature = "referneced_objects"))]
{
Some(Self {
dptr: ptr,
args_type: PhantomData,
})
}
#[cfg(feature = "referneced_objects")]
{
Some(Self {
handle: GCHandle::create_default(ptr as *mut crate::binds::MonoObject),
args_type: PhantomData,
})
}
}
}
default unsafe fn from_ptr_checked(ptr: *mut MonoDelegate) -> Option<Self> {
if ptr.is_null() {
None
} else {
#[cfg(not(feature = "referneced_objects"))]
{
Some(Self {
dptr: ptr,
args_type: PhantomData,
})
}
#[cfg(feature = "referneced_objects")]
{
Some(Self {
handle: GCHandle::create_default(ptr as *mut crate::binds::MonoObject),
args_type: PhantomData,
})
}
}
}
default fn invoke(&self, params: Args) -> Result<Option<Object>, Exception> {
let mut expect: *mut MonoException = null_mut();
let mut args = <Args as InteropSend>::get_mono_rep(params);
let mut params = &mut args as *mut _ as *mut c_void;
#[cfg(feature = "referneced_objects")]
let marker = gc_unsafe_enter();
let res_ptr = unsafe {
crate::binds::mono_runtime_delegate_invoke(
self.get_ptr() as *mut _,
&mut params as *mut *mut c_void,
&mut expect as *mut *mut MonoException as *mut *mut MonoObject,
)
};
crate::hold(&args);
let res = unsafe { Object::from_ptr(res_ptr) };
println!("expect:{}", expect as usize);
if expect.is_null() {
#[cfg(feature = "referneced_objects")]
gc_unsafe_exit(marker);
Ok(res)
} else {
let except = unsafe {
Exception::from_ptr(expect)
.expect("Imposible: pointer is null and not null at the same time.")
};
#[cfg(feature = "referneced_objects")]
gc_unsafe_exit(marker);
Err(except)
}
}
}
impl<Args: InteropSend> DelegateTrait<Args> for Delegate<Args>
where
<Args as InteropSend>::TargetType: TupleToPtrs + CompareClasses,
{
default unsafe fn from_ptr(ptr: *mut MonoDelegate) -> Option<Self> {
let res = {
if ptr.is_null() {
return None;
} else {
#[cfg(not(feature = "referneced_objects"))]
{
Self {
dptr: ptr,
args_type: PhantomData,
}
}
#[cfg(feature = "referneced_objects")]
{
Self {
handle: GCHandle::create_default(ptr as *mut crate::binds::MonoObject),
args_type: PhantomData,
}
}
}
};
let params = res.get_params();
if !<<Args as InteropSend>::TargetType as CompareClasses>::compare(¶ms) {
use std::fmt::Write;
let mut msg = format!(
"Delegate Type Mismatch! Got a deleagte accepting {} arguments of types:",
params.len()
);
for param in params {
write!(msg, ",\"{}\"", param.get_name_sig())
.expect("Could not print inproper function argument types!");
}
panic!("{}", msg);
}
Some(res)
}
default unsafe fn from_ptr_checked(ptr: *mut MonoDelegate) -> Option<Self> {
let res = {
if ptr.is_null() {
return None;
} else {
#[cfg(not(feature = "referneced_objects"))]
{
Self {
dptr: ptr,
args_type: PhantomData,
}
}
#[cfg(feature = "referneced_objects")]
{
Self {
handle: GCHandle::create_default(ptr as *mut crate::binds::MonoObject),
args_type: PhantomData,
}
}
}
};
let params = res.get_params();
if !<<Args as InteropSend>::TargetType as CompareClasses>::compare(¶ms) {
None
} else {
Some(res)
}
}
default fn invoke(&self, params: Args) -> Result<Option<Object>, Exception> {
let mut expect: *mut MonoException = null_mut();
let mut args = <Args as InteropSend>::get_mono_rep(params);
let mut params =
<<Args as InteropSend>::TargetType as TupleToPtrs>::get_ptrs(&mut args as *mut _);
#[cfg(feature = "referneced_objects")]
let marker = gc_unsafe_enter();
let res_ptr = unsafe {
crate::binds::mono_runtime_delegate_invoke(
self.get_ptr() as *mut _,
&mut params as *mut _ as *mut *mut c_void,
&mut expect as *mut *mut MonoException as *mut *mut MonoObject,
)
};
crate::hold(&args);
let res = unsafe { Object::from_ptr(res_ptr) };
if expect.is_null() {
#[cfg(feature = "referneced_objects")]
gc_unsafe_exit(marker);
Ok(res)
} else {
let except = unsafe {
Exception::from_ptr(expect)
.expect("Imposible: pointer is null and not null at the same time.")
};
#[cfg(feature = "referneced_objects")]
gc_unsafe_exit(marker);
Err(except)
}
}
}
impl<Args: InteropSend> InteropRecive for Delegate<Args> {
type SourceType = *mut MonoDelegate;
#[allow(clippy::not_unsafe_ptr_arg_deref)]
fn get_rust_rep(ptr: *mut MonoDelegate) -> Delegate<Args> {
unsafe { Self::from_ptr(ptr).expect("Expected non-null value but got null") }
}
}
impl<Args: InteropSend> InteropRecive for Option<Delegate<Args>> {
type SourceType = *mut MonoDelegate;
#[allow(clippy::not_unsafe_ptr_arg_deref)]
fn get_rust_rep(ptr: *mut MonoDelegate) -> Option<Delegate<Args>> {
unsafe { Delegate::from_ptr(ptr) }
}
}
impl<Args: InteropSend> InteropClass for Delegate<Args> {
fn get_mono_class() -> Class {
Class::get_delegate_class()
}
}
impl<Args: InteropSend> InteropSend for Delegate<Args> {
type TargetType = *mut MonoDelegate;
fn get_mono_rep(input: Delegate<Args>) -> Self::TargetType {
input.get_ptr()
}
}
impl<Args: InteropSend> ObjectTrait for Delegate<Args> {
fn hash(&self) -> i32 {
unsafe { crate::binds::mono_object_hash(self.get_ptr() as *mut _) }
}
fn get_domain(&self) -> Domain {
unsafe {
Domain::from_ptr(crate::binds::mono_object_get_domain(
self.get_ptr() as *mut _
))
}
}
fn get_size(&self) -> u32 {
unsafe { crate::binds::mono_object_get_size(self.get_ptr() as *mut _) }
}
fn reflection_get_token(&self) -> u32 {
unsafe { crate::binds::mono_reflection_get_token(self.get_ptr() as *mut _) }
}
fn get_class(&self) -> Class {
unsafe {
Class::from_ptr(crate::binds::mono_object_get_class(self.get_ptr() as *mut _))
.expect("Could not get class of an object")
}
}
fn to_mstring(&self) -> Result<Option<MString>, Exception> {
let mut exc: *mut crate::binds::MonoException = core::ptr::null_mut();
let res = unsafe {
MString::from_ptr(crate::binds::mono_object_to_string(
self.get_ptr() as *mut _,
&mut exc as *mut *mut crate::binds::MonoException
as *mut *mut crate::binds::MonoObject,
))
};
let exc = unsafe { Exception::from_ptr(exc) };
match exc {
Some(e) => Err(e),
None => Ok(res),
}
}
fn cast_to_object(&self) -> Object {
unsafe { Object::from_ptr(self.get_ptr() as *mut _) }.unwrap()
}
fn cast_from_object(obj: &Object) -> Option<Self> {
if !Self::get_mono_class().is_assignable_from(&obj.get_class()) {
None
} else {
unsafe { Self::from_ptr_checked(obj.get_ptr() as *mut _) }
}
}
}
impl<O: ObjectTrait, Args: InteropSend> PartialEq<O> for Delegate<Args> {
fn eq(&self, other: &O) -> bool {
self.get_ptr() as *mut _ == other.cast_to_object().get_ptr()
}
}