use core::hash::Hash; use core::fmt; use core::ops::{Add, Sub, AddAssign, SubAssign}; use num_traits::identities; use num_traits::{Bounded, WrappingAdd, WrappingSub, CheckedAdd, Zero, One}; #[cfg(feature="use-serde")] use serde::{Deserialize, Serialize}; #[cfg(feature="use-serde")] pub trait AddressDiffAmount: Copy + Clone + PartialEq + PartialOrd + Eq + Ord + identities::Zero + identities::One + Serialize + for<'de> Deserialize<'de> {} #[cfg(not(feature="use-serde"))] pub trait AddressDiffAmount: Copy + Clone + PartialEq + PartialOrd + Eq + Ord + identities::Zero + identities::One {} impl AddressDiffAmount for u64 {} impl AddressDiffAmount for u32 {} impl AddressDiffAmount for u16 {} impl AddressDiffAmount for usize {} /// a struct describing the differece between some pair of `A: Address`. this is primarily useful /// in describing the size of an instruction, or the relative offset of a branch. /// /// for any address type `A`, the following must hold: /// ```rust /// use yaxpeax_arch::AddressBase; /// fn diff_check(left: A, right: A) { /// let diff = left.diff(&right); /// if let Some(offset) = diff { /// assert_eq!(left.wrapping_offset(offset), right); /// } /// } /// ``` /// /// which is to say, `yaxpeax` assumes associativity holds when `diff` yields a `Some`. #[cfg(feature="use-serde")] #[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)] pub struct AddressDiff { // the AddressDiffAmount trait fools `Deserialize`'s proc macro, so we have to explicitly write // the bound serde should use. #[serde(bound(deserialize = "T::Diff: AddressDiffAmount"))] amount: T::Diff, } /// a struct describing the differece between some pair of `A: Address`. this is primarily useful /// in describing the size of an instruction, or the relative offset of a branch. /// /// for any address type `A`, the following must hold: /// ```rust /// use yaxpeax_arch::AddressBase; /// fn diff_check(left: A, right: A) { /// let diff = left.diff(&right); /// if let Some(offset) = diff { /// assert_eq!(left.wrapping_offset(offset), right); /// } /// } /// ``` /// /// which is to say, `yaxpeax` assumes associativity holds when `diff` yields a `Some`. #[cfg(not(feature="use-serde"))] #[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord)] pub struct AddressDiff { amount: T::Diff, } impl AddressDiff { pub fn from_const(amount: T::Diff) -> Self { AddressDiff { amount } } } impl fmt::Debug for AddressDiff where T::Diff: fmt::Debug { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "AddressDiff({:?})", self.amount) } } impl AddressDiff { pub fn one() -> Self { AddressDiff { amount: ::Diff::one(), } } pub fn zero() -> Self { AddressDiff { amount: ::Diff::zero(), } } } impl Sub> for u16 { type Output = Self; fn sub(self, other: AddressDiff) -> Self::Output { self - other.amount } } impl Sub> for u32 { type Output = Self; fn sub(self, other: AddressDiff) -> Self::Output { self - other.amount } } impl Sub> for u64 { type Output = Self; fn sub(self, other: AddressDiff) -> Self::Output { self - other.amount } } impl Sub> for usize { type Output = Self; fn sub(self, other: AddressDiff) -> Self::Output { self - other.amount } } impl Add> for u16 { type Output = Self; fn add(self, other: AddressDiff) -> Self::Output { self + other.amount } } impl Add> for u32 { type Output = Self; fn add(self, other: AddressDiff) -> Self::Output { self + other.amount } } impl Add> for u64 { type Output = Self; fn add(self, other: AddressDiff) -> Self::Output { self + other.amount } } impl Add> for usize { type Output = Self; fn add(self, other: AddressDiff) -> Self::Output { self + other.amount } } impl SubAssign> for u16 { fn sub_assign(&mut self, other: AddressDiff) { *self -= other.amount; } } impl SubAssign> for u32 { fn sub_assign(&mut self, other: AddressDiff) { *self -= other.amount; } } impl SubAssign> for u64 { fn sub_assign(&mut self, other: AddressDiff) { *self -= other.amount; } } impl SubAssign> for usize { fn sub_assign(&mut self, other: AddressDiff) { *self -= other.amount; } } impl AddAssign> for u16 { fn add_assign(&mut self, other: AddressDiff) { *self += other.amount; } } impl AddAssign> for u32 { fn add_assign(&mut self, other: AddressDiff) { *self += other.amount; } } impl AddAssign> for u64 { fn add_assign(&mut self, other: AddressDiff) { *self += other.amount; } } impl AddAssign> for usize { fn add_assign(&mut self, other: AddressDiff) { *self += other.amount; } } pub trait AddressBase where Self: AddressDisplay + Copy + Clone + Sized + Hash + Ord + Eq + PartialEq + Bounded + Add, Output=Self> + Sub, Output=Self> + AddAssign> + SubAssign> + identities::Zero + Hash { type Diff: AddressDiffAmount; fn to_linear(&self) -> usize; /// compute the `AddressDiff` beetween `self` and `other`. /// /// may return `None` if the two addresses aren't comparable. for example, if a pair of /// addresses are a data-space address and code-space address, there may be no scalar that can /// describe the difference between them. fn diff(&self, other: &Self) -> Option>; /* { Some(AddressDiff { amount: self.wrapping_sub(other) }) } */ fn wrapping_offset(&self, other: AddressDiff) -> Self; /* { self.wrapping_add(&other.amount) } */ fn checked_offset(&self, other: AddressDiff) -> Option; /* { self.checked_add(&other.amount) } */ } #[cfg(all(feature="use-serde", feature="address-parse"))] pub trait Address where Self: AddressBase + Serialize + for<'de> Deserialize<'de> + AddrParse { } #[cfg(all(feature="use-serde", not(feature="address-parse")))] pub trait Address where Self: AddressBase + Serialize + for<'de> Deserialize<'de> { } #[cfg(all(not(feature="use-serde"), feature="address-parse"))] pub trait Address where Self: AddressBase + AddrParse { } #[cfg(all(not(feature="use-serde"), not(feature="address-parse")))] pub trait Address where Self: AddressBase { } impl AddressBase for u16 { type Diff = Self; fn to_linear(&self) -> usize { *self as usize } fn diff(&self, other: &Self) -> Option> { Some(AddressDiff { amount: self.wrapping_sub(other) }) } fn wrapping_offset(&self, other: AddressDiff) -> Self { self.wrapping_add(&other.amount) } fn checked_offset(&self, other: AddressDiff) -> Option { self.checked_add(&other.amount) } } impl Address for u16 {} impl AddressBase for u32 { type Diff = Self; fn to_linear(&self) -> usize { *self as usize } fn diff(&self, other: &Self) -> Option> { Some(AddressDiff { amount: self.wrapping_sub(other) }) } fn wrapping_offset(&self, other: AddressDiff) -> Self { self.wrapping_add(&other.amount) } fn checked_offset(&self, other: AddressDiff) -> Option { self.checked_add(&other.amount) } } impl Address for u32 {} impl AddressBase for u64 { type Diff = Self; fn to_linear(&self) -> usize { *self as usize } fn diff(&self, other: &Self) -> Option> { Some(AddressDiff { amount: self.wrapping_sub(other) }) } fn wrapping_offset(&self, other: AddressDiff) -> Self { self.wrapping_add(&other.amount) } fn checked_offset(&self, other: AddressDiff) -> Option { self.checked_add(&other.amount) } } impl Address for u64 {} impl AddressBase for usize { type Diff = Self; fn to_linear(&self) -> usize { *self } fn diff(&self, other: &Self) -> Option> { Some(AddressDiff { amount: self.wrapping_sub(other) }) } fn wrapping_offset(&self, other: AddressDiff) -> Self { self.wrapping_add(&other.amount) } fn checked_offset(&self, other: AddressDiff) -> Option { self.checked_add(&other.amount) } } impl Address for usize {} pub trait AddressDisplay { type Show: fmt::Display; fn show(&self) -> Self::Show; } impl AddressDisplay for usize { type Show = AddressDisplayUsize; fn show(&self) -> AddressDisplayUsize { AddressDisplayUsize(*self) } } #[repr(transparent)] pub struct AddressDisplayUsize(usize); impl fmt::Display for AddressDisplayUsize { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:#x}", self.0) } } impl AddressDisplay for u64 { type Show = AddressDisplayU64; fn show(&self) -> AddressDisplayU64 { AddressDisplayU64(*self) } } #[repr(transparent)] pub struct AddressDisplayU64(u64); impl fmt::Display for AddressDisplayU64 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:#x}", self.0) } } impl AddressDisplay for u32 { type Show = AddressDisplayU32; fn show(&self) -> AddressDisplayU32 { AddressDisplayU32(*self) } } #[repr(transparent)] pub struct AddressDisplayU32(u32); impl fmt::Display for AddressDisplayU32 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:#x}", self.0) } } impl AddressDisplay for u16 { type Show = AddressDisplayU16; fn show(&self) -> AddressDisplayU16 { AddressDisplayU16(*self) } } #[repr(transparent)] pub struct AddressDisplayU16(u16); impl fmt::Display for AddressDisplayU16 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:#x}", self.0) } } /* * TODO: this should be FromStr. * that would require newtyping address primitives, though * * this is not out of the question, BUT is way more work than * i want to put in right now * * this is one of those "clean it up later" situations */ #[cfg(feature="address-parse")] use core::str::FromStr; #[cfg(feature="address-parse")] pub trait AddrParse: Sized { type Err; fn parse_from(s: &str) -> Result; } #[cfg(feature="address-parse")] impl AddrParse for usize { type Err = core::num::ParseIntError; fn parse_from(s: &str) -> Result { if s.starts_with("0x") { usize::from_str_radix(&s[2..], 16) } else { usize::from_str(s) } } } #[cfg(feature="address-parse")] impl AddrParse for u64 { type Err = core::num::ParseIntError; fn parse_from(s: &str) -> Result { if s.starts_with("0x") { u64::from_str_radix(&s[2..], 16) } else { u64::from_str(s) } } } #[cfg(feature="address-parse")] impl AddrParse for u32 { type Err = core::num::ParseIntError; fn parse_from(s: &str) -> Result { if s.starts_with("0x") { u32::from_str_radix(&s[2..], 16) } else { u32::from_str(s) } } } #[cfg(feature="address-parse")] impl AddrParse for u16 { type Err = core::num::ParseIntError; fn parse_from(s: &str) -> Result { if s.starts_with("0x") { u16::from_str_radix(&s[2..], 16) } else { u16::from_str(s) } } }