use std::path::Path;
pub use ldeflate::precompressed::{ContentHint, SNIFF_PREFIX_LEN, is_zlib_stream, looks_compressed};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct SkipPolicy(ldeflate::precompressed::SkipPolicy);
impl SkipPolicy {
pub const fn resolve() -> Self {
Self(ldeflate::precompressed::SkipPolicy::resolve())
}
pub const fn already_compressed() -> Self {
Self(ldeflate::precompressed::SkipPolicy::already_compressed())
}
pub const fn compress_everything() -> Self {
Self(ldeflate::precompressed::SkipPolicy::compress_everything())
}
pub const fn from_no_skip(no_skip: bool) -> Self {
if no_skip { Self::compress_everything() } else { Self::resolve() }
}
pub const fn from_hint(hint: ContentHint) -> Self {
Self(ldeflate::precompressed::SkipPolicy::from_hint(hint))
}
pub const fn hint(&self) -> ContentHint {
self.0.hint()
}
pub const fn as_ldeflate(&self) -> ldeflate::precompressed::SkipPolicy {
self.0
}
pub fn skip_by_path(&self, path: &Path) -> bool {
match self.0.hint() {
ContentHint::AlreadyCompressed => true,
ContentHint::Compressible => false,
ContentHint::Unknown => crate::index::is_probably_compressed(path),
}
}
pub fn skip_by_bytes(&self, prefix: &[u8]) -> bool {
self.0.skip(prefix)
}
}
impl From<ldeflate::precompressed::SkipPolicy> for SkipPolicy {
fn from(p: ldeflate::precompressed::SkipPolicy) -> Self {
Self(p)
}
}
impl From<SkipPolicy> for ldeflate::precompressed::SkipPolicy {
fn from(p: SkipPolicy) -> Self {
p.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_probe_is_ldeflates_and_not_a_second_copy() {
for bytes in [
b"PACK\x00\x00\x00\x02".as_slice(),
b"\x1f\x8b\x08\x00".as_slice(),
b"\x28\xb5\x2f\xfd\x00\x58".as_slice(),
b"RIFF\x24\x00\x00\x00WEBPVP8 ".as_slice(),
b"\x78\x9c".as_slice(),
b"SELECT * FROM njord WHERE id = 42;".as_slice(),
b"x = 1;\n".as_slice(),
b"".as_slice(),
] {
assert_eq!(
looks_compressed(bytes),
ldeflate::precompressed::looks_compressed(bytes),
"the re-export must BE ldeflate's probe: {bytes:?}"
);
assert_eq!(
is_zlib_stream(bytes),
ldeflate::precompressed::is_zlib_stream(bytes),
"the re-export must BE ldeflate's zlib probe: {bytes:?}"
);
assert_eq!(
SkipPolicy::resolve().skip_by_bytes(bytes),
ldeflate::precompressed::SkipPolicy::resolve().skip(bytes),
"skip_by_bytes must delegate: {bytes:?}"
);
}
assert_eq!(SNIFF_PREFIX_LEN, ldeflate::precompressed::SNIFF_PREFIX_LEN);
}
#[test]
fn the_hint_survives_the_wrapper_in_both_directions() {
for (p, want) in [
(SkipPolicy::resolve(), ContentHint::Unknown),
(SkipPolicy::already_compressed(), ContentHint::AlreadyCompressed),
(SkipPolicy::compress_everything(), ContentHint::Compressible),
] {
assert_eq!(p.hint(), want);
assert_eq!(p.as_ldeflate().hint(), want, "the ldeflate view must carry the same hint");
assert_eq!(SkipPolicy::from(p.as_ldeflate()), p, "round-trip through ldeflate");
assert_eq!(ldeflate::precompressed::SkipPolicy::from(p), p.as_ldeflate());
assert_eq!(SkipPolicy::from_hint(want), p, "from_hint must agree with the constructor");
}
assert_eq!(SkipPolicy::default(), SkipPolicy::resolve(), "the probe is the default");
}
#[test]
fn an_already_compressed_hint_is_honoured_without_inspection() {
let p = SkipPolicy::already_compressed();
assert!(p.skip_by_path(Path::new("objects/00ff")), "hint must win on the path");
assert!(p.skip_by_bytes(b"SELECT * FROM njord;"), "hint must win on the bytes");
}
#[test]
fn an_unhinted_batch_of_compressible_data_is_still_compressed() {
let p = SkipPolicy::resolve();
assert!(!p.skip_by_path(Path::new("dbdump/njord.dump")));
assert!(!p.skip_by_bytes(b"SELECT * FROM njord WHERE id = 42;"));
}
#[test]
fn a_compressible_hint_overrules_both_fallbacks() {
let p = SkipPolicy::compress_everything();
assert!(!p.skip_by_path(Path::new("photo.png")), "--no-skip must beat the extension table");
assert!(!p.skip_by_bytes(b"\x89PNG\r\n\x1a\n"), "--no-skip must beat the probe");
}
#[test]
fn no_skip_maps_onto_the_hint() {
assert_eq!(SkipPolicy::from_no_skip(true), SkipPolicy::compress_everything());
assert_eq!(SkipPolicy::from_no_skip(false), SkipPolicy::resolve());
}
#[test]
fn an_extension_that_lies_is_caught_by_the_bytes() {
let p = SkipPolicy::resolve();
let notes = Path::new("release-notes.txt");
let zstd_bytes = b"\x28\xb5\x2f\xfd\x00\x58\x2d\x00\x00";
assert!(!p.skip_by_path(notes), "the name says text, so the fast path lets it through");
assert!(p.skip_by_bytes(zstd_bytes), "the bytes say zstd, and the bytes are the authority");
}
#[test]
fn the_extension_fast_path_covers_a_whole_file_not_just_its_head() {
let p = SkipPolicy::resolve();
assert!(p.skip_by_path(Path::new("objects/pack/pack-9f2c.pack")));
assert!(p.skip_by_path(Path::new("objects/pack/pack-9f2c.idx")));
}
#[test]
fn an_oid_named_loose_object_is_reached_only_by_the_bytes() {
let p = SkipPolicy::resolve();
let oid = Path::new(".git/objects/9f/2c1e0b7a4d3f8c6e5a2b9d0c7f4e1a8b3d6c9e2f");
assert!(!p.skip_by_path(oid), "an oid has no extension for the table to match");
assert!(p.skip_by_bytes(b"\x78\x01\x4b\xca\x49"), "so the zlib header must catch it");
}
}