lzma_rust2/filter/
delta.rs

1//! Delta filter.
2
3#[cfg(feature = "encoder")]
4use alloc::vec::Vec;
5
6use crate::Read;
7#[cfg(feature = "encoder")]
8use crate::Write;
9
10const MAX_DISTANCE: usize = 256;
11const _MIN_DISTANCE: usize = 1;
12const DIS_MASK: usize = MAX_DISTANCE - 1;
13
14struct Delta {
15    distance: usize,
16    history: [u8; MAX_DISTANCE],
17    pos: u8,
18}
19
20impl Delta {
21    fn new(distance: usize) -> Self {
22        Self {
23            distance,
24            history: [0; MAX_DISTANCE],
25            pos: 0,
26        }
27    }
28
29    fn decode(&mut self, buf: &mut [u8]) {
30        for item in buf {
31            let pos = self.pos as usize;
32            let h = self.history[(self.distance.wrapping_add(pos)) & DIS_MASK];
33            *item = item.wrapping_add(h);
34            self.history[pos & DIS_MASK] = *item;
35            self.pos = self.pos.wrapping_sub(1);
36        }
37    }
38
39    #[cfg(feature = "encoder")]
40    fn encode(&mut self, buf: &mut [u8]) {
41        for item in buf {
42            let pos = self.pos as usize;
43            let h = self.history[(self.distance.wrapping_add(pos)) & DIS_MASK];
44            let original = *item;
45            *item = item.wrapping_sub(h);
46            self.history[pos & DIS_MASK] = original;
47            self.pos = self.pos.wrapping_sub(1);
48        }
49    }
50}
51
52/// Reader that applies delta filtering to decompress data.
53pub struct DeltaReader<R> {
54    inner: R,
55    delta: Delta,
56}
57
58impl<R> DeltaReader<R> {
59    /// Creates a new delta reader with the specified distance.
60    pub fn new(inner: R, distance: usize) -> Self {
61        Self {
62            inner,
63            delta: Delta::new(distance),
64        }
65    }
66
67    /// Unwraps the reader, returning the underlying reader.
68    pub fn into_inner(self) -> R {
69        self.inner
70    }
71
72    /// Returns a reference to the inner reader.
73    pub fn inner(&self) -> &R {
74        &self.inner
75    }
76
77    /// Returns a mutable reference to the inner reader.
78    pub fn inner_mut(&mut self) -> &mut R {
79        &mut self.inner
80    }
81}
82
83impl<R: Read> Read for DeltaReader<R> {
84    fn read(&mut self, buf: &mut [u8]) -> crate::Result<usize> {
85        let n = self.inner.read(buf)?;
86        if n == 0 {
87            return Ok(n);
88        }
89        self.delta.decode(&mut buf[..n]);
90        Ok(n)
91    }
92}
93
94#[cfg(feature = "encoder")]
95/// Writer that applies delta filtering before compression.
96pub struct DeltaWriter<W> {
97    inner: W,
98    delta: Delta,
99    buffer: Vec<u8>,
100}
101
102#[cfg(feature = "encoder")]
103impl<W> DeltaWriter<W> {
104    /// Creates a new delta writer with the specified distance.
105    pub fn new(inner: W, distance: usize) -> Self {
106        Self {
107            inner,
108            delta: Delta::new(distance),
109            buffer: Vec::with_capacity(4096),
110        }
111    }
112
113    /// Unwraps the writer, returning the underlying writer.
114    pub fn into_inner(self) -> W {
115        self.inner
116    }
117
118    /// Returns a reference to the inner writer.
119    pub fn inner(&self) -> &W {
120        &self.inner
121    }
122
123    /// Returns a mutable reference to the inner writer.
124    pub fn inner_mut(&mut self) -> &mut W {
125        &mut self.inner
126    }
127}
128
129#[cfg(feature = "encoder")]
130impl<W: Write> Write for DeltaWriter<W> {
131    fn write(&mut self, buf: &[u8]) -> crate::Result<usize> {
132        let data_size = buf.len();
133
134        if data_size > self.buffer.len() {
135            self.buffer.resize(data_size, 0);
136        }
137
138        self.buffer[..data_size].copy_from_slice(buf);
139        self.delta.encode(&mut self.buffer[..data_size]);
140        self.inner.write(&self.buffer[..data_size])
141    }
142
143    fn flush(&mut self) -> crate::Result<()> {
144        self.inner.flush()
145    }
146}
147
148#[cfg(all(feature = "encoder", feature = "std"))]
149#[cfg(test)]
150mod tests {
151    use std::io::Cursor;
152
153    use super::*;
154
155    #[test]
156    fn test_delta_roundtrip() {
157        let test_cases = [
158            vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
159            vec![1, 2, 3, 1, 2, 3, 1, 2, 3],
160            vec![42, 13, 255, 0, 128, 64, 32, 99, 200, 150],
161            vec![100; 20],
162            vec![0, 255, 0, 255, 0, 255, 0, 255],
163            (0..300).map(|i| (i % 256) as u8).collect(),
164        ];
165
166        let distances = vec![1, 2, 4, 8, 16, 32, 64, 128, 256];
167
168        for distance in distances {
169            for (i, original_data) in test_cases.iter().enumerate() {
170                let mut encoded_buffer = Vec::new();
171                let mut writer = DeltaWriter::new(Cursor::new(&mut encoded_buffer), distance);
172                std::io::copy(&mut original_data.as_slice(), &mut writer)
173                    .expect("Failed to encode data");
174
175                let mut decoded_data = Vec::new();
176                let mut reader = DeltaReader::new(Cursor::new(&encoded_buffer), distance);
177                std::io::copy(&mut reader, &mut decoded_data).expect("Failed to decode data");
178
179                assert_eq!(
180                    original_data, &decoded_data,
181                    "Roundtrip failed for distance {distance} with data set {i}",
182                );
183            }
184        }
185    }
186}