compression_codecs/zstd/
mod.rs

1mod decoder;
2mod encoder;
3pub mod params;
4
5pub use self::{decoder::ZstdDecoder, encoder::ZstdEncoder};
6
7use compression_core::{
8    unshared::Unshared,
9    util::{PartialBuffer, WriteBuffer},
10};
11use libzstd::stream::raw::{InBuffer, Operation, OutBuffer, WriteBuf};
12use std::io;
13
14#[repr(transparent)]
15struct WriteBufferWrapper<'a>(WriteBuffer<'a>);
16
17unsafe impl WriteBuf for WriteBufferWrapper<'_> {
18    fn as_slice(&self) -> &[u8] {
19        self.0.written()
20    }
21    fn capacity(&self) -> usize {
22        self.0.capacity()
23    }
24    fn as_mut_ptr(&mut self) -> *mut u8 {
25        self.0.as_mut_ptr()
26    }
27    unsafe fn filled_until(&mut self, n: usize) {
28        self.0.set_written_and_initialized_len(n);
29    }
30}
31
32trait WriteBufExt {
33    fn get_out_buf(&mut self) -> OutBuffer<'_, WriteBufferWrapper<'_>>;
34}
35
36impl WriteBufExt for WriteBuffer<'_> {
37    fn get_out_buf(&mut self) -> OutBuffer<'_, WriteBufferWrapper<'_>> {
38        {
39            use std::mem::{align_of, size_of};
40            assert_eq!(
41                size_of::<WriteBuffer<'static>>(),
42                size_of::<WriteBufferWrapper<'static>>()
43            );
44            assert_eq!(
45                align_of::<WriteBuffer<'static>>(),
46                align_of::<WriteBufferWrapper<'static>>()
47            );
48        }
49
50        // Pass written_len to avoid overwriting existing data in buffer.
51        let written_len = self.written_len();
52        OutBuffer::around_pos(
53            unsafe { &mut *(self as *mut _ as *mut WriteBufferWrapper<'_>) },
54            written_len,
55        )
56    }
57}
58
59trait OperationExt {
60    fn reinit(&mut self) -> io::Result<()>;
61
62    /// Return `true` if finished.
63    fn run(
64        &mut self,
65        input: &mut PartialBuffer<&[u8]>,
66        output: &mut WriteBuffer<'_>,
67    ) -> io::Result<bool>;
68
69    fn flush(&mut self, output: &mut WriteBuffer<'_>) -> io::Result<bool>;
70
71    fn finish(&mut self, output: &mut WriteBuffer<'_>) -> io::Result<bool>;
72}
73
74impl<C: Operation> OperationExt for Unshared<C> {
75    fn reinit(&mut self) -> io::Result<()> {
76        self.get_mut().reinit()
77    }
78
79    fn run(
80        &mut self,
81        input: &mut PartialBuffer<&[u8]>,
82        output: &mut WriteBuffer<'_>,
83    ) -> io::Result<bool> {
84        let mut in_buf = InBuffer::around(input.unwritten());
85        let result = self.get_mut().run(&mut in_buf, &mut output.get_out_buf());
86        input.advance(in_buf.pos());
87        Ok(result? == 0)
88    }
89
90    fn flush(&mut self, output: &mut WriteBuffer<'_>) -> io::Result<bool> {
91        Ok(self.get_mut().flush(&mut output.get_out_buf())? == 0)
92    }
93
94    fn finish(&mut self, output: &mut WriteBuffer<'_>) -> io::Result<bool> {
95        Ok(self.get_mut().finish(&mut output.get_out_buf(), true)? == 0)
96    }
97}