use std::io::Read;
use crate::error::{CliError, EngineResult};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[expect(
clippy::struct_field_names,
reason = "the shared max prefix makes each public budget field's bound explicit"
)]
pub struct LoadBudget {
pub max_chart_archive_bytes: usize,
pub max_schema_document_bytes: usize,
pub max_chart_archive_entries: usize,
pub max_chart_archive_unpacked_bytes: usize,
}
impl LoadBudget {
#[must_use]
pub const fn new(max_chart_archive_bytes: usize, max_schema_document_bytes: usize) -> Self {
Self {
max_chart_archive_bytes,
max_schema_document_bytes,
max_chart_archive_entries: 4096,
max_chart_archive_unpacked_bytes: 256 * 1024 * 1024,
}
}
}
impl Default for LoadBudget {
fn default() -> Self {
Self::new(64 * 1024 * 1024, 16 * 1024 * 1024)
}
}
pub(crate) fn read_to_end_capped(
reader: &mut impl Read,
limit_bytes: usize,
subject: impl Into<String>,
) -> EngineResult<Vec<u8>> {
let subject = subject.into();
let limit_plus_one = u64::try_from(limit_bytes)
.unwrap_or(u64::MAX)
.saturating_add(1);
let mut limited = reader.take(limit_plus_one);
let mut bytes = Vec::new();
limited.read_to_end(&mut bytes)?;
if bytes.len() > limit_bytes {
return Err(CliError::LoadBudgetExceeded {
subject,
limit_bytes,
});
}
Ok(bytes)
}