evalit/runtime/object/
function.rs

1use std::{fmt, marker::PhantomData};
2
3use crate::{Object, RuntimeError, Value, ValueRef, bytecode::FunctionId};
4
5#[derive(Debug, Clone, Copy)]
6pub struct UserFunction(FunctionId);
7
8impl UserFunction {
9    pub fn new(id: FunctionId) -> Self {
10        Self(id)
11    }
12
13    pub fn id(&self) -> FunctionId {
14        self.0
15    }
16}
17
18impl Object for UserFunction {
19    fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20        write!(f, "UserFunction({:?})", self.0)
21    }
22}
23
24/// NativeFunction
25pub struct NativeFunction {
26    pub name: String,
27    pub func: Box<dyn Function>,
28}
29
30impl NativeFunction {
31    pub fn new(name: impl ToString, func: Box<dyn Function>) -> Self {
32        Self {
33            name: name.to_string(),
34            func,
35        }
36    }
37}
38
39impl fmt::Debug for NativeFunction {
40    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41        write!(f, "<NativeFunction`{}`>", self.name)
42    }
43}
44
45impl Object for NativeFunction {
46    fn call(&mut self, args: &[ValueRef]) -> Result<Option<Value>, RuntimeError> {
47        (self.func).call(args)
48    }
49}
50
51/// Function trait for external functions.
52pub trait Function: Send + 'static {
53    fn call(&mut self, args: &[ValueRef]) -> Result<Option<Value>, RuntimeError>;
54}
55
56pub struct IntoFunction<F, Args> {
57    func: F,
58    _marker: PhantomData<fn(Args) -> ()>,
59}
60
61impl<F, Args> Function for IntoFunction<F, Args>
62where
63    F: Callable<Args> + Clone + Send,
64    Args: 'static,
65{
66    fn call(&mut self, args: &[ValueRef]) -> Result<Option<Value>, RuntimeError> {
67        self.func.call(args)
68    }
69}
70
71pub trait IntoRet {
72    fn into_ret(self) -> Result<Option<Value>, RuntimeError>;
73}
74
75// impl IntoRet for Value {
76//     fn into_ret(self) -> Result<Option<Value>, RuntimeError> {
77//         Ok(Some(self))
78//     }
79// }
80
81impl<T: Object> IntoRet for T {
82    fn into_ret(self) -> Result<Option<Value>, RuntimeError> {
83        Ok(Some(Value::new(self)))
84    }
85}
86
87// impl IntoRet for Result<Value, RuntimeError> {
88//     fn into_ret(self) -> Result<Option<Value>, RuntimeError> {
89//         self.map(Some)
90//     }
91// }
92
93impl<T: Object> IntoRet for Result<T, RuntimeError> {
94    fn into_ret(self) -> Result<Option<Value>, RuntimeError> {
95        self.map(|v| Some(Value::new(v)))
96    }
97}
98
99impl<T: Object> IntoRet for Result<Option<T>, RuntimeError> {
100    fn into_ret(self) -> Result<Option<Value>, RuntimeError> {
101        self.map(|v| v.map(Value::new))
102    }
103}
104
105pub trait FromValue: Sized {
106    fn from_value(value: &ValueRef) -> Result<Self, RuntimeError>;
107}
108
109impl<T> FromValue for T
110where
111    T: Object + Clone,
112{
113    fn from_value(value: &ValueRef) -> Result<T, RuntimeError> {
114        let value = value
115            .downcast_ref::<T>()
116            .ok_or(RuntimeError::invalid_type::<T>(value))?;
117
118        Ok(value.clone())
119    }
120}
121
122pub trait Callable<Args>: Clone + Sized + 'static {
123    fn call(&mut self, args: &[ValueRef]) -> Result<Option<Value>, RuntimeError>;
124
125    fn into_function(self) -> IntoFunction<Self, Args> {
126        IntoFunction {
127            func: self,
128            _marker: PhantomData,
129        }
130    }
131}
132
133impl<F, Ret> Callable<&[ValueRef]> for F
134where
135    F: Fn(&[ValueRef]) -> Ret + Clone + 'static,
136    Ret: IntoRet,
137{
138    fn call(&mut self, args: &[ValueRef]) -> Result<Option<Value>, RuntimeError> {
139        (self)(args).into_ret()
140    }
141}
142
143impl<F, Ret> Callable<()> for F
144where
145    F: Fn() -> Ret + Clone + 'static,
146    Ret: IntoRet,
147{
148    fn call(&mut self, _args: &[ValueRef]) -> Result<Option<Value>, RuntimeError> {
149        self().into_ret()
150    }
151}
152
153macro_rules! impl_callable {
154    ($($idx: expr => $arg: ident),+) => {
155        #[allow(non_snake_case)]
156        impl<F, Ret, $($arg,)*> Callable<($($arg,)*)> for F
157        where
158            F: Fn($($arg,)*) -> Ret + Clone  + 'static,
159            Ret: IntoRet,
160            $( $arg: FromValue + 'static, )*
161        {
162            fn call(&mut self, args: &[ValueRef]) -> Result<Option<Value>, RuntimeError> {
163                $(
164                    let $arg = <$arg>::from_value(args.get($idx).ok_or(RuntimeError::invalid_argument::<$arg>($idx, "NoThing"))?)?;
165                )*
166                (self)($($arg,)*).into_ret()
167            }
168        }
169    }
170}
171
172impl_callable!(0=>T0);
173impl_callable!(0=>T0, 1=>T1);
174impl_callable!(0=>T0, 1=>T1, 2=>T2);
175impl_callable!(0=>T0, 1=>T1, 2=>T2, 3=>T3);
176impl_callable!(0=>T0, 1=>T1, 2=>T2, 3=>T3, 4=>T4);
177impl_callable!(0=>T0, 1=>T1, 2=>T2, 3=>T3, 4=>T4, 5=>T5);
178impl_callable!(0=>T0, 1=>T1, 2=>T2, 3=>T3, 4=>T4, 5=>T5, 6=>T6);
179impl_callable!(0=>T0, 1=>T1, 2=>T2, 3=>T3, 4=>T4, 5=>T5, 6=>T6, 7=>T7);
180impl_callable!(0=>T0, 1=>T1, 2=>T2, 3=>T3, 4=>T4, 5=>T5, 6=>T6, 7=>T7, 8=>T8);
181impl_callable!(0=>T0, 1=>T1, 2=>T2, 3=>T3, 4=>T4, 5=>T5, 6=>T6, 7=>T7, 8=>T8, 9=>T9);
182impl_callable!(0=>T0, 1=>T1, 2=>T2, 3=>T3, 4=>T4, 5=>T5, 6=>T6, 7=>T7, 8=>T8, 9=>T9, 10=>T10);
183impl_callable!(0=>T0, 1=>T1, 2=>T2, 3=>T3, 4=>T4, 5=>T5, 6=>T6, 7=>T7, 8=>T8, 9=>T9, 10=>T10, 11=>T11);
184impl_callable!(0=>T0, 1=>T1, 2=>T2, 3=>T3, 4=>T4, 5=>T5, 6=>T6, 7=>T7, 8=>T8, 9=>T9, 10=>T10, 11=>T11, 12=>T12);
185impl_callable!(0=>T0, 1=>T1, 2=>T2, 3=>T3, 4=>T4, 5=>T5, 6=>T6, 7=>T7, 8=>T8, 9=>T9, 10=>T10, 11=>T11, 12=>T12, 13=>T13);
186impl_callable!(0=>T0, 1=>T1, 2=>T2, 3=>T3, 4=>T4, 5=>T5, 6=>T6, 7=>T7, 8=>T8, 9=>T9, 10=>T10, 11=>T11, 12=>T12, 13=>T13, 14=>T14);
187impl_callable!(0=>T0, 1=>T1, 2=>T2, 3=>T3, 4=>T4, 5=>T5, 6=>T6, 7=>T7, 8=>T8, 9=>T9, 10=>T10, 11=>T11, 12=>T12, 13=>T13, 14=>T14, 15=>T15);
188
189/* use this when [feature(macro_metavar_expr)](https://github.com/rust-lang/rust/pull/122808) is available
190macro_rules! impl_callable_tuple {
191    ($($arg: ident),+) => {
192        #[allow(non_snake_case)]
193        impl<F, Ret, $($arg,)*> Callable<($($arg,)*)> for F
194        where
195            F: Fn($($arg,)*) -> Ret + Clone + Send + 'static,
196            Ret: IntoRet,
197            $( $arg: FromValue, )*
198        {
199            fn call(&mut self, args: &[Value]) -> Result<Option<Value>, RuntimeError> {
200                $(
201                    let $arg = <$arg>::from_value(&args[${index()}])?;
202                )*
203                (self)($($arg,)*).into_ret()
204            }
205        }
206    }
207}
208impl_callable_tuple!(T0);
209impl_callable_tuple!(T0, T1);
210impl_callable_tuple!(T0, T1, T2);
211impl_callable_tuple!(T0, T1, T2, T3);
212impl_callable_tuple!(T0, T1, T2, T3, T4);
213impl_callable_tuple!(T0, T1, T2, T3, T4, T5);
214impl_callable_tuple!(T0, T1, T2, T3, T4, T5, T6);
215impl_callable_tuple!(T0, T1, T2, T3, T4, T5, T6, T7);
216impl_callable_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
217impl_callable_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
218impl_callable_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
219impl_callable_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
220impl_callable_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
221impl_callable_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
222impl_callable_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
223impl_callable_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15);
224impl_callable_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16);
225 */
226
227/* TODO:
228pub struct Method<T> {
229    pub name: String,
230    pub func: Box<dyn MethodFunction<T>>,
231}
232
233impl<T> fmt::Debug for Method<T> {
234    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
235        write!(f, "Method<{}.{}>", type_name::<T>(), self.Value)
236    }
237}
238
239impl<T: Object> Method<T> {
240    pub fn new<Args>(name: impl ToString, method: impl MethodCallable<T, Args>) -> Self
241    where
242        Args: 'static,
243    {
244        Method {
245            name: name.to_string(),
246            func: Box::new(method.into_function()),
247        }
248    }
249}
250
251/// Function trait for external functions.
252pub trait MethodFunction<T>: Send + 'static {
253    fn call(&mut self, this: &mut T, args: &[Value]) -> Result<Option<Value>, RuntimeError>;
254}
255
256pub struct IntoMethodFunction<F, Args> {
257    func: F,
258    _marker: PhantomData<fn(Args) -> ()>,
259}
260
261impl<T, F, Args> MethodFunction<T> for IntoMethodFunction<F, Args>
262where
263    F: MethodCallable<T, Args> + Clone,
264    Args: 'static,
265{
266    fn call(&mut self, this: &mut T, args: &[Value]) -> Result<Option<Value>, RuntimeError> {
267        self.func.call(this, args)
268    }
269}
270
271pub trait MethodCallable<T, Args>: Clone + Send + Sized + 'static {
272    fn call(&mut self, this: &mut T, args: &[Value]) -> Result<Option<Value>, RuntimeError>;
273
274    fn into_function(self) -> IntoMethodFunction<Self, Args> {
275        IntoMethodFunction {
276            func: self,
277            _marker: PhantomData,
278        }
279    }
280}
281
282impl<T, F, Ret> MethodCallable<T, &[Value]> for F
283where
284    T: Object,
285    F: Fn(&mut T, &[Value]) -> Ret + Clone + Send + 'static,
286    Ret: IntoRet,
287{
288    fn call(&mut self, this: &mut T, args: &[Value]) -> Result<Option<Value>, RuntimeError> {
289        (self)(this, args).into_ret()
290    }
291}
292
293impl<T, F, Ret> MethodCallable<T, ()> for F
294where
295    F: Fn(&T) -> Ret + Clone + Send + 'static,
296    Ret: IntoRet,
297{
298    fn call(&mut self, this: &mut T, args: &[Value]) -> Result<Option<Value>, RuntimeError> {
299        self(this).into_ret()
300    }
301}
302
303impl<T, F, Ret, Arg> MethodCallable<T, Arg> for F
304where
305    F: Fn(&mut T, Arg) -> Ret + Clone + Send + 'static,
306    Ret: IntoRet,
307    Arg: FromValue,
308{
309    fn call(&mut self, this: &mut T, args: &[Value]) -> Result<Option<Value>, RuntimeError> {
310        let arg = Arg::from_value(&args[0])?;
311
312        (self)(this, arg).into_ret()
313    }
314}
315
316*/