use crate::Result;
use crate::btree::internal::{self, Internal, InternalEntry};
use crate::btree::node;
use crate::errors::PagedbError;
pub(crate) type Child = (u64, Vec<u8>);
pub(crate) struct LevelAccum {
children: Vec<Child>,
used: usize,
total: u64,
}
impl LevelAccum {
pub(crate) fn new() -> Self {
Self {
children: Vec::new(),
used: node::HEADER_LEN,
total: 0,
}
}
pub(crate) fn sole_child(&self) -> Option<u64> {
if self.total == 1 {
self.children.first().map(|(page_id, _)| *page_id)
} else {
None
}
}
pub(crate) fn try_push(&mut self, child: &Child, body_cap: usize) -> Result<bool> {
if self.children.is_empty() {
self.children.push(child.clone());
self.total += 1;
return Ok(true);
}
let entry_size = internal::separator_entry_size(child.1.len())?;
let needed = self
.used
.checked_add(entry_size)
.ok_or(PagedbError::PayloadTooLarge)?;
if needed > body_cap {
if self.children.len() == 1 {
return Err(PagedbError::PayloadTooLarge);
}
return Ok(false);
}
self.used = needed;
self.children.push(child.clone());
self.total += 1;
Ok(true)
}
pub(crate) fn restart(&mut self, child: Child) {
self.children.clear();
self.children.push(child);
self.used = node::HEADER_LEN;
self.total += 1;
}
pub(crate) fn take_node(&mut self) -> Option<(Internal, Vec<u8>)> {
if self.children.is_empty() {
return None;
}
let children = std::mem::take(&mut self.children);
self.used = node::HEADER_LEN;
let mut children = children.into_iter();
let (leftmost_child, separator) = children.next()?;
let entries = children
.map(|(right_child, key)| InternalEntry { key, right_child })
.collect();
Some((
Internal {
leftmost_child,
entries,
},
separator,
))
}
}
impl Default for LevelAccum {
fn default() -> Self {
Self::new()
}
}