rune/shared/
caller.rs

1use core::marker::PhantomData;
2
3use rust_alloc::sync::Arc;
4
5use crate::runtime::{FixedArgs, FunctionHandler, InstAddress, Output, VmResult};
6use crate::FromValue;
7
8/// Helper struct to conveniently call native functions.
9///
10/// Note: This can only be used with functions that take at least one argument.
11/// Otherwise it will panic.
12#[derive(Clone)]
13pub(crate) struct Caller<A, const N: usize, T> {
14    handler: Arc<FunctionHandler>,
15    _marker: PhantomData<(A, T)>,
16}
17
18impl<A, const N: usize, T> Caller<A, N, T>
19where
20    A: FixedArgs<N>,
21    T: FromValue,
22{
23    /// Construct a new caller helper
24    pub(crate) fn new(handler: Arc<FunctionHandler>) -> Self {
25        Self {
26            handler,
27            _marker: PhantomData,
28        }
29    }
30
31    /// Modify the return value of the caller.
32    pub(crate) fn with_return<U>(&self) -> Caller<A, N, U>
33    where
34        U: FromValue,
35    {
36        Caller {
37            handler: self.handler.clone(),
38            _marker: PhantomData,
39        }
40    }
41
42    /// Perform a call.
43    pub(crate) fn call(&self, args: A) -> VmResult<T> {
44        const {
45            assert!(N > 0, "Must be used with non-zero arguments");
46        }
47
48        let mut args = vm_try!(args.into_array());
49
50        vm_try!((self.handler)(
51            &mut args,
52            InstAddress::ZERO,
53            N,
54            Output::keep(0)
55        ));
56
57        let Some(value) = args.into_iter().next() else {
58            unreachable!();
59        };
60
61        VmResult::Ok(vm_try!(T::from_value(value)))
62    }
63}
64
65// SAFETY: The marker doesn't matter.
66unsafe impl<A, const N: usize, T> Send for Caller<A, N, T> {}
67unsafe impl<A, const N: usize, T> Sync for Caller<A, N, T> {}