1use crate::{Composite, Execute, Field, Message, PopStack, PrepareMessage, PushStack, StackValue};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub struct PopFromStack<Values>(pub Values);
19
20impl<Values: 'static> Message for PopFromStack<Values> {}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub struct PushToStack<Values>(pub Values);
30
31pub trait HasOperandStack<I> {
45 type Source;
47
48 fn operand_stack(&mut self, arity: usize) -> &mut Self::Source;
55}
56
57pub trait Apply<E> {
71 fn apply(&mut self, effect: E);
73}
74
75impl<C, F, I, Context: ?Sized> PrepareMessage<C, F, I, Context> for PopFromStack<()>
76where
77 C: Composite + Field<F> + HasOperandStack<I>,
78 C::Child: Execute<I, Message = PopFromStack<()>>,
79{
80 #[inline]
81 fn prepare(_: &mut C, _: &I, _: &Context) -> eyre::Result<Self> {
82 Ok(PopFromStack(()))
83 }
84}
85
86impl<D> Apply<PushToStack<()>> for D {
87 #[inline]
88 fn apply(&mut self, _: PushToStack<()>) {}
89}
90
91impl<D, T: StackValue, const N: usize> Apply<PushToStack<[T; N]>> for D
92where
93 D: PushStack<T::Storage>,
94{
95 #[inline]
96 fn apply(&mut self, effect: PushToStack<[T; N]>) {
97 for value in effect.0 {
98 value.push_to(self);
99 }
100 }
101}
102
103macro_rules! stack_tuple {
107 (@pop $source:ident;) => {};
108 (@pop $source:ident; $ty:ident:$value:ident $(, $rest:ident:$other:ident)*) => {
109 stack_tuple!(@pop $source; $($rest:$other),*);
110 let $value = $ty::pop_from($source)?;
111 };
112 ($($ty:ident:$value:ident),+) => {
113 impl<Parent, Route, Inst, Context: ?Sized, $($ty: StackValue),+>
114 PrepareMessage<Parent, Route, Inst, Context> for PopFromStack<($($ty,)+)>
115 where
116 Parent: Composite + Field<Route> + HasOperandStack<Inst>,
117 Parent::Child: Execute<Inst, Message = PopFromStack<($($ty,)+)>>,
118 Parent::Source: $(PopStack<$ty::Storage> +)+ Sized,
119 {
120 #[inline]
121 fn prepare(parent: &mut Parent, _: &Inst, _: &Context) -> eyre::Result<Self> {
122 let source = parent.operand_stack([$(stringify!($ty)),+].len());
123 stack_tuple!(@pop source; $($ty:$value),+);
124 Ok(PopFromStack(($($value,)+)))
125 }
126 }
127
128 impl<Destination, $($ty: StackValue),+>
129 Apply<PushToStack<($($ty,)+)>> for Destination
130 where
131 Destination: $(PushStack<$ty::Storage> +)+ Sized,
132 {
133 #[inline]
134 fn apply(&mut self, effect: PushToStack<($($ty,)+)>) {
135 let ($($value,)+) = effect.0;
136 $($value.push_to(self);)+
137 }
138 }
139 };
140}
141
142stack_tuple!(A:a);
143
144stack_tuple!(A:a, B:b);
145
146stack_tuple!(A:a, B:b, C:c);
147
148stack_tuple!(A:a, B:b, C:c, D:d);
149
150stack_tuple!(A:a, B:b, C:c, D:d, E:e);
151
152stack_tuple!(A:a, B:b, C:c, D:d, E:e, F:f);
153
154stack_tuple!(A:a, B:b, C:c, D:d, E:e, F:f, G:g);
155
156stack_tuple!(A:a, B:b, C:c, D:d, E:e, F:f, G:g, H:h);
157
158stack_tuple!(A:a, B:b, C:c, D:d, E:e, F:f, G:g, H:h, I:i);
159
160stack_tuple!(A:a, B:b, C:c, D:d, E:e, F:f, G:g, H:h, I:i, J:j);
161
162stack_tuple!(A:a, B:b, C:c, D:d, E:e, F:f, G:g, H:h, I:i, J:j, K:k);
163
164stack_tuple!(A:a, B:b, C:c, D:d, E:e, F:f, G:g, H:h, I:i, J:j, K:k, L:l);
165
166stack_tuple!(A:a, B:b, C:c, D:d, E:e, F:f, G:g, H:h, I:i, J:j, K:k, L:l, M:m);
167
168stack_tuple!(A:a, B:b, C:c, D:d, E:e, F:f, G:g, H:h, I:i, J:j, K:k, L:l, M:m, N:n);
169
170stack_tuple!(A:a, B:b, C:c, D:d, E:e, F:f, G:g, H:h, I:i, J:j, K:k, L:l, M:m, N:n, O:o);
171
172stack_tuple!(A:a, B:b, C:c, D:d, E:e, F:f, G:g, H:h, I:i, J:j, K:k, L:l, M:m, N:n, O:o, P:p);
173
174#[derive(Debug, Clone, Copy, PartialEq, Eq)]
176pub enum InputCount {
177 Immediate(usize),
179 FromStack,
181}
182
183pub trait StackInputCount<I> {
188 fn input_count(instruction: &I) -> eyre::Result<InputCount>;
189}
190
191impl<C, F, I, T, Context: ?Sized> PrepareMessage<C, F, I, Context>
192 for PopFromStack<crate::StackBatch<T>>
193where
194 C: Composite + Field<F> + HasOperandStack<I>,
195 C::Child: Execute<I, Message = PopFromStack<crate::StackBatch<T>>> + StackInputCount<I>,
196 T: StackValue + 'static,
197 C::Source: PopStack<T::Storage> + PopStack<vihaco_abi::word::Word>,
198{
199 fn prepare(parent: &mut C, instruction: &I, _: &Context) -> eyre::Result<Self> {
200 let count = match C::Child::input_count(instruction)? {
201 InputCount::Immediate(count) => count,
202 InputCount::FromStack => {
203 let word = PopStack::<vihaco_abi::word::Word>::pop(parent.operand_stack(1))?;
204 usize::try_from(word)?
205 }
206 };
207 let mut values = smallvec::SmallVec::new();
208 values
211 .try_reserve_exact(count)
212 .map_err(|error| eyre::eyre!("cannot reserve operand batch: {error:?}"))?;
213 if count != 0 {
214 let source = parent.operand_stack(count);
215 for _ in 0..count {
216 values.push(T::pop_from(source)?);
217 }
218 values.reverse();
219 }
220 Ok(PopFromStack(crate::StackBatch { values }))
221 }
222}
223
224impl<C: crate::HasProgram, I> HasOperandStack<I> for C {
227 type Source = C::Program;
228 #[inline]
229 fn operand_stack(&mut self, _: usize) -> &mut Self::Source {
230 self.program_mut()
231 }
232}