lzfse_rust/encode/
ring_encoder.rs

1use crate::fse::{V1_MAX_BLOCK_LEN, V2_MAX_BLOCK_LEN};
2use crate::ops::FlushLimit;
3use crate::ring::{RingBox, RingShortWriter};
4
5use super::constants::*;
6use super::encoder::LzfseEncoder;
7use super::frontend_ring::FrontendRing;
8use super::writer::LzfseWriter;
9use super::writer_bytes::LzfseWriterBytes;
10
11use std::fmt;
12use std::io::{self, Read, Write};
13
14/// LZFSE ring encoder.
15///
16///
17/// This implementation builds upon [LzfseEncoder] with the addition of internal ring buffers that
18/// enable efficient IO operations. It can be converted to a mutable [LzfseEncoder] reference using
19/// [as_mut()](AsMut::as_mut).
20pub struct LzfseRingEncoder {
21    core: LzfseEncoder,
22    input: RingBox<Input>,
23    output: RingBox<Output>,
24}
25
26impl LzfseRingEncoder {
27    /// Encode `reader` into `writer` returning a tuple (u, v) where u is the number of unencoded
28    /// bytes read from the reader and v is the number of encoded bytes written into the writer.
29    ///
30    /// Both the `reader` and `writer` are accessed efficiently by internal ring buffers, there is
31    /// no need to wrap them in [BufReader](std::io::BufReader) or
32    /// [BufWriter](std::io::BufWriter).
33    ///
34    ///
35    /// # Errors
36    ///
37    /// * [Error](std::io::Error) in case of `reader` or `writer` IO errors.
38    ///
39    /// # Examples
40    ///
41    /// ```
42    /// use lzfse_rust::LzfseRingEncoder;
43    /// use std::io;
44    ///
45    /// fn main() -> io::Result<()> {
46    ///     let mut enc = Vec::default();
47    ///     let mut encoder = LzfseRingEncoder::default();
48    ///     let n_bytes = encoder.encode_bytes(b"test", &mut enc)?;
49    ///     // "test" string encoded.
50    ///     assert_eq!(enc, &[0x62, 0x76, 0x78, 0x2d, 0x04, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74,
51    ///                       0x62, 0x76, 0x78, 0x24]);
52    ///     Ok(())
53    /// }
54    /// ```
55    pub fn encode<I, O>(&mut self, reader: &mut I, writer: &mut O) -> io::Result<(u64, u64)>
56    where
57        I: Read,
58        O: Write,
59    {
60        let mut frontend = FrontendRing::new((&mut self.input).into(), &mut self.core.table);
61        frontend.init();
62        let mut writer = RingShortWriter::new((&mut self.output).into(), writer);
63        let n_raw_bytes = frontend.copy(&mut self.core.backend, &mut writer, reader)?;
64        frontend.flush(&mut self.core.backend, &mut writer)?;
65        let (_, n_payload_bytes) = writer.into_inner()?;
66        Ok((n_raw_bytes, n_payload_bytes))
67    }
68
69    /// This method bypasses the internal ring buffers and operates over the supplied buffers,
70    /// it is functionally identical to [LzfseEncoder::encode_bytes].
71    pub fn encode_bytes(&mut self, src: &[u8], dst: &mut Vec<u8>) -> io::Result<u64> {
72        self.core.encode_bytes(src, dst)
73    }
74
75    /// Create a new [LzfseWriter] encoder instance using the supplied `inner` writer.
76    ///
77    /// **It is imperative that the writer is [finalized](LzfseWriterBytes::finalize) after use to
78    /// complete the encoding process, [flushing](std::io::Write::flush) is not sufficient.**
79    pub fn writer<O: Write>(&mut self, inner: O) -> LzfseWriter<O> {
80        let mut frontend = FrontendRing::new((&mut self.input).into(), &mut self.core.table);
81        frontend.init();
82        let writer = RingShortWriter::new((&mut self.output).into(), inner);
83        LzfseWriter::new(frontend, &mut self.core.backend, writer)
84    }
85
86    /// Create a new [LzfseWriterBytes] decoder instance using the supplied `vec`.
87    ///
88    /// This method offers greater efficiency in comparison to [LzfseRingEncoder::writer]
89    /// when operating over byte vectors.
90    ///
91    /// **It is imperative that the writer is [finalized](LzfseWriterBytes::finalize) after use to
92    /// complete the encoding process, [flushing](std::io::Write::flush) is not sufficient.**
93    pub fn writer_bytes(&mut self, vec: Vec<u8>) -> LzfseWriterBytes {
94        let mut frontend = FrontendRing::new((&mut self.input).into(), &mut self.core.table);
95        frontend.init();
96        LzfseWriterBytes::new(frontend, &mut self.core.backend, vec)
97    }
98}
99
100impl Default for LzfseRingEncoder {
101    #[allow(clippy::assertions_on_constants)]
102    fn default() -> Self {
103        assert!(V1_MAX_BLOCK_LEN + 64 < RingShortWriter::<(), Output>::FLUSH_LIMIT);
104        assert!(V2_MAX_BLOCK_LEN + 64 < RingShortWriter::<(), Output>::FLUSH_LIMIT);
105        Self {
106            core: LzfseEncoder::default(),
107            input: RingBox::<Input>::default(),
108            output: RingBox::<Output>::default(),
109        }
110    }
111}
112
113impl fmt::Debug for LzfseRingEncoder {
114    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115        f.debug_struct("LzfseRingEncoder").finish()
116    }
117}