rune/runtime/
args.rs

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