zstd_safe/
lib.rs

1#![no_std]
2//! Minimal safe wrapper around zstd-sys.
3//!
4//! This crates provides a minimal translation of the [zstd-sys] methods.
5//! For a more comfortable high-level library, see the [zstd] crate.
6//!
7//! [zstd-sys]: https://crates.io/crates/zstd-sys
8//! [zstd]: https://crates.io/crates/zstd
9//!
10//! Most of the functions here map 1-for-1 to a function from
11//! [the C zstd library][zstd-c] mentioned in their descriptions.
12//! Check the [source documentation][doc] for more information on their
13//! behaviour.
14//!
15//! [doc]: https://facebook.github.io/zstd/zstd_manual.html
16//! [zstd-c]: https://facebook.github.io/zstd/
17//!
18//! Features denoted as experimental in the C library are hidden behind an
19//! `experimental` feature.
20#![cfg_attr(feature = "doc-cfg", feature(doc_cfg))]
21
22#[cfg(feature = "std")]
23extern crate std;
24
25#[cfg(test)]
26mod tests;
27
28// Re-export zstd-sys
29pub use zstd_sys;
30
31/// How to compress data.
32pub use zstd_sys::ZSTD_strategy as Strategy;
33
34/// Reset directive.
35pub use zstd_sys::ZSTD_ResetDirective as ResetDirective;
36
37#[cfg(feature = "std")]
38use std::os::raw::{c_char, c_int, c_ulonglong, c_void};
39
40#[cfg(not(feature = "std"))]
41use libc::{c_char, c_int, c_ulonglong, c_void};
42
43use core::marker::PhantomData;
44use core::ops::{Deref, DerefMut};
45use core::ptr::NonNull;
46use core::str;
47
48include!("constants.rs");
49
50#[cfg(feature = "experimental")]
51include!("constants_experimental.rs");
52
53/// Represents the compression level used by zstd.
54pub type CompressionLevel = i32;
55
56/// Represents a possible error from the zstd library.
57pub type ErrorCode = usize;
58
59/// Wrapper result around most zstd functions.
60///
61/// Either a success code (usually number of bytes written), or an error code.
62pub type SafeResult = Result<usize, ErrorCode>;
63
64/// Returns true if code represents error.
65fn is_error(code: usize) -> bool {
66    unsafe { zstd_sys::ZSTD_isError(code) != 0 }
67}
68
69/// Parse the result code
70///
71/// Returns the number of bytes written if the code represents success,
72/// or the error message code otherwise.
73fn parse_code(code: usize) -> SafeResult {
74    if !is_error(code) {
75        Ok(code)
76    } else {
77        Err(code)
78    }
79}
80
81fn ptr_void(src: &[u8]) -> *const c_void {
82    src.as_ptr() as *const c_void
83}
84
85fn ptr_mut_void(dst: &mut (impl WriteBuf + ?Sized)) -> *mut c_void {
86    dst.as_mut_ptr() as *mut c_void
87}
88
89pub fn version_number() -> u32 {
90    unsafe { zstd_sys::ZSTD_versionNumber() as u32 }
91}
92
93pub fn version_string() -> &'static str {
94    unsafe { c_char_to_str(zstd_sys::ZSTD_versionString()) }
95}
96
97/// Returns the minimum (fastest) compression level supported.
98pub fn min_c_level() -> CompressionLevel {
99    unsafe { zstd_sys::ZSTD_minCLevel() as CompressionLevel }
100}
101
102/// Returns the maximum (slowest) compression level supported.
103pub fn max_c_level() -> CompressionLevel {
104    unsafe { zstd_sys::ZSTD_maxCLevel() as CompressionLevel }
105}
106
107/// Wraps the `ZSTD_compress` function.
108pub fn compress<C: WriteBuf + ?Sized>(
109    dst: &mut C,
110    src: &[u8],
111    compression_level: CompressionLevel,
112) -> SafeResult {
113    unsafe {
114        dst.write_from(|buffer, capacity| {
115            parse_code(zstd_sys::ZSTD_compress(
116                buffer,
117                capacity,
118                ptr_void(src),
119                src.len(),
120                compression_level,
121            ))
122        })
123    }
124}
125
126/// Wraps the `ZSTD_decompress` function.
127pub fn decompress<C: WriteBuf + ?Sized>(
128    dst: &mut C,
129    src: &[u8],
130) -> SafeResult {
131    unsafe {
132        dst.write_from(|buffer, capacity| {
133            parse_code(zstd_sys::ZSTD_decompress(
134                buffer,
135                capacity,
136                ptr_void(src),
137                src.len(),
138            ))
139        })
140    }
141}
142
143/// Wraps the `ZSTD_getDecompressedSize` function.
144#[deprecated(note = "Use ZSTD_getFrameContentSize instead")]
145pub fn get_decompressed_size(src: &[u8]) -> u64 {
146    unsafe {
147        zstd_sys::ZSTD_getDecompressedSize(ptr_void(src), src.len()) as u64
148    }
149}
150
151/// maximum compressed size in worst case single-pass scenario
152pub fn compress_bound(src_size: usize) -> usize {
153    unsafe { zstd_sys::ZSTD_compressBound(src_size) }
154}
155
156pub struct CCtx<'a>(NonNull<zstd_sys::ZSTD_CCtx>, PhantomData<&'a ()>);
157
158impl Default for CCtx<'_> {
159    fn default() -> Self {
160        CCtx::create()
161    }
162}
163
164impl CCtx<'static> {
165    /// Tries to create a new context.
166    ///
167    /// Returns `None` if zstd returns a NULL pointer - may happen if allocation fails.
168    pub fn try_create() -> Option<Self> {
169        Some(CCtx(
170            NonNull::new(unsafe { zstd_sys::ZSTD_createCCtx() })?,
171            PhantomData,
172        ))
173    }
174
175    /// Wrap `ZSTD_createCCtx`
176    ///
177    /// # Panics
178    ///
179    /// If zstd returns a NULL pointer.
180    pub fn create() -> Self {
181        Self::try_create()
182            .expect("zstd returned null pointer when creating new context")
183    }
184}
185
186impl<'a> CCtx<'a> {
187    /// Wraps the `ZSTD_compressCCtx()` function
188    pub fn compress<C: WriteBuf + ?Sized>(
189        &mut self,
190        dst: &mut C,
191        src: &[u8],
192        compression_level: CompressionLevel,
193    ) -> SafeResult {
194        unsafe {
195            dst.write_from(|buffer, capacity| {
196                parse_code(zstd_sys::ZSTD_compressCCtx(
197                    self.0.as_ptr(),
198                    buffer,
199                    capacity,
200                    ptr_void(src),
201                    src.len(),
202                    compression_level,
203                ))
204            })
205        }
206    }
207
208    /// Wraps the `ZSTD_compress2()` function.
209    pub fn compress2<C: WriteBuf + ?Sized>(
210        &mut self,
211        dst: &mut C,
212        src: &[u8],
213    ) -> SafeResult {
214        unsafe {
215            dst.write_from(|buffer, capacity| {
216                parse_code(zstd_sys::ZSTD_compress2(
217                    self.0.as_ptr(),
218                    buffer,
219                    capacity,
220                    ptr_void(src),
221                    src.len(),
222                ))
223            })
224        }
225    }
226
227    /// Wraps the `ZSTD_compress_usingDict()` function.
228    pub fn compress_using_dict<C: WriteBuf + ?Sized>(
229        &mut self,
230        dst: &mut C,
231        src: &[u8],
232        dict: &[u8],
233        compression_level: CompressionLevel,
234    ) -> SafeResult {
235        unsafe {
236            dst.write_from(|buffer, capacity| {
237                parse_code(zstd_sys::ZSTD_compress_usingDict(
238                    self.0.as_ptr(),
239                    buffer,
240                    capacity,
241                    ptr_void(src),
242                    src.len(),
243                    ptr_void(dict),
244                    dict.len(),
245                    compression_level,
246                ))
247            })
248        }
249    }
250
251    /// Wraps the `ZSTD_compress_usingCDict()` function.
252    pub fn compress_using_cdict<C: WriteBuf + ?Sized>(
253        &mut self,
254        dst: &mut C,
255        src: &[u8],
256        cdict: &CDict<'_>,
257    ) -> SafeResult {
258        unsafe {
259            dst.write_from(|buffer, capacity| {
260                parse_code(zstd_sys::ZSTD_compress_usingCDict(
261                    self.0.as_ptr(),
262                    buffer,
263                    capacity,
264                    ptr_void(src),
265                    src.len(),
266                    cdict.0.as_ptr(),
267                ))
268            })
269        }
270    }
271
272    pub fn init(&mut self, compression_level: CompressionLevel) -> usize {
273        unsafe {
274            zstd_sys::ZSTD_initCStream(self.0.as_ptr(), compression_level)
275        }
276    }
277
278    /// Wraps the `ZSTD_initCStream_srcSize()` function.
279    #[cfg(feature = "experimental")]
280    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
281    #[deprecated]
282    pub fn init_src_size(
283        &mut self,
284        compression_level: CompressionLevel,
285        pledged_src_size: u64,
286    ) -> usize {
287        unsafe {
288            zstd_sys::ZSTD_initCStream_srcSize(
289                self.0.as_ptr(),
290                compression_level as c_int,
291                pledged_src_size as c_ulonglong,
292            )
293        }
294    }
295
296    /// Wraps the `ZSTD_initCStream_usingDict()` function.
297    #[cfg(feature = "experimental")]
298    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
299    #[deprecated]
300    pub fn init_using_dict(
301        &mut self,
302        dict: &[u8],
303        compression_level: CompressionLevel,
304    ) -> SafeResult {
305        let code = unsafe {
306            zstd_sys::ZSTD_initCStream_usingDict(
307                self.0.as_ptr(),
308                ptr_void(dict),
309                dict.len(),
310                compression_level,
311            )
312        };
313        parse_code(code)
314    }
315
316    /// Wraps the `ZSTD_initCStream_usingCDict()` function.
317    #[cfg(feature = "experimental")]
318    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
319    #[deprecated]
320    pub fn init_using_cdict<'b>(&mut self, cdict: &CDict<'b>) -> SafeResult
321    where
322        'b: 'a, // Dictionary outlives the stream.
323    {
324        let code = unsafe {
325            zstd_sys::ZSTD_initCStream_usingCDict(
326                self.0.as_ptr(),
327                cdict.0.as_ptr(),
328            )
329        };
330        parse_code(code)
331    }
332
333    pub fn load_dictionary(&mut self, dict: &[u8]) -> SafeResult {
334        parse_code(unsafe {
335            zstd_sys::ZSTD_CCtx_loadDictionary(
336                self.0.as_ptr(),
337                ptr_void(dict),
338                dict.len(),
339            )
340        })
341    }
342
343    /// Wraps the `ZSTD_CCtx_refCDict()` function.
344    ///
345    /// Dictionary must outlive the context.
346    pub fn ref_cdict<'b>(&mut self, cdict: &CDict<'b>) -> SafeResult
347    where
348        'b: 'a,
349    {
350        parse_code(unsafe {
351            zstd_sys::ZSTD_CCtx_refCDict(self.0.as_ptr(), cdict.0.as_ptr())
352        })
353    }
354
355    pub fn ref_prefix<'b>(&mut self, prefix: &'b [u8]) -> SafeResult
356    where
357        'b: 'a,
358    {
359        parse_code(unsafe {
360            zstd_sys::ZSTD_CCtx_refPrefix(
361                self.0.as_ptr(),
362                ptr_void(prefix),
363                prefix.len(),
364            )
365        })
366    }
367
368    pub fn compress_stream<C: WriteBuf + ?Sized>(
369        &mut self,
370        output: &mut OutBuffer<'_, C>,
371        input: &mut InBuffer<'_>,
372    ) -> SafeResult {
373        let mut output = output.wrap();
374        let mut input = input.wrap();
375        let code = unsafe {
376            zstd_sys::ZSTD_compressStream(
377                self.0.as_ptr(),
378                ptr_mut(&mut output),
379                ptr_mut(&mut input),
380            )
381        };
382        parse_code(code)
383    }
384
385    /// Wraps the `ZSTD_compressStream2()` function.
386    pub fn compress_stream2<C: WriteBuf + ?Sized>(
387        &mut self,
388        output: &mut OutBuffer<'_, C>,
389        input: &mut InBuffer<'_>,
390        end_op: zstd_sys::ZSTD_EndDirective,
391    ) -> SafeResult {
392        let mut output = output.wrap();
393        let mut input = input.wrap();
394        parse_code(unsafe {
395            zstd_sys::ZSTD_compressStream2(
396                self.0.as_ptr(),
397                ptr_mut(&mut output),
398                ptr_mut(&mut input),
399                end_op,
400            )
401        })
402    }
403
404    /// Wraps the `ZSTD_flushStream()` function.
405    pub fn flush_stream<C: WriteBuf + ?Sized>(
406        &mut self,
407        output: &mut OutBuffer<'_, C>,
408    ) -> SafeResult {
409        let mut output = output.wrap();
410        let code = unsafe {
411            zstd_sys::ZSTD_flushStream(self.0.as_ptr(), ptr_mut(&mut output))
412        };
413        parse_code(code)
414    }
415
416    /// Wraps the `ZSTD_endStream()` function.
417    pub fn end_stream<C: WriteBuf + ?Sized>(
418        &mut self,
419        output: &mut OutBuffer<'_, C>,
420    ) -> SafeResult {
421        let mut output = output.wrap();
422        let code = unsafe {
423            zstd_sys::ZSTD_endStream(self.0.as_ptr(), ptr_mut(&mut output))
424        };
425        parse_code(code)
426    }
427
428    pub fn sizeof(&self) -> usize {
429        unsafe { zstd_sys::ZSTD_sizeof_CCtx(self.0.as_ptr()) }
430    }
431
432    pub fn reset(&mut self, reset: ResetDirective) -> SafeResult {
433        parse_code(unsafe {
434            zstd_sys::ZSTD_CCtx_reset(self.0.as_ptr(), reset)
435        })
436    }
437
438    #[cfg(feature = "experimental")]
439    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
440    #[deprecated]
441    pub fn reset_cstream(&mut self, pledged_src_size: u64) -> SafeResult {
442        let code = unsafe {
443            zstd_sys::ZSTD_resetCStream(
444                self.0.as_ptr(),
445                pledged_src_size as c_ulonglong,
446            )
447        };
448        parse_code(code)
449    }
450
451    pub fn set_parameter(&mut self, param: CParameter) -> SafeResult {
452        // TODO: Until bindgen properly generates a binding for this, we'll need to do it here.
453
454        #[cfg(feature = "experimental")]
455        use zstd_sys::ZSTD_cParameter::{
456            ZSTD_c_experimentalParam1 as ZSTD_c_rsyncable,
457            ZSTD_c_experimentalParam10 as ZSTD_c_stableOutBuffer,
458            ZSTD_c_experimentalParam11 as ZSTD_c_blockDelimiters,
459            ZSTD_c_experimentalParam12 as ZSTD_c_validateSequences,
460            ZSTD_c_experimentalParam13 as ZSTD_c_useBlockSplitter,
461            ZSTD_c_experimentalParam14 as ZSTD_c_useRowMatchFinder,
462            ZSTD_c_experimentalParam15 as ZSTD_c_deterministicRefPrefix,
463            ZSTD_c_experimentalParam2 as ZSTD_c_format,
464            ZSTD_c_experimentalParam3 as ZSTD_c_forceMaxWindow,
465            ZSTD_c_experimentalParam4 as ZSTD_c_forceAttachDict,
466            ZSTD_c_experimentalParam5 as ZSTD_c_literalCompressionMode,
467            ZSTD_c_experimentalParam6 as ZSTD_c_targetCBlockSize,
468            ZSTD_c_experimentalParam7 as ZSTD_c_srcSizeHint,
469            ZSTD_c_experimentalParam8 as ZSTD_c_enableDedicatedDictSearch,
470            ZSTD_c_experimentalParam9 as ZSTD_c_stableInBuffer,
471        };
472
473        use zstd_sys::ZSTD_cParameter::*;
474        use CParameter::*;
475
476        let (param, value) = match param {
477            #[cfg(feature = "experimental")]
478            RSyncable(rsyncable) => (ZSTD_c_rsyncable, rsyncable as c_int),
479            #[cfg(feature = "experimental")]
480            Format(format) => (ZSTD_c_format, format as c_int),
481            #[cfg(feature = "experimental")]
482            ForceMaxWindow(force) => (ZSTD_c_forceMaxWindow, force as c_int),
483            #[cfg(feature = "experimental")]
484            ForceAttachDict(force) => (ZSTD_c_forceAttachDict, force as c_int),
485            #[cfg(feature = "experimental")]
486            TargetCBlockSize(value) => {
487                (ZSTD_c_targetCBlockSize, value as c_int)
488            }
489            #[cfg(feature = "experimental")]
490            SrcSizeHint(value) => (ZSTD_c_srcSizeHint, value as c_int),
491            #[cfg(feature = "experimental")]
492            EnableDedicatedDictSearch(enable) => {
493                (ZSTD_c_enableDedicatedDictSearch, enable as c_int)
494            }
495            #[cfg(feature = "experimental")]
496            StableInBuffer(stable) => (ZSTD_c_stableInBuffer, stable as c_int),
497            #[cfg(feature = "experimental")]
498            StableOutBuffer(stable) => {
499                (ZSTD_c_stableOutBuffer, stable as c_int)
500            }
501            #[cfg(feature = "experimental")]
502            BlockDelimiters(value) => (ZSTD_c_blockDelimiters, value as c_int),
503            #[cfg(feature = "experimental")]
504            ValidateSequences(validate) => {
505                (ZSTD_c_validateSequences, validate as c_int)
506            }
507            #[cfg(feature = "experimental")]
508            UseBlockSplitter(split) => {
509                (ZSTD_c_useBlockSplitter, split as c_int)
510            }
511            #[cfg(feature = "experimental")]
512            UseRowMatchFinder(mode) => {
513                (ZSTD_c_useRowMatchFinder, mode as c_int)
514            }
515            #[cfg(feature = "experimental")]
516            DeterministicRefPrefix(deterministic) => {
517                (ZSTD_c_deterministicRefPrefix, deterministic as c_int)
518            }
519            CompressionLevel(level) => (ZSTD_c_compressionLevel, level),
520            WindowLog(value) => (ZSTD_c_windowLog, value as c_int),
521            HashLog(value) => (ZSTD_c_hashLog, value as c_int),
522            ChainLog(value) => (ZSTD_c_chainLog, value as c_int),
523            SearchLog(value) => (ZSTD_c_searchLog, value as c_int),
524            MinMatch(value) => (ZSTD_c_minMatch, value as c_int),
525            TargetLength(value) => (ZSTD_c_targetLength, value as c_int),
526            Strategy(strategy) => (ZSTD_c_strategy, strategy as c_int),
527            #[cfg(feature = "experimental")]
528            LiteralCompressionMode(mode) => {
529                (ZSTD_c_literalCompressionMode, mode as c_int)
530            }
531            EnableLongDistanceMatching(flag) => {
532                (ZSTD_c_enableLongDistanceMatching, flag as c_int)
533            }
534            LdmHashLog(value) => (ZSTD_c_ldmHashLog, value as c_int),
535            LdmMinMatch(value) => (ZSTD_c_ldmMinMatch, value as c_int),
536            LdmBucketSizeLog(value) => {
537                (ZSTD_c_ldmBucketSizeLog, value as c_int)
538            }
539            LdmHashRateLog(value) => (ZSTD_c_ldmHashRateLog, value as c_int),
540            ContentSizeFlag(flag) => (ZSTD_c_contentSizeFlag, flag as c_int),
541            ChecksumFlag(flag) => (ZSTD_c_checksumFlag, flag as c_int),
542            DictIdFlag(flag) => (ZSTD_c_dictIDFlag, flag as c_int),
543
544            NbWorkers(value) => (ZSTD_c_nbWorkers, value as c_int),
545
546            JobSize(value) => (ZSTD_c_jobSize, value as c_int),
547
548            OverlapSizeLog(value) => (ZSTD_c_overlapLog, value as c_int),
549        };
550
551        parse_code(unsafe {
552            zstd_sys::ZSTD_CCtx_setParameter(self.0.as_ptr(), param, value)
553        })
554    }
555
556    pub fn set_pledged_src_size(
557        &mut self,
558        pledged_src_size: u64,
559    ) -> SafeResult {
560        parse_code(unsafe {
561            zstd_sys::ZSTD_CCtx_setPledgedSrcSize(
562                self.0.as_ptr(),
563                pledged_src_size as c_ulonglong,
564            )
565        })
566    }
567
568    /// Creates a copy of this context.
569    ///
570    /// This only works before any data has been compressed. An error will be
571    /// returned otherwise.
572    #[cfg(feature = "experimental")]
573    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
574    pub fn try_clone(
575        &self,
576        pledged_src_size: Option<u64>,
577    ) -> Result<Self, ErrorCode> {
578        let context = NonNull::new(unsafe { zstd_sys::ZSTD_createCCtx() })
579            .ok_or(0usize)?;
580
581        parse_code(unsafe {
582            zstd_sys::ZSTD_copyCCtx(
583                context.as_ptr(),
584                self.0.as_ptr(),
585                pledged_src_size.unwrap_or(CONTENTSIZE_UNKNOWN),
586            )
587        })?;
588
589        Ok(CCtx(context, self.1))
590    }
591
592    /// Wraps the `ZSTD_getBlockSize()` function.
593    #[cfg(feature = "experimental")]
594    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
595    pub fn get_block_size(&self) -> usize {
596        unsafe { zstd_sys::ZSTD_getBlockSize(self.0.as_ptr()) }
597    }
598
599    /// Wraps the `ZSTD_compressBlock()` function.
600    #[cfg(feature = "experimental")]
601    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
602    pub fn compress_block<C: WriteBuf + ?Sized>(
603        &mut self,
604        dst: &mut C,
605        src: &[u8],
606    ) -> SafeResult {
607        unsafe {
608            dst.write_from(|buffer, capacity| {
609                parse_code(zstd_sys::ZSTD_compressBlock(
610                    self.0.as_ptr(),
611                    buffer,
612                    capacity,
613                    ptr_void(src),
614                    src.len(),
615                ))
616            })
617        }
618    }
619    pub fn in_size() -> usize {
620        unsafe { zstd_sys::ZSTD_CStreamInSize() }
621    }
622
623    pub fn out_size() -> usize {
624        unsafe { zstd_sys::ZSTD_CStreamOutSize() }
625    }
626}
627
628pub fn create_cctx<'a>() -> CCtx<'a> {
629    CCtx::create()
630}
631
632impl<'a> Drop for CCtx<'a> {
633    fn drop(&mut self) {
634        unsafe {
635            zstd_sys::ZSTD_freeCCtx(self.0.as_ptr());
636        }
637    }
638}
639
640unsafe impl<'a> Send for CCtx<'a> {}
641// CCtx can't be shared across threads, so it does not implement Sync.
642
643unsafe fn c_char_to_str(text: *const c_char) -> &'static str {
644    #[cfg(not(feature = "std"))]
645    {
646        // To be safe, we need to compute right now its length
647        let len = libc::strlen(text);
648
649        // Cast it to a slice
650        let slice = core::slice::from_raw_parts(text as *mut u8, len);
651        // And hope it's still text.
652        str::from_utf8(slice).expect("bad error message from zstd")
653    }
654
655    #[cfg(feature = "std")]
656    {
657        std::ffi::CStr::from_ptr(text)
658            .to_str()
659            .expect("bad error message from zstd")
660    }
661}
662
663pub fn get_error_name(code: usize) -> &'static str {
664    unsafe {
665        let name = zstd_sys::ZSTD_getErrorName(code);
666        c_char_to_str(name)
667    }
668}
669
670/// Wraps the `ZSTD_compressCCtx()` function
671pub fn compress_cctx(
672    ctx: &mut CCtx<'_>,
673    dst: &mut [u8],
674    src: &[u8],
675    compression_level: CompressionLevel,
676) -> SafeResult {
677    ctx.compress(dst, src, compression_level)
678}
679
680/// Wraps the `ZSTD_compress2()` function.
681pub fn compress2(
682    ctx: &mut CCtx<'_>,
683    dst: &mut [u8],
684    src: &[u8],
685) -> SafeResult {
686    ctx.compress2(dst, src)
687}
688
689/// A Decompression Context.
690///
691/// The lifetime references the potential dictionary used for this context.
692///
693/// If no dictionary was used, it will most likely be `'static`.
694///
695/// Same as `DStream`.
696pub struct DCtx<'a>(NonNull<zstd_sys::ZSTD_DCtx>, PhantomData<&'a ()>);
697
698impl Default for DCtx<'_> {
699    fn default() -> Self {
700        DCtx::create()
701    }
702}
703
704impl DCtx<'static> {
705    pub fn try_create() -> Option<Self> {
706        Some(DCtx(
707            NonNull::new(unsafe { zstd_sys::ZSTD_createDCtx() })?,
708            PhantomData,
709        ))
710    }
711    pub fn create() -> Self {
712        Self::try_create()
713            .expect("zstd returned null pointer when creating new context")
714    }
715}
716
717impl<'a> DCtx<'a> {
718    /// Wraps the `ZSTD_decompressDCtx()` function.
719    pub fn decompress<C: WriteBuf + ?Sized>(
720        &mut self,
721        dst: &mut C,
722        src: &[u8],
723    ) -> SafeResult {
724        unsafe {
725            dst.write_from(|buffer, capacity| {
726                parse_code(zstd_sys::ZSTD_decompressDCtx(
727                    self.0.as_ptr(),
728                    buffer,
729                    capacity,
730                    ptr_void(src),
731                    src.len(),
732                ))
733            })
734        }
735    }
736
737    /// Wraps `ZSTD_decompress_usingDict`
738    pub fn decompress_using_dict<C: WriteBuf + ?Sized>(
739        &mut self,
740        dst: &mut C,
741        src: &[u8],
742        dict: &[u8],
743    ) -> SafeResult {
744        unsafe {
745            dst.write_from(|buffer, capacity| {
746                parse_code(zstd_sys::ZSTD_decompress_usingDict(
747                    self.0.as_ptr(),
748                    buffer,
749                    capacity,
750                    ptr_void(src),
751                    src.len(),
752                    ptr_void(dict),
753                    dict.len(),
754                ))
755            })
756        }
757    }
758
759    /// Wraps the `ZSTD_decompress_usingDDict()` function.
760    pub fn decompress_using_ddict<C: WriteBuf + ?Sized>(
761        &mut self,
762        dst: &mut C,
763        src: &[u8],
764        ddict: &DDict<'_>,
765    ) -> SafeResult {
766        unsafe {
767            dst.write_from(|buffer, capacity| {
768                parse_code(zstd_sys::ZSTD_decompress_usingDDict(
769                    self.0.as_ptr(),
770                    buffer,
771                    capacity,
772                    ptr_void(src),
773                    src.len(),
774                    ddict.0.as_ptr(),
775                ))
776            })
777        }
778    }
779
780    /// Wraps the `ZSTD_initCStream()` function.
781    ///
782    /// Initializes an existing `DStream` for decompression.
783    pub fn init(&mut self) -> usize {
784        unsafe { zstd_sys::ZSTD_initDStream(self.0.as_ptr()) }
785    }
786
787    /// Wraps the `ZSTD_initDStream_usingDict()` function.
788    #[cfg(feature = "experimental")]
789    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
790    #[deprecated]
791    pub fn init_using_dict(&mut self, dict: &[u8]) -> SafeResult {
792        let code = unsafe {
793            zstd_sys::ZSTD_initDStream_usingDict(
794                self.0.as_ptr(),
795                ptr_void(dict),
796                dict.len(),
797            )
798        };
799        parse_code(code)
800    }
801
802    /// Wraps the `ZSTD_initDStream_usingDDict()` function.
803    #[cfg(feature = "experimental")]
804    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
805    #[deprecated]
806    pub fn init_using_ddict<'b>(&mut self, ddict: &DDict<'b>) -> SafeResult
807    where
808        'b: 'a,
809    {
810        let code = unsafe {
811            zstd_sys::ZSTD_initDStream_usingDDict(
812                self.0.as_ptr(),
813                ddict.0.as_ptr(),
814            )
815        };
816        parse_code(code)
817    }
818
819    /// Wraps the `ZSTD_resetDStream()` function.
820    pub fn reset(&mut self) -> SafeResult {
821        let code = unsafe {
822            zstd_sys::ZSTD_DCtx_reset(
823                self.0.as_ptr(),
824                ResetDirective::ZSTD_reset_session_only,
825            )
826        };
827        parse_code(code)
828    }
829
830    pub fn load_dictionary(&mut self, dict: &[u8]) -> SafeResult {
831        parse_code(unsafe {
832            zstd_sys::ZSTD_DCtx_loadDictionary(
833                self.0.as_ptr(),
834                ptr_void(dict),
835                dict.len(),
836            )
837        })
838    }
839
840    pub fn ref_ddict<'b>(&mut self, ddict: &DDict<'b>) -> SafeResult
841    where
842        'b: 'a,
843    {
844        parse_code(unsafe {
845            zstd_sys::ZSTD_DCtx_refDDict(self.0.as_ptr(), ddict.0.as_ptr())
846        })
847    }
848
849    pub fn ref_prefix<'b>(&mut self, prefix: &'b [u8]) -> SafeResult
850    where
851        'b: 'a,
852    {
853        parse_code(unsafe {
854            zstd_sys::ZSTD_DCtx_refPrefix(
855                self.0.as_ptr(),
856                ptr_void(prefix),
857                prefix.len(),
858            )
859        })
860    }
861
862    pub fn set_parameter(&mut self, param: DParameter) -> SafeResult {
863        #[cfg(feature = "experimental")]
864        use zstd_sys::ZSTD_dParameter::{
865            ZSTD_d_experimentalParam1 as ZSTD_d_format,
866            ZSTD_d_experimentalParam2 as ZSTD_d_stableOutBuffer,
867            ZSTD_d_experimentalParam3 as ZSTD_d_forceIgnoreChecksum,
868            ZSTD_d_experimentalParam4 as ZSTD_d_refMultipleDDicts,
869        };
870
871        use zstd_sys::ZSTD_dParameter::*;
872        use DParameter::*;
873
874        let (param, value) = match param {
875            #[cfg(feature = "experimental")]
876            Format(format) => (ZSTD_d_format, format as c_int),
877            #[cfg(feature = "experimental")]
878            StableOutBuffer(stable) => {
879                (ZSTD_d_stableOutBuffer, stable as c_int)
880            }
881            #[cfg(feature = "experimental")]
882            ForceIgnoreChecksum(force) => {
883                (ZSTD_d_forceIgnoreChecksum, force as c_int)
884            }
885            #[cfg(feature = "experimental")]
886            RefMultipleDDicts(value) => {
887                (ZSTD_d_refMultipleDDicts, value as c_int)
888            }
889
890            WindowLogMax(value) => (ZSTD_d_windowLogMax, value as c_int),
891        };
892
893        parse_code(unsafe {
894            zstd_sys::ZSTD_DCtx_setParameter(self.0.as_ptr(), param, value)
895        })
896    }
897
898    /// Wraps the `ZSTD_decompressStream()` function.
899    pub fn decompress_stream<C: WriteBuf + ?Sized>(
900        &mut self,
901        output: &mut OutBuffer<'_, C>,
902        input: &mut InBuffer<'_>,
903    ) -> SafeResult {
904        let mut output = output.wrap();
905        let mut input = input.wrap();
906        let code = unsafe {
907            zstd_sys::ZSTD_decompressStream(
908                self.0.as_ptr(),
909                ptr_mut(&mut output),
910                ptr_mut(&mut input),
911            )
912        };
913        parse_code(code)
914    }
915
916    /// Wraps the `ZSTD_DStreamInSize()` function.
917    ///
918    /// Returns a hint for the recommended size of the input buffer for decompression.
919    pub fn in_size() -> usize {
920        unsafe { zstd_sys::ZSTD_DStreamInSize() }
921    }
922
923    /// Wraps the `ZSTD_DStreamOutSize()` function.
924    ///
925    /// Returns a hint for the recommended size of the output buffer for decompression.
926    pub fn out_size() -> usize {
927        unsafe { zstd_sys::ZSTD_DStreamOutSize() }
928    }
929
930    /// Wraps the `ZSTD_sizeof_DCtx()` function.
931    pub fn sizeof(&self) -> usize {
932        unsafe { zstd_sys::ZSTD_sizeof_DCtx(self.0.as_ptr()) }
933    }
934
935    /// Wraps the `ZSTD_decompressBlock()` function.
936    #[cfg(feature = "experimental")]
937    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
938    pub fn decompress_block<C: WriteBuf + ?Sized>(
939        &mut self,
940        dst: &mut C,
941        src: &[u8],
942    ) -> SafeResult {
943        unsafe {
944            dst.write_from(|buffer, capacity| {
945                parse_code(zstd_sys::ZSTD_decompressBlock(
946                    self.0.as_ptr(),
947                    buffer,
948                    capacity,
949                    ptr_void(src),
950                    src.len(),
951                ))
952            })
953        }
954    }
955
956    /// Wraps the `ZSTD_insertBlock()` function.
957    #[cfg(feature = "experimental")]
958    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
959    pub fn insert_block(&mut self, block: &[u8]) -> usize {
960        unsafe {
961            zstd_sys::ZSTD_insertBlock(
962                self.0.as_ptr(),
963                ptr_void(block),
964                block.len(),
965            )
966        }
967    }
968
969    /// Creates a copy of this context.
970    ///
971    /// This only works before any data has been decompressed. An error will be
972    /// returned otherwise.
973    #[cfg(feature = "experimental")]
974    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
975    pub fn try_clone(&self) -> Result<Self, ErrorCode> {
976        let context = NonNull::new(unsafe { zstd_sys::ZSTD_createDCtx() })
977            .ok_or(0usize)?;
978
979        unsafe { zstd_sys::ZSTD_copyDCtx(context.as_ptr(), self.0.as_ptr()) };
980
981        Ok(DCtx(context, self.1))
982    }
983}
984
985/// Prepares a new decompression context without dictionary.
986pub fn create_dctx() -> DCtx<'static> {
987    DCtx::create()
988}
989
990impl Drop for DCtx<'_> {
991    fn drop(&mut self) {
992        unsafe {
993            zstd_sys::ZSTD_freeDCtx(self.0.as_ptr());
994        }
995    }
996}
997
998unsafe impl Send for DCtx<'_> {}
999// DCtx can't be shared across threads, so it does not implement Sync.
1000
1001/// Wraps the `ZSTD_decompressDCtx()` function.
1002pub fn decompress_dctx(
1003    ctx: &mut DCtx<'_>,
1004    dst: &mut [u8],
1005    src: &[u8],
1006) -> SafeResult {
1007    ctx.decompress(dst, src)
1008}
1009
1010/// Wraps the `ZSTD_compress_usingDict()` function.
1011pub fn compress_using_dict(
1012    ctx: &mut CCtx<'_>,
1013    dst: &mut [u8],
1014    src: &[u8],
1015    dict: &[u8],
1016    compression_level: CompressionLevel,
1017) -> SafeResult {
1018    ctx.compress_using_dict(dst, src, dict, compression_level)
1019}
1020
1021/// Wraps the `ZSTD_decompress_usingDict()` function.
1022pub fn decompress_using_dict(
1023    dctx: &mut DCtx<'_>,
1024    dst: &mut [u8],
1025    src: &[u8],
1026    dict: &[u8],
1027) -> SafeResult {
1028    dctx.decompress_using_dict(dst, src, dict)
1029}
1030
1031/// Compression dictionary.
1032pub struct CDict<'a>(NonNull<zstd_sys::ZSTD_CDict>, PhantomData<&'a ()>);
1033
1034impl CDict<'static> {
1035    pub fn create(
1036        dict_buffer: &[u8],
1037        compression_level: CompressionLevel,
1038    ) -> Self {
1039        Self::try_create(dict_buffer, compression_level)
1040            .expect("zstd returned null pointer when creating dict")
1041    }
1042
1043    pub fn try_create(
1044        dict_buffer: &[u8],
1045        compression_level: CompressionLevel,
1046    ) -> Option<Self> {
1047        Some(CDict(
1048            NonNull::new(unsafe {
1049                zstd_sys::ZSTD_createCDict(
1050                    ptr_void(dict_buffer),
1051                    dict_buffer.len(),
1052                    compression_level,
1053                )
1054            })?,
1055            PhantomData,
1056        ))
1057    }
1058}
1059
1060impl<'a> CDict<'a> {
1061    #[cfg(feature = "experimental")]
1062    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1063    pub fn create_by_reference(
1064        dict_buffer: &'a [u8],
1065        compression_level: CompressionLevel,
1066    ) -> Self {
1067        CDict(
1068            NonNull::new(unsafe {
1069                zstd_sys::ZSTD_createCDict_byReference(
1070                    ptr_void(dict_buffer),
1071                    dict_buffer.len(),
1072                    compression_level,
1073                )
1074            })
1075            .expect("zstd returned null pointer"),
1076            PhantomData,
1077        )
1078    }
1079
1080    pub fn sizeof(&self) -> usize {
1081        unsafe { zstd_sys::ZSTD_sizeof_CDict(self.0.as_ptr()) }
1082    }
1083
1084    pub fn get_dict_id(&self) -> u32 {
1085        unsafe { zstd_sys::ZSTD_getDictID_fromCDict(self.0.as_ptr()) as u32 }
1086    }
1087}
1088
1089/// Wraps the `ZSTD_createCDict()` function.
1090pub fn create_cdict(
1091    dict_buffer: &[u8],
1092    compression_level: CompressionLevel,
1093) -> CDict<'static> {
1094    CDict::create(dict_buffer, compression_level)
1095}
1096
1097impl<'a> Drop for CDict<'a> {
1098    fn drop(&mut self) {
1099        unsafe {
1100            zstd_sys::ZSTD_freeCDict(self.0.as_ptr());
1101        }
1102    }
1103}
1104
1105unsafe impl<'a> Send for CDict<'a> {}
1106unsafe impl<'a> Sync for CDict<'a> {}
1107
1108/// Wraps the `ZSTD_compress_usingCDict()` function.
1109pub fn compress_using_cdict(
1110    cctx: &mut CCtx<'_>,
1111    dst: &mut [u8],
1112    src: &[u8],
1113    cdict: &CDict<'_>,
1114) -> SafeResult {
1115    cctx.compress_using_cdict(dst, src, cdict)
1116}
1117
1118/// A digested decompression dictionary.
1119pub struct DDict<'a>(NonNull<zstd_sys::ZSTD_DDict>, PhantomData<&'a ()>);
1120
1121impl DDict<'static> {
1122    pub fn create(dict_buffer: &[u8]) -> Self {
1123        Self::try_create(dict_buffer)
1124            .expect("zstd returned null pointer when creating dict")
1125    }
1126
1127    pub fn try_create(dict_buffer: &[u8]) -> Option<Self> {
1128        Some(DDict(
1129            NonNull::new(unsafe {
1130                zstd_sys::ZSTD_createDDict(
1131                    ptr_void(dict_buffer),
1132                    dict_buffer.len(),
1133                )
1134            })?,
1135            PhantomData,
1136        ))
1137    }
1138}
1139
1140impl<'a> DDict<'a> {
1141    pub fn sizeof(&self) -> usize {
1142        unsafe { zstd_sys::ZSTD_sizeof_DDict(self.0.as_ptr()) }
1143    }
1144
1145    /// Wraps the `ZSTD_createDDict_byReference()` function.
1146    ///
1147    /// The dictionary will keep referencing `dict_buffer`.
1148    #[cfg(feature = "experimental")]
1149    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1150    pub fn create_by_reference(dict_buffer: &'a [u8]) -> Self {
1151        DDict(
1152            NonNull::new(unsafe {
1153                zstd_sys::ZSTD_createDDict_byReference(
1154                    ptr_void(dict_buffer),
1155                    dict_buffer.len(),
1156                )
1157            })
1158            .expect("zstd returned null pointer"),
1159            PhantomData,
1160        )
1161    }
1162
1163    pub fn get_dict_id(&self) -> u32 {
1164        unsafe { zstd_sys::ZSTD_getDictID_fromDDict(self.0.as_ptr()) as u32 }
1165    }
1166}
1167
1168/// Wraps the `ZSTD_createDDict()` function.
1169///
1170/// It copies the dictionary internally, so the resulting `DDict` is `'static`.
1171pub fn create_ddict(dict_buffer: &[u8]) -> DDict<'static> {
1172    DDict::create(dict_buffer)
1173}
1174
1175impl<'a> Drop for DDict<'a> {
1176    fn drop(&mut self) {
1177        unsafe {
1178            zstd_sys::ZSTD_freeDDict(self.0.as_ptr());
1179        }
1180    }
1181}
1182
1183unsafe impl<'a> Send for DDict<'a> {}
1184unsafe impl<'a> Sync for DDict<'a> {}
1185
1186/// Wraps the `ZSTD_decompress_usingDDict()` function.
1187pub fn decompress_using_ddict(
1188    dctx: &mut DCtx<'_>,
1189    dst: &mut [u8],
1190    src: &[u8],
1191    ddict: &DDict<'_>,
1192) -> SafeResult {
1193    dctx.decompress_using_ddict(dst, src, ddict)
1194}
1195
1196/// Compression stream.
1197///
1198/// Same as `CCtx`.
1199pub type CStream<'a> = CCtx<'a>;
1200
1201// CStream can't be shared across threads, so it does not implement Sync.
1202
1203/// Allocates a new `CStream`.
1204pub fn create_cstream<'a>() -> CStream<'a> {
1205    CCtx::create()
1206}
1207
1208/// Prepares an existing `CStream` for compression at the given level.
1209pub fn init_cstream(
1210    zcs: &mut CStream<'_>,
1211    compression_level: CompressionLevel,
1212) -> usize {
1213    zcs.init(compression_level)
1214}
1215
1216#[derive(Debug)]
1217/// Wrapper around an input buffer.
1218///
1219/// Bytes will be read starting at `src[pos]`.
1220///
1221/// `pos` will be updated after reading.
1222pub struct InBuffer<'a> {
1223    pub src: &'a [u8],
1224    pub pos: usize,
1225}
1226
1227/// Describe a resizeable bytes container like `Vec<u8>`.
1228///
1229/// Can start from uninitialized memory, and will be partially filled.
1230///
1231/// Should be implemented by a contiguous chunk of memory.
1232///
1233/// The main implementors are:
1234/// * `Vec<u8>` and similar structures. These can start empty with a non-zero capacity, and they
1235///   will be resized to cover the data written.
1236/// * `[u8]` and `[u8; N]`. These must start already-initialized, and will not be resized. It will
1237///   be up to the caller to only use the part that was written.
1238pub unsafe trait WriteBuf {
1239    /// Returns the valid data part of this container. Should only cover initialized data.
1240    fn as_slice(&self) -> &[u8];
1241
1242    /// Returns the full capacity of this container. May include uninitialized data.
1243    fn capacity(&self) -> usize;
1244
1245    /// Returns a pointer to the start of the data.
1246    fn as_mut_ptr(&mut self) -> *mut u8;
1247
1248    /// Indicates that the first `n` bytes of the container have been written.
1249    unsafe fn filled_until(&mut self, n: usize);
1250
1251    /// Call the given closure using the pointer and capacity from `self`.
1252    ///
1253    /// Assumes the given function returns a parseable code, which if valid, represents how many
1254    /// bytes were written to `self`.
1255    ///
1256    /// The given closure must treat its first argument as pointing to potentially uninitialized
1257    /// memory, and should not read from it.
1258    ///
1259    /// In addition, it must have written at least `n` bytes contiguously from this pointer, where
1260    /// `n` is the returned value.
1261    unsafe fn write_from<F>(&mut self, f: F) -> SafeResult
1262    where
1263        F: FnOnce(*mut c_void, usize) -> SafeResult,
1264    {
1265        let res = f(ptr_mut_void(self), self.capacity());
1266        if let Ok(n) = res {
1267            self.filled_until(n);
1268        }
1269        res
1270    }
1271}
1272
1273#[cfg(feature = "std")]
1274#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "std")))]
1275unsafe impl WriteBuf for std::vec::Vec<u8> {
1276    fn as_slice(&self) -> &[u8] {
1277        &self[..]
1278    }
1279    fn capacity(&self) -> usize {
1280        self.capacity()
1281    }
1282    fn as_mut_ptr(&mut self) -> *mut u8 {
1283        self.as_mut_ptr()
1284    }
1285    unsafe fn filled_until(&mut self, n: usize) {
1286        self.set_len(n);
1287    }
1288}
1289
1290#[cfg(feature = "arrays")]
1291#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "arrays")))]
1292unsafe impl<const N: usize> WriteBuf for [u8; N] {
1293    fn as_slice(&self) -> &[u8] {
1294        self
1295    }
1296    fn capacity(&self) -> usize {
1297        self.len()
1298    }
1299
1300    fn as_mut_ptr(&mut self) -> *mut u8 {
1301        (&mut self[..]).as_mut_ptr()
1302    }
1303
1304    unsafe fn filled_until(&mut self, _n: usize) {
1305        // Assume the slice is already initialized
1306    }
1307}
1308
1309unsafe impl WriteBuf for [u8] {
1310    fn as_slice(&self) -> &[u8] {
1311        self
1312    }
1313    fn capacity(&self) -> usize {
1314        self.len()
1315    }
1316
1317    fn as_mut_ptr(&mut self) -> *mut u8 {
1318        self.as_mut_ptr()
1319    }
1320
1321    unsafe fn filled_until(&mut self, _n: usize) {
1322        // Assume the slice is already initialized
1323    }
1324}
1325
1326/*
1327// This is possible, but... why?
1328unsafe impl<'a> WriteBuf for OutBuffer<'a, [u8]> {
1329    fn as_slice(&self) -> &[u8] {
1330        self.dst
1331    }
1332    fn capacity(&self) -> usize {
1333        self.dst.len()
1334    }
1335    fn as_mut_ptr(&mut self) -> *mut u8 {
1336        self.dst.as_mut_ptr()
1337    }
1338    unsafe fn filled_until(&mut self, n: usize) {
1339        self.pos = n;
1340    }
1341}
1342*/
1343
1344#[derive(Debug)]
1345/// Wrapper around an output buffer.
1346///
1347/// `C` is usually either `[u8]` or `Vec<u8>`.
1348///
1349/// Bytes will be written starting at `dst[pos]`.
1350///
1351/// `pos` will be updated after writing.
1352///
1353/// # Invariant
1354///
1355/// `pos <= dst.capacity()`
1356pub struct OutBuffer<'a, C: WriteBuf + ?Sized> {
1357    pub dst: &'a mut C,
1358    pos: usize,
1359}
1360
1361/// Convenience method to get a mut pointer from a mut ref.
1362fn ptr_mut<B>(ptr_void: &mut B) -> *mut B {
1363    ptr_void as *mut B
1364}
1365
1366/// Interface between a C-level ZSTD_outBuffer and a rust-level `OutBuffer`.
1367///
1368/// Will update the parent buffer from the C buffer on drop.
1369struct OutBufferWrapper<'a, 'b, C: WriteBuf + ?Sized> {
1370    buf: zstd_sys::ZSTD_outBuffer,
1371    parent: &'a mut OutBuffer<'b, C>,
1372}
1373
1374impl<'a, 'b: 'a, C: WriteBuf + ?Sized> Deref for OutBufferWrapper<'a, 'b, C> {
1375    type Target = zstd_sys::ZSTD_outBuffer;
1376
1377    fn deref(&self) -> &Self::Target {
1378        &self.buf
1379    }
1380}
1381
1382impl<'a, 'b: 'a, C: WriteBuf + ?Sized> DerefMut
1383    for OutBufferWrapper<'a, 'b, C>
1384{
1385    fn deref_mut(&mut self) -> &mut Self::Target {
1386        &mut self.buf
1387    }
1388}
1389
1390impl<'a, C: WriteBuf + ?Sized> OutBuffer<'a, C> {
1391    /// Returns a new `OutBuffer` around the given slice.
1392    ///
1393    /// Starts with `pos = 0`.
1394    pub fn around(dst: &'a mut C) -> Self {
1395        OutBuffer { dst, pos: 0 }
1396    }
1397
1398    /// Returns a new `OutBuffer` around the given slice, starting at the given position.
1399    ///
1400    /// # Panics
1401    ///
1402    /// If `pos >= dst.capacity()`.
1403    pub fn around_pos(dst: &'a mut C, pos: usize) -> Self {
1404        if pos >= dst.capacity() {
1405            panic!("Given position outside of the buffer bounds.");
1406        }
1407
1408        OutBuffer { dst, pos }
1409    }
1410
1411    /// Returns the current cursor position.
1412    pub fn pos(&self) -> usize {
1413        self.pos
1414    }
1415
1416    /// Sets the new cursor position.
1417    ///
1418    /// # Panics
1419    ///
1420    /// If `pos > self.dst.capacity()`.
1421    ///
1422    /// # Safety
1423    ///
1424    /// Data up to `pos` must have actually been written to.
1425    pub unsafe fn set_pos(&mut self, pos: usize) {
1426        if pos > self.dst.capacity() {
1427            panic!("Given position outside of the buffer bounds.");
1428        }
1429
1430        self.dst.filled_until(pos);
1431
1432        self.pos = pos;
1433    }
1434
1435    fn wrap<'b>(&'b mut self) -> OutBufferWrapper<'b, 'a, C> {
1436        OutBufferWrapper {
1437            buf: zstd_sys::ZSTD_outBuffer {
1438                dst: ptr_mut_void(self.dst),
1439                size: self.dst.capacity(),
1440                pos: self.pos,
1441            },
1442            parent: self,
1443        }
1444    }
1445
1446    /// Returns the part of this buffer that was written to.
1447    pub fn as_slice<'b>(&'b self) -> &'a [u8]
1448    where
1449        'b: 'a,
1450    {
1451        let pos = self.pos;
1452        &self.dst.as_slice()[..pos]
1453    }
1454}
1455
1456impl<'a, 'b, C: WriteBuf + ?Sized> Drop for OutBufferWrapper<'a, 'b, C> {
1457    fn drop(&mut self) {
1458        // Safe because we guarantee that data until `self.buf.pos` has been written.
1459        unsafe { self.parent.set_pos(self.buf.pos) };
1460    }
1461}
1462
1463struct InBufferWrapper<'a, 'b> {
1464    buf: zstd_sys::ZSTD_inBuffer,
1465    parent: &'a mut InBuffer<'b>,
1466}
1467
1468impl<'a, 'b: 'a> Deref for InBufferWrapper<'a, 'b> {
1469    type Target = zstd_sys::ZSTD_inBuffer;
1470
1471    fn deref(&self) -> &Self::Target {
1472        &self.buf
1473    }
1474}
1475
1476impl<'a, 'b: 'a> DerefMut for InBufferWrapper<'a, 'b> {
1477    fn deref_mut(&mut self) -> &mut Self::Target {
1478        &mut self.buf
1479    }
1480}
1481
1482impl<'a> InBuffer<'a> {
1483    /// Returns a new `InBuffer` around the given slice.
1484    ///
1485    /// Starts with `pos = 0`.
1486    pub fn around(src: &'a [u8]) -> Self {
1487        InBuffer { src, pos: 0 }
1488    }
1489
1490    /// Returns the current cursor position.
1491    pub fn pos(&self) -> usize {
1492        self.pos
1493    }
1494
1495    /// Sets the new cursor position.
1496    ///
1497    /// # Panics
1498    ///
1499    /// If `pos > self.src.len()`.
1500    pub fn set_pos(&mut self, pos: usize) {
1501        if pos > self.src.len() {
1502            panic!("Given position outside of the buffer bounds.");
1503        }
1504        self.pos = pos;
1505    }
1506
1507    fn wrap<'b>(&'b mut self) -> InBufferWrapper<'b, 'a> {
1508        InBufferWrapper {
1509            buf: zstd_sys::ZSTD_inBuffer {
1510                src: ptr_void(self.src),
1511                size: self.src.len(),
1512                pos: self.pos,
1513            },
1514            parent: self,
1515        }
1516    }
1517}
1518
1519impl<'a, 'b> Drop for InBufferWrapper<'a, 'b> {
1520    fn drop(&mut self) {
1521        self.parent.set_pos(self.buf.pos);
1522    }
1523}
1524
1525/// Wraps the `ZSTD_compressStream()` function.
1526pub fn compress_stream<C: WriteBuf + ?Sized>(
1527    zcs: &mut CStream<'_>,
1528    output: &mut OutBuffer<'_, C>,
1529    input: &mut InBuffer<'_>,
1530) -> SafeResult {
1531    zcs.compress_stream(output, input)
1532}
1533
1534pub fn compress_stream2<C: WriteBuf + ?Sized>(
1535    cctx: &mut CCtx<'_>,
1536    output: &mut OutBuffer<'_, C>,
1537    input: &mut InBuffer<'_>,
1538    end_op: zstd_sys::ZSTD_EndDirective,
1539) -> SafeResult {
1540    cctx.compress_stream2(output, input, end_op)
1541}
1542
1543/// Wraps the `ZSTD_flushStream()` function.
1544pub fn flush_stream<C: WriteBuf + ?Sized>(
1545    zcs: &mut CStream<'_>,
1546    output: &mut OutBuffer<'_, C>,
1547) -> SafeResult {
1548    zcs.flush_stream(output)
1549}
1550
1551/// Wraps the `ZSTD_endStream()` function.
1552pub fn end_stream<C: WriteBuf + ?Sized>(
1553    zcs: &mut CStream<'_>,
1554    output: &mut OutBuffer<'_, C>,
1555) -> SafeResult {
1556    zcs.end_stream(output)
1557}
1558
1559/// Wraps `ZSTD_CStreamInSize()`
1560pub fn cstream_in_size() -> usize {
1561    CCtx::in_size()
1562}
1563
1564/// Wraps `ZSTD_CStreamOutSize()`
1565pub fn cstream_out_size() -> usize {
1566    CCtx::out_size()
1567}
1568
1569/// A Decompression stream.
1570///
1571/// Same as `DCtx`.
1572pub type DStream<'a> = DCtx<'a>;
1573
1574pub fn create_dstream() -> DStream<'static> {
1575    DStream::create()
1576}
1577
1578/// Wraps the `ZSTD_initCStream()` function.
1579///
1580/// Initializes an existing `DStream` for decompression.
1581pub fn init_dstream(zds: &mut DStream<'_>) -> usize {
1582    zds.init()
1583}
1584
1585/// Wraps the `ZSTD_decompressStream()` function.
1586pub fn decompress_stream<C: WriteBuf + ?Sized>(
1587    zds: &mut DStream<'_>,
1588    output: &mut OutBuffer<'_, C>,
1589    input: &mut InBuffer<'_>,
1590) -> SafeResult {
1591    zds.decompress_stream(output, input)
1592}
1593
1594/// Wraps the `ZSTD_DStreamInSize()` function.
1595///
1596/// Returns a hint for the recommended size of the input buffer for decompression.
1597pub fn dstream_in_size() -> usize {
1598    DStream::in_size()
1599}
1600
1601/// Wraps the `ZSTD_DStreamOutSize()` function.
1602///
1603/// Returns a hint for the recommended size of the output buffer for decompression.
1604pub fn dstream_out_size() -> usize {
1605    DStream::out_size()
1606}
1607
1608/// Wraps the `ZSTD_findFrameCompressedSize()` function.
1609///
1610/// `src` should contain at least an entire frame.
1611pub fn find_frame_compressed_size(src: &[u8]) -> SafeResult {
1612    let code = unsafe {
1613        zstd_sys::ZSTD_findFrameCompressedSize(ptr_void(src), src.len())
1614    };
1615    parse_code(code)
1616}
1617
1618/// Wraps the `ZSTD_getFrameContentSize()` function.
1619///
1620/// `src` should contain at least a frame header.
1621pub fn get_frame_content_size(src: &[u8]) -> u64 {
1622    unsafe { zstd_sys::ZSTD_getFrameContentSize(ptr_void(src), src.len()) }
1623}
1624
1625/// Wraps the `ZSTD_findDecompressedSize()` function.
1626///
1627/// `src` should be exactly a sequence of ZSTD frames.
1628#[cfg(feature = "experimental")]
1629#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1630pub fn find_decompressed_size(src: &[u8]) -> u64 {
1631    unsafe { zstd_sys::ZSTD_findDecompressedSize(ptr_void(src), src.len()) }
1632}
1633
1634/// Wraps the `ZSTD_sizeofCCtx()` function.
1635pub fn sizeof_cctx(cctx: &CCtx<'_>) -> usize {
1636    cctx.sizeof()
1637}
1638
1639/// Wraps the `ZSTD_sizeof_DCtx()` function.
1640pub fn sizeof_dctx(dctx: &DCtx<'_>) -> usize {
1641    dctx.sizeof()
1642}
1643
1644/// Wraps the `ZSTD_sizeof_CStream()` function.
1645pub fn sizeof_cstream(zcs: &CStream<'_>) -> usize {
1646    zcs.sizeof()
1647}
1648
1649/// Wraps the `ZSTD_sizeof_DStream()` function.
1650pub fn sizeof_dstream(zds: &DStream<'_>) -> usize {
1651    zds.sizeof()
1652}
1653
1654/// Wraps the `ZSTD_sizeof_CDict()` function.
1655pub fn sizeof_cdict(cdict: &CDict<'_>) -> usize {
1656    cdict.sizeof()
1657}
1658
1659/// Wraps the `ZSTD_sizeof_DDict()` function.
1660pub fn sizeof_ddict(ddict: &DDict<'_>) -> usize {
1661    ddict.sizeof()
1662}
1663
1664/// Wraps the `ZSTD_createCDict_byReference()` function.
1665///
1666/// The dictionary will keep referencing `dict_buffer`.
1667#[cfg(feature = "experimental")]
1668#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1669pub fn create_cdict_by_reference<'a>(
1670    dict_buffer: &'a [u8],
1671    compression_level: CompressionLevel,
1672) -> CDict<'a> {
1673    CDict::create_by_reference(dict_buffer, compression_level)
1674}
1675
1676/// Wraps the `ZSTD_isFrame()` function.
1677#[cfg(feature = "experimental")]
1678#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1679pub fn is_frame(buffer: &[u8]) -> u32 {
1680    unsafe { zstd_sys::ZSTD_isFrame(ptr_void(buffer), buffer.len()) as u32 }
1681}
1682
1683/// Wraps the `ZSTD_createDDict_byReference()` function.
1684///
1685/// The dictionary will keep referencing `dict_buffer`.
1686#[cfg(feature = "experimental")]
1687#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1688pub fn create_ddict_by_reference(dict_buffer: &[u8]) -> DDict {
1689    DDict::create_by_reference(dict_buffer)
1690}
1691
1692/// Wraps the `ZSTD_getDictID_fromDict()` function.
1693pub fn get_dict_id_from_dict(dict: &[u8]) -> u32 {
1694    unsafe {
1695        zstd_sys::ZSTD_getDictID_fromDict(ptr_void(dict), dict.len()) as u32
1696    }
1697}
1698
1699/// Wraps the `ZSTD_getDictID_fromDDict()` function.
1700pub fn get_dict_id_from_ddict(ddict: &DDict<'_>) -> u32 {
1701    ddict.get_dict_id()
1702}
1703
1704/// Wraps the `ZSTD_getDictID_fromFrame()` function.
1705pub fn get_dict_id_from_frame(src: &[u8]) -> u32 {
1706    unsafe {
1707        zstd_sys::ZSTD_getDictID_fromFrame(ptr_void(src), src.len()) as u32
1708    }
1709}
1710
1711/// Wraps the `ZSTD_initCStream_srcSize()` function.
1712#[cfg(feature = "experimental")]
1713#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1714#[deprecated]
1715#[allow(deprecated)]
1716pub fn init_cstream_src_size(
1717    zcs: &mut CStream,
1718    compression_level: CompressionLevel,
1719    pledged_src_size: u64,
1720) -> usize {
1721    zcs.init_src_size(compression_level, pledged_src_size)
1722}
1723
1724/// Wraps the `ZSTD_initCStream_usingDict()` function.
1725#[cfg(feature = "experimental")]
1726#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1727#[deprecated]
1728#[allow(deprecated)]
1729pub fn init_cstream_using_dict(
1730    zcs: &mut CStream,
1731    dict: &[u8],
1732    compression_level: CompressionLevel,
1733) -> SafeResult {
1734    zcs.init_using_dict(dict, compression_level)
1735}
1736
1737/// Wraps the `ZSTD_initCStream_usingCDict()` function.
1738#[cfg(feature = "experimental")]
1739#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1740#[deprecated]
1741#[allow(deprecated)]
1742pub fn init_cstream_using_cdict<'a, 'b>(
1743    zcs: &mut CStream<'a>,
1744    cdict: &CDict<'b>,
1745) -> SafeResult
1746where
1747    'b: 'a, // Dictionary outlives the stream.
1748{
1749    zcs.init_using_cdict(cdict)
1750}
1751
1752/// Wraps the `ZSTD_CCtx_loadDictionary()` function.
1753pub fn cctx_load_dictionary(cctx: &mut CCtx<'_>, dict: &[u8]) -> SafeResult {
1754    cctx.load_dictionary(dict)
1755}
1756
1757/// Wraps the `ZSTD_CCtx_refCDict()` function.
1758///
1759/// Dictionary must outlive the context.
1760pub fn cctx_ref_cdict<'a, 'b>(
1761    cctx: &mut CCtx<'a>,
1762    cdict: &CDict<'b>,
1763) -> SafeResult
1764where
1765    'b: 'a,
1766{
1767    cctx.ref_cdict(cdict)
1768}
1769
1770/// Wraps the `ZSTD_CCtx_refPrefix()` function.
1771///
1772/// Dictionary must outlive the prefix.
1773pub fn cctx_ref_prefix<'a, 'b>(
1774    cctx: &mut CCtx<'a>,
1775    prefix: &'b [u8],
1776) -> SafeResult
1777where
1778    'b: 'a,
1779{
1780    cctx.ref_prefix(prefix)
1781}
1782
1783/// Wraps the `ZSTD_DCtx_loadDictionary()` function.
1784pub fn dctx_load_dictionary(dctx: &mut DCtx<'_>, dict: &[u8]) -> SafeResult {
1785    dctx.load_dictionary(dict)
1786}
1787
1788/// Wraps the `ZSTD_DCtx_refDDict()` function.
1789pub fn dctx_ref_ddict<'a, 'b>(
1790    dctx: &mut DCtx<'a>,
1791    ddict: &'b DDict<'b>,
1792) -> SafeResult
1793where
1794    'b: 'a,
1795{
1796    dctx.ref_ddict(ddict)
1797}
1798
1799/// Wraps the `ZSTD_DCtx_refPrefix()` function.
1800pub fn dctx_ref_prefix<'a, 'b>(
1801    dctx: &mut DCtx<'a>,
1802    prefix: &'b [u8],
1803) -> SafeResult
1804where
1805    'b: 'a,
1806{
1807    dctx.ref_prefix(prefix)
1808}
1809
1810/// Wraps the `ZSTD_CCtx_reset()` function.
1811pub fn cctx_reset(cctx: &mut CCtx<'_>, reset: ResetDirective) -> SafeResult {
1812    cctx.reset(reset)
1813}
1814
1815/// Wraps the `ZSTD_DCtx_reset()` function.
1816pub fn dctx_reset(dctx: &mut DCtx<'_>, reset: ResetDirective) -> SafeResult {
1817    parse_code(unsafe { zstd_sys::ZSTD_DCtx_reset(dctx.0.as_ptr(), reset) })
1818}
1819
1820/// Wraps the `ZSTD_resetCStream()` function.
1821#[cfg(feature = "experimental")]
1822#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1823#[deprecated]
1824#[allow(deprecated)]
1825pub fn reset_cstream(zcs: &mut CStream, pledged_src_size: u64) -> SafeResult {
1826    zcs.reset_cstream(pledged_src_size)
1827}
1828
1829/// Wraps the `ZSTD_initDStream_usingDict()` function.
1830#[cfg(feature = "experimental")]
1831#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1832#[deprecated]
1833#[allow(deprecated)]
1834pub fn init_dstream_using_dict(zds: &mut DStream, dict: &[u8]) -> SafeResult {
1835    zds.init_using_dict(dict)
1836}
1837
1838/// Wraps the `ZSTD_initDStream_usingDDict()` function.
1839#[cfg(feature = "experimental")]
1840#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1841#[deprecated]
1842#[allow(deprecated)]
1843pub fn init_dstream_using_ddict<'a, 'b>(
1844    zds: &mut DStream<'a>,
1845    ddict: &DDict<'b>,
1846) -> SafeResult
1847where
1848    'b: 'a,
1849{
1850    zds.init_using_ddict(ddict)
1851}
1852
1853/// Wraps the `ZSTD_resetDStream()` function.
1854#[cfg(feature = "experimental")]
1855#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1856pub fn reset_dstream(zds: &mut DStream) -> SafeResult {
1857    zds.reset()
1858}
1859
1860#[cfg(feature = "experimental")]
1861#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1862#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1863#[repr(u32)]
1864pub enum FrameFormat {
1865    /// Regular zstd format.
1866    One = zstd_sys::ZSTD_format_e::ZSTD_f_zstd1 as u32,
1867
1868    /// Skip the 4 bytes identifying the content as zstd-compressed data.
1869    Magicless = zstd_sys::ZSTD_format_e::ZSTD_f_zstd1_magicless as u32,
1870}
1871
1872#[cfg(feature = "experimental")]
1873#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1874#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1875#[repr(u32)]
1876pub enum DictAttachPref {
1877    DefaultAttach =
1878        zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictDefaultAttach as u32,
1879    ForceAttach = zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictForceAttach as u32,
1880    ForceCopy = zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictForceCopy as u32,
1881    ForceLoad = zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictForceLoad as u32,
1882}
1883
1884#[cfg(feature = "experimental")]
1885#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1886#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1887#[repr(u32)]
1888pub enum ParamSwitch {
1889    Auto = zstd_sys::ZSTD_paramSwitch_e::ZSTD_ps_auto as u32,
1890    Enable = zstd_sys::ZSTD_paramSwitch_e::ZSTD_ps_enable as u32,
1891    Disable = zstd_sys::ZSTD_paramSwitch_e::ZSTD_ps_disable as u32,
1892}
1893
1894/// A compression parameter.
1895#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1896pub enum CParameter {
1897    #[cfg(feature = "experimental")]
1898    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1899    RSyncable(bool),
1900
1901    #[cfg(feature = "experimental")]
1902    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1903    Format(FrameFormat),
1904
1905    #[cfg(feature = "experimental")]
1906    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1907    ForceMaxWindow(bool),
1908
1909    #[cfg(feature = "experimental")]
1910    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1911    ForceAttachDict(DictAttachPref),
1912
1913    #[cfg(feature = "experimental")]
1914    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1915    LiteralCompressionMode(ParamSwitch),
1916
1917    #[cfg(feature = "experimental")]
1918    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1919    TargetCBlockSize(u32),
1920
1921    #[cfg(feature = "experimental")]
1922    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1923    SrcSizeHint(u32),
1924
1925    #[cfg(feature = "experimental")]
1926    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1927    EnableDedicatedDictSearch(bool),
1928
1929    #[cfg(feature = "experimental")]
1930    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1931    StableInBuffer(bool),
1932
1933    #[cfg(feature = "experimental")]
1934    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1935    StableOutBuffer(bool),
1936
1937    #[cfg(feature = "experimental")]
1938    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1939    BlockDelimiters(bool),
1940
1941    #[cfg(feature = "experimental")]
1942    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1943    ValidateSequences(bool),
1944
1945    #[cfg(feature = "experimental")]
1946    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1947    UseBlockSplitter(ParamSwitch),
1948
1949    #[cfg(feature = "experimental")]
1950    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1951    UseRowMatchFinder(ParamSwitch),
1952
1953    #[cfg(feature = "experimental")]
1954    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1955    DeterministicRefPrefix(bool),
1956
1957    CompressionLevel(CompressionLevel),
1958
1959    WindowLog(u32),
1960
1961    HashLog(u32),
1962
1963    ChainLog(u32),
1964
1965    SearchLog(u32),
1966
1967    MinMatch(u32),
1968
1969    TargetLength(u32),
1970
1971    Strategy(Strategy),
1972
1973    EnableLongDistanceMatching(bool),
1974
1975    LdmHashLog(u32),
1976
1977    LdmMinMatch(u32),
1978
1979    LdmBucketSizeLog(u32),
1980
1981    LdmHashRateLog(u32),
1982
1983    ContentSizeFlag(bool),
1984
1985    ChecksumFlag(bool),
1986
1987    DictIdFlag(bool),
1988
1989    /// Note: this will only work if the `zstdmt` feature is activated.
1990    NbWorkers(u32),
1991
1992    JobSize(u32),
1993
1994    OverlapSizeLog(u32),
1995}
1996
1997/// A decompression parameter.
1998pub enum DParameter {
1999    WindowLogMax(u32),
2000
2001    /// See `FrameFormat`.
2002    #[cfg(feature = "experimental")]
2003    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2004    Format(FrameFormat),
2005
2006    #[cfg(feature = "experimental")]
2007    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2008    StableOutBuffer(bool),
2009
2010    #[cfg(feature = "experimental")]
2011    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2012    ForceIgnoreChecksum(bool),
2013
2014    #[cfg(feature = "experimental")]
2015    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2016    RefMultipleDDicts(bool),
2017}
2018
2019/// Wraps the `ZSTD_DCtx_setParameter()` function.
2020pub fn dctx_set_parameter(
2021    dctx: &mut DCtx<'_>,
2022    param: DParameter,
2023) -> SafeResult {
2024    dctx.set_parameter(param)
2025}
2026
2027/// Wraps the `ZSTD_CCtx_setParameter()` function.
2028pub fn cctx_set_parameter(
2029    cctx: &mut CCtx<'_>,
2030    param: CParameter,
2031) -> SafeResult {
2032    cctx.set_parameter(param)
2033}
2034
2035/// Wraps the `ZSTD_CCtx_setPledgedSrcSize()` function.
2036pub fn cctx_set_pledged_src_size(
2037    cctx: &mut CCtx<'_>,
2038    pledged_src_size: u64,
2039) -> SafeResult {
2040    cctx.set_pledged_src_size(pledged_src_size)
2041}
2042
2043/// Wraps the `ZDICT_trainFromBuffer()` function.
2044#[cfg(feature = "zdict_builder")]
2045#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "zdict_builder")))]
2046pub fn train_from_buffer<C: WriteBuf + ?Sized>(
2047    dict_buffer: &mut C,
2048    samples_buffer: &[u8],
2049    samples_sizes: &[usize],
2050) -> SafeResult {
2051    assert_eq!(samples_buffer.len(), samples_sizes.iter().sum());
2052
2053    unsafe {
2054        dict_buffer.write_from(|buffer, capacity| {
2055            parse_code(zstd_sys::ZDICT_trainFromBuffer(
2056                buffer,
2057                capacity,
2058                ptr_void(samples_buffer),
2059                samples_sizes.as_ptr(),
2060                samples_sizes.len() as u32,
2061            ))
2062        })
2063    }
2064}
2065
2066/// Wraps the `ZSTD_getDictID_fromDict()` function.
2067#[cfg(feature = "zdict_builder")]
2068#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "zdict_builder")))]
2069pub fn get_dict_id(dict_buffer: &[u8]) -> Option<u32> {
2070    let id = unsafe {
2071        zstd_sys::ZDICT_getDictID(ptr_void(dict_buffer), dict_buffer.len())
2072    };
2073    if id > 0 {
2074        Some(id)
2075    } else {
2076        None
2077    }
2078}
2079
2080/// Wraps the `ZSTD_getBlockSize()` function.
2081#[cfg(feature = "experimental")]
2082#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2083pub fn get_block_size(cctx: &CCtx) -> usize {
2084    unsafe { zstd_sys::ZSTD_getBlockSize(cctx.0.as_ptr()) }
2085}
2086
2087/// Wraps the `ZSTD_compressBlock()` function.
2088#[cfg(feature = "experimental")]
2089#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2090pub fn compress_block(
2091    cctx: &mut CCtx,
2092    dst: &mut [u8],
2093    src: &[u8],
2094) -> SafeResult {
2095    cctx.compress_block(dst, src)
2096}
2097
2098/// Wraps the `ZSTD_decompressBlock()` function.
2099#[cfg(feature = "experimental")]
2100#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2101pub fn decompress_block(
2102    dctx: &mut DCtx,
2103    dst: &mut [u8],
2104    src: &[u8],
2105) -> SafeResult {
2106    dctx.decompress_block(dst, src)
2107}
2108
2109/// Wraps the `ZSTD_insertBlock()` function.
2110#[cfg(feature = "experimental")]
2111#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2112pub fn insert_block(dctx: &mut DCtx, block: &[u8]) -> usize {
2113    dctx.insert_block(block)
2114}
2115
2116/// Wraps the `ZSTD_decompressBound` function
2117#[cfg(feature = "experimental")]
2118#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2119pub fn decompress_bound(data: &[u8]) -> Result<u64, ErrorCode> {
2120    let bound =
2121        unsafe { zstd_sys::ZSTD_decompressBound(ptr_void(data), data.len()) };
2122    if is_error(bound as usize) {
2123        Err(bound as usize)
2124    } else {
2125        Ok(bound)
2126    }
2127}