1use core::mem;
4
5pub type Words<'a> = &'a [u32];
6pub type Bytes<'a> = &'a [u8];
7pub type EnumValue = i32;
8
9#[inline(always)]
10pub const fn word_size(size: usize) -> usize {
11 size.div_ceil(4)
12}
13
14pub trait Scalar: Copy + Sized {
15 const WIDTH: usize;
16 fn from_words(words: &[u32]) -> Option<Self>;
17 fn write_words(self, words: &mut [u32]) -> Option<()>;
18}
19
20macro_rules! impl_scalar {
21 ($($ty:ty),* $(,)?) => {
22 $(
23 impl Scalar for $ty {
24 const WIDTH: usize = word_size(mem::size_of::<$ty>());
25
26 #[inline(always)]
27 fn from_words(words: &[u32]) -> Option<Self> {
28 if words.len() != Self::WIDTH {
29 return None;
30 }
31 let mut bytes = [0u8; mem::size_of::<$ty>()];
32 let raw = unsafe {
33 core::slice::from_raw_parts(
34 words.as_ptr().cast::<u8>(),
35 words.len() * mem::size_of::<u32>(),
36 )
37 };
38 bytes.copy_from_slice(raw.get(..mem::size_of::<$ty>())?);
39 Some(<$ty>::from_le_bytes(bytes))
40 }
41
42 #[inline(always)]
43 fn write_words(self, words: &mut [u32]) -> Option<()> {
44 if words.len() != Self::WIDTH {
45 return None;
46 }
47 words.fill(0);
48 let raw = unsafe {
49 core::slice::from_raw_parts_mut(
50 words.as_mut_ptr().cast::<u8>(),
51 words.len() * mem::size_of::<u32>(),
52 )
53 };
54 raw.get_mut(..mem::size_of::<$ty>())?
55 .copy_from_slice(&self.to_le_bytes());
56 Some(())
57 }
58 }
59 )*
60 };
61}
62
63impl_scalar!(u32, i32, u64, i64, f32, f64);
64
65impl Scalar for bool {
66 const WIDTH: usize = 1;
67
68 #[inline(always)]
69 fn from_words(words: &[u32]) -> Option<Self> {
70 Some(u32::from_words(words)? != 0)
71 }
72
73 #[inline(always)]
74 fn write_words(self, words: &mut [u32]) -> Option<()> {
75 if words.len() != Self::WIDTH {
76 return None;
77 }
78 words[0] = u32::from(self);
79 Some(())
80 }
81}
82
83#[derive(Clone, Copy, Debug, Eq, PartialEq)]
84pub enum CorruptionKind {
85 Truncated,
86 InvalidHeader,
87 InvalidUtf8,
88 IntegerOverflow,
89}
90
91#[derive(Clone, Copy, Debug, Eq, PartialEq)]
92pub struct ReadError {
93 pub kind: CorruptionKind,
94}
95
96impl ReadError {
97 pub const fn new(kind: CorruptionKind) -> Self {
98 Self { kind }
99 }
100}
101
102impl core::fmt::Display for ReadError {
103 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
104 write!(f, "{:?}", self.kind)
105 }
106}
107
108impl std::error::Error for ReadError {}
109
110#[derive(Clone, Debug, Default)]
111pub struct Buffer {
112 data: Vec<u32>,
113 off: usize,
114}
115
116impl Buffer {
117 #[inline(always)]
118 pub fn new() -> Self {
119 Self::default()
120 }
121
122 #[inline(always)]
123 pub fn with_capacity_words(words: usize) -> Self {
124 Self {
125 data: vec![0; words],
126 off: words,
127 }
128 }
129
130 #[inline(always)]
131 pub fn clear(&mut self) {
132 self.off = self.data.len();
133 }
134
135 #[inline(always)]
136 pub fn allocated_words(&self) -> usize {
137 self.data.len()
138 }
139
140 #[inline(always)]
141 pub fn len(&self) -> usize {
142 self.data.len().saturating_sub(self.off)
143 }
144
145 #[inline(always)]
146 pub fn is_empty(&self) -> bool {
147 self.len() == 0
148 }
149
150 #[inline(always)]
151 pub fn view(&self) -> &[u32] {
152 &self.data[self.off..]
153 }
154
155 #[inline(always)]
156 pub fn head(&self) -> &[u32] {
157 self.view()
158 }
159
160 #[inline(always)]
161 pub fn head_mut(&mut self) -> &mut [u32] {
162 let off = self.off;
163 &mut self.data[off..]
164 }
165
166 #[inline(always)]
167 pub fn at_from_end(&self, words: usize) -> Option<&[u32]> {
168 if words > self.data.len() {
169 return None;
170 }
171 let start = self.data.len() - words;
172 Some(&self.data[start..])
173 }
174
175 #[inline(always)]
176 pub fn at_from_end_mut(&mut self, words: usize) -> Option<&mut [u32]> {
177 if words > self.data.len() {
178 return None;
179 }
180 let start = self.data.len() - words;
181 Some(&mut self.data[start..])
182 }
183
184 #[inline(always)]
185 pub fn reserve_words(&mut self, words: usize) {
186 if words > self.data.len() {
187 self.grow(words);
188 }
189 }
190
191 #[inline(always)]
192 pub fn expand(&mut self, delta: usize) -> &mut [u32] {
193 if self.off < delta {
194 let needed = self.len().saturating_add(delta);
195 self.grow(needed);
196 }
197 self.off -= delta;
198 let ptr = unsafe { self.data.as_mut_ptr().add(self.off) };
199 unsafe { core::slice::from_raw_parts_mut(ptr, delta) }
201 }
202
203 #[inline(always)]
204 pub fn shrink(&mut self, delta: usize) {
205 assert!(delta <= self.len());
206 self.off += delta;
207 }
208
209 #[inline(always)]
210 pub fn put(&mut self, value: u32) {
211 self.expand(1)[0] = value;
212 }
213
214 #[inline(always)]
215 pub fn put_words(&mut self, words: &[u32]) {
216 let dst = self.expand(words.len());
217 unsafe { core::ptr::copy_nonoverlapping(words.as_ptr(), dst.as_mut_ptr(), words.len()) };
219 }
220
221 #[inline(always)]
222 fn grow(&mut self, min_words: usize) {
223 let active_len = self.len();
224 let mut new_words = self.data.len().max(8);
225 while new_words < min_words {
226 new_words = new_words.saturating_mul(2);
227 }
228 if new_words < min_words {
229 new_words = min_words;
230 }
231 let mut new_data = vec![0; new_words];
232 let new_off = new_words - active_len;
233 new_data[new_off..].copy_from_slice(self.view());
234 self.data = new_data;
235 self.off = new_off;
236 }
237}
238
239pub fn load_file(path: impl AsRef<std::path::Path>) -> std::io::Result<Vec<u8>> {
240 std::fs::read(path)
241}
242
243pub fn compress(src: &[u8]) -> Vec<u8> {
244 let mut out = Vec::new();
245 compress_into(src, &mut out);
246 out
247}
248
249pub fn compress_into(src: &[u8], out: &mut Vec<u8>) {
250 if src.is_empty() {
251 out.clear();
252 return;
253 }
254
255 let header_len = varint_len(src.len());
256 let capacity = header_len + src.len() + src.len().div_ceil(14);
257 out.clear();
258 if out.capacity() < capacity {
259 out.reserve(capacity - out.capacity());
260 }
261
262 let mut size = src.len();
263 while (size & !0x7f) != 0 {
264 out.push(0x80 | (size as u8 & 0x7f));
265 size >>= 7;
266 }
267 out.push(size as u8);
268
269 let base = out.len();
274 let mut off = 0usize;
275 let dst = unsafe { out.as_mut_ptr().add(base) };
276
277 let mut pos = 0usize;
278 while pos < src.len() {
279 let a_start = pos;
280 let a = pick_run(src, &mut pos);
281 if pos == src.len() {
282 unsafe {
283 dst.add(off).write(a);
284 }
285 off += 1;
286 if (a & 0x8) == 0 {
287 off = emit_run_raw(src, a_start, pos, dst, off);
288 }
289 break;
290 }
291 let b_start = pos;
292 let b = pick_run(src, &mut pos);
293 unsafe {
294 dst.add(off).write(a | (b << 4));
295 }
296 off += 1;
297 if (a & 0x8) == 0 {
298 off = emit_run_raw(src, a_start, b_start, dst, off);
299 }
300 if (b & 0x8) == 0 {
301 off = emit_run_raw(src, b_start, pos, dst, off);
302 }
303 }
304
305 unsafe {
306 out.set_len(base + off);
307 }
308}
309
310pub fn decompress(src: &[u8]) -> Result<Vec<u8>, ReadError> {
311 let mut out = Vec::new();
312 decompress_into(src, &mut out)?;
313 Ok(out)
314}
315
316pub fn decompress_into(src: &[u8], out: &mut Vec<u8>) -> Result<(), ReadError> {
317 if src.is_empty() {
318 out.clear();
319 return Ok(());
320 }
321 let (target, mut pos) = parse_varint(src)?;
322 out.resize(target + 7, 0u8);
326 let mut out_pos = 0usize;
327 let buf = out.as_mut_slice();
328 while pos < src.len() {
329 let mark = src[pos];
330 pos += 1;
331 unpack(mark & 0x0f, src, &mut pos, buf, &mut out_pos, target)?;
332 unpack(mark >> 4, src, &mut pos, buf, &mut out_pos, target)?;
333 }
334 if out_pos != target {
335 out.clear();
336 return Err(ReadError::new(CorruptionKind::Truncated));
337 }
338 out.truncate(target);
339 Ok(())
340}
341
342#[inline]
343fn varint_len(mut value: usize) -> usize {
344 let mut len = 1usize;
345 while (value & !0x7f) != 0 {
346 value >>= 7;
347 len += 1;
348 }
349 len
350}
351
352#[inline(always)]
353fn pick_run(src: &[u8], pos: &mut usize) -> u8 {
354 let start = *pos;
355 let first = src[start];
356 *pos += 1;
357 let fi = first as i8;
360 if fi == fi >> 1 {
361 while *pos < src.len() && *pos - start < 4 && src[*pos] == first {
362 *pos += 1;
363 }
364 0x8 | (first & 0x4) | ((*pos - start - 1) as u8)
366 } else {
367 while *pos < src.len() && *pos - start < 7 && src[*pos] != 0 && src[*pos] != 0xff {
368 *pos += 1;
369 }
370 (*pos - start) as u8
371 }
372}
373
374#[inline(always)]
377fn emit_run_raw(src: &[u8], start: usize, end: usize, dst: *mut u8, off: usize) -> usize {
378 let len = end - start;
379 if len == 0 {
380 return off;
381 }
382 unsafe {
383 if start + 8 <= src.len() {
386 let src_ptr = src.as_ptr().add(start) as *const u64;
387 (dst.add(off) as *mut u64).write_unaligned(src_ptr.read_unaligned());
388 } else {
389 std::ptr::copy_nonoverlapping(src.as_ptr().add(start), dst.add(off), len);
390 }
391 }
392 off + len
393}
394
395fn parse_varint(src: &[u8]) -> Result<(usize, usize), ReadError> {
396 let mut size = 0usize;
397 let mut pos = 0usize;
398 for shift in (0..32).step_by(7) {
399 let byte = *src
400 .get(pos)
401 .ok_or(ReadError::new(CorruptionKind::Truncated))?;
402 pos += 1;
403 if (byte & 0x80) != 0 {
404 size |= ((byte & 0x7f) as usize) << shift;
405 } else {
406 size |= (byte as usize) << shift;
407 return Ok((size, pos));
408 }
409 }
410 Err(ReadError::new(CorruptionKind::InvalidHeader))
411}
412
413#[inline(always)]
414fn unpack(
415 mark: u8,
416 src: &[u8],
417 pos: &mut usize,
418 out: &mut [u8],
419 out_pos: &mut usize,
420 target: usize,
421) -> Result<(), ReadError> {
422 if *out_pos >= target {
424 return Ok(());
425 }
426 if (mark & 0x8) != 0 {
427 let count = ((mark & 0x3) + 1) as usize;
428 if count > target - *out_pos {
429 return Err(ReadError::new(CorruptionKind::Truncated));
430 }
431 let fill_val: u32 = if (mark & 0x4) != 0 { u32::MAX } else { 0 };
434 unsafe {
435 (out.as_mut_ptr().add(*out_pos) as *mut u32).write_unaligned(fill_val);
436 }
437 *out_pos += count;
438 return Ok(());
439 }
440 let len = (mark & 0x7) as usize;
441 if len == 0 {
442 return Ok(());
443 }
444 if len > src.len() - *pos || len > target - *out_pos {
445 return Err(ReadError::new(CorruptionKind::Truncated));
446 }
447 if src.len() - *pos >= 8 {
451 unsafe {
452 let src_ptr = src.as_ptr().add(*pos) as *const u64;
453 let dst_ptr = out.as_mut_ptr().add(*out_pos) as *mut u64;
454 dst_ptr.write_unaligned(src_ptr.read_unaligned());
455 }
456 *pos += len;
457 *out_pos += len;
458 } else {
459 let end = *pos + len;
460 let out_end = *out_pos + len;
461 out[*out_pos..out_end].copy_from_slice(&src[*pos..end]);
462 *pos = end;
463 *out_pos = out_end;
464 }
465 Ok(())
466}
467
468#[cfg(test)]
469mod tests {
470 use super::{Buffer, compress, compress_into, decompress, decompress_into};
471
472 #[test]
473 fn put_prepends_words() {
474 let mut buffer = Buffer::new();
475 buffer.put(3);
476 buffer.put(2);
477 buffer.put(1);
478 assert_eq!(buffer.view(), &[1, 2, 3]);
479 }
480
481 #[test]
482 fn expand_preserves_existing_payload() {
483 let mut buffer = Buffer::with_capacity_words(4);
484 buffer.put_words(&[3, 4]);
485 buffer.put_words(&[1, 2]);
486 assert_eq!(buffer.view(), &[1, 2, 3, 4]);
487
488 buffer.put_words(&[0]);
489 assert_eq!(buffer.view(), &[0, 1, 2, 3, 4]);
490 assert!(buffer.allocated_words() >= 5);
491 }
492
493 #[test]
494 fn shrink_discards_from_front() {
495 let mut buffer = Buffer::new();
496 buffer.put_words(&[1, 2, 3, 4]);
497 buffer.shrink(2);
498 assert_eq!(buffer.view(), &[3, 4]);
499 buffer.clear();
500 assert!(buffer.is_empty());
501 }
502
503 #[test]
504 fn compression_roundtrip_preserves_payload() {
505 let src = b"\0\0\0\0abcd\xff\xff\xffefgh\0";
506 let compressed = compress(src);
507 let restored = decompress(&compressed).unwrap();
508 assert_eq!(restored, src);
509 }
510
511 #[test]
512 fn compression_into_reuses_buffers() {
513 let src = b"\0\0\0\0abcd\xff\xff\xffefgh\0";
514 let mut compressed = Vec::with_capacity(128);
515 let compressed_capacity = compressed.capacity();
516 compress_into(src, &mut compressed);
517 assert_eq!(compressed.capacity(), compressed_capacity);
518
519 let mut restored = Vec::with_capacity(128);
520 let restored_capacity = restored.capacity();
521 decompress_into(&compressed, &mut restored).unwrap();
522 assert_eq!(restored, src);
523 assert_eq!(restored.capacity(), restored_capacity);
524 }
525}