use crate::storage::page::PageId;
pub(crate) const SLOT_BITS: u32 = 16;
pub(crate) const SLOT_MASK: u64 = (1_u64 << SLOT_BITS) - 1;
pub(crate) const MAX_PAGE_ID: u64 = (1_u64 << (64 - SLOT_BITS)) - 1;
pub(crate) const MAX_SLOT_ID: u16 = u16::MAX;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[repr(transparent)]
pub(crate) struct Rid(u64);
impl Rid {
#[must_use]
pub(crate) const fn try_new(page_id: u64, slot_id: u16) -> Option<Self> {
if page_id > MAX_PAGE_ID {
return None;
}
Some(Self((page_id << SLOT_BITS) | (slot_id as u64)))
}
#[must_use]
pub(crate) const fn new(page_id: u64, slot_id: u16) -> Self {
debug_assert!(page_id <= MAX_PAGE_ID);
Self((page_id << SLOT_BITS) | (slot_id as u64))
}
#[must_use]
pub(crate) const fn page_id(self) -> PageId {
PageId::new(self.0 >> SLOT_BITS)
}
#[must_use]
pub(crate) const fn slot_id(self) -> u16 {
(self.0 & SLOT_MASK) as u16
}
#[must_use]
pub(crate) const fn raw(self) -> u64 {
self.0
}
#[must_use]
pub(crate) const fn from_raw(raw: u64) -> Self {
Self(raw)
}
}
#[cfg(test)]
mod tests {
use super::{Rid, MAX_PAGE_ID, MAX_SLOT_ID};
#[test]
fn round_trip_packs_and_unpacks() {
let rid = Rid::new(1234, 56);
assert_eq!(rid.page_id().get(), 1234);
assert_eq!(rid.slot_id(), 56);
}
#[test]
fn round_trip_at_boundaries() {
let zero = Rid::new(0, 0);
assert_eq!(zero.page_id().get(), 0);
assert_eq!(zero.slot_id(), 0);
let max = Rid::new(MAX_PAGE_ID, MAX_SLOT_ID);
assert_eq!(max.page_id().get(), MAX_PAGE_ID);
assert_eq!(max.slot_id(), MAX_SLOT_ID);
}
#[test]
fn raw_round_trip_preserves_value() {
let rid = Rid::new(0x0001_0203_0405, 0xABCD);
let raw = rid.raw();
let decoded = Rid::from_raw(raw);
assert_eq!(decoded, rid);
}
#[test]
fn try_new_rejects_oversized_page_id() {
let too_big = Rid::try_new(MAX_PAGE_ID + 1, 0);
assert!(too_big.is_none());
}
#[test]
fn try_new_accepts_max_page_id() {
let ok = Rid::try_new(MAX_PAGE_ID, MAX_SLOT_ID);
assert!(ok.is_some());
}
#[test]
fn rid_is_copy_and_eight_bytes() {
assert_eq!(core::mem::size_of::<Rid>(), 8);
let a = Rid::new(7, 9);
let b = a;
assert_eq!(a, b);
}
#[test]
fn ordering_matches_page_id_then_slot_id() {
let a = Rid::new(1, 0);
let b = Rid::new(1, 1);
let c = Rid::new(2, 0);
assert!(a < b);
assert!(b < c);
assert!(a < c);
}
}