#[derive(Default, Debug)]
pub struct Freelist {
pub max_page: u64, pub released_pages: Vec<u64>,
}
impl Freelist {
pub fn get_next_page(&mut self) -> u64 {
self.released_pages.pop().unwrap_or_else(|| {
self.max_page += 1;
self.max_page
})
}
pub fn release_page(&mut self, _page_number: u64) {
}
pub fn serialize(&self, buffer: &mut [u8]) {
let mut offset = 0;
buffer[offset..offset + 8].clone_from_slice(u64::to_le_bytes(self.max_page).as_ref());
offset += 8;
let freeed_cnt = self.released_pages.len();
buffer[offset..offset + 2].clone_from_slice(u16::to_le_bytes(freeed_cnt as u16).as_ref());
offset += 2;
for i in 0..freeed_cnt {
let element = self.released_pages[i];
buffer[offset..offset + 8].clone_from_slice(u64::to_le_bytes(element).as_ref());
offset += 8;
}
}
pub fn deserialize(&mut self, buffer: &[u8]) {
if buffer.len() < 2 {
return;
}
let mut offset = 0;
self.max_page = u64::from_le_bytes(buffer[offset..offset + 8].try_into().unwrap());
offset += 8;
let freeed_cnt = u16::from_le_bytes(buffer[offset..offset + 2].try_into().unwrap());
offset += 2;
if freeed_cnt == 0 {
return;
}
for _ in 0..freeed_cnt {
let element = u64::from_le_bytes(buffer[offset..offset + 8].try_into().unwrap());
self.released_pages.push(element);
offset += 8;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn test_freelist_basic_operations() {
let free_size = |freelist: &Freelist| -> usize {
8 + 2 + freelist.released_pages.len() * 8 };
let mut freelist = Freelist {
max_page: 0,
released_pages: Vec::new(),
};
assert_eq!(freelist.max_page, 0);
assert!(freelist.released_pages.is_empty());
freelist.release_page(100);
assert_eq!(freelist.get_next_page(), 100);
assert_eq!(freelist.get_next_page(), 1);
let pages_to_release = vec![300, 400, 500];
for page in pages_to_release.iter() {
freelist.release_page(*page);
}
let mut serialization_buffer = vec![0; free_size(&freelist)];
freelist.serialize(&mut serialization_buffer[..]);
let mut deserialized_freelist = Freelist::default();
deserialized_freelist.deserialize(&serialization_buffer);
assert_eq!(deserialized_freelist.max_page, freelist.max_page);
assert_eq!(
deserialized_freelist.released_pages,
freelist.released_pages
);
for expected_page in pages_to_release.iter().rev() {
assert_eq!(deserialized_freelist.get_next_page(), *expected_page);
}
assert_eq!(deserialized_freelist.get_next_page(), freelist.max_page + 1);
}
fn test_freelist_basic_functionality() {
let mut freelist = Freelist::default();
assert_eq!(freelist.get_next_page(), 1); freelist.release_page(1); assert_eq!(freelist.get_next_page(), 1); freelist.release_page(2); }
fn test_freelist_serialization_deserialization() {
let mut freelist = Freelist::default();
freelist.get_next_page(); freelist.get_next_page(); freelist.release_page(2);
let mut buffer = vec![0; 20]; freelist.serialize(&mut buffer);
let mut deserialized_freelist = Freelist::default();
deserialized_freelist.deserialize(&buffer);
assert_eq!(deserialized_freelist.get_next_page(), 2); assert_eq!(deserialized_freelist.get_next_page(), 3); assert_eq!(deserialized_freelist.get_next_page(), 4); }
fn test_freelist_boundary_conditions() {
let mut freelist = Freelist::default();
for _ in 0..10 {
let page = freelist.get_next_page(); freelist.release_page(page); }
for page in 1..=10 {
assert_eq!(freelist.get_next_page(), page); }
assert_eq!(freelist.get_next_page(), 11); }
fn test_freelist_exception_handling() {
let mut freelist = Freelist::default();
freelist.get_next_page(); freelist.get_next_page();
let incomplete_buffer = vec![0; 10]; freelist.deserialize(&incomplete_buffer);
assert_eq!(freelist.get_next_page(), 1); assert_eq!(freelist.get_next_page(), 2);
}
}