wasmer_interface_types_fl/
macros.rs

1//! Collection of helpful macros.
2
3/// This macro creates a `Vec1` by checking at compile-time that its
4/// invariant holds.
5#[macro_export]
6macro_rules! ne_vec {
7    ($item:expr; 0) => {
8        compile_error!("Cannot create an empty `Vec1`, it violates its invariant.")
9    };
10
11    () => {
12        compile_error!("Cannot create an empty `Vec1`, it violates its invariant.")
13    };
14
15    ($item:expr; $length:expr) => {
16        {
17            fluence_it_types::ne_vec::NEVec::new(vec![$item; $length]).unwrap()
18        }
19    };
20
21    ($($item:expr),+ $(,)?) => {
22        {
23            fluence_it_types::ne_vec::NEVec::new(vec![$($item),*]).unwrap()
24        }
25    };
26}
27
28/// This macro runs a parser, extracts the next input and the parser
29/// output, and positions the next input on `$input`.
30macro_rules! consume {
31    (($input:ident, $parser_output:ident) = $parser_expression:expr) => {
32        let (next_input, $parser_output) = $parser_expression;
33        $input = next_input;
34    };
35
36    (($input:ident, mut $parser_output:ident) = $parser_expression:expr) => {
37        let (next_input, mut $parser_output) = $parser_expression;
38        $input = next_input;
39    };
40}
41
42/// This macro creates an executable instruction for the interpreter.
43///
44/// # Example
45///
46/// The following example creates a `foo` executable instruction.clone(),
47/// which takes 2 arguments (`x` and `y`), and does something
48/// mysterious by using the `interpreter::Runtime` API.
49///
50/// ```rust,ignore
51/// executable_instruction!(
52///     foo(x: u64, y: u64, instruction_name: String) -> _ {
53/// //                                                   ^ output type is purposely blank
54/// //                      ^^^^^^^^^^^^^^^^ the instruction name, for debugging purposes
55/// //              ^ the `y` argument
56/// //      ^ the `x` argument
57///
58///     // an executable instruction is a closure that takes a `Runtime` instance
59///     move |runtime| -> Pin<Box<dyn Future<Output = Result<(), InstructionError>> + 'static>> _ {
60///         // Do something.
61///
62///         Ok(())
63///     }
64/// );
65/// ```
66///
67/// Check the existing executable instruction to get more examples.
68macro_rules! impl_async_executable_instruction {
69    ($getter_name:ident($($argument_name:ident: $argument_type:ty),*) -> _ $getter_implementation:block $name:ident $($implementation:tt)*) => {
70        impl<Instance, Export, LocalImport, Memory, MemoryView, Store> crate::interpreter::AsyncExecutableInstructionImpl<Instance, Export, LocalImport, Memory, MemoryView, Store> for $name
71        where
72            Export: crate::interpreter::wasm::structures::Export,
73            LocalImport: crate::interpreter::wasm::structures::LocalImport<Store>,
74            Memory: crate::interpreter::wasm::structures::Memory<MemoryView, Store>,
75            MemoryView: crate::interpreter::wasm::structures::MemoryView<Store>,
76            Instance: crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView, Store>,
77            Store: crate::interpreter::wasm::structures::Store, $($implementation)*
78
79        pub(crate) fn $getter_name<Instance, Export, LocalImport, Memory, MemoryView, Store>($($argument_name: $argument_type),*) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView, Store>
80        where
81        Export: crate::interpreter::wasm::structures::Export,
82        LocalImport: crate::interpreter::wasm::structures::LocalImport<Store>,
83        Memory: crate::interpreter::wasm::structures::Memory<MemoryView, Store>,
84        MemoryView: crate::interpreter::wasm::structures::MemoryView<Store>,
85        Instance: crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView, Store>,
86        Store: crate::interpreter::wasm::structures::Store, {
87            crate::interpreter::ExecutableInstruction::Async($getter_implementation)
88        }
89    }
90}
91
92macro_rules! impl_sync_executable_instruction {
93    ($name:ident ( $($argument_name:ident: $argument_type:ty),* ) -> _ $implementation:block ) => {
94        pub(crate) fn $name<Instance, Export, LocalImport, Memory, MemoryView, Store>(
95            $($argument_name: $argument_type),*
96        ) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView, Store>
97        where
98            Export: crate::interpreter::wasm::structures::Export,
99            LocalImport: crate::interpreter::wasm::structures::LocalImport<Store>,
100            Memory: crate::interpreter::wasm::structures::Memory<MemoryView, Store>,
101            MemoryView: crate::interpreter::wasm::structures::MemoryView<Store>,
102            Instance: crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView, Store>,
103            Store: crate::interpreter::wasm::structures::Store,
104        {
105            #[allow(unused_imports)]
106            use crate::interpreter::{stack::Stackable};
107
108            crate::interpreter::ExecutableInstruction::Sync(Box::new($implementation))
109        }
110    };
111}
112
113#[cfg(test)]
114macro_rules! test_executable_instruction {
115    (
116        $test_name:ident =
117            instructions: [ $($instructions:expr),* $(,)* ],
118            invocation_inputs: [ $($invocation_inputs:expr),* $(,)* ],
119            instance: $instance:expr,
120            stack: [ $($stack:expr),* $(,)* ]
121            $(,)*
122    ) => {
123        #[test]
124        #[allow(non_snake_case, unused)]
125        fn $test_name() {
126            use crate::{
127                interpreter::{
128                    instructions::tests::{Export, Instance, LocalImport, Memory, MemoryView},
129                    stack::Stackable,
130                    Instruction, Interpreter,
131                },
132                types::IType,
133                values::IValue,
134            };
135            use std::{cell::Cell, collections::HashMap, convert::TryInto};
136
137            let interpreter: Interpreter<Instance, Export, LocalImport, Memory, MemoryView> =
138                (&vec![$($instructions),*]).try_into().unwrap();
139
140            let invocation_inputs = vec![$($invocation_inputs),*];
141            let mut instance = $instance;
142            let run = interpreter.run(&invocation_inputs, &mut instance);
143
144            let err = match &run {
145                Ok(_) => "".to_string(),
146                Err(e) => e.to_string(),
147            };
148
149            assert!(run.is_ok(), err);
150
151            let stack = run.unwrap();
152
153            assert_eq!(stack.as_slice(), &[$($stack),*]);
154        }
155    };
156
157    (
158        $test_name:ident =
159            instructions: [ $($instructions:expr),* $(,)* ],
160            invocation_inputs: [ $($invocation_inputs:expr),* $(,)* ],
161            instance: $instance:expr,
162            error: $error:expr
163            $(,)*
164    ) => {
165        #[test]
166        #[allow(non_snake_case, unused)]
167        fn $test_name() {
168            use crate::{
169                interpreter::{
170                    instructions::tests::{Export, Instance, LocalImport, Memory, MemoryView},
171                    stack::Stackable,
172                    Instruction, Interpreter,
173                },
174                types::IType,
175                values::IValue,
176            };
177            use std::{cell::Cell, collections::HashMap, convert::TryInto};
178
179            let interpreter: Interpreter<Instance, Export, LocalImport, Memory, MemoryView> =
180                (&vec![$($instructions),*]).try_into().unwrap();
181
182            let invocation_inputs = vec![$($invocation_inputs),*];
183            let mut instance = $instance;
184            let run = interpreter.run(&invocation_inputs, &mut instance);
185
186            assert!(run.is_err());
187
188            let error = run.unwrap_err().to_string();
189
190            assert_eq!(error, String::from($error));
191        }
192    };
193}