#![forbid(unsafe_code)]
use crate::pager::page::{Page, PAGE_SIZE, PAGE_TRAILER_SIZE};
pub const TYPE_FREE_LIST: u8 = 0x05;
const OFF_NEXT: usize = 8;
const _: () = assert!(PAGE_SIZE >= PAGE_TRAILER_SIZE + OFF_NEXT + 8);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FreeListPage {
pub next: u64,
}
impl FreeListPage {
#[must_use]
pub const fn new(next: u64) -> Self {
Self { next }
}
}
pub fn encode(entry: FreeListPage, page: &mut Page) {
let buf = page.as_bytes_mut();
buf.fill(0);
buf[0] = TYPE_FREE_LIST;
buf[OFF_NEXT..OFF_NEXT + 8].copy_from_slice(&entry.next.to_le_bytes());
}
#[must_use]
pub fn decode(page: &Page) -> Option<FreeListPage> {
let buf = page.as_bytes();
if buf[0] != TYPE_FREE_LIST {
return None;
}
let mut next_bytes = [0u8; 8];
next_bytes.copy_from_slice(&buf[OFF_NEXT..OFF_NEXT + 8]);
Some(FreeListPage {
next: u64::from_le_bytes(next_bytes),
})
}
#[cfg(test)]
mod tests {
use super::{decode, encode, FreeListPage};
use crate::pager::page::Page;
#[test]
fn round_trip() {
for &next in &[0u64, 1, 42, u64::MAX] {
let mut p = Page::zeroed();
encode(FreeListPage::new(next), &mut p);
assert_eq!(decode(&p), Some(FreeListPage { next }));
}
}
#[test]
fn decode_rejects_bad_tag() {
let mut p = Page::zeroed();
p.as_bytes_mut()[0] = 0x03; assert!(decode(&p).is_none());
}
}