use super::PAGE_SIZE;
pub struct PageAllocator {
next_page: u32,
pages: Vec<(u32, Vec<u8>)>,
}
impl PageAllocator {
pub fn new() -> Self {
Self {
next_page: 1,
pages: Vec::new(),
}
}
pub fn alloc(&mut self) -> u32 {
let n = self.next_page;
self.next_page += 1;
n
}
pub fn write(&mut self, page_num: u32, bytes: Vec<u8>) {
debug_assert_eq!(
bytes.len(),
PAGE_SIZE,
"page {page_num}: expected {PAGE_SIZE} bytes, got {}",
bytes.len()
);
self.pages.push((page_num, bytes));
}
pub fn page_count(&self) -> u32 {
self.next_page - 1
}
pub fn finalize(mut self) -> Vec<u8> {
let total = self.page_count() as usize;
self.pages.sort_by_key(|(n, _)| *n);
let mut out = Vec::with_capacity(total * PAGE_SIZE);
let mut committed_iter = self.pages.into_iter().peekable();
for page_idx in 1..=(total as u32) {
let has_this_page = committed_iter
.peek()
.map(|(n, _)| *n == page_idx)
.unwrap_or(false);
if has_this_page {
if let Some((_, bytes)) = committed_iter.next() {
if bytes.len() == PAGE_SIZE {
out.extend_from_slice(&bytes);
} else {
let mut padded = bytes;
padded.resize(PAGE_SIZE, 0);
out.extend_from_slice(&padded);
}
}
} else {
out.extend_from_slice(&[0u8; PAGE_SIZE]);
}
}
out
}
}
impl Default for PageAllocator {
fn default() -> Self {
Self::new()
}
}