use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WasmPtr(u32);
impl WasmPtr {
#[inline]
#[must_use]
pub const fn new(addr: u32) -> Self {
Self(addr)
}
#[inline]
#[must_use]
pub const fn as_u32(self) -> u32 {
self.0
}
#[inline]
#[must_use]
pub const fn as_usize(self) -> usize {
self.0 as usize
}
#[inline]
#[must_use]
pub const fn checked_add(self, offset: u32) -> Option<Self> {
match self.0.checked_add(offset) {
Some(addr) => Some(Self(addr)),
None => None,
}
}
#[inline]
#[must_use]
pub const fn would_overflow(self, size: WasmSize) -> bool {
self.0.checked_add(size.as_u32()).is_none()
}
}
impl From<u32> for WasmPtr {
fn from(addr: u32) -> Self {
Self::new(addr)
}
}
impl From<i32> for WasmPtr {
fn from(addr: i32) -> Self {
Self::new(addr as u32)
}
}
impl fmt::Display for WasmPtr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "0x{:08x}", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WasmSize(u32);
impl WasmSize {
pub const MAX_SIZE: u32 = 16 * 1024 * 1024;
#[inline]
#[must_use]
pub const fn new(size: u32) -> Self {
Self(size)
}
#[inline]
#[must_use]
pub const fn new_checked(size: u32) -> Option<Self> {
if size <= Self::MAX_SIZE {
Some(Self(size))
} else {
None
}
}
#[inline]
#[must_use]
pub const fn as_u32(self) -> u32 {
self.0
}
#[inline]
#[must_use]
pub const fn as_usize(self) -> usize {
self.0 as usize
}
#[inline]
#[must_use]
pub const fn is_zero(self) -> bool {
self.0 == 0
}
}
impl From<u32> for WasmSize {
fn from(size: u32) -> Self {
Self::new(size)
}
}
impl From<i32> for WasmSize {
fn from(size: i32) -> Self {
Self::new(size as u32)
}
}
impl fmt::Display for WasmSize {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} bytes", self.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_wasm_ptr_basic() {
let ptr = WasmPtr::new(0x1000);
assert_eq!(ptr.as_u32(), 0x1000);
assert_eq!(ptr.as_usize(), 0x1000);
}
#[test]
fn test_wasm_ptr_checked_add() {
let ptr = WasmPtr::new(100);
assert_eq!(ptr.checked_add(50).unwrap().as_u32(), 150);
let ptr = WasmPtr::new(u32::MAX);
assert!(ptr.checked_add(1).is_none());
}
#[test]
fn test_wasm_ptr_overflow_check() {
let ptr = WasmPtr::new(u32::MAX - 10);
let size = WasmSize::new(20);
assert!(ptr.would_overflow(size));
let ptr = WasmPtr::new(100);
let size = WasmSize::new(50);
assert!(!ptr.would_overflow(size));
}
#[test]
fn test_wasm_size_basic() {
let size = WasmSize::new(1024);
assert_eq!(size.as_u32(), 1024);
assert_eq!(size.as_usize(), 1024);
}
#[test]
fn test_wasm_size_checked() {
assert!(WasmSize::new_checked(1024).is_some());
assert!(WasmSize::new_checked(WasmSize::MAX_SIZE).is_some());
assert!(WasmSize::new_checked(WasmSize::MAX_SIZE + 1).is_none());
}
#[test]
fn test_wasm_size_is_zero() {
assert!(WasmSize::new(0).is_zero());
assert!(!WasmSize::new(1).is_zero());
}
}