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