mid_compression/zstd/
decompressor.rs1use 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
17pub struct ZStdDctx {
19 ptr: ptr::NonNull<ZSTD_DCtx>,
20}
21
22impl 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 Err(error::SizeRetrievalError::InvalidData)
61 } else {
62 Ok(result)
63 }
64 }
65}
66
67impl ZStdDctx {
68 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}