cao_lang/
traits.rs

1use crate::{procedures::ExecutionErrorPayload, value::Value, vm::Vm};
2use std::{any::type_name, convert::TryFrom};
3
4pub const MAX_STR_LEN: usize = 256;
5
6type ShallowExecutionResult = Result<Value, ExecutionErrorPayload>;
7
8#[derive(Debug)]
9pub enum StringDecodeError {
10    /// Could not decode lengt
11    LengthDecodeError,
12    /// Got an invalid length
13    LengthError(usize),
14    /// Did not fit into available space
15    CapacityError(usize),
16    Utf8DecodeError(std::str::Utf8Error),
17}
18
19/// Objects that can act as Cao-Lang functions
20pub trait VmFunction<Aux> {
21    fn call(&self, vm: &mut Vm<Aux>) -> ShallowExecutionResult;
22}
23
24pub type VmFunction1<Aux, T1> = fn(&mut Vm<Aux>, T1) -> ShallowExecutionResult;
25pub type VmFunction2<Aux, T1, T2> = fn(&mut Vm<Aux>, T1, T2) -> ShallowExecutionResult;
26pub type VmFunction3<Aux, T1, T2, T3> = fn(&mut Vm<Aux>, T1, T2, T3) -> ShallowExecutionResult;
27pub type VmFunction4<Aux, T1, T2, T3, T4> =
28    fn(&mut Vm<Aux>, T1, T2, T3, T4) -> ShallowExecutionResult;
29
30/// Casts the given function pointer to a Cao-Lang VM function taking 1 argument
31///
32/// See also:
33///
34/// - [into_f2]
35/// - [into_f3]
36/// - [into_f4]
37///
38/// ```
39/// use cao_lang::prelude::*;
40///
41/// let mut vm = Vm::new(()).unwrap();
42///
43/// fn fun(_vm: &mut Vm<()>, _param: i64) -> Result<Value, ExecutionErrorPayload> {
44///     Ok(Value::Nil)
45/// }
46///
47/// vm.register_native_function("my function", into_f1(fun));
48///
49/// ```
50pub fn into_f1<Aux, T1>(f: fn(&mut Vm<Aux>, T1) -> ShallowExecutionResult) -> VmFunction1<Aux, T1> {
51    f as VmFunction1<_, _>
52}
53
54pub fn into_f2<Aux, T1, T2>(
55    f: fn(&mut Vm<Aux>, T1, T2) -> ShallowExecutionResult,
56) -> VmFunction2<Aux, T1, T2> {
57    f as VmFunction2<_, _, _>
58}
59
60pub fn into_f3<Aux, T1, T2, T3>(
61    f: fn(&mut Vm<Aux>, T1, T2, T3) -> ShallowExecutionResult,
62) -> VmFunction3<Aux, T1, T2, T3> {
63    f as VmFunction3<_, _, _, _>
64}
65
66pub fn into_f4<Aux, T1, T2, T3, T4>(
67    f: fn(&mut Vm<Aux>, T1, T2, T3, T4) -> ShallowExecutionResult,
68) -> VmFunction4<Aux, T1, T2, T3, T4> {
69    f as VmFunction4<_, _, _, _, _>
70}
71
72impl<Aux, F> VmFunction<Aux> for F
73where
74    F: Fn(&mut Vm<Aux>) -> ShallowExecutionResult,
75{
76    fn call(&self, vm: &mut Vm<Aux>) -> ShallowExecutionResult {
77        self(vm)
78    }
79}
80
81fn conversion_error(input: usize, expected: &str, actual: &str) -> ExecutionErrorPayload {
82    ExecutionErrorPayload::invalid_argument(format!(
83        "Failed to convert function input #{}: Expected: {}, Found: {}",
84        input, expected, actual
85    ))
86}
87
88impl<Aux, T1> VmFunction<Aux> for VmFunction1<Aux, T1>
89where
90    T1: TryFrom<Value>,
91{
92    fn call(&self, vm: &mut Vm<Aux>) -> ShallowExecutionResult {
93        let v1 = vm.stack_pop();
94        let v1 =
95            T1::try_from(v1).map_err(|_| conversion_error(1, type_name::<T1>(), v1.type_name()))?;
96        self(vm, v1)
97    }
98}
99
100impl<Aux, T1, T2> VmFunction<Aux> for fn(&mut Vm<Aux>, T1, T2) -> ShallowExecutionResult
101where
102    T1: TryFrom<Value>,
103    T2: TryFrom<Value>,
104{
105    fn call(&self, vm: &mut Vm<Aux>) -> ShallowExecutionResult {
106        let v2 = vm.stack_pop();
107        let v2 =
108            T2::try_from(v2).map_err(|_| conversion_error(2, type_name::<T2>(), v2.type_name()))?;
109        let v1 = vm.stack_pop();
110        let v1 =
111            T1::try_from(v1).map_err(|_| conversion_error(1, type_name::<T1>(), v1.type_name()))?;
112        self(vm, v1, v2)
113    }
114}
115
116impl<Aux, T1, T2, T3> VmFunction<Aux> for fn(&mut Vm<Aux>, T1, T2, T3) -> ShallowExecutionResult
117where
118    T1: TryFrom<Value>,
119    T2: TryFrom<Value>,
120    T3: TryFrom<Value>,
121{
122    fn call(&self, vm: &mut Vm<Aux>) -> ShallowExecutionResult {
123        let v3 = vm.stack_pop();
124        let v3 =
125            T3::try_from(v3).map_err(|_| conversion_error(3, type_name::<T3>(), v3.type_name()))?;
126        let v2 = vm.stack_pop();
127        let v2 =
128            T2::try_from(v2).map_err(|_| conversion_error(2, type_name::<T2>(), v2.type_name()))?;
129        let v1 = vm.stack_pop();
130        let v1 =
131            T1::try_from(v1).map_err(|_| conversion_error(1, type_name::<T1>(), v1.type_name()))?;
132        self(vm, v1, v2, v3)
133    }
134}
135
136impl<Aux, T1, T2, T3, T4> VmFunction<Aux>
137    for fn(&mut Vm<Aux>, T1, T2, T3, T4) -> ShallowExecutionResult
138where
139    T1: TryFrom<Value>,
140    T2: TryFrom<Value>,
141    T3: TryFrom<Value>,
142    T4: TryFrom<Value>,
143{
144    fn call(&self, vm: &mut Vm<Aux>) -> ShallowExecutionResult {
145        let v4 = vm.stack_pop();
146        let v4 =
147            T4::try_from(v4).map_err(|_| conversion_error(4, type_name::<T4>(), v4.type_name()))?;
148        let v3 = vm.stack_pop();
149        let v3 =
150            T3::try_from(v3).map_err(|_| conversion_error(3, type_name::<T3>(), v3.type_name()))?;
151        let v2 = vm.stack_pop();
152        let v2 =
153            T2::try_from(v2).map_err(|_| conversion_error(2, type_name::<T2>(), v2.type_name()))?;
154        let v1 = vm.stack_pop();
155        let v1 =
156            T1::try_from(v1).map_err(|_| conversion_error(1, type_name::<T1>(), v1.type_name()))?;
157        self(vm, v1, v2, v3, v4)
158    }
159}