use super::StreamError;
const DIRECTORY_NODE_BUDGET: usize = 8192;
pub(super) const COALESCE_GAP_BYTES: u64 = 4096;
#[derive(Clone, Copy, Debug, Default)]
pub struct StreamLimits {
pub max_reads: Option<usize>,
pub max_read_bytes: Option<u64>,
pub max_items: Option<usize>,
pub directory_budget_bytes: Option<u64>,
pub coalesce_gap_bytes: Option<u64>,
}
pub(super) struct Budget {
limits: StreamLimits,
reads: usize,
bytes: u64,
items: usize,
}
impl Budget {
pub(super) fn new(limits: StreamLimits) -> Self {
Self {
limits,
reads: 0,
bytes: 0,
items: 0,
}
}
pub(super) fn charge_read(&mut self, len: usize) -> Result<(), StreamError> {
self.reads += 1;
self.bytes += len as u64;
if self.limits.max_reads.is_some_and(|m| self.reads > m)
|| self.limits.max_read_bytes.is_some_and(|m| self.bytes > m)
{
return Err(StreamError::LimitExceeded);
}
Ok(())
}
pub(super) fn charge_item(&mut self) -> Result<(), StreamError> {
self.items += 1;
if self.limits.max_items.is_some_and(|m| self.items > m) {
return Err(StreamError::LimitExceeded);
}
Ok(())
}
}
pub(super) fn directory_node_budget(
limits: &StreamLimits,
box_stride: usize,
interleaved: bool,
) -> usize {
match limits.directory_budget_bytes {
Some(bytes) => {
let per_node = (box_stride + if interleaved { 0 } else { 8 }).max(1) as u64;
(bytes / per_node).min(usize::MAX as u64) as usize
}
None => DIRECTORY_NODE_BUDGET,
}
}