reth_nippy_jar/compression/
lz4.rs

1use crate::{compression::Compression, NippyJarError};
2use serde::{Deserialize, Serialize};
3
4/// Wrapper type for `lz4_flex` that implements [`Compression`].
5#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
6#[non_exhaustive]
7pub struct Lz4;
8
9impl Compression for Lz4 {
10    fn decompress_to(&self, value: &[u8], dest: &mut Vec<u8>) -> Result<(), NippyJarError> {
11        let previous_length = dest.len();
12
13        // Create a mutable slice from the spare capacity
14        let spare_capacity = dest.spare_capacity_mut();
15        // SAFETY: This is safe because we're using MaybeUninit's as_mut_ptr
16        let output = unsafe {
17            std::slice::from_raw_parts_mut(
18                spare_capacity.as_mut_ptr() as *mut u8,
19                spare_capacity.len(),
20            )
21        };
22
23        match lz4_flex::decompress_into(value, output) {
24            Ok(written) => {
25                // SAFETY: `compress_into` can only write if there's enough capacity. Therefore, it
26                // shouldn't write more than our capacity.
27                unsafe {
28                    dest.set_len(previous_length + written);
29                }
30                Ok(())
31            }
32            Err(_) => Err(NippyJarError::OutputTooSmall),
33        }
34    }
35
36    fn decompress(&self, value: &[u8]) -> Result<Vec<u8>, NippyJarError> {
37        let mut multiplier = 1;
38
39        loop {
40            match lz4_flex::decompress(value, multiplier * value.len()) {
41                Ok(v) => return Ok(v),
42                Err(err) => {
43                    multiplier *= 2;
44                    if multiplier == 16 {
45                        return Err(NippyJarError::Custom(err.to_string()))
46                    }
47                }
48            }
49        }
50    }
51
52    fn compress_to(&self, src: &[u8], dest: &mut Vec<u8>) -> Result<usize, NippyJarError> {
53        let previous_length = dest.len();
54
55        // Create a mutable slice from the spare capacity
56        let spare_capacity = dest.spare_capacity_mut();
57        // SAFETY: This is safe because we're using MaybeUninit's as_mut_ptr
58        let output = unsafe {
59            std::slice::from_raw_parts_mut(
60                spare_capacity.as_mut_ptr() as *mut u8,
61                spare_capacity.len(),
62            )
63        };
64
65        match lz4_flex::compress_into(src, output) {
66            Ok(written) => {
67                // SAFETY: `compress_into` can only write if there's enough capacity. Therefore, it
68                // shouldn't write more than our capacity.
69                unsafe {
70                    dest.set_len(previous_length + written);
71                }
72                Ok(written)
73            }
74            Err(_) => Err(NippyJarError::OutputTooSmall),
75        }
76    }
77
78    fn compress(&self, src: &[u8]) -> Result<Vec<u8>, NippyJarError> {
79        Ok(lz4_flex::compress(src))
80    }
81}