use capstone_sys::cs_arch::*;
use capstone_sys::cs_opt_value::*;
use capstone_sys::*;
use core::convert::From;
use core::fmt::{self, Display};
use core::str::FromStr;
pub trait EnumList
where
Self: Sized,
{
fn variants() -> &'static [Self];
}
macro_rules! define_cs_rust_enum {
( [
$( #[$enum_attr:meta] )*
=> $rust_enum:ident = $cs_enum:ty
]
$( $( #[$attr:meta] )*
=> $rust_variant:ident = $cs_variant:tt; )* ) => {
$( #[$enum_attr] )*
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum $rust_enum {
$(
$( #[$attr] )*
$rust_variant,
)*
}
}
}
macro_rules! define_cs_enum_wrapper {
( [
$( #[$enum_attr:meta] )*
=> $rust_enum:ident = $cs_enum:ty
]
$( $( #[$attr:meta] )*
=> $rust_variant:ident = $cs_variant:tt; )* ) => {
define_cs_rust_enum!(
[
$( #[$enum_attr] )*
=> $rust_enum = $cs_enum
]
$( $( #[$attr] )*
=> $rust_variant = $cs_variant; )*
);
impl ::core::convert::From<$rust_enum> for $cs_enum {
fn from(other: $rust_enum) -> Self {
match other {
$(
$rust_enum::$rust_variant => $cs_variant,
)*
}
}
}
impl EnumList for $rust_enum {
fn variants() -> &'static [Self] {
&[
$(
$rust_enum::$rust_variant,
)*
]
}
}
impl FromStr for $rust_enum {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase();
$(
if s == stringify!($rust_variant).to_lowercase() {
return Ok($rust_enum::$rust_variant);
}
)*
Err(concat!("Failed to parse ", stringify!($rust_enum)))
}
}
impl Display for $rust_enum {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
$(
$rust_enum::$rust_variant => write!(f, "{}", stringify!($rust_variant)),
)*
}
}
}
}
}
#[macro_export]
macro_rules! define_cs_enum_wrapper_reverse {
( [
$( #[$enum_attr:meta] )*
=> $rust_enum:ident = $cs_enum:ident,
$( from_u32 = $gen_from_u32:ident,)*
]
$( $( #[$attr:meta] )*
=> $rust_variant:ident = $cs_variant:tt; )* ) => {
define_cs_rust_enum!(
[
$( #[$enum_attr] )*
=> $rust_enum = $cs_enum
]
$( $( #[$attr] )*
=> $rust_variant = $cs_variant; )*
);
impl ::core::convert::From<$cs_enum> for $rust_enum {
fn from(other: $cs_enum) -> Self {
match other {
$(
$cs_enum::$cs_variant => $rust_enum::$rust_variant,
)*
}
}
}
impl $rust_enum {
#[allow(dead_code)]
pub(crate) fn from_u32(other: u32) -> Option<$rust_enum> {
match other {
$(
x if x == ($cs_enum::$cs_variant as u32) => Some($rust_enum::$rust_variant),
)*
_ => None,
}
}
}
}
}
#[macro_export]
macro_rules! define_impl_bitmask {
(
impl $struct:ident < $($impl_lifetime:lifetime),* > ;
$mask_getter:ident : $mask_getter_ty:ty = { $get_mask:expr }
test_mod = $test_mod:ident;
$(
$( #[$attr:meta] )*
=> $getter:ident = $mask_constant:ident;
)*
) => {
impl < $($impl_lifetime),* > $struct < $($impl_lifetime),* > {
pub(crate) fn $mask_getter(&self) -> $mask_getter_ty {
$get_mask(self)
}
$(
$( #[$attr] )*
pub fn $getter(&self) -> bool {
($get_mask(self) & $mask_constant) != 0
}
)*
}
#[allow(non_snake_case)]
#[cfg(test)]
mod $test_mod {
use super::*;
$(
#[test]
fn $getter() {
assert_eq!($mask_constant.count_ones(), 1);
}
)*
}
}
}
define_cs_enum_wrapper!(
[
=> Arch = cs_arch
]
=> ARM = CS_ARCH_ARM;
=> ARM64 = CS_ARCH_ARM64;
=> MIPS = CS_ARCH_MIPS;
=> X86 = CS_ARCH_X86;
=> PPC = CS_ARCH_PPC;
=> SPARC = CS_ARCH_SPARC;
=> SYSZ = CS_ARCH_SYSZ;
=> XCORE = CS_ARCH_XCORE;
=> M68K = CS_ARCH_M68K;
=> TMS320C64X = CS_ARCH_TMS320C64X;
=> M680X = CS_ARCH_M680X;
=> EVM = CS_ARCH_EVM;
=> RISCV = CS_ARCH_RISCV;
);
define_cs_enum_wrapper!(
[
=> Mode = cs_mode
]
=> Arm = CS_MODE_ARM;
=> Mode16 = CS_MODE_16;
=> Mode32 = CS_MODE_32;
=> Mode64 = CS_MODE_64;
=> Thumb = CS_MODE_THUMB;
=> Mips2 = CS_MODE_MIPS2;
=> Mips3 = CS_MODE_MIPS3;
=> Mips32R6 = CS_MODE_MIPS32R6;
=> Mips32 = CS_MODE_MIPS32;
=> Mips64 = CS_MODE_MIPS64;
=> V9 = CS_MODE_V9;
=> Qpx = CS_MODE_QPX;
=> M68k000 = CS_MODE_M68K_000;
=> M68k010 = CS_MODE_M68K_010;
=> M68k020 = CS_MODE_M68K_020;
=> M68k030 = CS_MODE_M68K_030;
=> M68k040 = CS_MODE_M68K_040;
=> M680x6301 = CS_MODE_M680X_6301;
=> M680x6309 = CS_MODE_M680X_6309;
=> M680x6800 = CS_MODE_M680X_6800;
=> M680x6801 = CS_MODE_M680X_6801;
=> M680x6805 = CS_MODE_M680X_6805;
=> M680x6808 = CS_MODE_M680X_6808;
=> M680x6809 = CS_MODE_M680X_6809;
=> M680x6811 = CS_MODE_M680X_6811;
=> M680xCpu12 = CS_MODE_M680X_CPU12;
=> M680xHcs08 = CS_MODE_M680X_HCS08;
=> RiscV32 = CS_MODE_RISCV32;
=> RiscV64 = CS_MODE_RISCV64;
=> Default = CS_MODE_LITTLE_ENDIAN;
);
define_cs_enum_wrapper!(
[
=> ExtraMode = cs_mode
]
=> MClass = CS_MODE_MCLASS;
=> V8 = CS_MODE_V8;
=> Micro = CS_MODE_MICRO;
=> RiscVC = CS_MODE_RISCVC;
);
define_cs_enum_wrapper!(
[
=> Endian = cs_mode
]
=> Little = CS_MODE_LITTLE_ENDIAN;
=> Big = CS_MODE_BIG_ENDIAN;
);
define_cs_enum_wrapper!(
[
=> Syntax = cs_opt_value::Type
]
=> Intel = CS_OPT_SYNTAX_INTEL;
=> Att = CS_OPT_SYNTAX_ATT;
=> Masm = CS_OPT_SYNTAX_MASM;
=> NoRegName = CS_OPT_SYNTAX_NOREGNAME;
);
pub(crate) struct OptValue(pub cs_opt_value::Type);
impl From<bool> for OptValue {
fn from(value: bool) -> Self {
if value {
OptValue(cs_opt_value::CS_OPT_ON)
} else {
OptValue(cs_opt_value::CS_OPT_OFF)
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn parse_arch() {
assert_eq!(Arch::from_str("x86"), Ok(Arch::X86));
assert_eq!(Arch::from_str("X86"), Ok(Arch::X86));
}
}