1 //! Pulley bytecode operations with their operands. 2 3 #[cfg(feature = "encode")] 4 use crate::encode::Encode; 5 use crate::imms::*; 6 use crate::regs::*; 7 8 macro_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 #[expect(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 } 53 for_each_op!(define_op); 54 55 impl From<ExtendedOp> for Op { 56 #[inline] from(op: ExtendedOp) -> Self57 fn from(op: ExtendedOp) -> Self { 58 Op::ExtendedOp(op) 59 } 60 } 61 62 macro_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 #[expect(missing_docs, reason = "macro-generated code")] 90 pub $field : $field_ty, 91 )* 92 )? } 93 94 #[doc(hidden)] 95 #[expect(non_camel_case_types, reason = "used in macros as an alternative to camel case")] 96 pub type $snake_name = $name; 97 98 impl From<$name> for Op { 99 #[inline] 100 fn from(op: $name) -> Self { 101 Self::ExtendedOp(ExtendedOp::$name(op)) 102 } 103 } 104 105 impl From<$name> for ExtendedOp { 106 #[inline] 107 fn from(op: $name) -> Self { 108 Self::$name(op) 109 } 110 } 111 )* 112 }; 113 } 114 for_each_extended_op!(define_extended_op); 115 116 macro_rules! define_op_encode { 117 ( 118 $( 119 $( #[$attr:meta] )* 120 $snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ; 121 )* 122 ) => { 123 impl Op { 124 /// Encode this op into the given sink. 125 #[cfg(feature = "encode")] 126 pub fn encode<E>(&self, into: &mut E) 127 where 128 E: Extend<u8>, 129 { 130 match self { 131 $( 132 Self::$name(op) => op.encode(into), 133 )* 134 Self::ExtendedOp(op) => op.encode(into), 135 } 136 } 137 138 /// Returns the encoded size of this op. 139 #[cfg(feature = "encode")] 140 pub fn width(&self) -> u8 { 141 match self { 142 $( 143 Self::$name(_) => <$name as Encode>::WIDTH, 144 )* 145 Self::ExtendedOp(op) => op.width(), 146 } 147 } 148 } 149 150 $( 151 impl $name { 152 /// Encode this 153 #[doc = concat!("`", stringify!($name), "`")] 154 /// op into the given sink. 155 #[cfg(feature = "encode")] 156 pub fn encode<E>(&self, into: &mut E) 157 where 158 E: Extend<u8>, 159 { 160 crate::encode::$snake_name(into $( $( , self.$field )* )?); 161 } 162 } 163 )* 164 }; 165 } 166 for_each_op!(define_op_encode); 167 168 macro_rules! define_extended_op_encode { 169 ( 170 $( 171 $( #[$attr:meta] )* 172 $snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ; 173 )* 174 ) => { 175 impl ExtendedOp { 176 /// Encode this extended op into the given sink. 177 #[cfg(feature = "encode")] 178 pub fn encode<E>(&self, into: &mut E) 179 where 180 E: Extend<u8>, 181 { 182 match self { 183 $( 184 Self::$name(op) => op.encode(into), 185 )* 186 } 187 } 188 189 /// Returns the encoded size of this op. 190 #[cfg(feature = "encode")] 191 pub fn width(&self) -> u8 { 192 match self { 193 $( 194 Self::$name(_) => <$name as Encode>::WIDTH, 195 )* 196 } 197 } 198 } 199 200 $( 201 impl $name { 202 /// Encode this 203 #[doc = concat!("`", stringify!($name), "`")] 204 /// op into the given sink. 205 #[cfg(feature = "encode")] 206 pub fn encode<E>(&self, into: &mut E) 207 where 208 E: Extend<u8>, 209 { 210 crate::encode::$snake_name(into $( $( , self.$field )* )?); 211 } 212 } 213 )* 214 }; 215 } 216 for_each_extended_op!(define_extended_op_encode); 217 218 /// A visitor that materializes whole `Op`s as it decodes the bytecode stream. 219 #[cfg(feature = "decode")] 220 #[derive(Default)] 221 pub struct MaterializeOpsVisitor<B> { 222 bytecode: B, 223 } 224 225 #[cfg(feature = "decode")] 226 impl<B> MaterializeOpsVisitor<B> { 227 /// Create a new op-materializing visitor for the given bytecode. new(bytecode: B) -> Self228 pub fn new(bytecode: B) -> Self { 229 Self { bytecode } 230 } 231 } 232 233 macro_rules! define_materialize_op_visitor { 234 ( 235 $( 236 $( #[$attr:meta] )* 237 $snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ; 238 )* 239 ) => { 240 #[cfg(feature = "decode")] 241 impl<B: crate::decode::BytecodeStream> crate::decode::OpVisitor for MaterializeOpsVisitor<B> { 242 type BytecodeStream = B; 243 244 fn bytecode(&mut self) -> &mut Self::BytecodeStream { 245 &mut self.bytecode 246 } 247 248 type Return = crate::op::Op; 249 250 $( 251 $( #[$attr] )* 252 fn $snake_name(&mut self $( $( , $field : $field_ty )* )? ) -> Self::Return { 253 crate::op::Op::$name(crate::op::$name { $( $( 254 $field, 255 )* )? }) 256 } 257 )* 258 } 259 }; 260 } 261 for_each_op!(define_materialize_op_visitor); 262 263 macro_rules! define_materialize_extended_op_visitor { 264 ( 265 $( 266 $( #[$attr:meta] )* 267 $snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ; 268 )* 269 ) => { 270 #[cfg(feature = "decode")] 271 impl<B: crate::decode::BytecodeStream> crate::decode::ExtendedOpVisitor for MaterializeOpsVisitor<B> { 272 $( 273 $( #[$attr] )* 274 fn $snake_name(&mut self $( $( , $field : $field_ty )* )? ) -> Self::Return { 275 crate::op::ExtendedOp::$name(crate::op::$name { $( $( 276 $field, 277 )* )? }).into() 278 } 279 )* 280 } 281 }; 282 } 283 for_each_extended_op!(define_materialize_extended_op_visitor); 284