heddle_pack/store/pack/
compact_frame.rs1use crate::store::Result;
4
5#[derive(Clone, Copy, Debug)]
12pub struct CompactFrameCompression {
13 pub level: i32,
14 pub window_log: u32,
15 pub long_distance_matching: bool,
16}
17
18impl CompactFrameCompression {
19 pub const DEFAULT: Self = Self {
21 level: 19,
22 window_log: 27,
23 long_distance_matching: true,
24 };
25 pub const ADOPTION: Self = Self {
28 level: 3,
29 window_log: 27,
30 long_distance_matching: true,
31 };
32}
33
34impl Default for CompactFrameCompression {
35 fn default() -> Self {
36 Self::DEFAULT
37 }
38}
39
40pub fn compress_compact_frame(data: &[u8]) -> Result<Vec<u8>> {
46 compress_compact_frame_with(data, CompactFrameCompression::DEFAULT)
47}
48
49pub fn compress_compact_frame_with(
52 data: &[u8],
53 options: CompactFrameCompression,
54) -> Result<Vec<u8>> {
55 #[cfg(feature = "zstd")]
56 {
57 use std::io::Write;
58
59 let mut compressed = Vec::new();
60 let mut encoder = zstd::stream::write::Encoder::new(&mut compressed, options.level)?;
61 encoder.window_log(options.window_log)?;
62 encoder.long_distance_matching(options.long_distance_matching)?;
63 encoder.include_checksum(true)?;
64 encoder.set_pledged_src_size(Some(data.len() as u64))?;
65 encoder.write_all(data)?;
66 encoder.finish()?;
67 if compressed.len() < data.len() {
68 return Ok(compressed);
69 }
70 }
71 #[cfg(not(feature = "zstd"))]
72 {
73 let _ = options;
74 }
75 Ok(data.to_vec())
76}
77
78#[cfg(all(test, feature = "zstd"))]
79mod tests {
80 use super::*;
81 use crate::store::pack::{decompress_pack_payload, has_zstd_magic};
82
83 fn lineage_input() -> Vec<u8> {
84 (0..32_768u32)
87 .flat_map(|i| format!("directory version {}\n", i % 97).into_bytes())
88 .collect()
89 }
90
91 #[test]
92 fn solid_compression_round_trips_and_carries_a_zstd_checksum() {
93 let input = b"directory version\n".repeat(32_768);
94 let compressed = compress_compact_frame(&input).unwrap();
95 assert!(has_zstd_magic(&compressed));
96 assert!(compressed.len() < input.len());
97 assert_eq!(
98 decompress_pack_payload(&compressed, input.len()).unwrap(),
99 input
100 );
101 }
102
103 #[test]
104 fn local_default_is_level_nineteen_and_adoption_is_level_three() {
105 let options = CompactFrameCompression::DEFAULT;
106 let adoption = CompactFrameCompression::ADOPTION;
107 assert_eq!(options.level, 19);
108 assert_eq!(adoption.level, 3);
109 assert_eq!(adoption.window_log, 27);
110 assert!(adoption.long_distance_matching);
111 assert_eq!(options.window_log, 27);
112 assert!(options.long_distance_matching);
113 let input = lineage_input();
114 assert_eq!(
115 compress_compact_frame(&input).unwrap(),
116 compress_compact_frame_with(&input, CompactFrameCompression::DEFAULT).unwrap(),
117 "the plain entry point is exactly the DEFAULT policy"
118 );
119 }
120
121 #[test]
122 fn pre_change_level_nineteen_fixture_and_adoption_frames_decode() {
123 let input = lineage_input();
124 let solid = include_bytes!("../../../tests/fixtures/compact-level19.zstd");
127 let fast = compress_compact_frame_with(&input, CompactFrameCompression::ADOPTION).unwrap();
128 assert!(has_zstd_magic(solid) && has_zstd_magic(&fast));
129 assert_ne!(
130 solid.as_slice(),
131 fast.as_slice(),
132 "the two levels must exercise different encoders"
133 );
134 assert_eq!(decompress_pack_payload(solid, input.len()).unwrap(), input);
137 assert_eq!(decompress_pack_payload(&fast, input.len()).unwrap(), input);
138 }
139
140 #[test]
141 fn explicit_options_change_the_encoder() {
142 let input = lineage_input();
143 let no_ldm = compress_compact_frame_with(
144 &input,
145 CompactFrameCompression {
146 level: 1,
147 window_log: 20,
148 long_distance_matching: false,
149 },
150 )
151 .unwrap();
152 assert!(has_zstd_magic(&no_ldm));
153 assert_eq!(
154 decompress_pack_payload(&no_ldm, input.len()).unwrap(),
155 input
156 );
157 assert_ne!(
158 no_ldm,
159 compress_compact_frame_with(&input, CompactFrameCompression::DEFAULT).unwrap()
160 );
161 }
162
163 #[test]
164 fn incompressible_input_stays_raw_under_every_policy() {
165 let mut word = 0x9E37_79B9_7F4A_7C15_u64;
167 let input: Vec<u8> = (0..4096)
168 .map(|_| {
169 word ^= word << 13;
170 word ^= word >> 7;
171 word ^= word << 17;
172 (word >> 56) as u8
173 })
174 .collect();
175 for options in [
176 CompactFrameCompression::DEFAULT,
177 CompactFrameCompression::ADOPTION,
178 ] {
179 assert_eq!(compress_compact_frame_with(&input, options).unwrap(), input);
180 }
181 }
182}