Skip to main content

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