corevm-host 0.1.28

Types that are common across CoreVM service, builder, monitor, tooling
Documentation
use codec::{ConstEncodedLen, Decode, Encode, MaxEncodedLen};
use jam_types::SEGMENT_LEN;

/// Inner VM page size.
pub const PAGE_SIZE: u32 = 4096;

pub(crate) const MIN_PAGE: u32 = 16;
pub(crate) const MAX_PAGE: u32 = u32::MAX / PAGE_SIZE;

/// Page number.
#[derive(
	Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Encode, Decode, MaxEncodedLen,
)]
pub struct PageNum(pub u32);

impl PageNum {
	pub const fn from_address(address: u32) -> Self {
		Self(address / PAGE_SIZE)
	}

	pub const fn address(self) -> u32 {
		self.0 * PAGE_SIZE
	}
}

impl core::fmt::Debug for PageNum {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
		let page = self.0;
		let address = page.saturating_mul(PAGE_SIZE);
		let comment = if (MIN_PAGE..=MAX_PAGE).contains(&page) { "" } else { " (invalid!)" };
		write!(f, "{page}/{address:#x}{comment}")
	}
}

impl core::fmt::Display for PageNum {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
		core::fmt::Debug::fmt(self, f)
	}
}

impl ConstEncodedLen for PageNum {}

/// An import/export segment that stores an inner VM page and its number.
///
/// The page is stored in the first 4096 bytes,
/// the number is encoded using little-endian format in the next 4 bytes.
/// The last 4 bytes are unused.
///
/// `[ page(4096) | page_number(4) | unused(4) ]`
pub trait PageSegmentOps {
	/// Get immutable reference to the page contents (excluding the address).
	fn page(&self) -> &[u8; PAGE_SIZE as usize];

	/// Get mutable reference to the page contents (excluding the address).
	fn page_mut(&mut self) -> &mut [u8; PAGE_SIZE as usize];

	/// Get page number.
	fn page_number(&self) -> PageNum;

	/// Set page number.
	fn set_page_number(&mut self, page: PageNum);
}

impl PageSegmentOps for [u8; SEGMENT_LEN] {
	fn page(&self) -> &[u8; PAGE_SIZE as usize] {
		(&self[..PAGE_SIZE as usize])
			.try_into()
			.expect("Slice and array have the same length")
	}

	fn page_mut(&mut self) -> &mut [u8; PAGE_SIZE as usize] {
		(&mut self[..PAGE_SIZE as usize])
			.try_into()
			.expect("Slice and array have the same length")
	}

	fn page_number(&self) -> PageNum {
		let a = &self[PAGE_SIZE as usize..];
		let page = u32::from_le_bytes([a[0], a[1], a[2], a[3]]);
		PageNum(page)
	}

	fn set_page_number(&mut self, page: PageNum) {
		self[PAGE_SIZE as usize..][..4].copy_from_slice(&page.0.to_le_bytes()[..]);
	}
}