rune/runtime/
guarded_args.rs

1use crate::alloc::Vec;
2use crate::runtime::Args;
3use crate::runtime::{Stack, UnsafeToValue, Value, VmError};
4
5/// Trait for converting arguments onto the stack.
6///
7/// This can take references, because it is unsafe to call. And should only be
8/// implemented in contexts where it can be guaranteed that the references will
9/// not outlive the call.
10pub trait GuardedArgs {
11    /// Guard that when dropped will invalidate any values encoded.
12    type Guard;
13
14    /// Encode arguments onto a stack.
15    ///
16    /// # Safety
17    ///
18    /// This can encode references onto the stack. The caller must ensure that
19    /// the guard is dropped before any references which have been encoded are
20    /// no longer alive.
21    unsafe fn guarded_into_stack(self, stack: &mut Stack) -> Result<Self::Guard, VmError>;
22
23    /// Encode arguments into a vector.
24    ///
25    /// # Safety
26    ///
27    /// This can encode references into the vector. The caller must ensure that
28    /// the guard is dropped before any references which have been encoded are
29    /// no longer alive.
30    unsafe fn guarded_into_vec(self) -> Result<(Vec<Value>, Self::Guard), VmError>;
31
32    /// The number of arguments.
33    fn count(&self) -> usize;
34}
35
36macro_rules! impl_into_args {
37    ($count:expr $(, $ty:ident $value:ident $_:expr)*) => {
38        impl<$($ty,)*> GuardedArgs for ($($ty,)*)
39        where
40            $($ty: UnsafeToValue,)*
41        {
42            type Guard = ($($ty::Guard,)*);
43
44            #[allow(unused)]
45            #[inline]
46            unsafe fn guarded_into_stack(self, stack: &mut Stack) -> Result<Self::Guard, VmError> {
47                let ($($value,)*) = self;
48                $(let $value = $value.unsafe_to_value()?;)*
49                $(stack.push($value.0)?;)*
50                Ok(($($value.1,)*))
51            }
52
53            #[allow(unused)]
54            #[inline]
55            unsafe fn guarded_into_vec(self) -> Result<(Vec<Value>, Self::Guard), VmError> {
56                let ($($value,)*) = self;
57                $(let $value = $value.unsafe_to_value()?;)*
58                let mut out = Vec::try_with_capacity($count)?;
59                $(out.try_push($value.0)?;)*
60                Ok((out, ($($value.1,)*)))
61            }
62
63            #[inline]
64            fn count(&self) -> usize {
65                $count
66            }
67        }
68    };
69}
70
71repeat_macro!(impl_into_args);
72
73impl GuardedArgs for Vec<Value> {
74    type Guard = ();
75
76    #[inline]
77    unsafe fn guarded_into_stack(self, stack: &mut Stack) -> Result<Self::Guard, VmError> {
78        self.into_stack(stack)
79    }
80
81    #[inline]
82    unsafe fn guarded_into_vec(self) -> Result<(Vec<Value>, Self::Guard), VmError> {
83        Ok((self, ()))
84    }
85
86    #[inline]
87    fn count(&self) -> usize {
88        (self as &dyn Args).count()
89    }
90}
91
92impl GuardedArgs for rust_alloc::vec::Vec<Value> {
93    type Guard = ();
94
95    #[inline]
96    unsafe fn guarded_into_stack(self, stack: &mut Stack) -> Result<Self::Guard, VmError> {
97        self.into_stack(stack)
98    }
99
100    #[inline]
101    unsafe fn guarded_into_vec(self) -> Result<(Vec<Value>, Self::Guard), VmError> {
102        Ok((Vec::try_from(self)?, ()))
103    }
104
105    #[inline]
106    fn count(&self) -> usize {
107        self.len()
108    }
109}