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
16pub(crate) trait DynArgs {
18 fn push_to_stack(&mut self, stack: &mut Stack) -> Result<(), VmError>;
20
21 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 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
94pub trait FixedArgs<const N: usize> {
96 fn into_array(self) -> Result<[Value; N], VmError>;
98}
99
100pub trait Args {
102 fn into_stack(self, stack: &mut Stack) -> Result<(), VmError>;
104
105 fn try_into_vec(self) -> Result<Vec<Value>, VmError>;
107
108 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}