compression_codecs/lz4/
decoder.rs

1use crate::Decode;
2use compression_core::{unshared::Unshared, util::PartialBuffer};
3use lz4::liblz4::{
4    check_error, LZ4FDecompressionContext, LZ4F_createDecompressionContext, LZ4F_decompress,
5    LZ4F_freeDecompressionContext, LZ4F_resetDecompressionContext, LZ4F_VERSION,
6};
7use std::io::Result;
8
9#[derive(Debug)]
10struct DecoderContext {
11    ctx: LZ4FDecompressionContext,
12}
13
14#[derive(Debug)]
15pub struct Lz4Decoder {
16    ctx: Unshared<DecoderContext>,
17}
18
19impl DecoderContext {
20    fn new() -> Result<Self> {
21        let mut context = LZ4FDecompressionContext(core::ptr::null_mut());
22        check_error(unsafe { LZ4F_createDecompressionContext(&mut context, LZ4F_VERSION) })?;
23        Ok(Self { ctx: context })
24    }
25}
26
27impl Drop for DecoderContext {
28    fn drop(&mut self) {
29        unsafe { LZ4F_freeDecompressionContext(self.ctx) };
30    }
31}
32
33impl Default for Lz4Decoder {
34    fn default() -> Self {
35        Self {
36            ctx: Unshared::new(DecoderContext::new().unwrap()),
37        }
38    }
39}
40
41impl Lz4Decoder {
42    pub fn new() -> Self {
43        Self::default()
44    }
45}
46
47impl Decode for Lz4Decoder {
48    fn reinit(&mut self) -> Result<()> {
49        unsafe { LZ4F_resetDecompressionContext(self.ctx.get_mut().ctx) };
50        Ok(())
51    }
52
53    fn decode(
54        &mut self,
55        input: &mut PartialBuffer<impl AsRef<[u8]>>,
56        output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>,
57    ) -> Result<bool> {
58        let mut output_size = output.unwritten().len();
59        let mut input_size = input.unwritten().len();
60        let remaining = unsafe {
61            check_error(LZ4F_decompress(
62                self.ctx.get_mut().ctx,
63                output.unwritten_mut().as_mut_ptr(),
64                &mut output_size,
65                input.unwritten().as_ptr(),
66                &mut input_size,
67                core::ptr::null(),
68            ))?
69        };
70        input.advance(input_size);
71        output.advance(output_size);
72        Ok(remaining == 0)
73    }
74
75    fn flush(
76        &mut self,
77        output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>,
78    ) -> Result<bool> {
79        self.decode(&mut PartialBuffer::new(&[][..]), output)?;
80
81        loop {
82            let old_len = output.written().len();
83            self.decode(&mut PartialBuffer::new(&[][..]), output)?;
84            if output.written().len() == old_len {
85                break;
86            }
87        }
88
89        Ok(!output.unwritten().is_empty())
90    }
91
92    fn finish(
93        &mut self,
94        output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>,
95    ) -> Result<bool> {
96        self.flush(output)
97    }
98}