use gix_error::{ResourceExhaustionKind, Result, ResultExt, bail};
pub mod entry;
pub mod header;
pub(crate) fn resize_with_limit(out: &mut Vec<u8>, len: usize, alloc_limit_bytes: Option<usize>) -> Result {
if alloc_limit_bytes.is_some_and(|limit| len > limit) {
bail!(allocation_error(ResourceExhaustionKind::AllocationLimit));
}
let additional = len.saturating_sub(out.len());
if alloc_limit_bytes.is_some() {
out.try_reserve_exact(additional)
} else {
out.try_reserve(additional)
}
.or_raise(|| allocation_error(ResourceExhaustionKind::AllocationFailure))?;
out.resize(len, 0);
Ok(())
}
struct DeltaCycle {
checkpoint: u64,
distance: usize,
interval: usize,
}
impl DeltaCycle {
fn new(offset: u64) -> Self {
Self {
checkpoint: offset,
distance: 0,
interval: 1,
}
}
fn check(&mut self, offset: u64) -> Result {
if offset == self.checkpoint {
bail!(gix_error::corruption("A pack delta chain contains a cycle"));
}
self.distance += 1;
if self.distance == self.interval {
self.checkpoint = offset;
self.interval = self.interval.saturating_mul(2);
self.distance = 0;
}
Ok(())
}
}
#[derive(Debug)]
pub struct DeltaBaseUnresolved(
pub gix_hash::ObjectId,
);
impl std::fmt::Display for DeltaBaseUnresolved {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"A delta chain could not be followed as the ref base with id {} could not be found",
self.0
)
}
}
impl std::error::Error for DeltaBaseUnresolved {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(const { &gix_error::ClassificationMarker::NOT_FOUND })
}
}
#[cold]
pub(super) fn allocation_error(kind: gix_error::ResourceExhaustionKind) -> gix_error::Message {
gix_error::resource_exhaustion(kind, "Entry too large to fit in memory")
}