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