use crate::persistence::{LoadError, read_u64_le_unchecked};
use super::limits::Budget;
use super::{StreamError, read_index};
#[derive(Clone)]
pub(crate) struct PayloadSection {
pub(crate) offsets_start: u64,
pub(crate) blobs_start: u64,
pub(crate) blob_total: u64,
pub(crate) stride: u64,
}
pub(super) fn payload_run_end(leaf_positions: &[usize], j: usize, max_gap: u64) -> usize {
let mut k = j;
while k + 1 < leaf_positions.len() {
let gap = (leaf_positions[k + 1] - leaf_positions[k]) as u64 * 8;
if gap > max_gap {
break;
}
k += 1;
}
k
}
pub(super) fn payload_blob_span(
off_buf: &[u8],
lo: usize,
hi: usize,
blob_total: u64,
) -> Result<(u64, u64), StreamError> {
let blob_lo = read_u64_le_unchecked(off_buf, 0);
let blob_hi = read_u64_le_unchecked(off_buf, (hi + 1 - lo) * 8);
if blob_hi < blob_lo || blob_hi > blob_total {
return Err(StreamError::Format(LoadError::InvalidTree));
}
Ok((blob_lo, blob_hi))
}
#[allow(clippy::too_many_arguments)]
pub(super) fn emit_run_payloads<F: FnMut(usize, &[u8])>(
leaf_positions: &[usize],
indices: &[u8],
j: usize,
k: usize,
lo: usize,
off_buf: &[u8],
blob_lo: u64,
blob_hi: u64,
blob_buf: &[u8],
num_items: usize,
budget: &mut Budget,
emit: &mut F,
) -> Result<(), StreamError> {
for (offset, &p) in leaf_positions[j..=k].iter().enumerate() {
let i = j + offset;
let o0 = read_u64_le_unchecked(off_buf, (p - lo) * 8);
let o1 = read_u64_le_unchecked(off_buf, (p + 1 - lo) * 8);
if o0 < blob_lo || o1 < o0 || o1 > blob_hi {
return Err(StreamError::Format(LoadError::InvalidTree));
}
let id = read_index(indices, i)?;
if id >= num_items {
return Err(StreamError::Format(LoadError::InvalidTree));
}
budget.charge_item()?;
emit(
id,
&blob_buf[(o0 - blob_lo) as usize..(o1 - blob_lo) as usize],
);
}
Ok(())
}
pub(super) fn payload_run_end_fixed(
leaf_positions: &[usize],
j: usize,
stride: usize,
max_gap: u64,
) -> usize {
let mut k = j;
while k + 1 < leaf_positions.len() {
let gap = (leaf_positions[k + 1] - leaf_positions[k]) as u64 * stride as u64;
if gap > max_gap {
break;
}
k += 1;
}
k
}
#[allow(clippy::too_many_arguments)]
pub(super) fn emit_run_payloads_fixed<F: FnMut(usize, &[u8])>(
leaf_positions: &[usize],
indices: &[u8],
j: usize,
k: usize,
lo: usize,
stride: usize,
blob_buf: &[u8],
num_items: usize,
budget: &mut Budget,
emit: &mut F,
) -> Result<(), StreamError> {
for (offset, &p) in leaf_positions[j..=k].iter().enumerate() {
let i = j + offset;
let within = (p - lo) * stride;
let id = read_index(indices, i)?;
if id >= num_items {
return Err(StreamError::Format(LoadError::InvalidTree));
}
budget.charge_item()?;
emit(id, &blob_buf[within..within + stride]);
}
Ok(())
}