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*/