use core::fmt;
use core::num::NonZeroU32;
use crate::error::{corrupt, DbResult};
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct DatabaseId(pub u32);
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct PageId(NonZeroU32);
impl PageId {
pub const FIRST: PageId = PageId(NonZeroU32::MIN);
pub fn new(value: u32) -> Option<PageId> {
NonZeroU32::new(value).map(PageId)
}
pub fn from_persisted(value: u32) -> DbResult<PageId> {
PageId::new(value).ok_or_else(|| corrupt("page number zero where a page was required"))
}
pub fn get(self) -> u32 {
self.0.get()
}
pub fn index(self) -> u32 {
self.0.get().saturating_sub(1)
}
pub fn next(self) -> Option<PageId> {
self.0.get().checked_add(1).and_then(PageId::new)
}
}
impl fmt::Display for PageId {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "{}", self.0.get())
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct RootPageId(pub PageId);
impl RootPageId {
pub fn page(self) -> PageId {
self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::PrimaryCode;
#[test]
fn page_zero_is_rejected() {
assert_eq!(PageId::new(0), None);
let error = PageId::from_persisted(0).expect_err("zero must not become a page");
assert_eq!(error.code(), PrimaryCode::Corrupt);
}
#[test]
fn page_numbering_is_one_based() {
let first = PageId::from_persisted(1).expect("page one is valid");
assert_eq!(first, PageId::FIRST);
assert_eq!(first.get(), 1);
assert_eq!(first.index(), 0);
}
#[test]
fn page_numbers_do_not_wrap_at_the_top_of_the_space() {
let last = PageId::new(u32::MAX).expect("u32::MAX is a valid page number");
assert_eq!(last.next(), None);
}
}