#Trying to improve my interface for reflection on a method

17 messages · Page 1 of 1 (latest)

willow plaza
#

So i'm writing a proc macro to be able to dynamically build some basic field & method reflection on values. First part I'm trying to handle is just store anonymized static function -> call it. The test below works, but having to cast everything outside of the structs methods is pretty terrible. Is there anyway to create generic method that takes ANY static method stores -> then I can cast it back? I keep getting compiler errors for 'unknown size of generic parameter' and can't seem to find a way to get the traits on the generics to work. Below an example of what I have and more the interface I'm looking for.

What works currently.

pub struct MethodInfo {
    method: *const ()
}

impl MethodInfo {

    fn new(method: *const ()) -> Self {
        return Self { method };
    }

    fn get(&self) -> *const () 
    {
        return self.method;
    }
}
    #[test]
    fn reflection_method_test() {

        let a = Point::new(2.5f32,-1.5f32);
        let b = Point::new(8.23f32,10.0f32);

        let method = MethodInfo::new(Point::add_points as *const ());
        let result = unsafe { std::mem::transmute::<*const (),fn(Point,Point)->Point>(method.get())(a,b) };
        assert_eq!(result.x,10.73f32);
        assert_eq!(result.y,8.5f32);
    }

Interface that matches more of hat I'm looking for.

    #[test]
    fn reflection_method_test() {

        let a = Point::new(2.5f32,-1.5f32);
        let b = Point::new(8.23f32,10.0f32);

        let method = MethodInfo::new(Point::add_points);
        let result = method.get::<fn(Point,Point)->Point>()(a,b);
        assert_eq!(result.x,10.73f32);
        assert_eq!(result.y,8.5f32);
    }
jolly ruin
#

?play ```rs
use core::any::Any;

pub struct Function {
ptr: &'static dyn Any
}

impl Function {
pub fn new<R>(func: &'static fn() -> R) -> Self {
Self {
ptr: func as _
}
}

pub fn new_1<A, R>(func: &'static fn(A) -> R) -> Self {
    Self {
        ptr: func as _
    }
}

pub fn new_2<A, B, R>(func: &'static fn(A, B) -> R) -> Self {
    Self {
        ptr: func as _
    }
}

pub fn call<R: 'static>(&self) -> R {
    (self.ptr.downcast_ref::<fn() -> R>().unwrap())()
}

pub fn call_1<A: 'static, R: 'static>(&self, a: A) -> R {
    (self.ptr.downcast_ref::<fn(A) -> R>().unwrap())(a)
}

pub fn call_2<A: 'static, B: 'static, R: 'static>(&self, a: A, b: B) -> R {
    (self.ptr.downcast_ref::<fn(A, B) -> R>().unwrap())(a, b)
}

}

fn test(a: i32, b: i32) -> i32 {
a + b
}

fn main() {
let f = Function::new_2(&(test as _));
dbg!(f.call_2::<i32, i32, i32>(1, 3));
}

raven leafBOT
#
[src/main.rs:45:5] f.call_2::<i32, i32, i32>(1, 3) = 4```
jolly ruin
#

here is one way

#

plus no unsafe

willow plaza
#

🤔 yeah that works, guess since there are no variadics enumerated methods are the only way. Was thinking there would be a way to just cast fn() -> () to any other method signature so the caller could just specify the signature then call the method appropriately. Is that not possible?

jolly ruin
willow plaza
#

the goal is to eventually build it with a method signature via proc macros that gets validated on 'get' but that might require variadics also as I haven't looked into seeing if I can get the parameter list of a method as like a tuple or something :/

jolly ruin
# willow plaza the goal is to eventually build it with a method signature via proc macros that ...

?play ```rs
use core::any::Any;

fn test(a: i32, b: i32) -> i32 {
a + b
}

fn main() {
let f = Function::new(&(test as fn(_, _) -> _));
dbg!(f.call::<fn(i32, i32) -> i32>((1, 3)));
}

pub struct Function {
func: &'static dyn StaticFn
}

impl Function {
pub fn new<F: StaticFn>(func: &'static F) -> Self {
Self { func }
}

pub fn call<F: FnPtr>(&self, args: F::Args) -> Option<F::Return> {
    self.func.call::<F>(args)
}

}

pub trait StaticFn: Any {
fn as_any(&self) -> &dyn Any;
}

impl dyn StaticFn {
pub fn call<F: FnPtr>(&self, args: F::Args) -> Option<F::Return> {
self.as_any().downcast_ref::<F>().map(|func| func.call(args))
}
}

pub trait FnPtr: 'static {
type Args: 'static;
type Return: 'static;

fn call(&self, args: Self::Args) -> Self::Return;

}

macro_rules! impl_fn {
($($generic:ident),) => {
impl<$($generic: 'static,)
R: 'static> StaticFn for fn($($generic),*) -> R {
fn as_any(&self) -> &dyn Any {
self
}
}

    #[allow(non_snake_case)]
    impl<$($generic: 'static,)* R: 'static> FnPtr for fn($($generic),*) -> R {
        type Args = ($($generic,)*);
        type Return = R;
        
        fn call(&self, ($($generic,)*): Self::Args) -> Self::Return {
            (self)($($generic),*)
        }
    }
}

}

impl_fn!();
impl_fn!(A);
impl_fn!(A, B);
impl_fn!(A, B, C);
impl_fn!(A, B, C, D);

raven leafBOT
#
[src/main.rs:9:5] f.call::<fn(i32, i32) -> i32>((1, 3)) = Some(
    4,
)```
jolly ruin
#

like this?

willow plaza
#

that looks pretty similar for sure, I'd have to mess around with it. But yeah that looks a lot like what i'm trying to do

#

thanks, i'll mess around with that

jolly ruin
#
use dungeon_cell::{layout_for, DungeonCore};

fn test(a: i32, b: i32) -> i32 {
    a + b
}

fn main() {
    let core = DungeonCore::<layout_for!(fn())>::new(test as fn(i32, i32) -> i32);
    dbg!((core.borrow::<fn(i32, i32) -> i32>().unwrap())(1, 2));
}
#

another win for dungeon-cell I guess