1use crate::{Error, EvalType, Result, TypeInfo};
2use std::{any::Any, ops::Deref};
3
4pub struct DynFn {
6 pub arg_type: TypeInfo,
7 pub ret_type: TypeInfo,
8 boxed_fun: Box<dyn ClonableAny>,
9}
10
11impl DynFn {
12 pub fn new<Arg, Ret>(
13 f: impl for<'a> Fn(&'a Arg) -> Ret::RefType<'a> + Clone + 'static,
14 ) -> Self
15 where
16 Arg: EvalType,
17 Ret: EvalType,
18 {
19 Self {
20 boxed_fun: Box::new(BoxedFn(Box::new(f))),
21 arg_type: Arg::type_info(),
22 ret_type: Ret::type_info(),
23 }
24 }
25
26 pub fn downcast<Arg, Ret>(&self) -> Result<BoxedFn<Arg, Ret>>
27 where
28 Arg: EvalType,
29 Ret: EvalType,
30 {
31 Ok(self.boxed_fun.as_any().downcast_ref().cloned().ok_or_else(
32 || Error::InternalDynFnDowncastError {
33 expected_arg: Arg::type_info(),
34 expected_ret: Ret::type_info(),
35 got_arg: self.arg_type,
36 got_ret: self.ret_type,
37 },
38 )?)
39 }
40}
41
42impl Clone for DynFn {
43 fn clone(&self) -> Self {
44 DynFn {
45 boxed_fun: self.boxed_fun.clone_box(),
46 ..*self
47 }
48 }
49}
50
51pub struct BoxedFn<Arg, Ret>(Box<dyn ClonableFn<Arg, Ret>>)
53where
54 Ret: EvalType;
55
56impl<Arg, Ret> Clone for BoxedFn<Arg, Ret>
57where
58 Ret: EvalType,
59{
60 fn clone(&self) -> Self {
61 self.clone_boxed()
62 }
63}
64
65impl<Arg, Ret> Deref for BoxedFn<Arg, Ret>
67where
68 Ret: EvalType,
69{
70 type Target = Box<dyn ClonableFn<Arg, Ret>>;
71 fn deref(&self) -> &Self::Target {
72 &self.0
73 }
74}
75
76trait ClonableAny: Any {
77 fn clone_box(&self) -> Box<dyn ClonableAny>;
78 fn as_any(&self) -> &dyn Any;
79}
80
81impl<T: Any + Clone> ClonableAny for T {
82 fn clone_box(&self) -> Box<dyn ClonableAny> {
83 Box::new(self.clone())
84 }
85 fn as_any(&self) -> &dyn Any {
86 self
87 }
88}
89
90pub trait ClonableFn<Arg, Ret>:
91 for<'a> Fn(&'a Arg) -> Ret::RefType<'a>
92where
93 Ret: EvalType,
94{
95 fn clone_boxed(&self) -> BoxedFn<Arg, Ret>;
96}
97
98impl<Arg, Ret, F> ClonableFn<Arg, Ret> for F
100where
101 Ret: EvalType,
102 F: for<'a> Fn(&'a Arg) -> Ret::RefType<'a> + Clone + 'static,
103{
104 fn clone_boxed(&self) -> BoxedFn<Arg, Ret> {
105 BoxedFn(Box::new(self.clone()))
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn test_dyn_fn() {
115 let dyn_fn = DynFn::new::<_, i64>(|a: &(i64, i64)| a.0);
118
119 let concrete_fn = dyn_fn.downcast::<(i64, i64), i64>().unwrap();
122
123 assert_eq!((concrete_fn)(&(10, 20)), 10);
125 }
126}