ppmd_rust/
encoder_8.rs

1use std::io::Write;
2
3use crate::{
4    internal::ppmd8::{Ppmd8, RangeEncoder},
5    Error, RestoreMethod, PPMD8_MAX_MEM_SIZE, PPMD8_MAX_ORDER, PPMD8_MIN_MEM_SIZE, PPMD8_MIN_ORDER,
6};
7
8/// A encoder to compress data using PPMd8 (PPMdI rev.1).
9pub struct Ppmd8Encoder<W: Write> {
10    ppmd: Ppmd8<RangeEncoder<W>>,
11}
12
13impl<W: Write> Ppmd8Encoder<W> {
14    /// Creates a new [`Ppmd8Encoder`] which provides a writer over the compressed data.
15    ///
16    /// The given `order` must be between [`PPMD8_MIN_ORDER`] and [`PPMD8_MAX_ORDER`] (inclusive).
17    /// The given `mem_size` must be between [`PPMD8_MIN_MEM_SIZE`] and [`PPMD8_MAX_MEM_SIZE`] (inclusive).
18    pub fn new(
19        writer: W,
20        order: u32,
21        mem_size: u32,
22        restore_method: RestoreMethod,
23    ) -> crate::Result<Self> {
24        if !(PPMD8_MIN_ORDER..=PPMD8_MAX_ORDER).contains(&order)
25            || !(PPMD8_MIN_MEM_SIZE..=PPMD8_MAX_MEM_SIZE).contains(&mem_size)
26        {
27            return Err(Error::InvalidParameter);
28        }
29
30        let ppmd = Ppmd8::new_encoder(writer, mem_size, order, restore_method)?;
31
32        Ok(Self { ppmd })
33    }
34
35    /// Returns the inner writer.
36    pub fn into_inner(self) -> W {
37        self.ppmd.into_inner()
38    }
39
40    fn inner_flush(&mut self) -> Result<(), std::io::Error> {
41        self.ppmd.flush_range_encoder()?;
42        Ok(())
43    }
44}
45
46impl<W: Write> Write for Ppmd8Encoder<W> {
47    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
48        if buf.is_empty() {
49            return Ok(0);
50        }
51
52        for &byte in buf {
53            self.ppmd.encode_symbol(byte)?;
54        }
55
56        Ok(buf.len())
57    }
58
59    fn flush(&mut self) -> std::io::Result<()> {
60        self.inner_flush()
61    }
62}
63
64#[cfg(test)]
65mod test {
66    use std::io::{Read, Write};
67
68    use super::Ppmd8Encoder;
69    use crate::{Ppmd8Decoder, RestoreMethod};
70
71    const ORDER: u32 = 8;
72    const MEM_SIZE: u32 = 262144;
73    const RESTORE_METHOD: RestoreMethod = RestoreMethod::Restart;
74
75    #[test]
76    fn ppmd8encoder_encode_decode() {
77        let test_data = include_str!("../tests/fixtures/apache2.txt");
78
79        let mut writer = Vec::new();
80        {
81            let mut encoder =
82                Ppmd8Encoder::new(&mut writer, ORDER, MEM_SIZE, RESTORE_METHOD).unwrap();
83            encoder.write_all(test_data.as_bytes()).unwrap();
84            encoder.flush().unwrap();
85        }
86
87        let mut decoder =
88            Ppmd8Decoder::new(writer.as_slice(), ORDER, MEM_SIZE, RESTORE_METHOD).unwrap();
89
90        let mut decoded = vec![0; test_data.len()];
91        decoder.read_exact(&mut decoded).unwrap();
92
93        assert_eq!(decoded.as_slice(), test_data.as_bytes());
94
95        let decoded_data = String::from_utf8(decoded).unwrap();
96
97        assert_eq!(decoded_data, test_data);
98    }
99}