use crate::store::NodeStore;
use super::super::cursor::{TreeError, load_node};
use super::super::node::{Hash, InternalNode, LeafNode, Node};
use super::super::policy::TreePolicy;
use super::{ChildRef, Entry};
pub(super) fn collect_leaf_refs<S: NodeStore + ?Sized>(
store: &S,
root_hash: Hash,
) -> Result<Vec<ChildRef>, TreeError> {
let height = tree_height(store, root_hash)?;
if height == 0 {
return Ok(vec![(Vec::new(), root_hash)]);
}
let mut leaves = Vec::new();
collect_leaf_refs_inner(store, root_hash, height, &mut leaves)?;
Ok(leaves)
}
fn tree_height<S: NodeStore + ?Sized>(store: &S, root_hash: Hash) -> Result<usize, TreeError> {
let mut height = 0;
let mut hash = root_hash;
loop {
match &*load_node(store, hash)? {
Node::Leaf(_leaf) => return Ok(height),
Node::Internal(internal) => {
let Some((_separator, child_hash)) = internal.children().first() else {
return Err(TreeError::InvalidNode);
};
height = height.saturating_add(1);
hash = *child_hash;
}
}
}
}
fn collect_leaf_refs_inner<S: NodeStore + ?Sized>(
store: &S,
hash: Hash,
levels_above_leaves: usize,
leaves: &mut Vec<ChildRef>,
) -> Result<(), TreeError> {
let node = load_node(store, hash)?;
let Node::Internal(internal) = &*node else {
return Err(TreeError::InvalidNode);
};
if levels_above_leaves <= 1 {
leaves.extend_from_slice(internal.children());
return Ok(());
}
for (_separator, child_hash) in internal.children() {
collect_leaf_refs_inner(store, *child_hash, levels_above_leaves - 1, leaves)?;
}
Ok(())
}
pub(super) fn store_leaf_replacements<S: NodeStore + ?Sized>(
store: &mut S,
entries: Vec<Entry>,
policy: TreePolicy,
) -> Result<Vec<ChildRef>, TreeError> {
if entries.is_empty() {
return Ok(Vec::new());
}
let mut replacements = Vec::new();
for chunk in group_leaf_entries(entries, policy) {
replacements.push(store_leaf(store, chunk)?);
}
Ok(replacements)
}
fn group_leaf_entries(entries: Vec<Entry>, policy: TreePolicy) -> Vec<Vec<Entry>> {
let mut chunks = Vec::new();
let mut current: Vec<Entry> = Vec::new();
for (key, value) in entries {
if !current.is_empty() && policy.leaf_boundary_before(key.len(), value.len()) {
chunks.push(std::mem::take(&mut current));
}
let closes = policy.leaf_boundary_after(key.as_slice(), value.len());
current.push((key, value));
if closes {
chunks.push(std::mem::take(&mut current));
}
}
if !current.is_empty() {
chunks.push(current);
}
chunks
}
fn store_internal_replacements<S: NodeStore + ?Sized>(
store: &mut S,
children: Vec<ChildRef>,
policy: TreePolicy,
) -> Result<Vec<ChildRef>, TreeError> {
match children.len() {
0 => Ok(Vec::new()),
1 => Ok(children),
_ => {
let mut replacements = Vec::new();
for chunk in group_internal_children(children, policy) {
replacements.push(store_internal(store, chunk)?);
}
Ok(replacements)
}
}
}
fn group_internal_children(children: Vec<ChildRef>, policy: TreePolicy) -> Vec<Vec<ChildRef>> {
let min_two = policy.is_v2();
let mut chunks = Vec::new();
let mut current: Vec<ChildRef> = Vec::new();
for (separator, hash) in children {
let closes = policy.internal_boundary_after(separator.as_slice());
current.push((separator, hash));
if closes && (!min_two || current.len() >= 2) {
chunks.push(std::mem::take(&mut current));
}
}
if !current.is_empty() {
chunks.push(current);
}
chunks
}
fn store_leaf<S: NodeStore + ?Sized>(
store: &mut S,
entries: Vec<Entry>,
) -> Result<ChildRef, TreeError> {
let separator = first_entry_key(entries.as_slice())?;
let leaf = LeafNode::new(entries)?;
let hash = store
.put(&Node::Leaf(leaf))
.map_err(|_| TreeError::InvalidNode)?;
Ok((separator, hash))
}
fn store_internal<S: NodeStore + ?Sized>(
store: &mut S,
children: Vec<ChildRef>,
) -> Result<ChildRef, TreeError> {
let separator = first_child_key(children.as_slice())?;
let internal = InternalNode::new(children)?;
let hash = store
.put(&Node::Internal(internal))
.map_err(|_| TreeError::InvalidNode)?;
Ok((separator, hash))
}
pub(super) fn finish_root<S: NodeStore + ?Sized>(
store: &mut S,
leaves: Vec<ChildRef>,
policy: TreePolicy,
) -> Result<Hash, TreeError> {
if leaves.is_empty() {
return store_empty_leaf(store);
}
let (_separator, hash) = build_spine(store, leaves, policy)?;
Ok(hash)
}
fn build_spine<S: NodeStore + ?Sized>(
store: &mut S,
mut children: Vec<ChildRef>,
policy: TreePolicy,
) -> Result<ChildRef, TreeError> {
loop {
match children.len() {
0 => return Err(TreeError::InvalidNode),
1 => return children.into_iter().next().ok_or(TreeError::InvalidNode),
len => {
let next = store_internal_replacements(store, children, policy)?;
if next.len() < len {
children = next;
} else {
return store_internal(store, next);
}
}
}
}
}
fn store_empty_leaf<S: NodeStore + ?Sized>(store: &mut S) -> Result<Hash, TreeError> {
let leaf = LeafNode::new(Vec::new())?;
store
.put(&Node::Leaf(leaf))
.map_err(|_| TreeError::InvalidNode)
}
fn first_entry_key(entries: &[Entry]) -> Result<Vec<u8>, TreeError> {
entries
.first()
.map(|(key, _value)| key.clone())
.ok_or(TreeError::InvalidNode)
}
fn first_child_key(children: &[ChildRef]) -> Result<Vec<u8>, TreeError> {
children
.first()
.map(|(key, _hash)| key.clone())
.ok_or(TreeError::InvalidNode)
}