macro_rules! define_opcode {
(
$(
$( #[$attr:meta] )*
$snake_name:ident = $name:ident $( {
$(
$( #[$field_attr:meta] )*
$field:ident : $field_ty:ty
),*
} )? ;
)*
) => {
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Opcode {
$(
$( #[$attr] )*
$name,
)*
ExtendedOp,
}
impl Opcode {
pub const MAX: u8 = Opcode::ExtendedOp as u8;
}
}
}
for_each_op!(define_opcode);
impl Opcode {
pub fn new(byte: u8) -> Option<Self> {
if byte <= Self::MAX {
Some(unsafe { Self::unchecked_new(byte) })
} else {
None
}
}
pub unsafe fn unchecked_new(byte: u8) -> Self {
debug_assert!(byte <= Self::MAX);
unsafe { core::mem::transmute(byte) }
}
}
macro_rules! define_extended_opcode {
(
$(
$( #[$attr:meta] )*
$snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ;
)*
) => {
#[repr(u16)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ExtendedOpcode {
$(
$( #[$attr] )*
$name,
)*
}
impl ExtendedOpcode {
pub const MAX: u16 = $(
if true { 1 } else { ExtendedOpcode::$name as u16 } +
)* 0;
}
};
}
for_each_extended_op!(define_extended_opcode);
impl ExtendedOpcode {
pub fn new(bytes: u16) -> Option<Self> {
if bytes <= Self::MAX {
Some(unsafe { Self::unchecked_new(bytes) })
} else {
None
}
}
pub unsafe fn unchecked_new(byte: u16) -> Self {
debug_assert!(byte <= Self::MAX);
unsafe { core::mem::transmute(byte) }
}
}