rune/runtime/
args.rs

1use core::fmt;
2
3use crate::alloc::Vec;
4use crate::runtime::{GuardedArgs, Stack, ToValue, Value, VmResult};
5
6#[derive(Debug)]
7#[cfg_attr(test, derive(PartialEq))]
8pub(crate) struct DynArgsUsed;
9
10impl fmt::Display for DynArgsUsed {
11    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
12        write!(f, "Dynamic arguments have already been used")
13    }
14}
15
16/// Object safe variant of args which errors instead of consumed itself.
17pub(crate) trait DynArgs {
18    /// Encode arguments onto a stack.
19    fn push_to_stack(&mut self, stack: &mut Stack) -> VmResult<()>;
20
21    /// Get the number of arguments.
22    fn count(&self) -> usize;
23}
24
25impl DynArgs for () {
26    fn push_to_stack(&mut self, _: &mut Stack) -> VmResult<()> {
27        VmResult::Ok(())
28    }
29
30    fn count(&self) -> usize {
31        0
32    }
33}
34
35impl<T> DynArgs for Option<T>
36where
37    T: Args,
38{
39    fn push_to_stack(&mut self, stack: &mut Stack) -> VmResult<()> {
40        let Some(args) = self.take() else {
41            return VmResult::err(DynArgsUsed);
42        };
43
44        vm_try!(args.into_stack(stack));
45        VmResult::Ok(())
46    }
47
48    fn count(&self) -> usize {
49        self.as_ref().map_or(0, Args::count)
50    }
51}
52
53pub(crate) struct DynGuardedArgs<T>
54where
55    T: GuardedArgs,
56{
57    value: Option<T>,
58    guard: Option<T::Guard>,
59}
60
61impl<T> DynGuardedArgs<T>
62where
63    T: GuardedArgs,
64{
65    pub(crate) fn new(value: T) -> Self {
66        Self {
67            value: Some(value),
68            guard: None,
69        }
70    }
71}
72
73impl<T> DynArgs for DynGuardedArgs<T>
74where
75    T: GuardedArgs,
76{
77    fn push_to_stack(&mut self, stack: &mut Stack) -> VmResult<()> {
78        let Some(value) = self.value.take() else {
79            return VmResult::err(DynArgsUsed);
80        };
81
82        // SAFETY: We've setup the type so that the caller cannot ignore the guard.
83        self.guard = unsafe { Some(vm_try!(GuardedArgs::guarded_into_stack(value, stack))) };
84
85        VmResult::Ok(())
86    }
87
88    fn count(&self) -> usize {
89        self.value.as_ref().map_or(0, GuardedArgs::count)
90    }
91}
92
93/// Trait for converting arguments into an array.
94pub trait FixedArgs<const N: usize> {
95    /// Encode arguments as array.
96    fn into_array(self) -> VmResult<[Value; N]>;
97}
98
99/// Trait for converting arguments onto the stack.
100pub trait Args {
101    /// Encode arguments onto a stack.
102    fn into_stack(self, stack: &mut Stack) -> VmResult<()>;
103
104    /// Convert arguments into a vector.
105    fn try_into_vec(self) -> VmResult<Vec<Value>>;
106
107    /// The number of arguments.
108    fn count(&self) -> usize;
109}
110
111macro_rules! impl_into_args {
112    ($count:expr $(, $ty:ident $value:ident $_:expr)*) => {
113        impl<$($ty,)*> FixedArgs<$count> for ($($ty,)*)
114        where
115            $($ty: ToValue,)*
116        {
117            #[allow(unused)]
118            fn into_array(self) -> VmResult<[Value; $count]> {
119                let ($($value,)*) = self;
120                $(let $value = vm_try!($value.to_value());)*
121                VmResult::Ok([$($value),*])
122            }
123        }
124
125        impl<$($ty,)*> Args for ($($ty,)*)
126        where
127            $($ty: ToValue,)*
128        {
129            #[allow(unused)]
130            fn into_stack(self, stack: &mut Stack) -> VmResult<()> {
131                let ($($value,)*) = self;
132                $(vm_try!(stack.push(vm_try!($value.to_value())));)*
133                VmResult::Ok(())
134            }
135
136            #[allow(unused)]
137            fn try_into_vec(self) -> VmResult<Vec<Value>> {
138                let ($($value,)*) = self;
139                let mut vec = vm_try!(Vec::try_with_capacity($count));
140                $(vm_try!(vec.try_push(vm_try!(<$ty>::to_value($value))));)*
141                VmResult::Ok(vec)
142            }
143
144            #[inline]
145            fn count(&self) -> usize {
146                $count
147            }
148        }
149    };
150}
151
152repeat_macro!(impl_into_args);
153
154impl Args for Vec<Value> {
155    fn into_stack(self, stack: &mut Stack) -> VmResult<()> {
156        for value in self {
157            vm_try!(stack.push(value));
158        }
159
160        VmResult::Ok(())
161    }
162
163    #[inline]
164    fn try_into_vec(self) -> VmResult<Vec<Value>> {
165        VmResult::Ok(self)
166    }
167
168    #[inline]
169    fn count(&self) -> usize {
170        self.len()
171    }
172}
173
174#[cfg(feature = "alloc")]
175impl Args for ::rust_alloc::vec::Vec<Value> {
176    fn into_stack(self, stack: &mut Stack) -> VmResult<()> {
177        for value in self {
178            vm_try!(stack.push(value));
179        }
180
181        VmResult::Ok(())
182    }
183
184    #[inline]
185    fn try_into_vec(self) -> VmResult<Vec<Value>> {
186        VmResult::Ok(vm_try!(Vec::try_from(self)))
187    }
188
189    #[inline]
190    fn count(&self) -> usize {
191        self.len()
192    }
193}