mid_compression/zstd/
decompressor.rs

1use std::ptr;
2
3use zstd_sys::{
4    ZSTD_DCtx,
5    ZSTD_createDCtx,
6    ZSTD_decompressDCtx,
7    ZSTD_freeDCtx,
8    ZSTD_getDecompressedSize,
9    ZSTD_isError,
10};
11
12use crate::{
13    error,
14    interface::IDecompressor,
15};
16
17/// ZStandard decompression context
18pub struct ZStdDctx {
19    ptr: ptr::NonNull<ZSTD_DCtx>,
20}
21
22// TODO: Implement precise error handling
23impl IDecompressor for ZStdDctx {
24    fn try_decompress(
25        &mut self,
26        buffer: &[u8],
27        to: &mut Vec<u8>,
28    ) -> Result<usize, error::DecompressError> {
29        let result = unsafe {
30            ZSTD_decompressDCtx(
31                self.ptr.as_ptr(),
32                to.as_ptr() as *mut _,
33                to.capacity(),
34                buffer.as_ptr() as *const _,
35                buffer.len(),
36            )
37        };
38
39        if unsafe { ZSTD_isError(result) } == 1 {
40            crate::cold();
41            Err(error::DecompressError::InsufficientBuffer)
42        } else {
43            unsafe { to.set_len(result) };
44            Ok(result)
45        }
46    }
47
48    fn try_decompressed_size(
49        &self,
50        of: &[u8],
51    ) -> Result<usize, error::SizeRetrievalError> {
52        let Ok(result) = unsafe {
53            ZSTD_getDecompressedSize(of.as_ptr() as *const _, of.len())
54        }.try_into() else {
55            return Err(error::SizeRetrievalError::InvalidData);
56        };
57
58        if unsafe { ZSTD_isError(result) } == 1 {
59            // TODO: see trait todo
60            Err(error::SizeRetrievalError::InvalidData)
61        } else {
62            Ok(result)
63        }
64    }
65}
66
67impl ZStdDctx {
68    /// Create ZStandard decompression context.
69    ///
70    /// # Panics
71    ///
72    /// - if underlying call to the `ZSTD_createDCtx()`
73    ///   fails (returns NULL pointer)
74    pub fn new() -> Self {
75        Self::default()
76    }
77}
78
79impl Default for ZStdDctx {
80    fn default() -> Self {
81        Self {
82            ptr: ptr::NonNull::new(unsafe { ZSTD_createDCtx() })
83                .expect("Failed to create ZStd decompression context"),
84        }
85    }
86}
87
88unsafe impl Send for ZStdDctx {}
89
90impl Drop for ZStdDctx {
91    fn drop(&mut self) {
92        if unsafe { ZSTD_isError(ZSTD_freeDCtx(self.ptr.as_ptr())) } == 1 {
93            panic!("Failed to deallocate ZStd decompression context");
94        }
95    }
96}