compression_codecs/lz4/
decoder.rs1use 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}