pulley_interpreter/
opcode.rs

1//! Pulley opcodes (without operands).
2
3macro_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 = Opcode::ExtendedOp as u8;
30        }
31    }
32}
33for_each_op!(define_opcode);
34
35impl Opcode {
36    /// Create a new `Opcode` from the given byte.
37    ///
38    /// Returns `None` if `byte` is not a valid opcode.
39    pub fn new(byte: u8) -> Option<Self> {
40        if byte <= Self::MAX {
41            Some(unsafe { Self::unchecked_new(byte) })
42        } else {
43            None
44        }
45    }
46
47    /// Like `new` but does not check whether `byte` is a valid opcode.
48    ///
49    /// # Safety
50    ///
51    /// It is unsafe to pass a `byte` that is not a valid opcode.
52    pub unsafe fn unchecked_new(byte: u8) -> Self {
53        debug_assert!(byte <= Self::MAX);
54        core::mem::transmute(byte)
55    }
56}
57
58macro_rules! define_extended_opcode {
59    (
60        $(
61            $( #[$attr:meta] )*
62            $snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ;
63        )*
64    ) => {
65        /// An extended opcode.
66        #[repr(u16)]
67        #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
68        pub enum ExtendedOpcode {
69            $(
70                $( #[$attr] )*
71                    $name,
72            )*
73        }
74
75        impl ExtendedOpcode {
76            /// The value of the maximum defined extended opcode.
77            pub const MAX: u16 = $(
78                if true { 1 } else { ExtendedOpcode::$name as u16 } +
79            )* 0;
80        }
81    };
82}
83for_each_extended_op!(define_extended_opcode);
84
85impl ExtendedOpcode {
86    /// Create a new `ExtendedOpcode` from the given bytes.
87    ///
88    /// Returns `None` if `bytes` is not a valid extended opcode.
89    pub fn new(bytes: u16) -> Option<Self> {
90        if bytes <= Self::MAX {
91            Some(unsafe { Self::unchecked_new(bytes) })
92        } else {
93            None
94        }
95    }
96
97    /// Like `new` but does not check whether `bytes` is a valid opcode.
98    ///
99    /// # Safety
100    ///
101    /// It is unsafe to pass `bytes` that is not a valid opcode.
102    pub unsafe fn unchecked_new(byte: u16) -> Self {
103        debug_assert!(byte <= Self::MAX);
104        core::mem::transmute(byte)
105    }
106}