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 = "with-rust-allocator")]
31mod rust_allocator;
32
33#[cfg(feature = "seekable")]
34pub mod seekable;
35
36// Re-export zstd-sys
37pub use zstd_sys;
38
39/// How to compress data.
40pub use zstd_sys::ZSTD_strategy as Strategy;
41
42/// Frame progression state.
43#[cfg(feature = "experimental")]
44#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
45pub use zstd_sys::ZSTD_frameProgression as FrameProgression;
46
47/// Reset directive.
48// pub use zstd_sys::ZSTD_ResetDirective as ResetDirective;
49use core::ffi::{c_char, c_int, c_ulonglong, c_void};
50
51use core::marker::PhantomData;
52use core::num::{NonZeroU32, NonZeroU64};
53use core::ops::{Deref, DerefMut};
54use core::ptr::NonNull;
55use core::str;
56
57include!("constants.rs");
58
59#[cfg(feature = "experimental")]
60include!("constants_experimental.rs");
61
62#[cfg(feature = "seekable")]
63include!("constants_seekable.rs");
64
65/// Represents the compression level used by zstd.
66pub type CompressionLevel = i32;
67
68/// Represents a possible error from the zstd library.
69pub type ErrorCode = usize;
70
71/// Wrapper result around most zstd functions.
72///
73/// Either a success code (usually number of bytes written), or an error code.
74pub type SafeResult = Result<usize, ErrorCode>;
75
76/// The error code zstd itself returns when an allocation fails
77/// (`-ZSTD_error_memory_allocation` as a `size_t`), for the places where a
78/// context is allocated on the Rust side of a call.
79#[cfg(feature = "experimental")]
80const MEMORY_ALLOCATION_ERROR: ErrorCode =
81    (zstd_sys::ZSTD_ErrorCode::ZSTD_error_memory_allocation as usize)
82        .wrapping_neg();
83
84/// The error code zstd itself returns for a parameter it does not support
85/// (`-ZSTD_error_parameter_unsupported` as a `size_t`), for the parameters
86/// that are refused on the Rust side of a call.
87#[cfg(feature = "experimental")]
88const PARAMETER_UNSUPPORTED_ERROR: ErrorCode =
89    (zstd_sys::ZSTD_ErrorCode::ZSTD_error_parameter_unsupported as usize)
90        .wrapping_neg();
91
92/// The error code zstd itself returns for an operation the context is in no
93/// state to perform (`-ZSTD_error_stage_wrong` as a `size_t`), for the places
94/// where that has to be decided on the Rust side of a call.
95const STAGE_WRONG_ERROR: ErrorCode =
96    (zstd_sys::ZSTD_ErrorCode::ZSTD_error_stage_wrong as usize).wrapping_neg();
97
98/// Indicates an error happened when parsing the frame content size.
99///
100/// The stream may be corrupted, or the given frame prefix was too small.
101#[derive(Debug)]
102pub struct ContentSizeError;
103
104impl core::fmt::Display for ContentSizeError {
105    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
106        f.write_str("Could not get content size")
107    }
108}
109
110/// Returns true if code represents error.
111fn is_error(code: usize) -> bool {
112    // Safety: Just FFI
113    unsafe { zstd_sys::ZSTD_isError(code) != 0 }
114}
115
116/// Parse the result code
117///
118/// Returns the number of bytes written if the code represents success,
119/// or the error message code otherwise.
120fn parse_code(code: usize) -> SafeResult {
121    if !is_error(code) {
122        Ok(code)
123    } else {
124        Err(code)
125    }
126}
127
128/// Parse a content size value.
129///
130/// zstd uses 2 special content size values to indicate either unknown size or parsing error.
131fn parse_content_size(
132    content_size: u64,
133) -> Result<Option<u64>, ContentSizeError> {
134    match content_size {
135        CONTENTSIZE_ERROR => Err(ContentSizeError),
136        CONTENTSIZE_UNKNOWN => Ok(None),
137        other => Ok(Some(other)),
138    }
139}
140
141fn ptr_void(src: &[u8]) -> *const c_void {
142    src.as_ptr() as *const c_void
143}
144
145fn ptr_mut_void(dst: &mut (impl WriteBuf + ?Sized)) -> *mut c_void {
146    dst.as_mut_ptr() as *mut c_void
147}
148
149/// Returns the ZSTD version.
150///
151/// Returns `major * 10_000 + minor * 100 + patch`.
152/// So 1.5.3 would be returned as `10_503`.
153pub fn version_number() -> u32 {
154    // Safety: Just FFI
155    unsafe { zstd_sys::ZSTD_versionNumber() as u32 }
156}
157
158/// Returns a string representation of the ZSTD version.
159///
160/// For example "1.5.3".
161pub fn version_string() -> &'static str {
162    // Safety: Assumes `ZSTD_versionString` returns a valid utf8 string.
163    unsafe { c_char_to_str(zstd_sys::ZSTD_versionString()) }
164}
165
166/// Returns the minimum (fastest) compression level supported.
167///
168/// This is likely going to be a _very_ large negative number.
169pub fn min_c_level() -> CompressionLevel {
170    // Safety: Just FFI
171    unsafe { zstd_sys::ZSTD_minCLevel() as CompressionLevel }
172}
173
174/// Returns the maximum (slowest) compression level supported.
175pub fn max_c_level() -> CompressionLevel {
176    // Safety: Just FFI
177    unsafe { zstd_sys::ZSTD_maxCLevel() as CompressionLevel }
178}
179
180/// Wraps the `ZSTD_compress` function.
181///
182/// This will try to compress `src` entirely and write the result to `dst`, returning the number of
183/// bytes written. If `dst` is too small to hold the compressed content, an error will be returned.
184///
185/// For streaming operations that don't require to store the entire input/output in memory, see
186/// `compress_stream`.
187pub fn compress<C: WriteBuf + ?Sized>(
188    dst: &mut C,
189    src: &[u8],
190    compression_level: CompressionLevel,
191) -> SafeResult {
192    // `ZSTD_compress` allocates its workspace with the C runtime's `malloc`.
193    // Route it through a context built on the Rust global allocator instead;
194    // `ZSTD_compressCCtx` on a fresh context is exactly what `ZSTD_compress`
195    // does internally.
196    #[cfg(feature = "with-rust-allocator")]
197    {
198        let mut cctx = CCtx::try_create().ok_or(MEMORY_ALLOCATION_ERROR)?;
199        cctx.compress(dst, src, compression_level)
200    }
201
202    // Safety: ZSTD_compress indeed returns how many bytes have been written.
203    #[cfg(not(feature = "with-rust-allocator"))]
204    unsafe {
205        dst.write_from(|buffer, capacity| {
206            parse_code(zstd_sys::ZSTD_compress(
207                buffer,
208                capacity,
209                ptr_void(src),
210                src.len(),
211                compression_level,
212            ))
213        })
214    }
215}
216
217/// Wraps the `ZSTD_decompress` function.
218///
219/// This is a one-step decompression (not streaming).
220///
221/// You will need to make sure `dst` is large enough to store all the decompressed content, or an
222/// error will be returned.
223///
224/// If decompression was a success, the number of bytes written will be returned.
225pub fn decompress<C: WriteBuf + ?Sized>(
226    dst: &mut C,
227    src: &[u8],
228) -> SafeResult {
229    // See `compress()`: keep the implicit context's allocations visible to
230    // the Rust global allocator.
231    #[cfg(feature = "with-rust-allocator")]
232    {
233        let mut dctx = DCtx::try_create().ok_or(MEMORY_ALLOCATION_ERROR)?;
234        dctx.decompress(dst, src)
235    }
236
237    // Safety: ZSTD_decompress indeed returns how many bytes have been written.
238    #[cfg(not(feature = "with-rust-allocator"))]
239    unsafe {
240        dst.write_from(|buffer, capacity| {
241            parse_code(zstd_sys::ZSTD_decompress(
242                buffer,
243                capacity,
244                ptr_void(src),
245                src.len(),
246            ))
247        })
248    }
249}
250
251/// Wraps the `ZSTD_getDecompressedSize` function.
252///
253/// Returns `None` if the size could not be found, or if the content is actually empty.
254#[deprecated(note = "Use get_frame_content_size instead.")]
255pub fn get_decompressed_size(src: &[u8]) -> Option<NonZeroU64> {
256    // Safety: Just FFI
257    NonZeroU64::new(unsafe {
258        zstd_sys::ZSTD_getDecompressedSize(ptr_void(src), src.len()) as u64
259    })
260}
261
262/// Maximum compressed size in worst case single-pass scenario
263pub fn compress_bound(src_size: usize) -> usize {
264    // Safety: Just FFI
265    unsafe { zstd_sys::ZSTD_compressBound(src_size) }
266}
267
268/// Remembers an error that may have left a context in a state zstd considers
269/// undefined.
270///
271/// zstd.h says of both `ZSTD_compressStream2()` and `ZSTD_decompressStream()`
272/// that "if an operation ends with an error, it may leave [the context] in an
273/// undefined state", and that calling them again on such a state is undefined
274/// behaviour - the context has to be reset first. So once a streaming
275/// operation fails, refuse to run another one until something resets the
276/// context, and hand the original error back instead.
277#[derive(Clone, Debug, Default)]
278struct Poison(Option<ErrorCode>);
279
280impl Poison {
281    /// Fails with the error that poisoned the context, if there was one.
282    fn guard(&self) -> Result<(), ErrorCode> {
283        match self.0 {
284            Some(code) => Err(code),
285            None => Ok(()),
286        }
287    }
288
289    /// Remembers `res` if it failed, and passes it through.
290    fn record(&mut self, res: SafeResult) -> SafeResult {
291        if let Err(code) = res {
292            self.0 = Some(code);
293        }
294        res
295    }
296
297    /// The context was reset, so it is usable again.
298    fn clear(&mut self) {
299        self.0 = None;
300    }
301}
302
303/// What a `CCtx` knows about its worker threads (`NbWorkers`).
304#[derive(Clone, Copy, Debug, Default)]
305struct Workers {
306    /// `NbWorkers` was ever set to a non-zero value, see `guard_own_tables`.
307    ever: bool,
308    /// `NbWorkers` is currently set to a non-zero value.
309    requested: bool,
310    /// A multithreaded frame was started and not finished.
311    ///
312    /// Its jobs may still be running on the worker threads, reading the
313    /// context's dictionary and job table: zstd only waits for them when the
314    /// next frame starts, or when the context is freed. Until then, nothing
315    /// may free or resize what they use. See `CCtx::wait_for_workers()`.
316    pending: bool,
317}
318
319/// Compression context
320///
321/// It is recommended to allocate a single context per thread and re-use it
322/// for many compression operations.
323pub struct CCtx<'a>(
324    NonNull<zstd_sys::ZSTD_CCtx>,
325    PhantomData<&'a ()>,
326    Poison,
327    Workers,
328);
329
330impl Default for CCtx<'_> {
331    fn default() -> Self {
332        CCtx::create()
333    }
334}
335
336impl<'a> CCtx<'a> {
337    /// Tries to create a new context.
338    ///
339    /// Returns `None` if zstd returns a NULL pointer - may happen if allocation fails.
340    ///
341    /// With the `with-rust-allocator` feature enabled, the context's internal
342    /// allocations go through Rust's global allocator instead of the C
343    /// runtime's `malloc`.
344    pub fn try_create() -> Option<Self> {
345        #[cfg(feature = "with-rust-allocator")]
346        // Safety: the callbacks satisfy zstd's allocation contract and remain
347        // valid for the lifetime of the context.
348        let context = unsafe {
349            zstd_sys::ZSTD_createCCtx_advanced(
350                crate::rust_allocator::RUST_GLOBAL_ALLOCATOR,
351            )
352        };
353        #[cfg(not(feature = "with-rust-allocator"))]
354        // Safety: zstd returns a newly owned context or null.
355        let context = unsafe { zstd_sys::ZSTD_createCCtx() };
356
357        Some(Self(
358            NonNull::new(context)?,
359            PhantomData,
360            Poison::default(),
361            Workers::default(),
362        ))
363    }
364
365    /// Wrap `ZSTD_createCCtx`
366    ///
367    /// # Panics
368    ///
369    /// If zstd returns a NULL pointer.
370    pub fn create() -> Self {
371        Self::try_create()
372            .expect("zstd returned null pointer when creating new context")
373    }
374
375    /// Ends the session of a one-shot compression, and passes `res` through.
376    ///
377    /// zstd.h has these calls imply a reset, but most of them leave the stream
378    /// stage alone (and their source size behind as the pledged one), while
379    /// `ZSTD_compress2()` stays mid-frame when it fails. A later stream call
380    /// would then carry on from a state that still points at buffers and
381    /// dictionaries borrowed for that one call. So reset explicitly: the next
382    /// stream starts from scratch.
383    fn finish_one_shot(&mut self, res: SafeResult) -> SafeResult {
384        self.reset(ResetDirective::SessionOnly).and(res)
385    }
386
387    /// Wraps the `ZSTD_compressCCtx()` function
388    pub fn compress<C: WriteBuf + ?Sized>(
389        &mut self,
390        dst: &mut C,
391        src: &[u8],
392        compression_level: CompressionLevel,
393    ) -> SafeResult {
394        // Safety: ZSTD_compressCCtx returns how many bytes were written.
395        let res = unsafe {
396            dst.write_from(|buffer, capacity| {
397                parse_code(zstd_sys::ZSTD_compressCCtx(
398                    self.0.as_ptr(),
399                    buffer,
400                    capacity,
401                    ptr_void(src),
402                    src.len(),
403                    compression_level,
404                ))
405            })
406        };
407        self.finish_one_shot(res)
408    }
409
410    /// Wraps the `ZSTD_compress2()` function.
411    pub fn compress2<C: WriteBuf + ?Sized>(
412        &mut self,
413        dst: &mut C,
414        src: &[u8],
415    ) -> SafeResult {
416        // Safety: ZSTD_compress2 returns how many bytes were written.
417        let res = unsafe {
418            dst.write_from(|buffer, capacity| {
419                parse_code(zstd_sys::ZSTD_compress2(
420                    self.0.as_ptr(),
421                    buffer,
422                    capacity,
423                    ptr_void(src),
424                    src.len(),
425                ))
426            })
427        };
428        // Unlike the others, this starts by resetting the session, and
429        // ends it when it succeeds. When it fails, it stays mid-frame,
430        // possibly with worker threads still running: leave it so (zstd then
431        // refuses to change the dictionary they read from), and make
432        // streaming calls wait for an explicit reset.
433        self.2.clear();
434        self.track_frame(res.is_ok());
435        self.2.record(res)
436    }
437
438    /// Wraps the `ZSTD_compress_usingDict()` function.
439    pub fn compress_using_dict<C: WriteBuf + ?Sized>(
440        &mut self,
441        dst: &mut C,
442        src: &[u8],
443        dict: &[u8],
444        compression_level: CompressionLevel,
445    ) -> SafeResult {
446        // Safety: ZSTD_compress_usingDict returns how many bytes were written.
447        let res = unsafe {
448            dst.write_from(|buffer, capacity| {
449                parse_code(zstd_sys::ZSTD_compress_usingDict(
450                    self.0.as_ptr(),
451                    buffer,
452                    capacity,
453                    ptr_void(src),
454                    src.len(),
455                    ptr_void(dict),
456                    dict.len(),
457                    compression_level,
458                ))
459            })
460        };
461        self.finish_one_shot(res)
462    }
463
464    /// Wraps the `ZSTD_compress_usingCDict()` function.
465    pub fn compress_using_cdict<C: WriteBuf + ?Sized>(
466        &mut self,
467        dst: &mut C,
468        src: &[u8],
469        cdict: &CDict<'_>,
470    ) -> SafeResult {
471        // Safety: ZSTD_compress_usingCDict returns how many bytes were written.
472        let res = unsafe {
473            dst.write_from(|buffer, capacity| {
474                parse_code(zstd_sys::ZSTD_compress_usingCDict(
475                    self.0.as_ptr(),
476                    buffer,
477                    capacity,
478                    ptr_void(src),
479                    src.len(),
480                    cdict.0.as_ptr(),
481                ))
482            })
483        };
484        self.finish_one_shot(res)
485    }
486
487    /// Initializes the context with the given compression level.
488    ///
489    /// This is equivalent to running:
490    /// * `reset()`
491    /// * `set_parameter(CompressionLevel, compression_level)`
492    ///
493    /// Fails while a multithreaded frame is left unfinished, see
494    /// [`CCtx::wait_for_workers()`].
495    pub fn init(&mut self, compression_level: CompressionLevel) -> SafeResult {
496        // This also unloads the dictionary.
497        self.guard_workers()?;
498        self.2.clear();
499        // Safety: Just FFI
500        let code = unsafe {
501            zstd_sys::ZSTD_initCStream(self.0.as_ptr(), compression_level)
502        };
503        self.2.record(parse_code(code))
504    }
505
506    /// Wraps the `ZSTD_initCStream_srcSize()` function.
507    #[cfg(feature = "experimental")]
508    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
509    #[deprecated(
510        note = "Use reset, set_parameter, and set_pledged_src_size instead."
511    )]
512    pub fn init_src_size(
513        &mut self,
514        compression_level: CompressionLevel,
515        pledged_src_size: u64,
516    ) -> SafeResult {
517        self.guard_workers()?;
518        self.2.clear();
519        // Safety: Just FFI
520        let code = unsafe {
521            zstd_sys::ZSTD_initCStream_srcSize(
522                self.0.as_ptr(),
523                compression_level as c_int,
524                pledged_src_size as c_ulonglong,
525            )
526        };
527        parse_code(code)
528    }
529
530    /// Wraps the `ZSTD_initCStream_usingDict()` function.
531    #[cfg(feature = "experimental")]
532    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
533    #[deprecated(
534        note = "Use reset, set_parameter, and load_dictionary instead."
535    )]
536    pub fn init_using_dict(
537        &mut self,
538        dict: &[u8],
539        compression_level: CompressionLevel,
540    ) -> SafeResult {
541        self.guard_workers()?;
542        self.2.clear();
543        // Safety: Just FFI
544        let code = unsafe {
545            zstd_sys::ZSTD_initCStream_usingDict(
546                self.0.as_ptr(),
547                ptr_void(dict),
548                dict.len(),
549                compression_level,
550            )
551        };
552        parse_code(code)
553    }
554
555    /// Wraps the `ZSTD_initCStream_usingCDict()` function.
556    ///
557    /// Dictionary must outlive the context.
558    ///
559    /// ```compile_fail,E0515
560    /// # #![allow(deprecated)]
561    /// fn compressor() -> zstd_safe::CCtx<'static> {
562    ///     let cdict = zstd_safe::CDict::create(b"dictionary", 3);
563    ///     let mut cctx = zstd_safe::CCtx::create();
564    ///     cctx.init_using_cdict(&cdict).unwrap();
565    ///     cctx // `cdict` would be dropped while `cctx` still points at it.
566    /// }
567    /// ```
568    #[cfg(feature = "experimental")]
569    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
570    #[deprecated(note = "Use reset and ref_cdict instead.")]
571    pub fn init_using_cdict<'b>(&mut self, cdict: &'a CDict<'b>) -> SafeResult
572    where
573        'b: 'a, // Dictionary outlives the stream.
574    {
575        self.guard_workers()?;
576        // Safety: Just FFI
577        let code = unsafe {
578            zstd_sys::ZSTD_initCStream_usingCDict(
579                self.0.as_ptr(),
580                cdict.0.as_ptr(),
581            )
582        };
583        parse_code(code)
584    }
585
586    /// Tries to load a dictionary.
587    ///
588    /// The dictionary content will be copied internally and does not need to be kept alive after
589    /// calling this function.
590    ///
591    /// If you need to use the same dictionary for multiple contexts, it may be more efficient to
592    /// create a `CDict` first, then loads that.
593    ///
594    /// The dictionary will apply to all compressed frames, until a new dictionary is set.
595    ///
596    /// Fails while a multithreaded frame is left unfinished, see
597    /// [`CCtx::wait_for_workers()`].
598    pub fn load_dictionary(&mut self, dict: &[u8]) -> SafeResult {
599        self.guard_workers()?;
600        // Safety: Just FFI
601        parse_code(unsafe {
602            zstd_sys::ZSTD_CCtx_loadDictionary(
603                self.0.as_ptr(),
604                ptr_void(dict),
605                dict.len(),
606            )
607        })
608    }
609
610    /// Wraps the `ZSTD_CCtx_refCDict()` function.
611    ///
612    /// Dictionary must outlive the context.
613    ///
614    /// Fails while a multithreaded frame is left unfinished, see
615    /// [`CCtx::wait_for_workers()`].
616    pub fn ref_cdict<'b>(&mut self, cdict: &'a CDict<'b>) -> SafeResult
617    where
618        'b: 'a,
619    {
620        self.guard_workers()?;
621        // Safety: Just FFI
622        parse_code(unsafe {
623            zstd_sys::ZSTD_CCtx_refCDict(self.0.as_ptr(), cdict.0.as_ptr())
624        })
625    }
626
627    /// Return to "no-dictionary" mode.
628    ///
629    /// This will disable any dictionary/prefix previously registered for future frames.
630    ///
631    /// Fails while a multithreaded frame is left unfinished, see
632    /// [`CCtx::wait_for_workers()`].
633    pub fn disable_dictionary(&mut self) -> SafeResult {
634        self.guard_workers()?;
635        // Safety: Just FFI
636        parse_code(unsafe {
637            zstd_sys::ZSTD_CCtx_loadDictionary(
638                self.0.as_ptr(),
639                core::ptr::null(),
640                0,
641            )
642        })
643    }
644
645    /// Use some prefix as single-use dictionary for the next compressed frame.
646    ///
647    /// Just like a dictionary, decompression will need to be given the same prefix.
648    ///
649    /// This is best used if the "prefix" looks like the data to be compressed.
650    ///
651    /// Fails while a multithreaded frame is left unfinished, see
652    /// [`CCtx::wait_for_workers()`].
653    pub fn ref_prefix<'b>(&mut self, prefix: &'b [u8]) -> SafeResult
654    where
655        'b: 'a,
656    {
657        self.guard_workers()?;
658        // Safety: Just FFI
659        parse_code(unsafe {
660            zstd_sys::ZSTD_CCtx_refPrefix(
661                self.0.as_ptr(),
662                ptr_void(prefix),
663                prefix.len(),
664            )
665        })
666    }
667
668    /// Performs a step of a streaming compression operation.
669    ///
670    /// This will read some data from `input` and/or write some data to `output`.
671    ///
672    /// # Returns
673    ///
674    /// A hint for the "ideal" amount of input data to provide in the next call.
675    ///
676    /// This hint is only for performance purposes.
677    ///
678    /// Wraps the `ZSTD_compressStream()` function.
679    pub fn compress_stream<C: WriteBuf + ?Sized>(
680        &mut self,
681        output: &mut OutBuffer<'_, C>,
682        input: &mut InBuffer<'_>,
683    ) -> SafeResult {
684        self.2.guard()?;
685        let mut output = output.wrap();
686        let mut input = input.wrap();
687        // Safety: Just FFI
688        let code = unsafe {
689            zstd_sys::ZSTD_compressStream(
690                self.0.as_ptr(),
691                ptr_mut(&mut output),
692                ptr_mut(&mut input),
693            )
694        };
695        let res = output.check(parse_code(code));
696        let res = self.2.record(input.check(res));
697        self.track_frame(false);
698        res
699    }
700
701    /// Performs a step of a streaming compression operation.
702    ///
703    /// This will read some data from `input` and/or write some data to `output`.
704    ///
705    /// The `end_op` directive can be used to specify what to do after: nothing special, flush
706    /// internal buffers, or end the frame.
707    ///
708    /// # Returns
709    ///
710    /// An lower bound for the amount of data that still needs to be flushed out.
711    ///
712    /// This is useful when flushing or ending the frame: you need to keep calling this function
713    /// until it returns 0.
714    ///
715    /// Wraps the `ZSTD_compressStream2()` function.
716    pub fn compress_stream2<C: WriteBuf + ?Sized>(
717        &mut self,
718        output: &mut OutBuffer<'_, C>,
719        input: &mut InBuffer<'_>,
720        end_op: zstd_sys::ZSTD_EndDirective,
721    ) -> SafeResult {
722        self.2.guard()?;
723        let mut output = output.wrap();
724        let mut input = input.wrap();
725        // Safety: Just FFI
726        let code = unsafe {
727            zstd_sys::ZSTD_compressStream2(
728                self.0.as_ptr(),
729                ptr_mut(&mut output),
730                ptr_mut(&mut input),
731                end_op,
732            )
733        };
734        let res = output.check(parse_code(code));
735        let res = self.2.record(input.check(res));
736        self.track_frame(
737            end_op == zstd_sys::ZSTD_EndDirective::ZSTD_e_end && res == Ok(0),
738        );
739        res
740    }
741
742    /// Flush any intermediate buffer.
743    ///
744    /// To fully flush, you should keep calling this function until it returns `Ok(0)`.
745    ///
746    /// Wraps the `ZSTD_flushStream()` function.
747    pub fn flush_stream<C: WriteBuf + ?Sized>(
748        &mut self,
749        output: &mut OutBuffer<'_, C>,
750    ) -> SafeResult {
751        self.2.guard()?;
752        let mut output = output.wrap();
753        // Safety: Just FFI
754        let code = unsafe {
755            zstd_sys::ZSTD_flushStream(self.0.as_ptr(), ptr_mut(&mut output))
756        };
757        let res = self.2.record(output.check(parse_code(code)));
758        self.track_frame(false);
759        res
760    }
761
762    /// Ends the stream.
763    ///
764    /// You should keep calling this function until it returns `Ok(0)`.
765    ///
766    /// Wraps the `ZSTD_endStream()` function.
767    pub fn end_stream<C: WriteBuf + ?Sized>(
768        &mut self,
769        output: &mut OutBuffer<'_, C>,
770    ) -> SafeResult {
771        self.2.guard()?;
772        let mut output = output.wrap();
773        // Safety: Just FFI
774        let code = unsafe {
775            zstd_sys::ZSTD_endStream(self.0.as_ptr(), ptr_mut(&mut output))
776        };
777        let res = self.2.record(output.check(parse_code(code)));
778        self.track_frame(res == Ok(0));
779        res
780    }
781
782    /// Records whether a streaming call left a multithreaded frame open.
783    fn track_frame(&mut self, frame_ended: bool) {
784        if self.3.requested {
785            self.3.pending = !frame_ended;
786        }
787    }
788
789    /// Fails if worker threads may still be running jobs of an unfinished
790    /// frame, see `Workers::pending`.
791    fn guard_workers(&self) -> Result<(), ErrorCode> {
792        if self.3.pending {
793            return Err(STAGE_WRONG_ERROR);
794        }
795        Ok(())
796    }
797
798    /// Abandons the current frame, if any, and waits for the worker threads
799    /// to be done with it.
800    ///
801    /// When a multithreaded frame (see `CParameter::NbWorkers`) is left
802    /// unfinished - abandoned, or interrupted by an error - its jobs may
803    /// still be running, reading the dictionary. zstd only waits for them
804    /// when the next frame starts or when the context is dropped. Until then,
805    /// anything that would unload the dictionary or change `NbWorkers` fails
806    /// with a `stage_wrong` error instead: `load_dictionary()`,
807    /// `ref_cdict()`, `ref_prefix()`, `disable_dictionary()`, `init()`, and
808    /// `reset()` with parameters.
809    ///
810    /// Calling this first lets them succeed. Like `reset(SessionOnly)`, it
811    /// discards the current frame and any pledged source size, and keeps
812    /// parameters and dictionary. It does nothing if no multithreaded frame
813    /// is unfinished.
814    pub fn wait_for_workers(&mut self) -> SafeResult {
815        if !self.3.pending {
816            return Ok(0);
817        }
818        self.reset(ResetDirective::SessionOnly)?;
819
820        // Starting a new frame is what makes zstd wait for the jobs of the
821        // previous one. With no input, this one has no jobs of its own.
822        let mut output = OutBuffer::around(&mut [][..]);
823        let mut input = InBuffer::around(&[]);
824        self.compress_stream2(
825            &mut output,
826            &mut input,
827            zstd_sys::ZSTD_EndDirective::ZSTD_e_continue,
828        )?;
829
830        self.reset(ResetDirective::SessionOnly)?;
831        self.3.pending = false;
832        Ok(0)
833    }
834
835    /// Returns the size currently used by this context.
836    ///
837    /// This may change over time.
838    pub fn sizeof(&self) -> usize {
839        // Safety: Just FFI
840        unsafe { zstd_sys::ZSTD_sizeof_CCtx(self.0.as_ptr()) }
841    }
842
843    /// Resets the state of the context.
844    ///
845    /// Depending on the reset mode, it can reset the session, the parameters, or both.
846    ///
847    /// Resetting the parameters also unloads the dictionary: this fails while
848    /// a multithreaded frame is left unfinished, see
849    /// [`CCtx::wait_for_workers()`]. Resetting only the session never does.
850    ///
851    /// Wraps the `ZSTD_CCtx_reset()` function.
852    pub fn reset(&mut self, reset: ResetDirective) -> SafeResult {
853        if !matches!(reset, ResetDirective::SessionOnly) {
854            self.guard_workers()?;
855        }
856        // Safety: Just FFI
857        let res = parse_code(unsafe {
858            zstd_sys::ZSTD_CCtx_reset(self.0.as_ptr(), reset.as_sys())
859        });
860        if res.is_ok() && reset.resets_session() {
861            self.2.clear();
862        }
863        if res.is_ok() && !matches!(reset, ResetDirective::SessionOnly) {
864            self.3.requested = false;
865        }
866        res
867    }
868
869    /// Sets a compression parameter.
870    ///
871    /// Some of these parameters need to be set during de-compression as well.
872    ///
873    /// Changing `NbWorkers` fails while a multithreaded frame is left
874    /// unfinished, see [`CCtx::wait_for_workers()`].
875    pub fn set_parameter(&mut self, param: CParameter) -> SafeResult {
876        if let CParameter::NbWorkers(_) = param {
877            // zstd would resize the job table the old jobs still use.
878            self.guard_workers()?;
879        }
880        // TODO: Until bindgen properly generates a binding for this, we'll need to do it here.
881
882        #[cfg(feature = "experimental")]
883        use zstd_sys::ZSTD_cParameter::{
884            ZSTD_c_experimentalParam1 as ZSTD_c_rsyncable,
885            ZSTD_c_experimentalParam10 as ZSTD_c_stableOutBuffer,
886            ZSTD_c_experimentalParam11 as ZSTD_c_blockDelimiters,
887            ZSTD_c_experimentalParam12 as ZSTD_c_validateSequences,
888            ZSTD_c_experimentalParam13 as ZSTD_c_useBlockSplitter,
889            ZSTD_c_experimentalParam14 as ZSTD_c_useRowMatchFinder,
890            ZSTD_c_experimentalParam15 as ZSTD_c_deterministicRefPrefix,
891            ZSTD_c_experimentalParam16 as ZSTD_c_prefetchCDictTables,
892            ZSTD_c_experimentalParam17 as ZSTD_c_enableSeqProducerFallback,
893            ZSTD_c_experimentalParam18 as ZSTD_c_maxBlockSize,
894            ZSTD_c_experimentalParam19 as ZSTD_c_searchForExternalRepcodes,
895            ZSTD_c_experimentalParam2 as ZSTD_c_format,
896            ZSTD_c_experimentalParam3 as ZSTD_c_forceMaxWindow,
897            ZSTD_c_experimentalParam4 as ZSTD_c_forceAttachDict,
898            ZSTD_c_experimentalParam5 as ZSTD_c_literalCompressionMode,
899            ZSTD_c_experimentalParam7 as ZSTD_c_srcSizeHint,
900            ZSTD_c_experimentalParam8 as ZSTD_c_enableDedicatedDictSearch,
901            ZSTD_c_experimentalParam9 as ZSTD_c_stableInBuffer,
902        };
903
904        use zstd_sys::ZSTD_cParameter::*;
905        use CParameter::*;
906
907        let (param, value) = match param {
908            #[cfg(feature = "experimental")]
909            RSyncable(rsyncable) => (ZSTD_c_rsyncable, rsyncable as c_int),
910            #[cfg(feature = "experimental")]
911            Format(format) => (ZSTD_c_format, format as c_int),
912            #[cfg(feature = "experimental")]
913            ForceMaxWindow(force) => (ZSTD_c_forceMaxWindow, force as c_int),
914            #[cfg(feature = "experimental")]
915            ForceAttachDict(force) => (ZSTD_c_forceAttachDict, force as c_int),
916            #[cfg(feature = "experimental")]
917            LiteralCompressionMode(mode) => {
918                (ZSTD_c_literalCompressionMode, mode as c_int)
919            }
920            #[cfg(feature = "experimental")]
921            SrcSizeHint(value) => (ZSTD_c_srcSizeHint, value as c_int),
922            #[cfg(feature = "experimental")]
923            EnableDedicatedDictSearch(enable) => {
924                (ZSTD_c_enableDedicatedDictSearch, enable as c_int)
925            }
926            // In stable mode zstd keeps reading from the `InBuffer` of one
927            // call during `flush_stream`/`end_stream`, but the slice is only
928            // borrowed for that one call: the safe API cannot uphold this.
929            #[cfg(feature = "experimental")]
930            StableInBuffer(true) => return Err(PARAMETER_UNSUPPORTED_ERROR),
931            #[cfg(feature = "experimental")]
932            StableInBuffer(false) => (ZSTD_c_stableInBuffer, 0),
933            #[cfg(feature = "experimental")]
934            StableOutBuffer(stable) => {
935                (ZSTD_c_stableOutBuffer, stable as c_int)
936            }
937            #[cfg(feature = "experimental")]
938            BlockDelimiters(value) => (ZSTD_c_blockDelimiters, value as c_int),
939            #[cfg(feature = "experimental")]
940            ValidateSequences(validate) => {
941                (ZSTD_c_validateSequences, validate as c_int)
942            }
943            #[cfg(feature = "experimental")]
944            UseBlockSplitter(split) => {
945                (ZSTD_c_useBlockSplitter, split as c_int)
946            }
947            #[cfg(feature = "experimental")]
948            UseRowMatchFinder(mode) => {
949                (ZSTD_c_useRowMatchFinder, mode as c_int)
950            }
951            #[cfg(feature = "experimental")]
952            DeterministicRefPrefix(deterministic) => {
953                (ZSTD_c_deterministicRefPrefix, deterministic as c_int)
954            }
955            #[cfg(feature = "experimental")]
956            PrefetchCDictTables(prefetch) => {
957                (ZSTD_c_prefetchCDictTables, prefetch as c_int)
958            }
959            #[cfg(feature = "experimental")]
960            EnableSeqProducerFallback(enable) => {
961                (ZSTD_c_enableSeqProducerFallback, enable as c_int)
962            }
963            #[cfg(feature = "experimental")]
964            MaxBlockSize(value) => (ZSTD_c_maxBlockSize, value as c_int),
965            #[cfg(feature = "experimental")]
966            SearchForExternalRepcodes(value) => {
967                (ZSTD_c_searchForExternalRepcodes, value as c_int)
968            }
969            TargetCBlockSize(value) => {
970                (ZSTD_c_targetCBlockSize, value as c_int)
971            }
972            CompressionLevel(level) => (ZSTD_c_compressionLevel, level),
973            WindowLog(value) => (ZSTD_c_windowLog, value as c_int),
974            HashLog(value) => (ZSTD_c_hashLog, value as c_int),
975            ChainLog(value) => (ZSTD_c_chainLog, value as c_int),
976            SearchLog(value) => (ZSTD_c_searchLog, value as c_int),
977            MinMatch(value) => (ZSTD_c_minMatch, value as c_int),
978            TargetLength(value) => (ZSTD_c_targetLength, value as c_int),
979            Strategy(strategy) => (ZSTD_c_strategy, strategy as c_int),
980            EnableLongDistanceMatching(flag) => {
981                (ZSTD_c_enableLongDistanceMatching, flag as c_int)
982            }
983            LdmHashLog(value) => (ZSTD_c_ldmHashLog, value as c_int),
984            LdmMinMatch(value) => (ZSTD_c_ldmMinMatch, value as c_int),
985            LdmBucketSizeLog(value) => {
986                (ZSTD_c_ldmBucketSizeLog, value as c_int)
987            }
988            LdmHashRateLog(value) => (ZSTD_c_ldmHashRateLog, value as c_int),
989            ContentSizeFlag(flag) => (ZSTD_c_contentSizeFlag, flag as c_int),
990            ChecksumFlag(flag) => (ZSTD_c_checksumFlag, flag as c_int),
991            DictIdFlag(flag) => (ZSTD_c_dictIDFlag, flag as c_int),
992
993            NbWorkers(value) => (ZSTD_c_nbWorkers, value as c_int),
994
995            JobSize(value) => (ZSTD_c_jobSize, value as c_int),
996
997            OverlapSizeLog(value) => (ZSTD_c_overlapLog, value as c_int),
998        };
999
1000        // Safety: Just FFI
1001        let res = parse_code(unsafe {
1002            zstd_sys::ZSTD_CCtx_setParameter(self.0.as_ptr(), param, value)
1003        });
1004        if res.is_ok() && matches!(param, ZSTD_c_nbWorkers) {
1005            self.3.requested = value != 0;
1006            self.3.ever |= value != 0;
1007        }
1008        res
1009    }
1010
1011    /// Guarantee that the input size will be this value.
1012    ///
1013    /// If given `None`, assumes the size is unknown.
1014    ///
1015    /// Unless explicitly disabled, this will cause the size to be written in the compressed frame
1016    /// header.
1017    ///
1018    /// If the actual data given to compress has a different size, an error will be returned.
1019    pub fn set_pledged_src_size(
1020        &mut self,
1021        pledged_src_size: Option<u64>,
1022    ) -> SafeResult {
1023        // Safety: Just FFI
1024        parse_code(unsafe {
1025            zstd_sys::ZSTD_CCtx_setPledgedSrcSize(
1026                self.0.as_ptr(),
1027                pledged_src_size.unwrap_or(CONTENTSIZE_UNKNOWN) as c_ulonglong,
1028            )
1029        })
1030    }
1031
1032    /// Fails if the tables of this context may not be the ones its applied
1033    /// parameters describe.
1034    ///
1035    /// Starting a multi-threaded frame overwrites the applied parameters with
1036    /// those of the workers, but leaves the context's own stage and workspace
1037    /// as the last single-threaded frame left them. If that frame was
1038    /// abandoned before its first block, zstd still accepts the calls that
1039    /// work on this context directly, and overruns a workspace that was sized
1040    /// for other parameters. The applied parameters cannot be queried, so
1041    /// refuse these calls as soon as a multi-threaded frame could have been
1042    /// started.
1043    #[cfg(feature = "experimental")]
1044    fn guard_own_tables(&self) -> Result<(), ErrorCode> {
1045        if self.3.ever {
1046            return Err(STAGE_WRONG_ERROR);
1047        }
1048        Ok(())
1049    }
1050
1051    /// Creates a copy of this context.
1052    ///
1053    /// This only works before any data has been compressed. An error will be
1054    /// returned otherwise.
1055    /// A poisoned context cannot be cloned until its session is reset.
1056    /// A context on which `NbWorkers` was ever set to a non-zero value cannot
1057    /// be cloned anymore.
1058    #[cfg(feature = "experimental")]
1059    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1060    #[deprecated(
1061        note = "Context copying is deprecated by zstd; create a new context and configure it instead."
1062    )]
1063    pub fn try_clone(
1064        &self,
1065        pledged_src_size: Option<u64>,
1066    ) -> Result<Self, ErrorCode> {
1067        // An error may leave the C context undefined; do not copy it.
1068        self.2.guard()?;
1069        self.guard_own_tables()?;
1070        // zstd copies the allocator callbacks from `self` into the new
1071        // context, so both must be created the same way; `try_create` always
1072        // picks the same allocator within a build.
1073        let context = Self::try_create().ok_or(MEMORY_ALLOCATION_ERROR)?;
1074
1075        // Safety: Just FFI
1076        parse_code(unsafe {
1077            zstd_sys::ZSTD_copyCCtx(
1078                context.0.as_ptr(),
1079                self.0.as_ptr(),
1080                pledged_src_size.unwrap_or(CONTENTSIZE_UNKNOWN),
1081            )
1082        })?;
1083
1084        Ok(context)
1085    }
1086
1087    /// Wraps the `ZSTD_getBlockSize()` function.
1088    #[cfg(feature = "experimental")]
1089    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1090    #[deprecated(
1091        note = "The block API is deprecated; use the normal compression API instead."
1092    )]
1093    pub fn get_block_size(&self) -> usize {
1094        // Safety: Just FFI
1095        unsafe { zstd_sys::ZSTD_getBlockSize(self.0.as_ptr()) }
1096    }
1097
1098    /// Wraps the `ZSTD_compressBlock()` function.
1099    ///
1100    /// Returns an error once `NbWorkers` was set to a non-zero value on this
1101    /// context.
1102    ///
1103    /// # Safety
1104    ///
1105    /// `src` becomes this context's history window, so it must stay allocated and unmodified until
1106    /// the next call to `compress_block` on this context (or until this context is dropped), as the
1107    /// following block is compressed against it.
1108    #[cfg(feature = "experimental")]
1109    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1110    #[deprecated(
1111        note = "The block API is deprecated; use compress_stream2 instead."
1112    )]
1113    pub unsafe fn compress_block<C: WriteBuf + ?Sized>(
1114        &mut self,
1115        dst: &mut C,
1116        src: &[u8],
1117    ) -> SafeResult {
1118        self.guard_own_tables()?;
1119        // Safety: ZSTD_compressBlock returns the number of bytes written.
1120        unsafe {
1121            dst.write_from(|buffer, capacity| {
1122                parse_code(zstd_sys::ZSTD_compressBlock(
1123                    self.0.as_ptr(),
1124                    buffer,
1125                    capacity,
1126                    ptr_void(src),
1127                    src.len(),
1128                ))
1129            })
1130        }
1131    }
1132
1133    /// Returns the recommended input buffer size.
1134    ///
1135    /// Using this size may result in minor performance boost.
1136    pub fn in_size() -> usize {
1137        // Safety: Just FFI
1138        unsafe { zstd_sys::ZSTD_CStreamInSize() }
1139    }
1140
1141    /// Returns the recommended output buffer size.
1142    ///
1143    /// Using this may result in minor performance boost.
1144    pub fn out_size() -> usize {
1145        // Safety: Just FFI
1146        unsafe { zstd_sys::ZSTD_CStreamOutSize() }
1147    }
1148
1149    /// Use a shared thread pool for this context.
1150    ///
1151    /// Thread pool must outlive the context.
1152    #[cfg(all(feature = "experimental", feature = "zstdmt"))]
1153    #[cfg_attr(
1154        feature = "doc-cfg",
1155        doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1156    )]
1157    pub fn ref_thread_pool<'b>(&mut self, pool: &'b ThreadPool) -> SafeResult
1158    where
1159        'b: 'a,
1160    {
1161        parse_code(unsafe {
1162            zstd_sys::ZSTD_CCtx_refThreadPool(self.0.as_ptr(), pool.0.as_ptr())
1163        })
1164    }
1165
1166    /// Return to using a private thread pool for this context.
1167    #[cfg(all(feature = "experimental", feature = "zstdmt"))]
1168    #[cfg_attr(
1169        feature = "doc-cfg",
1170        doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1171    )]
1172    pub fn disable_thread_pool(&mut self) -> SafeResult {
1173        parse_code(unsafe {
1174            zstd_sys::ZSTD_CCtx_refThreadPool(
1175                self.0.as_ptr(),
1176                core::ptr::null_mut(),
1177            )
1178        })
1179    }
1180
1181    #[cfg(feature = "experimental")]
1182    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1183    pub fn get_frame_progression(&self) -> FrameProgression {
1184        // Safety: Just FFI
1185        unsafe { zstd_sys::ZSTD_getFrameProgression(self.0.as_ptr()) }
1186    }
1187}
1188
1189impl<'a> Drop for CCtx<'a> {
1190    fn drop(&mut self) {
1191        // Safety: Just FFI
1192        unsafe {
1193            zstd_sys::ZSTD_freeCCtx(self.0.as_ptr());
1194        }
1195    }
1196}
1197
1198// Safety: the context is a plain heap allocation this handle owns; zstd keeps
1199// no thread-local state for it, so it can be moved between threads.
1200unsafe impl Send for CCtx<'_> {}
1201// Safety: every method that mutates the context takes `&mut self`, so a shared
1202// `&CCtx` only ever reads. There is no interior mutability to race on.
1203unsafe impl Sync for CCtx<'_> {}
1204
1205/// Converts a zstd-owned C string to a `str`.
1206///
1207/// # Safety
1208///
1209/// `text` must point to a nul-terminated C string that lives for the rest of
1210/// the program - which is what the zstd functions this is used with return,
1211/// as they hand back pointers to static string literals.
1212unsafe fn c_char_to_str(text: *const c_char) -> &'static str {
1213    // Safety: guaranteed by the caller, see above.
1214    core::ffi::CStr::from_ptr(text)
1215        .to_str()
1216        .expect("bad error message from zstd")
1217}
1218
1219/// Returns the error string associated with an error code.
1220pub fn get_error_name(code: usize) -> &'static str {
1221    unsafe {
1222        // Safety: assumes ZSTD returns a well-formed utf8 string.
1223        let name = zstd_sys::ZSTD_getErrorName(code);
1224        c_char_to_str(name)
1225    }
1226}
1227
1228/// A Decompression Context.
1229///
1230/// The lifetime references the potential dictionary used for this context.
1231///
1232/// If no dictionary was used, it will most likely be `'static`.
1233///
1234/// Same as `DStream`.
1235pub struct DCtx<'a>(
1236    NonNull<zstd_sys::ZSTD_DCtx>,
1237    PhantomData<&'a ()>,
1238    Poison,
1239    DState,
1240);
1241
1242/// What a `DCtx` remembers about its own use.
1243#[derive(Clone, Copy, Debug, Default)]
1244struct DState {
1245    /// `RefMultipleDDicts` was ever enabled, see `try_clone`.
1246    #[cfg(feature = "experimental")]
1247    multiple_ddicts: bool,
1248    /// A streaming (or block) call ran since the session was last reset, so
1249    /// a stream may be open, see `finish_one_shot`.
1250    streamed: bool,
1251}
1252
1253impl Default for DCtx<'_> {
1254    fn default() -> Self {
1255        DCtx::create()
1256    }
1257}
1258
1259impl<'a> DCtx<'a> {
1260    /// Try to create a new decompression context.
1261    ///
1262    /// Returns `None` if the operation failed (for example, not enough memory).
1263    ///
1264    /// With the `with-rust-allocator` feature enabled, the context's internal
1265    /// allocations go through Rust's global allocator instead of the C
1266    /// runtime's `malloc`.
1267    pub fn try_create() -> Option<Self> {
1268        #[cfg(feature = "with-rust-allocator")]
1269        // Safety: the callbacks satisfy zstd's allocation contract and remain
1270        // valid for the lifetime of the context.
1271        let context = unsafe {
1272            zstd_sys::ZSTD_createDCtx_advanced(
1273                crate::rust_allocator::RUST_GLOBAL_ALLOCATOR,
1274            )
1275        };
1276        #[cfg(not(feature = "with-rust-allocator"))]
1277        // Safety: zstd returns a newly owned context or null.
1278        let context = unsafe { zstd_sys::ZSTD_createDCtx() };
1279
1280        Some(Self(
1281            NonNull::new(context)?,
1282            PhantomData,
1283            Poison::default(),
1284            DState::default(),
1285        ))
1286    }
1287
1288    /// Creates a new decoding context.
1289    ///
1290    /// # Panics
1291    ///
1292    /// If the context creation fails.
1293    pub fn create() -> Self {
1294        Self::try_create()
1295            .expect("zstd returned null pointer when creating new context")
1296    }
1297
1298    /// Ends the session of a one-shot decompression, and passes `res` through.
1299    ///
1300    /// zstd.h has these calls imply a reset, but they leave the stream stage
1301    /// alone. A stream they interrupted would then carry on from a state that
1302    /// still points at buffers and dictionaries borrowed for that one call. So
1303    /// reset explicitly: the next stream starts from scratch.
1304    ///
1305    /// Only an open stream can carry on, though: a new one starts by setting
1306    /// everything up again from the context's own dictionary. So when no
1307    /// streaming call ran since the last reset, there is nothing to end, and
1308    /// skipping the reset saves a call per frame - which shows on tiny ones.
1309    ///
1310    /// Only the check is inlined: it runs once per frame.
1311    #[inline]
1312    fn finish_one_shot(&mut self, res: SafeResult) -> SafeResult {
1313        if self.3.streamed || self.2.guard().is_err() {
1314            self.reset_after_one_shot(res)
1315        } else {
1316            res
1317        }
1318    }
1319
1320    #[cold]
1321    #[inline(never)]
1322    fn reset_after_one_shot(&mut self, res: SafeResult) -> SafeResult {
1323        self.reset(ResetDirective::SessionOnly).and(res)
1324    }
1325
1326    /// Fully decompress the given frame.
1327    ///
1328    /// This decompress an entire frame in-memory. If you can have enough memory to store both the
1329    /// input and output buffer, then it may be faster that streaming decompression.
1330    ///
1331    /// Wraps the `ZSTD_decompressDCtx()` function.
1332    pub fn decompress<C: WriteBuf + ?Sized>(
1333        &mut self,
1334        dst: &mut C,
1335        src: &[u8],
1336    ) -> SafeResult {
1337        let res = unsafe {
1338            dst.write_from(|buffer, capacity| {
1339                parse_code(zstd_sys::ZSTD_decompressDCtx(
1340                    self.0.as_ptr(),
1341                    buffer,
1342                    capacity,
1343                    ptr_void(src),
1344                    src.len(),
1345                ))
1346            })
1347        };
1348        self.finish_one_shot(res)
1349    }
1350
1351    /// Fully decompress the given frame using a dictionary.
1352    ///
1353    /// Dictionary must be identical to the one used during compression.
1354    ///
1355    /// If you plan on using the same dictionary multiple times, it is faster to create a `DDict`
1356    /// first and use `decompress_using_ddict`.
1357    ///
1358    /// Wraps `ZSTD_decompress_usingDict`
1359    pub fn decompress_using_dict<C: WriteBuf + ?Sized>(
1360        &mut self,
1361        dst: &mut C,
1362        src: &[u8],
1363        dict: &[u8],
1364    ) -> SafeResult {
1365        let res = unsafe {
1366            dst.write_from(|buffer, capacity| {
1367                parse_code(zstd_sys::ZSTD_decompress_usingDict(
1368                    self.0.as_ptr(),
1369                    buffer,
1370                    capacity,
1371                    ptr_void(src),
1372                    src.len(),
1373                    ptr_void(dict),
1374                    dict.len(),
1375                ))
1376            })
1377        };
1378        self.finish_one_shot(res)
1379    }
1380
1381    /// Fully decompress the given frame using a dictionary.
1382    ///
1383    /// Dictionary must be identical to the one used during compression.
1384    ///
1385    /// Wraps the `ZSTD_decompress_usingDDict()` function.
1386    pub fn decompress_using_ddict<C: WriteBuf + ?Sized>(
1387        &mut self,
1388        dst: &mut C,
1389        src: &[u8],
1390        ddict: &DDict<'_>,
1391    ) -> SafeResult {
1392        let res = unsafe {
1393            dst.write_from(|buffer, capacity| {
1394                parse_code(zstd_sys::ZSTD_decompress_usingDDict(
1395                    self.0.as_ptr(),
1396                    buffer,
1397                    capacity,
1398                    ptr_void(src),
1399                    src.len(),
1400                    ddict.0.as_ptr(),
1401                ))
1402            })
1403        };
1404        self.finish_one_shot(res)
1405    }
1406
1407    /// Initializes an existing `DStream` for decompression.
1408    ///
1409    /// This is equivalent to calling:
1410    /// * `reset(SessionOnly)`
1411    /// * `disable_dictionary()`
1412    ///
1413    /// Wraps the `ZSTD_initCStream()` function.
1414    pub fn init(&mut self) -> SafeResult {
1415        self.2.clear();
1416        let code = unsafe { zstd_sys::ZSTD_initDStream(self.0.as_ptr()) };
1417        self.2.record(parse_code(code))
1418    }
1419
1420    /// Wraps the `ZSTD_initDStream_usingDict()` function.
1421    #[cfg(feature = "experimental")]
1422    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1423    #[deprecated(note = "Use reset and load_dictionary instead.")]
1424    pub fn init_using_dict(&mut self, dict: &[u8]) -> SafeResult {
1425        self.2.clear();
1426        self.2.clear();
1427        let code = unsafe {
1428            zstd_sys::ZSTD_initDStream_usingDict(
1429                self.0.as_ptr(),
1430                ptr_void(dict),
1431                dict.len(),
1432            )
1433        };
1434        parse_code(code)
1435    }
1436
1437    /// Wraps the `ZSTD_initDStream_usingDDict()` function.
1438    ///
1439    /// Dictionary must outlive the context.
1440    ///
1441    /// ```compile_fail,E0515
1442    /// # #![allow(deprecated)]
1443    /// fn decompressor() -> zstd_safe::DCtx<'static> {
1444    ///     let ddict = zstd_safe::DDict::create(b"dictionary");
1445    ///     let mut dctx = zstd_safe::DCtx::create();
1446    ///     dctx.init_using_ddict(&ddict).unwrap();
1447    ///     dctx // `ddict` would be dropped while `dctx` still points at it.
1448    /// }
1449    /// ```
1450    #[cfg(feature = "experimental")]
1451    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1452    #[deprecated(note = "Use reset and ref_ddict instead.")]
1453    pub fn init_using_ddict<'b>(&mut self, ddict: &'a DDict<'b>) -> SafeResult
1454    where
1455        'b: 'a,
1456    {
1457        let code = unsafe {
1458            zstd_sys::ZSTD_initDStream_usingDDict(
1459                self.0.as_ptr(),
1460                ddict.0.as_ptr(),
1461            )
1462        };
1463        parse_code(code)
1464    }
1465
1466    /// Resets the state of the context.
1467    ///
1468    /// Depending on the reset mode, it can reset the session, the parameters, or both.
1469    ///
1470    /// Wraps the `ZSTD_DCtx_reset()` function.
1471    pub fn reset(&mut self, reset: ResetDirective) -> SafeResult {
1472        let res = parse_code(unsafe {
1473            zstd_sys::ZSTD_DCtx_reset(self.0.as_ptr(), reset.as_sys())
1474        });
1475        if res.is_ok() && reset.resets_session() {
1476            self.2.clear();
1477            self.3.streamed = false;
1478        }
1479        res
1480    }
1481
1482    /// Loads a dictionary.
1483    ///
1484    /// This will let this context decompress frames that were compressed using this dictionary.
1485    ///
1486    /// The dictionary content will be copied internally and does not need to be kept alive after
1487    /// calling this function.
1488    ///
1489    /// If you need to use the same dictionary for multiple contexts, it may be more efficient to
1490    /// create a `DDict` first, then loads that.
1491    ///
1492    /// The dictionary will apply to all future frames, until a new dictionary is set.
1493    pub fn load_dictionary(&mut self, dict: &[u8]) -> SafeResult {
1494        parse_code(unsafe {
1495            zstd_sys::ZSTD_DCtx_loadDictionary(
1496                self.0.as_ptr(),
1497                ptr_void(dict),
1498                dict.len(),
1499            )
1500        })
1501    }
1502
1503    /// Return to "no-dictionary" mode.
1504    ///
1505    /// This will disable any dictionary/prefix previously registered for future frames.
1506    pub fn disable_dictionary(&mut self) -> SafeResult {
1507        parse_code(unsafe {
1508            zstd_sys::ZSTD_DCtx_loadDictionary(
1509                self.0.as_ptr(),
1510                core::ptr::null(),
1511                0,
1512            )
1513        })
1514    }
1515
1516    /// References a dictionary.
1517    ///
1518    /// This will let this context decompress frames compressed with the same dictionary.
1519    ///
1520    /// It will apply to all frames decompressed by this context (until a new dictionary is set).
1521    ///
1522    /// Wraps the `ZSTD_DCtx_refDDict()` function.
1523    ///
1524    /// Dictionary must outlive the context.
1525    pub fn ref_ddict<'b>(&mut self, ddict: &'a DDict<'b>) -> SafeResult
1526    where
1527        'b: 'a,
1528    {
1529        parse_code(unsafe {
1530            zstd_sys::ZSTD_DCtx_refDDict(self.0.as_ptr(), ddict.0.as_ptr())
1531        })
1532    }
1533
1534    /// Use some prefix as single-use dictionary for the next frame.
1535    ///
1536    /// Just like a dictionary, this only works if compression was done with the same prefix.
1537    ///
1538    /// But unlike a dictionary, this only applies to the next frame.
1539    ///
1540    /// Wraps the `ZSTD_DCtx_refPrefix()` function.
1541    pub fn ref_prefix<'b>(&mut self, prefix: &'b [u8]) -> SafeResult
1542    where
1543        'b: 'a,
1544    {
1545        parse_code(unsafe {
1546            zstd_sys::ZSTD_DCtx_refPrefix(
1547                self.0.as_ptr(),
1548                ptr_void(prefix),
1549                prefix.len(),
1550            )
1551        })
1552    }
1553
1554    /// Sets a decompression parameter.
1555    pub fn set_parameter(&mut self, param: DParameter) -> SafeResult {
1556        #[cfg(feature = "experimental")]
1557        use zstd_sys::ZSTD_dParameter::{
1558            ZSTD_d_experimentalParam1 as ZSTD_d_format,
1559            ZSTD_d_experimentalParam2 as ZSTD_d_stableOutBuffer,
1560            ZSTD_d_experimentalParam3 as ZSTD_d_forceIgnoreChecksum,
1561            ZSTD_d_experimentalParam4 as ZSTD_d_refMultipleDDicts,
1562        };
1563
1564        use zstd_sys::ZSTD_dParameter::*;
1565        use DParameter::*;
1566
1567        let (param, value) = match param {
1568            #[cfg(feature = "experimental")]
1569            Format(format) => (ZSTD_d_format, format as c_int),
1570            #[cfg(feature = "experimental")]
1571            StableOutBuffer(stable) => {
1572                (ZSTD_d_stableOutBuffer, stable as c_int)
1573            }
1574            #[cfg(feature = "experimental")]
1575            ForceIgnoreChecksum(force) => {
1576                (ZSTD_d_forceIgnoreChecksum, force as c_int)
1577            }
1578            #[cfg(feature = "experimental")]
1579            RefMultipleDDicts(value) => {
1580                // From now on `ref_ddict` may allocate the table of
1581                // dictionaries, which zstd keeps until the context is freed.
1582                self.3.multiple_ddicts |= value;
1583                (ZSTD_d_refMultipleDDicts, value as c_int)
1584            }
1585
1586            WindowLogMax(value) => (ZSTD_d_windowLogMax, value as c_int),
1587        };
1588
1589        parse_code(unsafe {
1590            zstd_sys::ZSTD_DCtx_setParameter(self.0.as_ptr(), param, value)
1591        })
1592    }
1593
1594    /// Performs a step of a streaming decompression operation.
1595    ///
1596    /// This will read some data from `input` and/or write some data to `output`.
1597    ///
1598    /// # Returns
1599    ///
1600    /// * `Ok(0)` if the current frame just finished decompressing successfully.
1601    /// * `Ok(hint)` with a hint for the "ideal" amount of input data to provide in the next call.
1602    ///   Can be safely ignored.
1603    ///
1604    /// Wraps the `ZSTD_decompressStream()` function.
1605    pub fn decompress_stream<C: WriteBuf + ?Sized>(
1606        &mut self,
1607        output: &mut OutBuffer<'_, C>,
1608        input: &mut InBuffer<'_>,
1609    ) -> SafeResult {
1610        self.2.guard()?;
1611        self.3.streamed = true;
1612        let mut output = output.wrap();
1613        let mut input = input.wrap();
1614        let code = unsafe {
1615            zstd_sys::ZSTD_decompressStream(
1616                self.0.as_ptr(),
1617                ptr_mut(&mut output),
1618                ptr_mut(&mut input),
1619            )
1620        };
1621        let res = output.check(parse_code(code));
1622        self.2.record(input.check(res))
1623    }
1624
1625    /// Wraps the `ZSTD_DStreamInSize()` function.
1626    ///
1627    /// Returns a hint for the recommended size of the input buffer for decompression.
1628    pub fn in_size() -> usize {
1629        unsafe { zstd_sys::ZSTD_DStreamInSize() }
1630    }
1631
1632    /// Wraps the `ZSTD_DStreamOutSize()` function.
1633    ///
1634    /// Returns a hint for the recommended size of the output buffer for decompression.
1635    pub fn out_size() -> usize {
1636        unsafe { zstd_sys::ZSTD_DStreamOutSize() }
1637    }
1638
1639    /// Wraps the `ZSTD_sizeof_DCtx()` function.
1640    pub fn sizeof(&self) -> usize {
1641        unsafe { zstd_sys::ZSTD_sizeof_DCtx(self.0.as_ptr()) }
1642    }
1643
1644    /// Wraps the `ZSTD_decompressBlock()` function.
1645    ///
1646    /// # Safety
1647    ///
1648    /// The bytes written to `dst` become this context's history window, so `dst` must stay
1649    /// allocated and unmodified until the next call to `decompress_block` or `insert_block` on this
1650    /// context (or until this context is dropped), as the following block is decoded against it.
1651    #[cfg(feature = "experimental")]
1652    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1653    #[deprecated(
1654        note = "The block API is deprecated; use decompress_stream instead."
1655    )]
1656    pub unsafe fn decompress_block<C: WriteBuf + ?Sized>(
1657        &mut self,
1658        dst: &mut C,
1659        src: &[u8],
1660    ) -> SafeResult {
1661        self.3.streamed = true;
1662        unsafe {
1663            dst.write_from(|buffer, capacity| {
1664                parse_code(zstd_sys::ZSTD_decompressBlock(
1665                    self.0.as_ptr(),
1666                    buffer,
1667                    capacity,
1668                    ptr_void(src),
1669                    src.len(),
1670                ))
1671            })
1672        }
1673    }
1674
1675    /// Wraps the `ZSTD_insertBlock()` function.
1676    ///
1677    /// # Safety
1678    ///
1679    /// `block` becomes this context's history window, so it must stay allocated and unmodified
1680    /// until the next call to `decompress_block` or `insert_block` on this context (or until this
1681    /// context is dropped), as the following block is decoded against it.
1682    #[cfg(feature = "experimental")]
1683    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1684    #[deprecated(
1685        note = "The block API is deprecated; use decompress_stream instead."
1686    )]
1687    pub unsafe fn insert_block(&mut self, block: &[u8]) -> usize {
1688        self.3.streamed = true;
1689        unsafe {
1690            zstd_sys::ZSTD_insertBlock(
1691                self.0.as_ptr(),
1692                ptr_void(block),
1693                block.len(),
1694            )
1695        }
1696    }
1697
1698    /// Creates a copy of this context.
1699    ///
1700    /// This only works before any data has been decompressed. An error will be
1701    /// returned otherwise.
1702    /// A poisoned context cannot be cloned until its session is reset.
1703    /// The copy always starts at the beginning of a frame.
1704    ///
1705    /// A dictionary this context merely references (see [`DCtx::ref_ddict`])
1706    /// is referenced by the copy too. One it owns cannot be shared, so an
1707    /// error is also returned while a dictionary from
1708    /// [`DCtx::load_dictionary`] or a prefix from [`DCtx::ref_prefix`] is set,
1709    /// and once [`DParameter::RefMultipleDDicts`] has been enabled.
1710    #[cfg(feature = "experimental")]
1711    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1712    #[deprecated(
1713        note = "Context copying is deprecated by zstd; create a new context and configure it instead."
1714    )]
1715    pub fn try_clone(&self) -> Result<Self, ErrorCode> {
1716        use zstd_sys::ZSTD_dParameter::{
1717            ZSTD_d_experimentalParam2 as ZSTD_d_stableOutBuffer,
1718            ZSTD_d_windowLogMax,
1719        };
1720
1721        // An error may leave the C context undefined; do not copy it.
1722        self.2.guard()?;
1723        // zstd copies the allocator callbacks from `self` into the new
1724        // context, so both must be created the same way; `try_create` always
1725        // picks the same allocator within a build.
1726        let mut context = Self::try_create().ok_or(MEMORY_ALLOCATION_ERROR)?;
1727
1728        // `ZSTD_copyDCtx()` is a plain `memcpy`, so a dictionary `self` owns
1729        // would end up owned, and freed, by both contexts. A loaded dictionary
1730        // or prefix shows up as memory a new context does not use - as do the
1731        // streaming buffers, once data has been decompressed. The table behind
1732        // `RefMultipleDDicts` is not counted there, and outlives the
1733        // parameter, hence the flag.
1734        if self.3.multiple_ddicts || self.sizeof() != context.sizeof() {
1735            return Err(STAGE_WRONG_ERROR);
1736        }
1737
1738        // `ZSTD_copyDCtx` stops where the streaming buffers start and leaves
1739        // the parameters stored past that point (the window limit and the
1740        // output buffer mode) at their defaults. Carry them over explicitly,
1741        // on the fresh context so that it is still in its initial stage; the
1742        // copy below does not touch these fields.
1743        // Only for values that differ: the window limit reads back as a log,
1744        // which rounds zstd's default limit down.
1745        let get = |dctx: &Self, param| {
1746            let mut value: c_int = 0;
1747            // Safety: Just FFI
1748            parse_code(unsafe {
1749                zstd_sys::ZSTD_DCtx_getParameter(
1750                    dctx.0.as_ptr(),
1751                    param,
1752                    &mut value,
1753                )
1754            })
1755            .map(|_| value)
1756        };
1757        for param in [ZSTD_d_windowLogMax, ZSTD_d_stableOutBuffer] {
1758            let value = get(self, param)?;
1759            if value == get(&context, param)? {
1760                continue;
1761            }
1762            // Safety: Just FFI
1763            parse_code(unsafe {
1764                zstd_sys::ZSTD_DCtx_setParameter(
1765                    context.0.as_ptr(),
1766                    param,
1767                    value,
1768                )
1769            })?;
1770        }
1771
1772        // Safety: Just FFI
1773        unsafe {
1774            zstd_sys::ZSTD_copyDCtx(context.0.as_ptr(), self.0.as_ptr())
1775        };
1776
1777        // The position within a frame is copied, but not the state that goes
1778        // with it (a partial header, a legacy context), so start from a frame
1779        // boundary rather than run on what the new context never initialized.
1780        context.reset(ResetDirective::SessionOnly)?;
1781
1782        Ok(context)
1783    }
1784}
1785
1786impl Drop for DCtx<'_> {
1787    fn drop(&mut self) {
1788        unsafe {
1789            zstd_sys::ZSTD_freeDCtx(self.0.as_ptr());
1790        }
1791    }
1792}
1793
1794// Safety: as for `CCtx` - an owned heap allocation with no thread-local state.
1795unsafe impl Send for DCtx<'_> {}
1796// Non thread-safe methods already take `&mut self`, so it's fine to implement Sync here.
1797// Safety: as for `CCtx` - the mutating methods all take `&mut self`.
1798unsafe impl Sync for DCtx<'_> {}
1799
1800/// Compression dictionary.
1801///
1802/// With `with-rust-allocator`, prepared dictionaries retain fixed compression
1803/// parameters rather than adapting them to later input sizes. This can change
1804/// compression ratio, speed, and memory usage compared with the C allocator.
1805pub struct CDict<'a>(NonNull<zstd_sys::ZSTD_CDict>, PhantomData<&'a ()>);
1806
1807impl CDict<'static> {
1808    /// Prepare a dictionary to compress data.
1809    ///
1810    /// This will make it easier for compression contexts to load this dictionary.
1811    ///
1812    /// The dictionary content will be copied internally, and does not need to be kept around.
1813    ///
1814    /// # Panics
1815    ///
1816    /// If loading this dictionary failed.
1817    pub fn create(
1818        dict_buffer: &[u8],
1819        compression_level: CompressionLevel,
1820    ) -> Self {
1821        Self::try_create(dict_buffer, compression_level)
1822            .expect("zstd returned null pointer when creating dict")
1823    }
1824
1825    /// Prepare a dictionary to compress data.
1826    ///
1827    /// This will make it easier for compression contexts to load this dictionary.
1828    ///
1829    /// The dictionary content will be copied internally, and does not need to be kept around.
1830    pub fn try_create(
1831        dict_buffer: &[u8],
1832        compression_level: CompressionLevel,
1833    ) -> Option<Self> {
1834        #[cfg(feature = "with-rust-allocator")]
1835        let ptr = unsafe {
1836            rust_allocator::create_cdict(
1837                dict_buffer,
1838                compression_level,
1839                zstd_sys::ZSTD_dictLoadMethod_e::ZSTD_dlm_byCopy,
1840            )
1841        };
1842        #[cfg(not(feature = "with-rust-allocator"))]
1843        let ptr = unsafe {
1844            zstd_sys::ZSTD_createCDict(
1845                ptr_void(dict_buffer),
1846                dict_buffer.len(),
1847                compression_level,
1848            )
1849        };
1850        Some(CDict(NonNull::new(ptr)?, PhantomData))
1851    }
1852}
1853
1854impl<'a> CDict<'a> {
1855    /// Prepare a dictionary to compress data, referencing `dict_buffer`.
1856    ///
1857    /// # Panics
1858    ///
1859    /// If loading this dictionary failed. See [`CDict::try_create_by_reference`].
1860    #[cfg(feature = "experimental")]
1861    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1862    pub fn create_by_reference(
1863        dict_buffer: &'a [u8],
1864        compression_level: CompressionLevel,
1865    ) -> Self {
1866        Self::try_create_by_reference(dict_buffer, compression_level)
1867            .expect("zstd returned null pointer")
1868    }
1869
1870    /// Prepare a dictionary to compress data, referencing `dict_buffer`.
1871    ///
1872    /// Returns `None` if zstd could not load the dictionary, for instance
1873    /// because it starts with the dictionary magic number but its header is
1874    /// corrupt.
1875    #[cfg(feature = "experimental")]
1876    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1877    pub fn try_create_by_reference(
1878        dict_buffer: &'a [u8],
1879        compression_level: CompressionLevel,
1880    ) -> Option<Self> {
1881        #[cfg(feature = "with-rust-allocator")]
1882        let ptr = unsafe {
1883            rust_allocator::create_cdict(
1884                dict_buffer,
1885                compression_level,
1886                zstd_sys::ZSTD_dictLoadMethod_e::ZSTD_dlm_byRef,
1887            )
1888        };
1889        #[cfg(not(feature = "with-rust-allocator"))]
1890        let ptr = unsafe {
1891            zstd_sys::ZSTD_createCDict_byReference(
1892                ptr_void(dict_buffer),
1893                dict_buffer.len(),
1894                compression_level,
1895            )
1896        };
1897        Some(CDict(NonNull::new(ptr)?, PhantomData))
1898    }
1899
1900    /// Returns the _current_ memory usage of this dictionary.
1901    ///
1902    /// Note that this may change over time.
1903    pub fn sizeof(&self) -> usize {
1904        unsafe { zstd_sys::ZSTD_sizeof_CDict(self.0.as_ptr()) }
1905    }
1906
1907    /// Returns the dictionary ID for this dict.
1908    ///
1909    /// Returns `None` if this dictionary is empty or invalid.
1910    pub fn get_dict_id(&self) -> Option<NonZeroU32> {
1911        NonZeroU32::new(unsafe {
1912            zstd_sys::ZSTD_getDictID_fromCDict(self.0.as_ptr()) as u32
1913        })
1914    }
1915}
1916
1917/// Wraps the `ZSTD_createCDict()` function.
1918pub fn create_cdict(
1919    dict_buffer: &[u8],
1920    compression_level: CompressionLevel,
1921) -> CDict<'static> {
1922    CDict::create(dict_buffer, compression_level)
1923}
1924
1925impl<'a> Drop for CDict<'a> {
1926    fn drop(&mut self) {
1927        unsafe {
1928            zstd_sys::ZSTD_freeCDict(self.0.as_ptr());
1929        }
1930    }
1931}
1932
1933// Safety: a digested dictionary is immutable once built. zstd.h: "ZSTD_CDict
1934// can be created once and shared by multiple threads concurrently, since its
1935// usage is read-only".
1936unsafe impl<'a> Send for CDict<'a> {}
1937unsafe impl<'a> Sync for CDict<'a> {}
1938
1939/// Wraps the `ZSTD_compress_usingCDict()` function.
1940pub fn compress_using_cdict(
1941    cctx: &mut CCtx<'_>,
1942    dst: &mut [u8],
1943    src: &[u8],
1944    cdict: &CDict<'_>,
1945) -> SafeResult {
1946    cctx.compress_using_cdict(dst, src, cdict)
1947}
1948
1949/// A digested decompression dictionary.
1950pub struct DDict<'a>(NonNull<zstd_sys::ZSTD_DDict>, PhantomData<&'a ()>);
1951
1952impl DDict<'static> {
1953    /// Prepare a dictionary to decompress data.
1954    ///
1955    /// The dictionary content will be copied internally, and does not need to be kept around.
1956    ///
1957    /// # Panics
1958    ///
1959    /// If loading this dictionary failed. See [`DDict::try_create`].
1960    pub fn create(dict_buffer: &[u8]) -> Self {
1961        Self::try_create(dict_buffer)
1962            .expect("zstd returned null pointer when creating dict")
1963    }
1964
1965    /// Prepare a dictionary to decompress data.
1966    ///
1967    /// The dictionary content will be copied internally, and does not need to be kept around.
1968    /// Returns `None` if zstd could not load the dictionary, for instance because it starts
1969    /// with the dictionary magic number but its header is corrupt.
1970    pub fn try_create(dict_buffer: &[u8]) -> Option<Self> {
1971        #[cfg(feature = "with-rust-allocator")]
1972        let ptr = unsafe {
1973            rust_allocator::create_ddict(
1974                dict_buffer,
1975                zstd_sys::ZSTD_dictLoadMethod_e::ZSTD_dlm_byCopy,
1976            )
1977        };
1978        #[cfg(not(feature = "with-rust-allocator"))]
1979        let ptr = unsafe {
1980            zstd_sys::ZSTD_createDDict(
1981                ptr_void(dict_buffer),
1982                dict_buffer.len(),
1983            )
1984        };
1985        Some(DDict(NonNull::new(ptr)?, PhantomData))
1986    }
1987}
1988
1989impl<'a> DDict<'a> {
1990    pub fn sizeof(&self) -> usize {
1991        unsafe { zstd_sys::ZSTD_sizeof_DDict(self.0.as_ptr()) }
1992    }
1993
1994    /// Wraps the `ZSTD_createDDict_byReference()` function.
1995    ///
1996    /// The dictionary will keep referencing `dict_buffer`.
1997    ///
1998    /// # Panics
1999    ///
2000    /// If loading this dictionary failed. See [`DDict::try_create_by_reference`].
2001    #[cfg(feature = "experimental")]
2002    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2003    pub fn create_by_reference(dict_buffer: &'a [u8]) -> Self {
2004        Self::try_create_by_reference(dict_buffer)
2005            .expect("zstd returned null pointer")
2006    }
2007
2008    /// Wraps the `ZSTD_createDDict_byReference()` function.
2009    ///
2010    /// The dictionary will keep referencing `dict_buffer`. Returns `None` if
2011    /// zstd could not load the dictionary, for instance because it starts with
2012    /// the dictionary magic number but its header is corrupt.
2013    #[cfg(feature = "experimental")]
2014    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2015    pub fn try_create_by_reference(dict_buffer: &'a [u8]) -> Option<Self> {
2016        #[cfg(feature = "with-rust-allocator")]
2017        let ptr = unsafe {
2018            rust_allocator::create_ddict(
2019                dict_buffer,
2020                zstd_sys::ZSTD_dictLoadMethod_e::ZSTD_dlm_byRef,
2021            )
2022        };
2023        #[cfg(not(feature = "with-rust-allocator"))]
2024        let ptr = unsafe {
2025            zstd_sys::ZSTD_createDDict_byReference(
2026                ptr_void(dict_buffer),
2027                dict_buffer.len(),
2028            )
2029        };
2030        Some(DDict(NonNull::new(ptr)?, PhantomData))
2031    }
2032
2033    /// Returns the dictionary ID for this dict.
2034    ///
2035    /// Returns `None` if this dictionary is empty or invalid.
2036    pub fn get_dict_id(&self) -> Option<NonZeroU32> {
2037        NonZeroU32::new(unsafe {
2038            zstd_sys::ZSTD_getDictID_fromDDict(self.0.as_ptr()) as u32
2039        })
2040    }
2041}
2042
2043/// Wraps the `ZSTD_createDDict()` function.
2044///
2045/// It copies the dictionary internally, so the resulting `DDict` is `'static`.
2046pub fn create_ddict(dict_buffer: &[u8]) -> DDict<'static> {
2047    DDict::create(dict_buffer)
2048}
2049
2050impl<'a> Drop for DDict<'a> {
2051    fn drop(&mut self) {
2052        unsafe {
2053            zstd_sys::ZSTD_freeDDict(self.0.as_ptr());
2054        }
2055    }
2056}
2057
2058// Safety: like `CDict`, a digested dictionary is only read once built - the
2059// contexts referencing it never write to it.
2060unsafe impl<'a> Send for DDict<'a> {}
2061unsafe impl<'a> Sync for DDict<'a> {}
2062
2063/// A shared thread pool for one or more compression contexts
2064#[cfg(all(feature = "experimental", feature = "zstdmt"))]
2065#[cfg_attr(
2066    feature = "doc-cfg",
2067    doc(cfg(all(feature = "experimental", feature = "zstdmt")))
2068)]
2069pub struct ThreadPool(NonNull<zstd_sys::ZSTD_threadPool>);
2070
2071#[cfg(all(feature = "experimental", feature = "zstdmt"))]
2072#[cfg_attr(
2073    feature = "doc-cfg",
2074    doc(cfg(all(feature = "experimental", feature = "zstdmt")))
2075)]
2076impl ThreadPool {
2077    /// Create a thread pool with the specified number of threads.
2078    ///
2079    /// # Panics
2080    ///
2081    /// If creating the thread pool failed.
2082    pub fn new(num_threads: usize) -> Self {
2083        Self::try_new(num_threads)
2084            .expect("zstd returned null pointer when creating thread pool")
2085    }
2086
2087    /// Create a thread pool with the specified number of threads.
2088    pub fn try_new(num_threads: usize) -> Option<Self> {
2089        Some(Self(NonNull::new(unsafe {
2090            zstd_sys::ZSTD_createThreadPool(num_threads)
2091        })?))
2092    }
2093}
2094
2095#[cfg(all(feature = "experimental", feature = "zstdmt"))]
2096#[cfg_attr(
2097    feature = "doc-cfg",
2098    doc(cfg(all(feature = "experimental", feature = "zstdmt")))
2099)]
2100impl Drop for ThreadPool {
2101    fn drop(&mut self) {
2102        unsafe {
2103            zstd_sys::ZSTD_freeThreadPool(self.0.as_ptr());
2104        }
2105    }
2106}
2107
2108#[cfg(all(feature = "experimental", feature = "zstdmt"))]
2109#[cfg_attr(
2110    feature = "doc-cfg",
2111    doc(cfg(all(feature = "experimental", feature = "zstdmt")))
2112)]
2113// Safety: the pool owns its worker threads and the queue guarding them; none
2114// of that is tied to the thread that created it.
2115unsafe impl Send for ThreadPool {}
2116#[cfg(all(feature = "experimental", feature = "zstdmt"))]
2117#[cfg_attr(
2118    feature = "doc-cfg",
2119    doc(cfg(all(feature = "experimental", feature = "zstdmt")))
2120)]
2121// Safety: sharing is what the pool is for - zstd.h offers these functions to
2122// "share a thread pool among multiple compression contexts" - and its work
2123// queue is guarded by an internal mutex.
2124unsafe impl Sync for ThreadPool {}
2125
2126/// Wraps the `ZSTD_decompress_usingDDict()` function.
2127pub fn decompress_using_ddict(
2128    dctx: &mut DCtx<'_>,
2129    dst: &mut [u8],
2130    src: &[u8],
2131    ddict: &DDict<'_>,
2132) -> SafeResult {
2133    dctx.decompress_using_ddict(dst, src, ddict)
2134}
2135
2136/// Compression stream.
2137///
2138/// Same as `CCtx`.
2139pub type CStream<'a> = CCtx<'a>;
2140
2141// `CStream` is an alias for `CCtx`, and shares its `Send` and `Sync` impls.
2142
2143/// Allocates a new `CStream`.
2144pub fn create_cstream<'a>() -> CStream<'a> {
2145    CCtx::create()
2146}
2147
2148/// Prepares an existing `CStream` for compression at the given level.
2149pub fn init_cstream(
2150    zcs: &mut CStream<'_>,
2151    compression_level: CompressionLevel,
2152) -> SafeResult {
2153    zcs.init(compression_level)
2154}
2155
2156#[derive(Debug)]
2157/// Wrapper around an input buffer.
2158///
2159/// Bytes will be read starting at `src[pos]`.
2160///
2161/// `pos` will be updated after reading.
2162///
2163/// # Invariant
2164///
2165/// `pos <= src.len()`
2166///
2167/// Both fields are public, so this is checked (and panics if it does not hold)
2168/// whenever the buffer is given to zstd.
2169pub struct InBuffer<'a> {
2170    pub src: &'a [u8],
2171    pub pos: usize,
2172}
2173
2174/// Describe a bytes container, like `Vec<u8>`.
2175///
2176/// Represents a contiguous segment of allocated memory, a prefix of which is initialized.
2177///
2178/// It allows starting from an uninitializes chunk of memory and writing to it, progressively
2179/// initializing it. No re-allocation typically occur after the initial creation.
2180///
2181/// The main implementors are:
2182/// * `Vec<u8>` and similar structures. These hold both a length (initialized data) and a capacity
2183///   (allocated memory).
2184///
2185///   Use `Vec::with_capacity` to create an empty `Vec` with non-zero capacity, and the length
2186///   field will be updated to cover the data written to it (as long as it fits in the given
2187///   capacity).
2188/// * `[u8]` and `[u8; N]`. These must start already-initialized, and will not be resized. It will
2189///   be up to the caller to only use the part that was written (as returned by the various writing
2190///   operations).
2191/// * `std::io::Cursor<T: WriteBuf>`. This will ignore data before the cursor's position, and
2192///   append data after that.
2193///
2194/// # Safety
2195///
2196/// An implementation has to keep three promises, because the zstd functions
2197/// this is handed to write straight through the pointer:
2198///
2199/// * `as_mut_ptr()` points at a buffer that is valid to write `capacity()`
2200///   bytes to.
2201/// * `as_slice()` covers only initialized bytes - never any of the capacity
2202///   that has not been written yet.
2203/// * `filled_until(n)` is what marks the first `n` bytes as initialized, so
2204///   after it returns, `as_slice()` must cover them.
2205pub unsafe trait WriteBuf {
2206    /// Returns the valid data part of this container. Should only cover initialized data.
2207    fn as_slice(&self) -> &[u8];
2208
2209    /// Returns the full capacity of this container. May include uninitialized data.
2210    fn capacity(&self) -> usize;
2211
2212    /// Returns a pointer to the start of the data.
2213    fn as_mut_ptr(&mut self) -> *mut u8;
2214
2215    /// Indicates that the first `n` bytes of the container have been written.
2216    ///
2217    /// # Safety
2218    ///
2219    /// The first `n` bytes of this buffer must actually have been initialized.
2220    unsafe fn filled_until(&mut self, n: usize);
2221
2222    /// Call the given closure using the pointer and capacity from `self`.
2223    ///
2224    /// The closure returns a parseable code which, if valid, is how many bytes
2225    /// it wrote to `self`.
2226    ///
2227    /// # Safety
2228    ///
2229    /// The closure must treat its first argument as pointing to potentially
2230    /// uninitialized memory, and must not read from it. It must have written
2231    /// at least `n` bytes contiguously from that pointer, where `n` is the
2232    /// value it returns.
2233    unsafe fn write_from<F>(&mut self, f: F) -> SafeResult
2234    where
2235        F: FnOnce(*mut c_void, usize) -> SafeResult,
2236    {
2237        let capacity = self.capacity();
2238        let res = f(ptr_mut_void(self), capacity);
2239        if let Ok(n) = res {
2240            // Nothing can have been written past the end of the buffer; a
2241            // larger count would mark memory we do not own as initialized.
2242            assert!(n <= capacity, "zstd reported writing past the buffer");
2243            self.filled_until(n);
2244        }
2245        res
2246    }
2247}
2248
2249/// The position of a `Cursor`, as an index into the buffer it wraps.
2250///
2251/// `Cursor` stores the position as a `u64` and lets it be set anywhere, so on a
2252/// target where `usize` is narrower it can name an offset no buffer can hold.
2253/// Saturating leaves such a position out of range, where the bounds checks
2254/// below reject it; casting would wrap it around into a valid-looking offset
2255/// and quietly read or write the wrong part of the buffer.
2256#[cfg(feature = "std")]
2257fn cursor_position<T>(cursor: &std::io::Cursor<T>) -> usize {
2258    use core::convert::TryFrom;
2259
2260    usize::try_from(cursor.position()).unwrap_or(usize::MAX)
2261}
2262
2263#[cfg(feature = "std")]
2264#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "std")))]
2265unsafe impl<T> WriteBuf for std::io::Cursor<T>
2266where
2267    T: WriteBuf,
2268{
2269    fn as_slice(&self) -> &[u8] {
2270        // A cursor past the inner buffer's initialized part has nothing
2271        // initialized after it yet (see `filled_until` below).
2272        self.get_ref()
2273            .as_slice()
2274            .get(cursor_position(self)..)
2275            .unwrap_or(&[])
2276    }
2277
2278    fn capacity(&self) -> usize {
2279        self.get_ref()
2280            .capacity()
2281            .saturating_sub(cursor_position(self))
2282    }
2283
2284    fn as_mut_ptr(&mut self) -> *mut u8 {
2285        let start = cursor_position(self);
2286        assert!(start <= self.get_ref().capacity());
2287        // Safety: start is still in the same memory allocation
2288        unsafe { self.get_mut().as_mut_ptr().add(start) }
2289    }
2290
2291    unsafe fn filled_until(&mut self, n: usize) {
2292        // Here we assume data _before_ self.position() was already initialized.
2293        // Egh it's not actually guaranteed by Cursor? So let's guarantee it ourselves.
2294        // Since the cursor wraps another `WriteBuf`, we know how much data is initialized there.
2295        let position = cursor_position(self);
2296        let capacity = self.get_ref().capacity();
2297        if n == 0 && position > capacity {
2298            // Nothing was written, and nothing could have been: there is
2299            // no room at all after the cursor.
2300            return;
2301        }
2302        // Otherwise the caller wrote `n` bytes starting at `position`, so
2303        // `position` is inside the buffer. Checking it before the zero-fill
2304        // below keeps a position that could not be converted from running off
2305        // the end.
2306        //
2307        // Note that `n == 0` still truncates the data after the cursor, like
2308        // any other `n` does: an empty result must not leave a previous one
2309        // in place.
2310        assert!(position <= capacity);
2311        let initialized = self.get_ref().as_slice().len();
2312        if let Some(uninitialized) = position.checked_sub(initialized) {
2313            // Here, the cursor is further than the known-initialized part.
2314            // Cursor's solution is to pad with zeroes, so let's do the same.
2315            // We'll zero bytes from the end of valid data (as_slice().len()) to the cursor position.
2316
2317            // Safety:
2318            // * We checked `position <= self.get_ref().capacity()`
2319            // * This means that `position` is within (or one past) the nested
2320            //   pointer's allocation.
2321            // * Finally, `initialized + uninitialized = position`, so the entire byte
2322            //   range here is within the allocation
2323            unsafe {
2324                self.get_mut()
2325                    .as_mut_ptr()
2326                    .add(initialized)
2327                    .write_bytes(0u8, uninitialized)
2328            };
2329        }
2330
2331        let start = position;
2332        assert!(start + n <= self.get_ref().capacity());
2333        self.get_mut().filled_until(start + n);
2334    }
2335}
2336
2337#[cfg(feature = "std")]
2338#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "std")))]
2339unsafe impl WriteBuf for &mut std::vec::Vec<u8> {
2340    fn as_slice(&self) -> &[u8] {
2341        std::vec::Vec::as_slice(self)
2342    }
2343
2344    fn capacity(&self) -> usize {
2345        std::vec::Vec::capacity(self)
2346    }
2347
2348    fn as_mut_ptr(&mut self) -> *mut u8 {
2349        std::vec::Vec::as_mut_ptr(self)
2350    }
2351
2352    unsafe fn filled_until(&mut self, n: usize) {
2353        std::vec::Vec::set_len(self, n)
2354    }
2355}
2356
2357#[cfg(feature = "std")]
2358#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "std")))]
2359unsafe impl WriteBuf for std::vec::Vec<u8> {
2360    fn as_slice(&self) -> &[u8] {
2361        &self[..]
2362    }
2363    fn capacity(&self) -> usize {
2364        self.capacity()
2365    }
2366    fn as_mut_ptr(&mut self) -> *mut u8 {
2367        self.as_mut_ptr()
2368    }
2369    unsafe fn filled_until(&mut self, n: usize) {
2370        self.set_len(n);
2371    }
2372}
2373
2374#[cfg(feature = "arrays")]
2375#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "arrays")))]
2376unsafe impl<const N: usize> WriteBuf for [u8; N] {
2377    fn as_slice(&self) -> &[u8] {
2378        self
2379    }
2380    fn capacity(&self) -> usize {
2381        self.len()
2382    }
2383
2384    fn as_mut_ptr(&mut self) -> *mut u8 {
2385        self[..].as_mut_ptr()
2386    }
2387
2388    unsafe fn filled_until(&mut self, _n: usize) {
2389        // Assume the slice is already initialized
2390    }
2391}
2392
2393unsafe impl WriteBuf for [u8] {
2394    fn as_slice(&self) -> &[u8] {
2395        self
2396    }
2397    fn capacity(&self) -> usize {
2398        self.len()
2399    }
2400
2401    fn as_mut_ptr(&mut self) -> *mut u8 {
2402        self.as_mut_ptr()
2403    }
2404
2405    unsafe fn filled_until(&mut self, _n: usize) {
2406        // Assume the slice is already initialized
2407    }
2408}
2409
2410/*
2411// This is possible, but... why?
2412unsafe impl<'a> WriteBuf for OutBuffer<'a, [u8]> {
2413    fn as_slice(&self) -> &[u8] {
2414        self.dst
2415    }
2416    fn capacity(&self) -> usize {
2417        self.dst.len()
2418    }
2419    fn as_mut_ptr(&mut self) -> *mut u8 {
2420        self.dst.as_mut_ptr()
2421    }
2422    unsafe fn filled_until(&mut self, n: usize) {
2423        self.pos = n;
2424    }
2425}
2426*/
2427
2428#[derive(Debug)]
2429/// Wrapper around an output buffer.
2430///
2431/// `C` is usually either `[u8]` or `Vec<u8>`.
2432///
2433/// Bytes will be written starting at `dst[pos]`.
2434///
2435/// `pos` will be updated after writing.
2436///
2437/// # Invariant
2438///
2439/// `pos <= dst.capacity()`
2440pub struct OutBuffer<'a, C: WriteBuf + ?Sized> {
2441    dst: &'a mut C,
2442    pos: usize,
2443}
2444
2445/// Convenience method to get a mut pointer from a mut ref.
2446fn ptr_mut<B>(ptr_void: &mut B) -> *mut B {
2447    ptr_void as *mut B
2448}
2449
2450/// Interface between a C-level ZSTD_outBuffer and a rust-level `OutBuffer`.
2451///
2452/// Will update the parent buffer from the C buffer on drop.
2453struct OutBufferWrapper<'a, 'b, C: WriteBuf + ?Sized> {
2454    buf: zstd_sys::ZSTD_outBuffer,
2455    parent: &'a mut OutBuffer<'b, C>,
2456}
2457
2458impl<'a, 'b: 'a, C: WriteBuf + ?Sized> Deref for OutBufferWrapper<'a, 'b, C> {
2459    type Target = zstd_sys::ZSTD_outBuffer;
2460
2461    fn deref(&self) -> &Self::Target {
2462        &self.buf
2463    }
2464}
2465
2466impl<'a, 'b: 'a, C: WriteBuf + ?Sized> DerefMut
2467    for OutBufferWrapper<'a, 'b, C>
2468{
2469    fn deref_mut(&mut self) -> &mut Self::Target {
2470        &mut self.buf
2471    }
2472}
2473
2474impl<'a, C: WriteBuf + ?Sized> OutBuffer<'a, C> {
2475    /// Returns a new `OutBuffer` around the given slice.
2476    ///
2477    /// Starts with `pos = 0`.
2478    pub fn around(dst: &'a mut C) -> Self {
2479        OutBuffer { dst, pos: 0 }
2480    }
2481
2482    /// Returns a new `OutBuffer` around the given slice, starting at the given position.
2483    ///
2484    /// If `pos` is past the initialized part of `dst` (for example a `Vec`
2485    /// whose `len()` is smaller than `pos`), the gap is zero-filled, as a
2486    /// `Cursor` would do.
2487    ///
2488    /// # Panics
2489    ///
2490    /// If `pos > dst.capacity()`.
2491    pub fn around_pos(dst: &'a mut C, pos: usize) -> Self {
2492        if pos > dst.capacity() {
2493            panic!("Given position outside of the buffer bounds.");
2494        }
2495
2496        let initialized = dst.as_slice().len();
2497        if pos > initialized {
2498            // Writing to this buffer marks everything before `pos` as
2499            // initialized (see `set_pos`), so it has to be before we start.
2500            // Safety: `initialized..pos` lies within `capacity()`, which
2501            // `WriteBuf` promises is valid to write to.
2502            unsafe {
2503                dst.as_mut_ptr()
2504                    .add(initialized)
2505                    .write_bytes(0u8, pos - initialized);
2506                dst.filled_until(pos);
2507            }
2508        }
2509
2510        OutBuffer { dst, pos }
2511    }
2512
2513    /// Returns the current cursor position.
2514    ///
2515    /// Guaranteed to be <= self.capacity()
2516    pub fn pos(&self) -> usize {
2517        assert!(self.pos <= self.dst.capacity());
2518        self.pos
2519    }
2520
2521    /// Returns the capacity of the underlying buffer.
2522    pub fn capacity(&self) -> usize {
2523        self.dst.capacity()
2524    }
2525
2526    /// Sets the new cursor position.
2527    ///
2528    /// # Panics
2529    ///
2530    /// If `pos > self.dst.capacity()`.
2531    ///
2532    /// # Safety
2533    ///
2534    /// Data up to `pos` must have actually been written to.
2535    pub unsafe fn set_pos(&mut self, pos: usize) {
2536        if pos > self.dst.capacity() {
2537            panic!("Given position outside of the buffer bounds.");
2538        }
2539
2540        self.dst.filled_until(pos);
2541
2542        self.pos = pos;
2543    }
2544
2545    fn wrap<'b>(&'b mut self) -> OutBufferWrapper<'b, 'a, C> {
2546        OutBufferWrapper {
2547            buf: zstd_sys::ZSTD_outBuffer {
2548                dst: ptr_mut_void(self.dst),
2549                size: self.dst.capacity(),
2550                pos: self.pos,
2551            },
2552            parent: self,
2553        }
2554    }
2555
2556    /// Returns the part of this buffer that was written to.
2557    pub fn as_slice<'b>(&'b self) -> &'a [u8]
2558    where
2559        'b: 'a,
2560    {
2561        let pos = self.pos;
2562        &self.dst.as_slice()[..pos]
2563    }
2564
2565    /// Returns a pointer to the start of this buffer.
2566    pub fn as_mut_ptr(&mut self) -> *mut u8 {
2567        self.dst.as_mut_ptr()
2568    }
2569}
2570
2571impl<'a, 'b, C: WriteBuf + ?Sized> OutBufferWrapper<'a, 'b, C> {
2572    /// Passes `res` through, and forgets the position reported by zstd if it
2573    /// is an error, so the parent keeps the one from before the call.
2574    ///
2575    /// zstd.h makes no promise about `pos` after a failed call, and the legacy
2576    /// decoders report the whole output buffer as written when they fail; only
2577    /// a successful call vouches for the bytes up to `pos` being initialized.
2578    fn check(&mut self, res: SafeResult) -> SafeResult {
2579        if res.is_err() {
2580            self.buf.pos = self.parent.pos;
2581        }
2582        res
2583    }
2584}
2585
2586impl<'a, 'b, C: WriteBuf + ?Sized> Drop for OutBufferWrapper<'a, 'b, C> {
2587    fn drop(&mut self) {
2588        // Safe because `self.buf.pos` either comes from a successful call,
2589        // which guarantees that data until there has been written, or was put
2590        // back to the parent's position by `check()`.
2591        unsafe { self.parent.set_pos(self.buf.pos) };
2592    }
2593}
2594
2595struct InBufferWrapper<'a, 'b> {
2596    buf: zstd_sys::ZSTD_inBuffer,
2597    parent: &'a mut InBuffer<'b>,
2598}
2599
2600impl<'a, 'b: 'a> Deref for InBufferWrapper<'a, 'b> {
2601    type Target = zstd_sys::ZSTD_inBuffer;
2602
2603    fn deref(&self) -> &Self::Target {
2604        &self.buf
2605    }
2606}
2607
2608impl<'a, 'b: 'a> DerefMut for InBufferWrapper<'a, 'b> {
2609    fn deref_mut(&mut self) -> &mut Self::Target {
2610        &mut self.buf
2611    }
2612}
2613
2614impl<'a> InBuffer<'a> {
2615    /// Returns a new `InBuffer` around the given slice.
2616    ///
2617    /// Starts with `pos = 0`.
2618    pub fn around(src: &'a [u8]) -> Self {
2619        InBuffer { src, pos: 0 }
2620    }
2621
2622    /// Returns the current cursor position.
2623    pub fn pos(&self) -> usize {
2624        self.pos
2625    }
2626
2627    /// Sets the new cursor position.
2628    ///
2629    /// # Panics
2630    ///
2631    /// If `pos > self.src.len()`.
2632    pub fn set_pos(&mut self, pos: usize) {
2633        if pos > self.src.len() {
2634            panic!("Given position outside of the buffer bounds.");
2635        }
2636        self.pos = pos;
2637    }
2638
2639    fn wrap<'b>(&'b mut self) -> InBufferWrapper<'b, 'a> {
2640        // The fields are public, so `pos` may not have gone through `set_pos`.
2641        // Not all zstd functions check it before reading from `src + pos`.
2642        if self.pos > self.src.len() {
2643            panic!("Given position outside of the buffer bounds.");
2644        }
2645
2646        InBufferWrapper {
2647            buf: zstd_sys::ZSTD_inBuffer {
2648                src: ptr_void(self.src),
2649                size: self.src.len(),
2650                pos: self.pos,
2651            },
2652            parent: self,
2653        }
2654    }
2655}
2656
2657impl<'a, 'b> InBufferWrapper<'a, 'b> {
2658    /// Passes `res` through, and forgets the position reported by zstd if it
2659    /// is an error, so the parent keeps the one from before the call.
2660    ///
2661    /// See `OutBufferWrapper::check()`: a failed call consumed nothing usable,
2662    /// and the legacy decoders report the whole input as read.
2663    fn check(&mut self, res: SafeResult) -> SafeResult {
2664        if res.is_err() {
2665            self.buf.pos = self.parent.pos;
2666        }
2667        res
2668    }
2669}
2670
2671impl<'a, 'b> Drop for InBufferWrapper<'a, 'b> {
2672    fn drop(&mut self) {
2673        self.parent.set_pos(self.buf.pos);
2674    }
2675}
2676
2677/// A Decompression stream.
2678///
2679/// Same as `DCtx`.
2680pub type DStream<'a> = DCtx<'a>;
2681
2682// Some functions work on a "frame prefix".
2683// TODO: Define `struct FramePrefix(&[u8]);` and move these functions to it?
2684//
2685// Some other functions work on a dictionary (not CDict or DDict).
2686// Same thing?
2687
2688/// Wraps the `ZSTD_findFrameCompressedSize()` function.
2689///
2690/// `src` should contain at least an entire frame.
2691pub fn find_frame_compressed_size(src: &[u8]) -> SafeResult {
2692    let code = unsafe {
2693        zstd_sys::ZSTD_findFrameCompressedSize(ptr_void(src), src.len())
2694    };
2695    parse_code(code)
2696}
2697
2698/// Wraps the `ZSTD_getFrameContentSize()` function.
2699///
2700/// Args:
2701/// * `src`: A prefix of the compressed frame. It should at least include the frame header.
2702///
2703/// Returns:
2704/// * `Err(ContentSizeError)` if `src` is too small of a prefix, or if it appears corrupted.
2705/// * `Ok(None)` if the frame does not include a content size.
2706/// * `Ok(Some(content_size_in_bytes))` otherwise.
2707pub fn get_frame_content_size(
2708    src: &[u8],
2709) -> Result<Option<u64>, ContentSizeError> {
2710    parse_content_size(unsafe {
2711        zstd_sys::ZSTD_getFrameContentSize(ptr_void(src), src.len())
2712    })
2713}
2714
2715/// Wraps the `ZSTD_findDecompressedSize()` function.
2716///
2717/// `src` should be exactly a sequence of ZSTD frames.
2718#[cfg(feature = "experimental")]
2719#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2720pub fn find_decompressed_size(
2721    src: &[u8],
2722) -> Result<Option<u64>, ContentSizeError> {
2723    parse_content_size(unsafe {
2724        zstd_sys::ZSTD_findDecompressedSize(ptr_void(src), src.len())
2725    })
2726}
2727
2728/// Wraps the `ZSTD_isFrame()` function.
2729#[cfg(feature = "experimental")]
2730#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2731pub fn is_frame(buffer: &[u8]) -> bool {
2732    unsafe { zstd_sys::ZSTD_isFrame(ptr_void(buffer), buffer.len()) > 0 }
2733}
2734
2735/// Wraps the `ZSTD_getDictID_fromDict()` function.
2736///
2737/// Returns `None` if the dictionary is not a valid zstd dictionary.
2738pub fn get_dict_id_from_dict(dict: &[u8]) -> Option<NonZeroU32> {
2739    NonZeroU32::new(unsafe {
2740        zstd_sys::ZSTD_getDictID_fromDict(ptr_void(dict), dict.len()) as u32
2741    })
2742}
2743
2744/// Wraps the `ZSTD_getDictID_fromFrame()` function.
2745///
2746/// Returns `None` if the dictionary ID could not be decoded. This may happen if:
2747/// * The frame was not encoded with a dictionary.
2748/// * The frame intentionally did not include dictionary ID.
2749/// * The dictionary was non-conformant.
2750/// * `src` is too small and does not include the frame header.
2751/// * `src` is not a valid zstd frame prefix.
2752pub fn get_dict_id_from_frame(src: &[u8]) -> Option<NonZeroU32> {
2753    NonZeroU32::new(unsafe {
2754        zstd_sys::ZSTD_getDictID_fromFrame(ptr_void(src), src.len()) as u32
2755    })
2756}
2757
2758/// What kind of context reset should be applied.
2759#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2760pub enum ResetDirective {
2761    /// Only the session will be reset.
2762    ///
2763    /// All parameters will be preserved (including the dictionary).
2764    /// But any frame being processed will be dropped.
2765    ///
2766    /// It can be useful to start re-using a context after an error or when an
2767    /// ongoing compression is no longer needed.
2768    SessionOnly,
2769
2770    /// Only reset parameters (including dictionary or referenced prefix).
2771    ///
2772    /// All parameters will be reset to default values.
2773    ///
2774    /// This can only be done between sessions - no compression or decompression must be ongoing.
2775    Parameters,
2776
2777    /// Reset both the session and parameters.
2778    ///
2779    /// The result is similar to a newly created context.
2780    SessionAndParameters,
2781}
2782
2783impl ResetDirective {
2784    /// Does this drop a session in progress?
2785    ///
2786    /// Only a session reset brings a context back from the undefined state an
2787    /// error can leave it in - `Parameters` alone is refused while a session is
2788    /// open.
2789    fn resets_session(self) -> bool {
2790        matches!(
2791            self,
2792            ResetDirective::SessionOnly | ResetDirective::SessionAndParameters
2793        )
2794    }
2795
2796    fn as_sys(self) -> zstd_sys::ZSTD_ResetDirective {
2797        match self {
2798            ResetDirective::SessionOnly => zstd_sys::ZSTD_ResetDirective::ZSTD_reset_session_only,
2799            ResetDirective::Parameters => zstd_sys::ZSTD_ResetDirective::ZSTD_reset_parameters,
2800            ResetDirective::SessionAndParameters => zstd_sys::ZSTD_ResetDirective::ZSTD_reset_session_and_parameters,
2801        }
2802    }
2803}
2804
2805#[cfg(feature = "experimental")]
2806#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2807#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2808#[repr(u32)]
2809pub enum FrameFormat {
2810    /// Regular zstd format.
2811    One = zstd_sys::ZSTD_format_e::ZSTD_f_zstd1 as u32,
2812
2813    /// Skip the 4 bytes identifying the content as zstd-compressed data.
2814    Magicless = zstd_sys::ZSTD_format_e::ZSTD_f_zstd1_magicless as u32,
2815}
2816
2817#[cfg(feature = "experimental")]
2818#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2819#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2820#[repr(u32)]
2821pub enum DictAttachPref {
2822    DefaultAttach =
2823        zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictDefaultAttach as u32,
2824    ForceAttach = zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictForceAttach as u32,
2825    ForceCopy = zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictForceCopy as u32,
2826    ForceLoad = zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictForceLoad as u32,
2827}
2828
2829#[cfg(feature = "experimental")]
2830#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2831#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2832#[repr(u32)]
2833pub enum ParamSwitch {
2834    Auto = zstd_sys::ZSTD_ParamSwitch_e::ZSTD_ps_auto as u32,
2835    Enable = zstd_sys::ZSTD_ParamSwitch_e::ZSTD_ps_enable as u32,
2836    Disable = zstd_sys::ZSTD_ParamSwitch_e::ZSTD_ps_disable as u32,
2837}
2838
2839/// A compression parameter.
2840#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2841#[non_exhaustive]
2842pub enum CParameter {
2843    #[cfg(feature = "experimental")]
2844    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2845    RSyncable(bool),
2846
2847    #[cfg(feature = "experimental")]
2848    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2849    Format(FrameFormat),
2850
2851    #[cfg(feature = "experimental")]
2852    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2853    ForceMaxWindow(bool),
2854
2855    #[cfg(feature = "experimental")]
2856    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2857    ForceAttachDict(DictAttachPref),
2858
2859    #[cfg(feature = "experimental")]
2860    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2861    LiteralCompressionMode(ParamSwitch),
2862
2863    #[cfg(feature = "experimental")]
2864    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2865    SrcSizeHint(u32),
2866
2867    #[cfg(feature = "experimental")]
2868    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2869    EnableDedicatedDictSearch(bool),
2870
2871    /// Whether zstd may keep referencing the input buffer instead of copying
2872    /// it.
2873    ///
2874    /// This requires the input to stay allocated and unmodified until the
2875    /// frame is complete, which a borrowed `InBuffer` cannot guarantee:
2876    /// `CCtx::set_parameter` refuses to enable it and returns an error.
2877    #[cfg(feature = "experimental")]
2878    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2879    StableInBuffer(bool),
2880
2881    #[cfg(feature = "experimental")]
2882    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2883    StableOutBuffer(bool),
2884
2885    #[cfg(feature = "experimental")]
2886    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2887    BlockDelimiters(bool),
2888
2889    #[cfg(feature = "experimental")]
2890    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2891    ValidateSequences(bool),
2892
2893    #[cfg(feature = "experimental")]
2894    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2895    UseBlockSplitter(ParamSwitch),
2896
2897    #[cfg(feature = "experimental")]
2898    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2899    UseRowMatchFinder(ParamSwitch),
2900
2901    #[cfg(feature = "experimental")]
2902    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2903    DeterministicRefPrefix(bool),
2904
2905    #[cfg(feature = "experimental")]
2906    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2907    PrefetchCDictTables(ParamSwitch),
2908
2909    #[cfg(feature = "experimental")]
2910    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2911    EnableSeqProducerFallback(bool),
2912
2913    #[cfg(feature = "experimental")]
2914    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2915    MaxBlockSize(u32),
2916
2917    #[cfg(feature = "experimental")]
2918    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2919    SearchForExternalRepcodes(ParamSwitch),
2920
2921    /// Target CBlock size.
2922    ///
2923    /// Tries to make compressed blocks fit in this size (not a guarantee, just a target).
2924    /// Useful to reduce end-to-end latency in low-bandwidth environments.
2925    ///
2926    /// No target when the value is 0.
2927    TargetCBlockSize(u32),
2928
2929    /// Compression level to use.
2930    ///
2931    /// Compression levels are global presets for the other compression parameters.
2932    CompressionLevel(CompressionLevel),
2933
2934    /// Maximum allowed back-reference distance.
2935    ///
2936    /// The actual distance is 2 power "this value".
2937    WindowLog(u32),
2938
2939    HashLog(u32),
2940
2941    ChainLog(u32),
2942
2943    SearchLog(u32),
2944
2945    MinMatch(u32),
2946
2947    TargetLength(u32),
2948
2949    Strategy(Strategy),
2950
2951    EnableLongDistanceMatching(bool),
2952
2953    LdmHashLog(u32),
2954
2955    LdmMinMatch(u32),
2956
2957    LdmBucketSizeLog(u32),
2958
2959    LdmHashRateLog(u32),
2960
2961    ContentSizeFlag(bool),
2962
2963    ChecksumFlag(bool),
2964
2965    DictIdFlag(bool),
2966
2967    /// How many threads will be spawned.
2968    ///
2969    /// With a default value of `0`, `compress_stream*` functions block until they complete.
2970    ///
2971    /// With any other value (including 1, a single compressing thread), these methods directly
2972    /// return, and the actual compression is done in the background (until a flush is requested).
2973    ///
2974    /// Note: this will only work if the `zstdmt` feature is activated.
2975    NbWorkers(u32),
2976
2977    /// Size in bytes of a compression job.
2978    ///
2979    /// Does not have any effect when `NbWorkers` is set to 0.
2980    ///
2981    /// The default value of 0 finds the best job size based on the compression parameters.
2982    ///
2983    /// Note: this will only work if the `zstdmt` feature is activated.
2984    JobSize(u32),
2985
2986    /// Specifies how much overlap must be given to each worker.
2987    ///
2988    /// Possible values:
2989    ///
2990    /// * `0` (default value): automatic overlap based on compression strategy.
2991    /// * `1`: No overlap
2992    /// * `1 < n < 9`: Overlap a fraction of the window size, defined as `1/(2 ^ 9-n)`.
2993    /// * `9`: Full overlap (as long as the window)
2994    /// * `9 < m`: Will return an error.
2995    ///
2996    /// Note: this will only work if the `zstdmt` feature is activated.
2997    OverlapSizeLog(u32),
2998}
2999
3000/// A decompression parameter.
3001#[derive(Copy, Clone, Debug, PartialEq, Eq)]
3002#[non_exhaustive]
3003pub enum DParameter {
3004    WindowLogMax(u32),
3005
3006    #[cfg(feature = "experimental")]
3007    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
3008    /// See `FrameFormat`.
3009    Format(FrameFormat),
3010
3011    #[cfg(feature = "experimental")]
3012    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
3013    StableOutBuffer(bool),
3014
3015    #[cfg(feature = "experimental")]
3016    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
3017    ForceIgnoreChecksum(bool),
3018
3019    #[cfg(feature = "experimental")]
3020    #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
3021    RefMultipleDDicts(bool),
3022}
3023
3024/// Wraps the `ZDICT_trainFromBuffer()` function.
3025#[cfg(feature = "zdict_builder")]
3026#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "zdict_builder")))]
3027pub fn train_from_buffer<C: WriteBuf + ?Sized>(
3028    dict_buffer: &mut C,
3029    samples_buffer: &[u8],
3030    samples_sizes: &[usize],
3031) -> SafeResult {
3032    // A plain `sum()` wraps around when overflow checks are disabled, and
3033    // would accept sizes reaching far outside of `samples_buffer`.
3034    let total_size = samples_sizes
3035        .iter()
3036        .try_fold(0usize, |total, &size| total.checked_add(size));
3037    assert_eq!(
3038        Some(samples_buffer.len()),
3039        total_size,
3040        "sample sizes don't add up to the samples buffer length"
3041    );
3042
3043    unsafe {
3044        dict_buffer.write_from(|buffer, capacity| {
3045            parse_code(zstd_sys::ZDICT_trainFromBuffer(
3046                buffer,
3047                capacity,
3048                ptr_void(samples_buffer),
3049                samples_sizes.as_ptr(),
3050                samples_sizes.len() as u32,
3051            ))
3052        })
3053    }
3054}
3055
3056/// Wraps the `ZDICT_getDictID()` function.
3057#[cfg(feature = "zdict_builder")]
3058#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "zdict_builder")))]
3059pub fn get_dict_id(dict_buffer: &[u8]) -> Option<NonZeroU32> {
3060    NonZeroU32::new(unsafe {
3061        zstd_sys::ZDICT_getDictID(ptr_void(dict_buffer), dict_buffer.len())
3062    })
3063}
3064
3065/// Wraps the `ZSTD_getBlockSize()` function.
3066#[cfg(feature = "experimental")]
3067#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
3068#[deprecated(
3069    note = "The block API is deprecated; use the normal compression API instead."
3070)]
3071pub fn get_block_size(cctx: &CCtx) -> usize {
3072    unsafe { zstd_sys::ZSTD_getBlockSize(cctx.0.as_ptr()) }
3073}
3074
3075/// Wraps the `ZSTD_decompressBound` function
3076#[cfg(feature = "experimental")]
3077#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
3078pub fn decompress_bound(data: &[u8]) -> Result<u64, ErrorCode> {
3079    let bound =
3080        unsafe { zstd_sys::ZSTD_decompressBound(ptr_void(data), data.len()) };
3081    if is_error(bound as usize) {
3082        Err(bound as usize)
3083    } else {
3084        Ok(bound)
3085    }
3086}
3087
3088/// Given a buffer of size `src_size`, returns the maximum number of sequences that can ge
3089/// generated.
3090#[cfg(feature = "experimental")]
3091#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
3092pub fn sequence_bound(src_size: usize) -> usize {
3093    // Safety: Just FFI.
3094    unsafe { zstd_sys::ZSTD_sequenceBound(src_size) }
3095}
3096
3097/// Returns the minimum extra space when output and input buffer overlap.
3098///
3099/// When using in-place decompression, the output buffer must be at least this much bigger (in
3100/// bytes) than the input buffer. The extra space must be at the front of the output buffer (the
3101/// input buffer must be at the end of the output buffer).
3102#[cfg(feature = "experimental")]
3103#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
3104pub fn decompression_margin(
3105    compressed_data: &[u8],
3106) -> Result<usize, ErrorCode> {
3107    parse_code(unsafe {
3108        zstd_sys::ZSTD_decompressionMargin(
3109            ptr_void(compressed_data),
3110            compressed_data.len(),
3111        )
3112    })
3113}