pulley_interpreter/
op.rs

1//! Pulley bytecode operations with their operands.
2
3#[cfg(feature = "encode")]
4use crate::encode::Encode;
5use crate::imms::*;
6use crate::regs::*;
7
8macro_rules! define_op {
9    (
10        $(
11            $( #[$attr:meta] )*
12            $snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ;
13        )*
14    ) => {
15        /// A complete, materialized operation/instruction.
16        ///
17        /// This type is useful for debugging, writing tests, etc... but is not
18        /// actually ever used by the interpreter, encoder, or decoder, all of
19        /// which avoid materializing ops.
20        #[derive(Clone, Copy, Debug, PartialEq, Eq)]
21        #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
22        pub enum Op {
23            $(
24                $( #[$attr] )*
25                $name($name),
26            )*
27            /// An extended operation/instruction.
28            ExtendedOp(ExtendedOp),
29        }
30
31        $(
32            $( #[$attr] )*
33            #[derive(Clone, Copy, Debug, PartialEq, Eq)]
34            #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
35            pub struct $name { $(
36                $(
37                    // TODO: add doc comments to all fields and update all
38                    // the macros to match them.
39                    #[allow(missing_docs, reason = "macro-generated code")]
40                    pub $field : $field_ty,
41                )*
42            )? }
43
44            impl From<$name> for Op {
45                #[inline]
46                fn from(op: $name) -> Self {
47                    Self::$name(op)
48                }
49            }
50        )*
51    };
52}
53for_each_op!(define_op);
54
55impl From<ExtendedOp> for Op {
56    #[inline]
57    fn from(op: ExtendedOp) -> Self {
58        Op::ExtendedOp(op)
59    }
60}
61
62macro_rules! define_extended_op {
63    (
64        $(
65            $( #[$attr:meta] )*
66            $snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ;
67        )*
68    ) => {
69        /// An extended operation/instruction.
70        ///
71        /// These tend to be colder than `Op`s.
72        #[derive(Clone, Copy, Debug, PartialEq, Eq)]
73        #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
74        pub enum ExtendedOp {
75            $(
76                $( #[$attr] )*
77                $name($name),
78            )*
79        }
80
81        $(
82            $( #[$attr] )*
83            #[derive(Clone, Copy, Debug, PartialEq, Eq)]
84            #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
85            pub struct $name { $(
86                $(
87                    // TODO: add doc comments to all fields and update all
88                    // the macros to match them.
89                    #[allow(missing_docs, reason = "macro-generated code")]
90                    pub $field : $field_ty,
91                )*
92            )? }
93
94            impl From<$name> for Op {
95                #[inline]
96                fn from(op: $name) -> Self {
97                    Self::ExtendedOp(ExtendedOp::$name(op))
98                }
99            }
100
101            impl From<$name> for ExtendedOp {
102                #[inline]
103                fn from(op: $name) -> Self {
104                    Self::$name(op)
105                }
106            }
107        )*
108    };
109}
110for_each_extended_op!(define_extended_op);
111
112macro_rules! define_op_encode {
113    (
114        $(
115            $( #[$attr:meta] )*
116            $snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ;
117        )*
118    ) => {
119        impl Op {
120            /// Encode this op into the given sink.
121            #[cfg(feature = "encode")]
122            pub fn encode<E>(&self, into: &mut E)
123            where
124                E: Extend<u8>,
125            {
126                match self {
127                    $(
128                        Self::$name(op) => op.encode(into),
129                    )*
130                    Self::ExtendedOp(op) => op.encode(into),
131                }
132            }
133
134            /// Returns the encoded size of this op.
135            #[cfg(feature = "encode")]
136            pub fn width(&self) -> u8 {
137                match self {
138                    $(
139                        Self::$name(_) => <$name as Encode>::WIDTH,
140                    )*
141                    Self::ExtendedOp(op) => op.width(),
142                }
143            }
144        }
145
146        $(
147            impl $name {
148                /// Encode this
149                #[doc = concat!("`", stringify!($name), "`")]
150                /// op into the given sink.
151                #[cfg(feature = "encode")]
152                pub fn encode<E>(&self, into: &mut E)
153                where
154                    E: Extend<u8>,
155                {
156                    crate::encode::$snake_name(into $( $( , self.$field )* )?);
157                }
158            }
159        )*
160    };
161}
162for_each_op!(define_op_encode);
163
164macro_rules! define_extended_op_encode {
165    (
166        $(
167            $( #[$attr:meta] )*
168            $snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ;
169        )*
170    ) => {
171        impl ExtendedOp {
172            /// Encode this extended op into the given sink.
173            #[cfg(feature = "encode")]
174            pub fn encode<E>(&self, into: &mut E)
175            where
176                E: Extend<u8>,
177            {
178                match self {
179                    $(
180                        Self::$name(op) => op.encode(into),
181                    )*
182                }
183            }
184
185            /// Returns the encoded size of this op.
186            #[cfg(feature = "encode")]
187            pub fn width(&self) -> u8 {
188                match self {
189                    $(
190                        Self::$name(_) => <$name as Encode>::WIDTH,
191                    )*
192                }
193            }
194        }
195
196        $(
197            impl $name {
198                /// Encode this
199                #[doc = concat!("`", stringify!($name), "`")]
200                /// op into the given sink.
201                #[cfg(feature = "encode")]
202                pub fn encode<E>(&self, into: &mut E)
203                where
204                    E: Extend<u8>,
205                {
206                    crate::encode::$snake_name(into $( $( , self.$field )* )?);
207                }
208            }
209        )*
210    };
211}
212for_each_extended_op!(define_extended_op_encode);
213
214/// A visitor that materializes whole `Op`s as it decodes the bytecode stream.
215#[cfg(feature = "decode")]
216#[derive(Default)]
217pub struct MaterializeOpsVisitor<B> {
218    bytecode: B,
219}
220
221#[cfg(feature = "decode")]
222impl<B> MaterializeOpsVisitor<B> {
223    /// Create a new op-materializing visitor for the given bytecode.
224    pub fn new(bytecode: B) -> Self {
225        Self { bytecode }
226    }
227}
228
229macro_rules! define_materialize_op_visitor {
230    (
231        $(
232            $( #[$attr:meta] )*
233            $snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ;
234        )*
235    ) => {
236        #[cfg(feature = "decode")]
237        impl<B: crate::decode::BytecodeStream> crate::decode::OpVisitor for MaterializeOpsVisitor<B> {
238            type BytecodeStream = B;
239
240            fn bytecode(&mut self) -> &mut Self::BytecodeStream {
241                &mut self.bytecode
242            }
243
244            type Return = crate::op::Op;
245
246            $(
247                $( #[$attr] )*
248                fn $snake_name(&mut self $( $( , $field : $field_ty )* )? ) -> Self::Return {
249                    crate::op::Op::$name(crate::op::$name { $( $(
250                        $field,
251                    )* )? })
252                }
253            )*
254        }
255    };
256}
257for_each_op!(define_materialize_op_visitor);
258
259macro_rules! define_materialize_extended_op_visitor {
260    (
261        $(
262            $( #[$attr:meta] )*
263            $snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ;
264        )*
265    ) => {
266        #[cfg(feature = "decode")]
267        impl<B: crate::decode::BytecodeStream> crate::decode::ExtendedOpVisitor for MaterializeOpsVisitor<B> {
268            $(
269                $( #[$attr] )*
270                fn $snake_name(&mut self $( $( , $field : $field_ty )* )? ) -> Self::Return {
271                    crate::op::ExtendedOp::$name(crate::op::$name { $( $(
272                        $field,
273                    )* )? }).into()
274                }
275            )*
276        }
277    };
278}
279for_each_extended_op!(define_materialize_extended_op_visitor);