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 LengthDecodeError,
12 LengthError(usize),
14 CapacityError(usize),
16 Utf8DecodeError(std::str::Utf8Error),
17}
18
19pub 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
30pub 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}