#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum WasmAddrType {
Memory,
Object,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WasmAddr(u64);
impl WasmAddr {
const TYPE_BITS: u32 = 2;
const MODULE_BITS: u32 = 30;
const OFFSET_BITS: u32 = 32;
const MODULE_SHIFT: u32 = Self::OFFSET_BITS;
const TYPE_SHIFT: u32 = Self::OFFSET_BITS + Self::MODULE_BITS;
const TYPE_MASK: u64 = (1u64 << Self::TYPE_BITS) - 1;
const MODULE_MASK: u64 = (1u64 << Self::MODULE_BITS) - 1;
const OFFSET_MASK: u64 = (1u64 << Self::OFFSET_BITS) - 1;
pub fn from_raw(raw: u64) -> Option<Self> {
let type_bits = (raw >> Self::TYPE_SHIFT) & Self::TYPE_MASK;
if type_bits > 1 {
return None;
}
Some(WasmAddr(raw))
}
pub fn as_raw(self) -> u64 {
self.0
}
pub fn new(addr_type: WasmAddrType, module_index: u32, offset: u32) -> Option<Self> {
if module_index >> Self::MODULE_BITS != 0 {
return None;
}
let type_bits: u64 = match addr_type {
WasmAddrType::Memory => 0,
WasmAddrType::Object => 1,
};
Some(WasmAddr(
(type_bits << Self::TYPE_SHIFT)
| ((u64::from(module_index)) << Self::MODULE_SHIFT)
| (u64::from(offset)),
))
}
pub fn addr_type(self) -> WasmAddrType {
match (self.0 >> Self::TYPE_SHIFT) & Self::TYPE_MASK {
0 => WasmAddrType::Memory,
1 => WasmAddrType::Object,
#[allow(clippy::unreachable)]
_ => unreachable!(),
}
}
pub fn module_index(self) -> u32 {
((self.0 >> Self::MODULE_SHIFT) & Self::MODULE_MASK) as u32
}
pub fn offset(self) -> u32 {
(self.0 & Self::OFFSET_MASK) as u32
}
}
impl core::fmt::Display for WasmAddr {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let type_str = match self.addr_type() {
WasmAddrType::Memory => "Memory",
WasmAddrType::Object => "Object",
};
write!(
f,
"{}(module={}, offset={:#x})",
type_str,
self.module_index(),
self.offset()
)
}
}
impl core::fmt::Debug for WasmAddr {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "WasmAddr({self})")
}
}