diff --git a/src/action.rs b/src/action.rs index f6ce636..66daa01 100644 --- a/src/action.rs +++ b/src/action.rs @@ -1,6 +1,9 @@ use xed_sys::*; -use super::Flag; +use super::{ + raw::{AsRaw, IntoRaw}, + Flag, +}; crate::macros::xed_enum! { pub enum Action => XED_FLAG_ACTION { @@ -39,31 +42,12 @@ impl Action { } } -#[repr(transparent)] -pub struct FlagAction(xed_flag_action_t); +crate::macros::wrapper_type! { + #[derive(FromRaw, AsRaw, AsRawMut, IntoRaw)] + pub struct FlagAction(xed_flag_action_t); +} impl FlagAction { - pub fn from_ref(raw: &xed_flag_action_t) -> &Self { - // SAFETY: SimpleFlag is #[repr(transparent)] - unsafe { std::mem::transmute(raw) } - } - - pub fn from_raw(raw: xed_flag_action_t) -> Self { - Self(raw) - } - - pub fn into_raw(self) -> xed_flag_action_t { - self.0 - } - - pub fn as_raw(&self) -> &xed_flag_action_t { - &self.0 - } - - pub fn as_raw_mut(&mut self) -> &mut xed_flag_action_t { - &mut self.0 - } - /// The action performed by this flag. pub fn action(&self) -> Action { // Note: xed takes an index i but it is entirely unused by the actual function diff --git a/src/chip_features.rs b/src/chip_features.rs index 0d8a4d2..4933723 100644 --- a/src/chip_features.rs +++ b/src/chip_features.rs @@ -1,31 +1,13 @@ use xed_sys::*; -use super::{Chip, IsaSet}; - -#[repr(transparent)] -pub struct ChipFeatures(xed_chip_features_t); - -impl ChipFeatures { - pub fn from_ref(raw: &xed_chip_features_t) -> &Self { - // SAFETY: ChipFeatures is #[repr(transparent)] - unsafe { std::mem::transmute(raw) } - } - - pub fn from_raw(raw: xed_chip_features_t) -> Self { - Self(raw) - } - - pub fn into_raw(self) -> xed_chip_features_t { - self.0 - } - - pub fn as_raw(&self) -> &xed_chip_features_t { - &self.0 - } - - pub fn as_raw_mut(&mut self) -> &mut xed_chip_features_t { - &mut self.0 - } +use super::{ + raw::{AsRawMut, IntoRaw}, + Chip, IsaSet, +}; + +crate::macros::wrapper_type! { + #[derive(FromRaw, AsRaw, AsRawMut, IntoRaw)] + pub struct ChipFeatures(xed_chip_features_t); } impl ChipFeatures { diff --git a/src/decode.rs b/src/decode.rs index b58f175..a12da77 100644 --- a/src/decode.rs +++ b/src/decode.rs @@ -2,7 +2,7 @@ use std::mem::MaybeUninit; use xed_sys::*; -use super::{ChipFeatures, DecodedInst, Error, State}; +use super::{raw::AsRawMut, ChipFeatures, DecodedInst, Error, State}; /// Options for [`decode`]. /// diff --git a/src/decoded_inst.rs b/src/decoded_inst.rs index 11ecbf1..8f66f13 100644 --- a/src/decoded_inst.rs +++ b/src/decoded_inst.rs @@ -4,6 +4,7 @@ use std::marker::PhantomData; use xed_sys::*; use crate::{ + raw::{FromRaw, IntoRaw}, Attribute, Category, Chip, Extension, IClass, IForm, IsaSet, Operand, OperandAction, OperandElementType, Register, SimpleFlag, Syntax, }; @@ -475,7 +476,7 @@ impl<'d> DecodedInst<'d> { unsafe { xed_decoded_inst_get_rflags_info(self.as_raw()) .as_ref() - .map(SimpleFlag::from_ref) + .map(FromRaw::from_ref) } } diff --git a/src/flag_set.rs b/src/flag_set.rs index d83f72a..982bbea 100644 --- a/src/flag_set.rs +++ b/src/flag_set.rs @@ -1,29 +1,13 @@ use xed_sys::*; -pub struct FlagSet(xed_flag_set_t); +use crate::raw::AsRaw; -impl FlagSet { - pub fn from_ref(raw: &xed_flag_set_t) -> &Self { - // SAFETY: SimpleFlag is #[repr(transparent)] - unsafe { std::mem::transmute(raw) } - } - - pub fn from_raw(raw: xed_flag_set_t) -> Self { - Self(raw) - } - - pub fn into_raw(self) -> xed_flag_set_t { - self.0 - } - - pub fn as_raw(&self) -> &xed_flag_set_t { - &self.0 - } - - pub fn as_raw_mut(&mut self) -> &mut xed_flag_set_t { - &mut self.0 - } +crate::macros::wrapper_type! { + #[derive(FromRaw, AsRaw, AsRawMut, IntoRaw)] + pub struct FlagSet(xed_flag_set_t); +} +impl FlagSet { /// Get the flags as a mask. pub fn as_mask(&self) -> u32 { unsafe { xed_flag_set_mask(self.as_raw()) } diff --git a/src/inst.rs b/src/inst.rs index b82099a..c5fc833 100644 --- a/src/inst.rs +++ b/src/inst.rs @@ -1,6 +1,7 @@ use xed_sys::*; use super::{ + raw::{AsRaw, IntoRaw}, Attribute, Category, DecodedInst, Exception, Extension, IClass, IForm, IsaSet, NonTerminal, Operand, OperandAction, OperandElementXType, OperandType, OperandValue, OperandVisibility, OperandWidth, Register, @@ -8,31 +9,10 @@ use super::{ used_in_docs!(DecodedInst, OperandValue); -/// Constant information about a decoded instruction form. -#[repr(transparent)] -pub struct Inst(xed_inst_t); - -impl Inst { - pub fn from_ref(raw: &xed_inst_t) -> &Self { - // SAFETY: Inst is #[repr(transparent)] - unsafe { std::mem::transmute(raw) } - } - - pub fn from_raw(raw: xed_inst_t) -> Self { - Self(raw) - } - - pub fn into_raw(self) -> xed_inst_t { - self.0 - } - - pub fn as_raw(&self) -> &xed_inst_t { - &self.0 - } - - pub fn as_raw_mut(&mut self) -> &mut xed_inst_t { - &mut self.0 - } +crate::macros::wrapper_type! { + /// Constant information about a decoded instruction form. + #[derive(FromRaw, AsRaw, AsRawMut, IntoRaw)] + pub struct Inst(xed_inst_t); } impl Inst { @@ -99,30 +79,9 @@ impl Inst { } } -#[repr(transparent)] -pub struct InstOperand(xed_operand_t); - -impl InstOperand { - pub fn from_ref(raw: &xed_operand_t) -> &Self { - // SAFETY: Inst is #[repr(transparent)] - unsafe { std::mem::transmute(raw) } - } - - pub fn from_raw(raw: xed_operand_t) -> Self { - Self(raw) - } - - pub fn into_raw(self) -> xed_operand_t { - self.0 - } - - pub fn as_raw(&self) -> &xed_operand_t { - &self.0 - } - - pub fn as_raw_mut(&mut self) -> &mut xed_operand_t { - &mut self.0 - } +crate::macros::wrapper_type! { + #[derive(FromRaw, AsRaw, AsRawMut, IntoRaw)] + pub struct InstOperand(xed_operand_t); } impl InstOperand { diff --git a/src/lib.rs b/src/lib.rs index f04caeb..b9f41b8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,6 +43,7 @@ mod operand_type; mod operand_visibility; mod operand_width; mod operand_xtype; +mod raw; mod register; mod simple_flag; mod state; diff --git a/src/macros/mod.rs b/src/macros/mod.rs index bb693e9..72e2d65 100644 --- a/src/macros/mod.rs +++ b/src/macros/mod.rs @@ -1,9 +1,11 @@ //! This module contains various macros used in the rest of the codebase. mod wrapper_enum; +mod wrapper_type; mod xed_enum; pub(crate) use wrapper_enum::{is_contiguous, wrapper_enum}; +pub(crate) use wrapper_type::wrapper_type; pub(crate) use xed_enum::xed_enum; macro_rules! first { diff --git a/src/macros/wrapper_type.rs b/src/macros/wrapper_type.rs new file mode 100644 index 0000000..8412f20 --- /dev/null +++ b/src/macros/wrapper_type.rs @@ -0,0 +1,75 @@ +// FIXME: move to a procedural macros +macro_rules! wrapper_type { + ( + $( #[doc = $comment:literal] )? + #[derive ( $( $trait:ident ),* ) ] + $vis:vis struct $name:ident ( $ctype:ident ); + ) => { + $( #[doc = $comment] )? + #[repr(transparent)] + $vis struct $name( $ctype ); + + crate::macros::wrapper_type! (__impl $name $ctype $( $trait )* ); + }; + + ( + __impl $name:ident $ctype:ident FromRaw $( $rest:ident )* + ) => { + impl crate::raw::FromRaw for $name { + type CType = $ctype; + + fn from_raw(raw: Self::CType) -> Self { + $name ( raw ) + } + + fn from_ref(raw: &Self::CType) -> &Self { + unsafe { std::mem::transmute(raw) } + } + } + + crate::macros::wrapper_type! (__impl $name $ctype $( $rest )* ); + }; + + ( + __impl $name:ident $ctype:ident AsRaw $( $rest:ident )* + ) => { + impl crate::raw::AsRaw for $name { + fn as_raw(&self) -> &Self::CType { + &self.0 + } + } + + crate::macros::wrapper_type! (__impl $name $ctype $( $rest )* ); + }; + + ( + __impl $name:ident $ctype:ident AsRawMut $( $rest:ident )* + ) => { + impl crate::raw::AsRawMut for $name { + fn as_raw_mut(&mut self) -> &mut Self::CType { + &mut self.0 + } + } + + crate::macros::wrapper_type! (__impl $name $ctype $( $rest )* ); + }; + + ( + __impl $name:ident $ctype:ident IntoRaw $( $rest:ident )* + ) => { + impl crate::raw::IntoRaw for $name { + fn into_raw(self) -> Self::CType { + self.0 + } + } + + crate::macros::wrapper_type! (__impl $name $ctype $( $rest )* ); + }; + + ( + __impl $name:ident $ctype:ident + ) => { + }; +} + +pub(crate) use wrapper_type; diff --git a/src/macros/xed_enum.rs b/src/macros/xed_enum.rs index c8baf69..364b109 100644 --- a/src/macros/xed_enum.rs +++ b/src/macros/xed_enum.rs @@ -12,6 +12,7 @@ macro_rules! xed_enum { $( invalid = $invalid:ident; )? } => { $( #[$attr] )* + #[repr(transparent)] #[derive(Copy, Clone, Eq, PartialEq, Hash)] $vis struct $name(std::num::NonZeroU32); @@ -35,13 +36,11 @@ macro_rules! xed_enum { ); )* } - } - impl $name { #[doc = concat!( "Create a `", stringify!($name), "` from the underlying enum value." )] - pub const fn from_raw(value: u32) -> Option { + pub(crate) const fn from_raw(value: u32) -> Option { paste::paste! { if value >= [< $base _ LAST >] { return None; @@ -53,16 +52,29 @@ macro_rules! xed_enum { None => None } } + } + + impl crate::raw::FromRaw for $name { + type CType = u32; + + fn from_raw(value: Self::CType) -> Self { + $name::from_raw(value).expect("underlying enum value was invalid") + } + + fn from_ref(raw: &Self::CType) -> &Self { + unsafe { std::mem::transmute(raw) } + } + } - /// Convert this value into the underlying enum value. - pub const fn into_raw(self) -> u32 { + impl crate::raw::IntoRaw for $name { + fn into_raw(self) -> u32 { self.0.get() } } impl From<$name> for u32 { fn from(value: $name) -> u32 { - value.into_raw() + crate::raw::IntoRaw::into_raw(value) } } @@ -82,7 +94,7 @@ macro_rules! xed_enum { impl std::fmt::Debug for $name { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let value = self.into_raw(); + let value = crate::raw::IntoRaw::into_raw(*self); let cstr = unsafe { paste::paste!($crate::macros::first!( $( [ xed_sys::[< $enum_name 2str >](value) ] )? @@ -109,7 +121,7 @@ macro_rules! xed_enum { let max = variants .iter() .copied() - .map(|variant| variant.into_raw()) + .map(crate::raw::IntoRaw::into_raw) .max(); match max { diff --git a/src/operand.rs b/src/operand.rs index de0f086..b1a1af8 100644 --- a/src/operand.rs +++ b/src/operand.rs @@ -1,5 +1,7 @@ use xed_sys::*; +use crate::raw::IntoRaw; + crate::macros::xed_enum! { pub enum Operand { ABSBR, diff --git a/src/raw.rs b/src/raw.rs new file mode 100644 index 0000000..3b3f1e2 --- /dev/null +++ b/src/raw.rs @@ -0,0 +1,19 @@ +pub trait FromRaw { + type CType; + + fn from_raw(raw: Self::CType) -> Self; + + fn from_ref(raw: &Self::CType) -> &Self; +} + +pub trait AsRaw: FromRaw { + fn as_raw(&self) -> &Self::CType; +} + +pub trait AsRawMut: AsRaw { + fn as_raw_mut(&mut self) -> &mut Self::CType; +} + +pub trait IntoRaw: FromRaw { + fn into_raw(self) -> Self::CType; +} diff --git a/src/register.rs b/src/register.rs index a9fe99f..a0b4ccd 100644 --- a/src/register.rs +++ b/src/register.rs @@ -1,5 +1,7 @@ use xed_sys::*; +use crate::raw::IntoRaw; + crate::macros::xed_enum! { pub enum Register => XED_REG { BNDCFGU, diff --git a/src/simple_flag.rs b/src/simple_flag.rs index 26d9804..a5dce5a 100644 --- a/src/simple_flag.rs +++ b/src/simple_flag.rs @@ -1,32 +1,16 @@ use xed_sys::*; -use super::{FlagAction, FlagSet}; - -#[repr(transparent)] -pub struct SimpleFlag(xed_simple_flag_t); +use super::{ + raw::{AsRaw, FromRaw}, + FlagAction, FlagSet, +}; + +crate::macros::wrapper_type! { + #[derive(FromRaw, AsRaw, AsRawMut, IntoRaw)] + pub struct SimpleFlag(xed_simple_flag_t); +} impl SimpleFlag { - pub fn from_ref(raw: &xed_simple_flag_t) -> &Self { - // SAFETY: SimpleFlag is #[repr(transparent)] - unsafe { std::mem::transmute(raw) } - } - - pub fn from_raw(raw: xed_simple_flag_t) -> Self { - Self(raw) - } - - pub fn into_raw(self) -> xed_simple_flag_t { - self.0 - } - - pub fn as_raw(&self) -> &xed_simple_flag_t { - &self.0 - } - - pub fn as_raw_mut(&mut self) -> &mut xed_simple_flag_t { - &mut self.0 - } - /// Get the specific flag actions. pub fn flag_actions(&self) -> &[FlagAction] { let len = unsafe { xed_simple_flag_get_nflags(self.as_raw()) as usize };