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