1 //! Pulley opcodes (without operands). 2 3 macro_rules! define_opcode { 4 ( 5 $( 6 $( #[$attr:meta] )* 7 $snake_name:ident = $name:ident $( { 8 $( 9 $( #[$field_attr:meta] )* 10 $field:ident : $field_ty:ty 11 ),* 12 } )? ; 13 )* 14 ) => { 15 /// An opcode without its immediates and operands. 16 #[repr(u8)] 17 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 18 pub enum Opcode { 19 $( 20 $( #[$attr] )* 21 $name, 22 )* 23 /// The extended-op opcode. An `ExtendedOpcode` follows this opcode. 24 ExtendedOp, 25 } 26 27 impl Opcode { 28 /// The value of the maximum defined opcode. 29 pub const MAX: u8 = define_opcode!( @max $( $name )* ) + 1; 30 } 31 }; 32 33 ( @max $x:ident ) => { 0 }; 34 ( @max $x:ident $( $xs:ident )* ) => { 1 + define_opcode!(@max $( $xs )* ) }; 35 } 36 for_each_op!(define_opcode); 37 38 impl Opcode { 39 /// Create a new `Opcode` from the given byte. 40 /// 41 /// Returns `None` if `byte` is not a valid opcode. 42 pub fn new(byte: u8) -> Option<Self> { 43 if byte <= Self::MAX { 44 Some(unsafe { Self::unchecked_new(byte) }) 45 } else { 46 None 47 } 48 } 49 50 /// Like `new` but does not check whether `byte` is a valid opcode. 51 /// 52 /// # Safety 53 /// 54 /// It is unsafe to pass a `byte` that is not a valid opcode. 55 pub unsafe fn unchecked_new(byte: u8) -> Self { 56 debug_assert!(byte <= Self::MAX); 57 core::mem::transmute(byte) 58 } 59 } 60 61 macro_rules! define_extended_opcode { 62 ( 63 $( 64 $( #[$attr:meta] )* 65 $snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ; 66 )* 67 ) => { 68 /// An extended opcode. 69 #[repr(u16)] 70 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 71 pub enum ExtendedOpcode { 72 $( 73 $( #[$attr] )* 74 $name, 75 )* 76 } 77 78 impl ExtendedOpcode { 79 /// The value of the maximum defined extended opcode. 80 pub const MAX: u16 = define_opcode!( @max $( $name )* ); 81 } 82 }; 83 } 84 for_each_extended_op!(define_extended_opcode); 85 86 impl ExtendedOpcode { 87 #[cfg_attr(not(feature = "interp"), allow(unused))] 88 pub(crate) const ENCODED_SIZE_OF_TRAP: usize = 3; 89 90 /// Create a new `ExtendedOpcode` from the given bytes. 91 /// 92 /// Returns `None` if `bytes` is not a valid extended opcode. 93 pub fn new(bytes: u16) -> Option<Self> { 94 if bytes <= Self::MAX { 95 Some(unsafe { Self::unchecked_new(bytes) }) 96 } else { 97 None 98 } 99 } 100 101 /// Like `new` but does not check whether `bytes` is a valid opcode. 102 /// 103 /// # Safety 104 /// 105 /// It is unsafe to pass `bytes` that is not a valid opcode. 106 pub unsafe fn unchecked_new(byte: u16) -> Self { 107 debug_assert!(byte <= Self::MAX); 108 core::mem::transmute(byte) 109 } 110 } 111 112 #[cfg(all(test, feature = "encode"))] 113 mod tests { 114 use super::*; 115 use alloc::vec::Vec; 116 117 #[test] 118 fn encoded_size_of_trap() { 119 let mut buf = Vec::new(); 120 crate::encode::trap(&mut buf); 121 assert_eq!(ExtendedOpcode::ENCODED_SIZE_OF_TRAP, buf.len()); 122 } 123 } 124