pulley_interpreter/
opcode.rs1macro_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        #[repr(u8)]
17        #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
18        pub enum Opcode {
19            $(
20                $( #[$attr] )*
21                $name,
22            )*
23            ExtendedOp,
25        }
26
27        impl Opcode {
28            pub const MAX: u8 = Opcode::ExtendedOp as u8;
30        }
31    }
32}
33for_each_op!(define_opcode);
34
35impl Opcode {
36    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    pub unsafe fn unchecked_new(byte: u8) -> Self {
53        debug_assert!(byte <= Self::MAX);
54        unsafe { 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        #[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            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    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    pub unsafe fn unchecked_new(byte: u16) -> Self {
103        debug_assert!(byte <= Self::MAX);
104        unsafe { core::mem::transmute(byte) }
105    }
106}