use codec::{ConstEncodedLen, Decode, Encode, MaxEncodedLen};
use jam_types::SEGMENT_LEN;
pub const PAGE_SIZE: u32 = 4096;
pub(crate) const MIN_PAGE: u32 = 16;
pub(crate) const MAX_PAGE: u32 = u32::MAX / PAGE_SIZE;
#[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 {}
pub trait PageSegmentOps {
fn page(&self) -> &[u8; PAGE_SIZE as usize];
fn page_mut(&mut self) -> &mut [u8; PAGE_SIZE as usize];
fn page_number(&self) -> PageNum;
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()[..]);
}
}