1#![no_std]
2#![cfg_attr(feature = "doc-cfg", feature(doc_cfg))]
21
22#[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
36pub use zstd_sys;
38
39pub use zstd_sys::ZSTD_strategy as Strategy;
41
42#[cfg(feature = "experimental")]
44#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
45pub use zstd_sys::ZSTD_frameProgression as FrameProgression;
46
47use 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
65pub type CompressionLevel = i32;
67
68pub type ErrorCode = usize;
70
71pub type SafeResult = Result<usize, ErrorCode>;
75
76#[cfg(feature = "experimental")]
80const MEMORY_ALLOCATION_ERROR: ErrorCode =
81 (zstd_sys::ZSTD_ErrorCode::ZSTD_error_memory_allocation as usize)
82 .wrapping_neg();
83
84#[derive(Debug)]
88pub struct ContentSizeError;
89
90impl core::fmt::Display for ContentSizeError {
91 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
92 f.write_str("Could not get content size")
93 }
94}
95
96fn is_error(code: usize) -> bool {
98 unsafe { zstd_sys::ZSTD_isError(code) != 0 }
100}
101
102fn parse_code(code: usize) -> SafeResult {
107 if !is_error(code) {
108 Ok(code)
109 } else {
110 Err(code)
111 }
112}
113
114fn parse_content_size(
118 content_size: u64,
119) -> Result<Option<u64>, ContentSizeError> {
120 match content_size {
121 CONTENTSIZE_ERROR => Err(ContentSizeError),
122 CONTENTSIZE_UNKNOWN => Ok(None),
123 other => Ok(Some(other)),
124 }
125}
126
127fn ptr_void(src: &[u8]) -> *const c_void {
128 src.as_ptr() as *const c_void
129}
130
131fn ptr_mut_void(dst: &mut (impl WriteBuf + ?Sized)) -> *mut c_void {
132 dst.as_mut_ptr() as *mut c_void
133}
134
135pub fn version_number() -> u32 {
140 unsafe { zstd_sys::ZSTD_versionNumber() as u32 }
142}
143
144pub fn version_string() -> &'static str {
148 unsafe { c_char_to_str(zstd_sys::ZSTD_versionString()) }
150}
151
152pub fn min_c_level() -> CompressionLevel {
156 unsafe { zstd_sys::ZSTD_minCLevel() as CompressionLevel }
158}
159
160pub fn max_c_level() -> CompressionLevel {
162 unsafe { zstd_sys::ZSTD_maxCLevel() as CompressionLevel }
164}
165
166pub fn compress<C: WriteBuf + ?Sized>(
174 dst: &mut C,
175 src: &[u8],
176 compression_level: CompressionLevel,
177) -> SafeResult {
178 #[cfg(feature = "with-rust-allocator")]
183 {
184 let mut cctx = CCtx::try_create().ok_or(MEMORY_ALLOCATION_ERROR)?;
185 cctx.compress(dst, src, compression_level)
186 }
187
188 #[cfg(not(feature = "with-rust-allocator"))]
190 unsafe {
191 dst.write_from(|buffer, capacity| {
192 parse_code(zstd_sys::ZSTD_compress(
193 buffer,
194 capacity,
195 ptr_void(src),
196 src.len(),
197 compression_level,
198 ))
199 })
200 }
201}
202
203pub fn decompress<C: WriteBuf + ?Sized>(
212 dst: &mut C,
213 src: &[u8],
214) -> SafeResult {
215 #[cfg(feature = "with-rust-allocator")]
218 {
219 let mut dctx = DCtx::try_create().ok_or(MEMORY_ALLOCATION_ERROR)?;
220 dctx.decompress(dst, src)
221 }
222
223 #[cfg(not(feature = "with-rust-allocator"))]
225 unsafe {
226 dst.write_from(|buffer, capacity| {
227 parse_code(zstd_sys::ZSTD_decompress(
228 buffer,
229 capacity,
230 ptr_void(src),
231 src.len(),
232 ))
233 })
234 }
235}
236
237#[deprecated(note = "Use get_frame_content_size instead.")]
241pub fn get_decompressed_size(src: &[u8]) -> Option<NonZeroU64> {
242 NonZeroU64::new(unsafe {
244 zstd_sys::ZSTD_getDecompressedSize(ptr_void(src), src.len()) as u64
245 })
246}
247
248pub fn compress_bound(src_size: usize) -> usize {
250 unsafe { zstd_sys::ZSTD_compressBound(src_size) }
252}
253
254#[derive(Clone, Debug, Default)]
264struct Poison(Option<ErrorCode>);
265
266impl Poison {
267 fn guard(&self) -> Result<(), ErrorCode> {
269 match self.0 {
270 Some(code) => Err(code),
271 None => Ok(()),
272 }
273 }
274
275 fn record(&mut self, res: SafeResult) -> SafeResult {
277 if let Err(code) = res {
278 self.0 = Some(code);
279 }
280 res
281 }
282
283 fn clear(&mut self) {
285 self.0 = None;
286 }
287}
288
289pub struct CCtx<'a>(NonNull<zstd_sys::ZSTD_CCtx>, PhantomData<&'a ()>, Poison);
294
295impl Default for CCtx<'_> {
296 fn default() -> Self {
297 CCtx::create()
298 }
299}
300
301impl<'a> CCtx<'a> {
302 pub fn try_create() -> Option<Self> {
310 #[cfg(feature = "with-rust-allocator")]
311 let context = unsafe {
314 zstd_sys::ZSTD_createCCtx_advanced(
315 crate::rust_allocator::RUST_GLOBAL_ALLOCATOR,
316 )
317 };
318 #[cfg(not(feature = "with-rust-allocator"))]
319 let context = unsafe { zstd_sys::ZSTD_createCCtx() };
321
322 Some(Self(NonNull::new(context)?, PhantomData, Poison::default()))
323 }
324
325 pub fn create() -> Self {
331 Self::try_create()
332 .expect("zstd returned null pointer when creating new context")
333 }
334
335 pub fn compress<C: WriteBuf + ?Sized>(
337 &mut self,
338 dst: &mut C,
339 src: &[u8],
340 compression_level: CompressionLevel,
341 ) -> SafeResult {
342 self.2.clear();
343 unsafe {
345 dst.write_from(|buffer, capacity| {
346 parse_code(zstd_sys::ZSTD_compressCCtx(
347 self.0.as_ptr(),
348 buffer,
349 capacity,
350 ptr_void(src),
351 src.len(),
352 compression_level,
353 ))
354 })
355 }
356 }
357
358 pub fn compress2<C: WriteBuf + ?Sized>(
360 &mut self,
361 dst: &mut C,
362 src: &[u8],
363 ) -> SafeResult {
364 self.2.clear();
365 unsafe {
367 dst.write_from(|buffer, capacity| {
368 parse_code(zstd_sys::ZSTD_compress2(
369 self.0.as_ptr(),
370 buffer,
371 capacity,
372 ptr_void(src),
373 src.len(),
374 ))
375 })
376 }
377 }
378
379 pub fn compress_using_dict<C: WriteBuf + ?Sized>(
381 &mut self,
382 dst: &mut C,
383 src: &[u8],
384 dict: &[u8],
385 compression_level: CompressionLevel,
386 ) -> SafeResult {
387 self.2.clear();
388 unsafe {
390 dst.write_from(|buffer, capacity| {
391 parse_code(zstd_sys::ZSTD_compress_usingDict(
392 self.0.as_ptr(),
393 buffer,
394 capacity,
395 ptr_void(src),
396 src.len(),
397 ptr_void(dict),
398 dict.len(),
399 compression_level,
400 ))
401 })
402 }
403 }
404
405 pub fn compress_using_cdict<C: WriteBuf + ?Sized>(
407 &mut self,
408 dst: &mut C,
409 src: &[u8],
410 cdict: &CDict<'_>,
411 ) -> SafeResult {
412 self.2.clear();
413 unsafe {
415 dst.write_from(|buffer, capacity| {
416 parse_code(zstd_sys::ZSTD_compress_usingCDict(
417 self.0.as_ptr(),
418 buffer,
419 capacity,
420 ptr_void(src),
421 src.len(),
422 cdict.0.as_ptr(),
423 ))
424 })
425 }
426 }
427
428 pub fn init(&mut self, compression_level: CompressionLevel) -> SafeResult {
434 self.2.clear();
435 let code = unsafe {
437 zstd_sys::ZSTD_initCStream(self.0.as_ptr(), compression_level)
438 };
439 self.2.record(parse_code(code))
440 }
441
442 #[cfg(feature = "experimental")]
444 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
445 #[deprecated(
446 note = "Use reset, set_parameter, and set_pledged_src_size instead."
447 )]
448 pub fn init_src_size(
449 &mut self,
450 compression_level: CompressionLevel,
451 pledged_src_size: u64,
452 ) -> SafeResult {
453 self.2.clear();
454 let code = unsafe {
456 zstd_sys::ZSTD_initCStream_srcSize(
457 self.0.as_ptr(),
458 compression_level as c_int,
459 pledged_src_size as c_ulonglong,
460 )
461 };
462 parse_code(code)
463 }
464
465 #[cfg(feature = "experimental")]
467 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
468 #[deprecated(
469 note = "Use reset, set_parameter, and load_dictionary instead."
470 )]
471 pub fn init_using_dict(
472 &mut self,
473 dict: &[u8],
474 compression_level: CompressionLevel,
475 ) -> SafeResult {
476 self.2.clear();
477 self.2.clear();
478 let code = unsafe {
480 zstd_sys::ZSTD_initCStream_usingDict(
481 self.0.as_ptr(),
482 ptr_void(dict),
483 dict.len(),
484 compression_level,
485 )
486 };
487 parse_code(code)
488 }
489
490 #[cfg(feature = "experimental")]
492 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
493 #[deprecated(note = "Use reset and ref_cdict instead.")]
494 pub fn init_using_cdict<'b>(&mut self, cdict: &CDict<'b>) -> SafeResult
495 where
496 'b: 'a, {
498 let code = unsafe {
500 zstd_sys::ZSTD_initCStream_usingCDict(
501 self.0.as_ptr(),
502 cdict.0.as_ptr(),
503 )
504 };
505 parse_code(code)
506 }
507
508 pub fn load_dictionary(&mut self, dict: &[u8]) -> SafeResult {
518 parse_code(unsafe {
520 zstd_sys::ZSTD_CCtx_loadDictionary(
521 self.0.as_ptr(),
522 ptr_void(dict),
523 dict.len(),
524 )
525 })
526 }
527
528 pub fn ref_cdict<'b>(&mut self, cdict: &'a CDict<'b>) -> SafeResult
532 where
533 'b: 'a,
534 {
535 parse_code(unsafe {
537 zstd_sys::ZSTD_CCtx_refCDict(self.0.as_ptr(), cdict.0.as_ptr())
538 })
539 }
540
541 pub fn disable_dictionary(&mut self) -> SafeResult {
545 parse_code(unsafe {
547 zstd_sys::ZSTD_CCtx_loadDictionary(
548 self.0.as_ptr(),
549 core::ptr::null(),
550 0,
551 )
552 })
553 }
554
555 pub fn ref_prefix<'b>(&mut self, prefix: &'b [u8]) -> SafeResult
561 where
562 'b: 'a,
563 {
564 parse_code(unsafe {
566 zstd_sys::ZSTD_CCtx_refPrefix(
567 self.0.as_ptr(),
568 ptr_void(prefix),
569 prefix.len(),
570 )
571 })
572 }
573
574 pub fn compress_stream<C: WriteBuf + ?Sized>(
586 &mut self,
587 output: &mut OutBuffer<'_, C>,
588 input: &mut InBuffer<'_>,
589 ) -> SafeResult {
590 self.2.guard()?;
591 let mut output = output.wrap();
592 let mut input = input.wrap();
593 let code = unsafe {
595 zstd_sys::ZSTD_compressStream(
596 self.0.as_ptr(),
597 ptr_mut(&mut output),
598 ptr_mut(&mut input),
599 )
600 };
601 self.2.record(parse_code(code))
602 }
603
604 pub fn compress_stream2<C: WriteBuf + ?Sized>(
620 &mut self,
621 output: &mut OutBuffer<'_, C>,
622 input: &mut InBuffer<'_>,
623 end_op: zstd_sys::ZSTD_EndDirective,
624 ) -> SafeResult {
625 self.2.guard()?;
626 let mut output = output.wrap();
627 let mut input = input.wrap();
628 let code = unsafe {
630 zstd_sys::ZSTD_compressStream2(
631 self.0.as_ptr(),
632 ptr_mut(&mut output),
633 ptr_mut(&mut input),
634 end_op,
635 )
636 };
637 self.2.record(parse_code(code))
638 }
639
640 pub fn flush_stream<C: WriteBuf + ?Sized>(
646 &mut self,
647 output: &mut OutBuffer<'_, C>,
648 ) -> SafeResult {
649 self.2.guard()?;
650 let mut output = output.wrap();
651 let code = unsafe {
653 zstd_sys::ZSTD_flushStream(self.0.as_ptr(), ptr_mut(&mut output))
654 };
655 self.2.record(parse_code(code))
656 }
657
658 pub fn end_stream<C: WriteBuf + ?Sized>(
664 &mut self,
665 output: &mut OutBuffer<'_, C>,
666 ) -> SafeResult {
667 self.2.guard()?;
668 let mut output = output.wrap();
669 let code = unsafe {
671 zstd_sys::ZSTD_endStream(self.0.as_ptr(), ptr_mut(&mut output))
672 };
673 self.2.record(parse_code(code))
674 }
675
676 pub fn sizeof(&self) -> usize {
680 unsafe { zstd_sys::ZSTD_sizeof_CCtx(self.0.as_ptr()) }
682 }
683
684 pub fn reset(&mut self, reset: ResetDirective) -> SafeResult {
690 let res = parse_code(unsafe {
692 zstd_sys::ZSTD_CCtx_reset(self.0.as_ptr(), reset.as_sys())
693 });
694 if res.is_ok() && reset.resets_session() {
695 self.2.clear();
696 }
697 res
698 }
699
700 pub fn set_parameter(&mut self, param: CParameter) -> SafeResult {
704 #[cfg(feature = "experimental")]
707 use zstd_sys::ZSTD_cParameter::{
708 ZSTD_c_experimentalParam1 as ZSTD_c_rsyncable,
709 ZSTD_c_experimentalParam10 as ZSTD_c_stableOutBuffer,
710 ZSTD_c_experimentalParam11 as ZSTD_c_blockDelimiters,
711 ZSTD_c_experimentalParam12 as ZSTD_c_validateSequences,
712 ZSTD_c_experimentalParam13 as ZSTD_c_useBlockSplitter,
713 ZSTD_c_experimentalParam14 as ZSTD_c_useRowMatchFinder,
714 ZSTD_c_experimentalParam15 as ZSTD_c_deterministicRefPrefix,
715 ZSTD_c_experimentalParam16 as ZSTD_c_prefetchCDictTables,
716 ZSTD_c_experimentalParam17 as ZSTD_c_enableSeqProducerFallback,
717 ZSTD_c_experimentalParam18 as ZSTD_c_maxBlockSize,
718 ZSTD_c_experimentalParam19 as ZSTD_c_searchForExternalRepcodes,
719 ZSTD_c_experimentalParam2 as ZSTD_c_format,
720 ZSTD_c_experimentalParam3 as ZSTD_c_forceMaxWindow,
721 ZSTD_c_experimentalParam4 as ZSTD_c_forceAttachDict,
722 ZSTD_c_experimentalParam5 as ZSTD_c_literalCompressionMode,
723 ZSTD_c_experimentalParam7 as ZSTD_c_srcSizeHint,
724 ZSTD_c_experimentalParam8 as ZSTD_c_enableDedicatedDictSearch,
725 ZSTD_c_experimentalParam9 as ZSTD_c_stableInBuffer,
726 };
727
728 use zstd_sys::ZSTD_cParameter::*;
729 use CParameter::*;
730
731 let (param, value) = match param {
732 #[cfg(feature = "experimental")]
733 RSyncable(rsyncable) => (ZSTD_c_rsyncable, rsyncable as c_int),
734 #[cfg(feature = "experimental")]
735 Format(format) => (ZSTD_c_format, format as c_int),
736 #[cfg(feature = "experimental")]
737 ForceMaxWindow(force) => (ZSTD_c_forceMaxWindow, force as c_int),
738 #[cfg(feature = "experimental")]
739 ForceAttachDict(force) => (ZSTD_c_forceAttachDict, force as c_int),
740 #[cfg(feature = "experimental")]
741 LiteralCompressionMode(mode) => {
742 (ZSTD_c_literalCompressionMode, mode as c_int)
743 }
744 #[cfg(feature = "experimental")]
745 SrcSizeHint(value) => (ZSTD_c_srcSizeHint, value as c_int),
746 #[cfg(feature = "experimental")]
747 EnableDedicatedDictSearch(enable) => {
748 (ZSTD_c_enableDedicatedDictSearch, enable as c_int)
749 }
750 #[cfg(feature = "experimental")]
751 StableInBuffer(stable) => (ZSTD_c_stableInBuffer, stable as c_int),
752 #[cfg(feature = "experimental")]
753 StableOutBuffer(stable) => {
754 (ZSTD_c_stableOutBuffer, stable as c_int)
755 }
756 #[cfg(feature = "experimental")]
757 BlockDelimiters(value) => (ZSTD_c_blockDelimiters, value as c_int),
758 #[cfg(feature = "experimental")]
759 ValidateSequences(validate) => {
760 (ZSTD_c_validateSequences, validate as c_int)
761 }
762 #[cfg(feature = "experimental")]
763 UseBlockSplitter(split) => {
764 (ZSTD_c_useBlockSplitter, split as c_int)
765 }
766 #[cfg(feature = "experimental")]
767 UseRowMatchFinder(mode) => {
768 (ZSTD_c_useRowMatchFinder, mode as c_int)
769 }
770 #[cfg(feature = "experimental")]
771 DeterministicRefPrefix(deterministic) => {
772 (ZSTD_c_deterministicRefPrefix, deterministic as c_int)
773 }
774 #[cfg(feature = "experimental")]
775 PrefetchCDictTables(prefetch) => {
776 (ZSTD_c_prefetchCDictTables, prefetch as c_int)
777 }
778 #[cfg(feature = "experimental")]
779 EnableSeqProducerFallback(enable) => {
780 (ZSTD_c_enableSeqProducerFallback, enable as c_int)
781 }
782 #[cfg(feature = "experimental")]
783 MaxBlockSize(value) => (ZSTD_c_maxBlockSize, value as c_int),
784 #[cfg(feature = "experimental")]
785 SearchForExternalRepcodes(value) => {
786 (ZSTD_c_searchForExternalRepcodes, value as c_int)
787 }
788 TargetCBlockSize(value) => {
789 (ZSTD_c_targetCBlockSize, value as c_int)
790 }
791 CompressionLevel(level) => (ZSTD_c_compressionLevel, level),
792 WindowLog(value) => (ZSTD_c_windowLog, value as c_int),
793 HashLog(value) => (ZSTD_c_hashLog, value as c_int),
794 ChainLog(value) => (ZSTD_c_chainLog, value as c_int),
795 SearchLog(value) => (ZSTD_c_searchLog, value as c_int),
796 MinMatch(value) => (ZSTD_c_minMatch, value as c_int),
797 TargetLength(value) => (ZSTD_c_targetLength, value as c_int),
798 Strategy(strategy) => (ZSTD_c_strategy, strategy as c_int),
799 EnableLongDistanceMatching(flag) => {
800 (ZSTD_c_enableLongDistanceMatching, flag as c_int)
801 }
802 LdmHashLog(value) => (ZSTD_c_ldmHashLog, value as c_int),
803 LdmMinMatch(value) => (ZSTD_c_ldmMinMatch, value as c_int),
804 LdmBucketSizeLog(value) => {
805 (ZSTD_c_ldmBucketSizeLog, value as c_int)
806 }
807 LdmHashRateLog(value) => (ZSTD_c_ldmHashRateLog, value as c_int),
808 ContentSizeFlag(flag) => (ZSTD_c_contentSizeFlag, flag as c_int),
809 ChecksumFlag(flag) => (ZSTD_c_checksumFlag, flag as c_int),
810 DictIdFlag(flag) => (ZSTD_c_dictIDFlag, flag as c_int),
811
812 NbWorkers(value) => (ZSTD_c_nbWorkers, value as c_int),
813
814 JobSize(value) => (ZSTD_c_jobSize, value as c_int),
815
816 OverlapSizeLog(value) => (ZSTD_c_overlapLog, value as c_int),
817 };
818
819 parse_code(unsafe {
821 zstd_sys::ZSTD_CCtx_setParameter(self.0.as_ptr(), param, value)
822 })
823 }
824
825 pub fn set_pledged_src_size(
834 &mut self,
835 pledged_src_size: Option<u64>,
836 ) -> SafeResult {
837 parse_code(unsafe {
839 zstd_sys::ZSTD_CCtx_setPledgedSrcSize(
840 self.0.as_ptr(),
841 pledged_src_size.unwrap_or(CONTENTSIZE_UNKNOWN) as c_ulonglong,
842 )
843 })
844 }
845
846 #[cfg(feature = "experimental")]
852 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
853 #[deprecated(
854 note = "Context copying is deprecated by zstd; create a new context and configure it instead."
855 )]
856 pub fn try_clone(
857 &self,
858 pledged_src_size: Option<u64>,
859 ) -> Result<Self, ErrorCode> {
860 self.2.guard()?;
862 let context = Self::try_create().ok_or(MEMORY_ALLOCATION_ERROR)?;
866
867 parse_code(unsafe {
869 zstd_sys::ZSTD_copyCCtx(
870 context.0.as_ptr(),
871 self.0.as_ptr(),
872 pledged_src_size.unwrap_or(CONTENTSIZE_UNKNOWN),
873 )
874 })?;
875
876 Ok(context)
877 }
878
879 #[cfg(feature = "experimental")]
881 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
882 #[deprecated(
883 note = "The block API is deprecated; use the normal compression API instead."
884 )]
885 pub fn get_block_size(&self) -> usize {
886 unsafe { zstd_sys::ZSTD_getBlockSize(self.0.as_ptr()) }
888 }
889
890 #[cfg(feature = "experimental")]
898 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
899 #[deprecated(
900 note = "The block API is deprecated; use compress_stream2 instead."
901 )]
902 pub unsafe fn compress_block<C: WriteBuf + ?Sized>(
903 &mut self,
904 dst: &mut C,
905 src: &[u8],
906 ) -> SafeResult {
907 unsafe {
909 dst.write_from(|buffer, capacity| {
910 parse_code(zstd_sys::ZSTD_compressBlock(
911 self.0.as_ptr(),
912 buffer,
913 capacity,
914 ptr_void(src),
915 src.len(),
916 ))
917 })
918 }
919 }
920
921 pub fn in_size() -> usize {
925 unsafe { zstd_sys::ZSTD_CStreamInSize() }
927 }
928
929 pub fn out_size() -> usize {
933 unsafe { zstd_sys::ZSTD_CStreamOutSize() }
935 }
936
937 #[cfg(all(feature = "experimental", feature = "zstdmt"))]
941 #[cfg_attr(
942 feature = "doc-cfg",
943 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
944 )]
945 pub fn ref_thread_pool<'b>(&mut self, pool: &'b ThreadPool) -> SafeResult
946 where
947 'b: 'a,
948 {
949 parse_code(unsafe {
950 zstd_sys::ZSTD_CCtx_refThreadPool(self.0.as_ptr(), pool.0.as_ptr())
951 })
952 }
953
954 #[cfg(all(feature = "experimental", feature = "zstdmt"))]
956 #[cfg_attr(
957 feature = "doc-cfg",
958 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
959 )]
960 pub fn disable_thread_pool(&mut self) -> SafeResult {
961 parse_code(unsafe {
962 zstd_sys::ZSTD_CCtx_refThreadPool(
963 self.0.as_ptr(),
964 core::ptr::null_mut(),
965 )
966 })
967 }
968
969 #[cfg(feature = "experimental")]
970 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
971 pub fn get_frame_progression(&self) -> FrameProgression {
972 unsafe { zstd_sys::ZSTD_getFrameProgression(self.0.as_ptr()) }
974 }
975}
976
977impl<'a> Drop for CCtx<'a> {
978 fn drop(&mut self) {
979 unsafe {
981 zstd_sys::ZSTD_freeCCtx(self.0.as_ptr());
982 }
983 }
984}
985
986unsafe impl Send for CCtx<'_> {}
989unsafe impl Sync for CCtx<'_> {}
992
993unsafe fn c_char_to_str(text: *const c_char) -> &'static str {
1001 core::ffi::CStr::from_ptr(text)
1003 .to_str()
1004 .expect("bad error message from zstd")
1005}
1006
1007pub fn get_error_name(code: usize) -> &'static str {
1009 unsafe {
1010 let name = zstd_sys::ZSTD_getErrorName(code);
1012 c_char_to_str(name)
1013 }
1014}
1015
1016pub struct DCtx<'a>(NonNull<zstd_sys::ZSTD_DCtx>, PhantomData<&'a ()>, Poison);
1024
1025impl Default for DCtx<'_> {
1026 fn default() -> Self {
1027 DCtx::create()
1028 }
1029}
1030
1031impl<'a> DCtx<'a> {
1032 pub fn try_create() -> Option<Self> {
1040 #[cfg(feature = "with-rust-allocator")]
1041 let context = unsafe {
1044 zstd_sys::ZSTD_createDCtx_advanced(
1045 crate::rust_allocator::RUST_GLOBAL_ALLOCATOR,
1046 )
1047 };
1048 #[cfg(not(feature = "with-rust-allocator"))]
1049 let context = unsafe { zstd_sys::ZSTD_createDCtx() };
1051
1052 Some(Self(NonNull::new(context)?, PhantomData, Poison::default()))
1053 }
1054
1055 pub fn create() -> Self {
1061 Self::try_create()
1062 .expect("zstd returned null pointer when creating new context")
1063 }
1064
1065 pub fn decompress<C: WriteBuf + ?Sized>(
1072 &mut self,
1073 dst: &mut C,
1074 src: &[u8],
1075 ) -> SafeResult {
1076 self.2.clear();
1077 unsafe {
1078 dst.write_from(|buffer, capacity| {
1079 parse_code(zstd_sys::ZSTD_decompressDCtx(
1080 self.0.as_ptr(),
1081 buffer,
1082 capacity,
1083 ptr_void(src),
1084 src.len(),
1085 ))
1086 })
1087 }
1088 }
1089
1090 pub fn decompress_using_dict<C: WriteBuf + ?Sized>(
1099 &mut self,
1100 dst: &mut C,
1101 src: &[u8],
1102 dict: &[u8],
1103 ) -> SafeResult {
1104 self.2.clear();
1105 unsafe {
1106 dst.write_from(|buffer, capacity| {
1107 parse_code(zstd_sys::ZSTD_decompress_usingDict(
1108 self.0.as_ptr(),
1109 buffer,
1110 capacity,
1111 ptr_void(src),
1112 src.len(),
1113 ptr_void(dict),
1114 dict.len(),
1115 ))
1116 })
1117 }
1118 }
1119
1120 pub fn decompress_using_ddict<C: WriteBuf + ?Sized>(
1126 &mut self,
1127 dst: &mut C,
1128 src: &[u8],
1129 ddict: &DDict<'_>,
1130 ) -> SafeResult {
1131 self.2.clear();
1132 unsafe {
1133 dst.write_from(|buffer, capacity| {
1134 parse_code(zstd_sys::ZSTD_decompress_usingDDict(
1135 self.0.as_ptr(),
1136 buffer,
1137 capacity,
1138 ptr_void(src),
1139 src.len(),
1140 ddict.0.as_ptr(),
1141 ))
1142 })
1143 }
1144 }
1145
1146 pub fn init(&mut self) -> SafeResult {
1154 self.2.clear();
1155 let code = unsafe { zstd_sys::ZSTD_initDStream(self.0.as_ptr()) };
1156 self.2.record(parse_code(code))
1157 }
1158
1159 #[cfg(feature = "experimental")]
1161 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1162 #[deprecated(note = "Use reset and load_dictionary instead.")]
1163 pub fn init_using_dict(&mut self, dict: &[u8]) -> SafeResult {
1164 self.2.clear();
1165 self.2.clear();
1166 let code = unsafe {
1167 zstd_sys::ZSTD_initDStream_usingDict(
1168 self.0.as_ptr(),
1169 ptr_void(dict),
1170 dict.len(),
1171 )
1172 };
1173 parse_code(code)
1174 }
1175
1176 #[cfg(feature = "experimental")]
1178 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1179 #[deprecated(note = "Use reset and ref_ddict instead.")]
1180 pub fn init_using_ddict<'b>(&mut self, ddict: &DDict<'b>) -> SafeResult
1181 where
1182 'b: 'a,
1183 {
1184 let code = unsafe {
1185 zstd_sys::ZSTD_initDStream_usingDDict(
1186 self.0.as_ptr(),
1187 ddict.0.as_ptr(),
1188 )
1189 };
1190 parse_code(code)
1191 }
1192
1193 pub fn reset(&mut self, reset: ResetDirective) -> SafeResult {
1199 let res = parse_code(unsafe {
1200 zstd_sys::ZSTD_DCtx_reset(self.0.as_ptr(), reset.as_sys())
1201 });
1202 if res.is_ok() && reset.resets_session() {
1203 self.2.clear();
1204 }
1205 res
1206 }
1207
1208 pub fn load_dictionary(&mut self, dict: &[u8]) -> SafeResult {
1220 parse_code(unsafe {
1221 zstd_sys::ZSTD_DCtx_loadDictionary(
1222 self.0.as_ptr(),
1223 ptr_void(dict),
1224 dict.len(),
1225 )
1226 })
1227 }
1228
1229 pub fn disable_dictionary(&mut self) -> SafeResult {
1233 parse_code(unsafe {
1234 zstd_sys::ZSTD_DCtx_loadDictionary(
1235 self.0.as_ptr(),
1236 core::ptr::null(),
1237 0,
1238 )
1239 })
1240 }
1241
1242 pub fn ref_ddict<'b>(&mut self, ddict: &'a DDict<'b>) -> SafeResult
1252 where
1253 'b: 'a,
1254 {
1255 parse_code(unsafe {
1256 zstd_sys::ZSTD_DCtx_refDDict(self.0.as_ptr(), ddict.0.as_ptr())
1257 })
1258 }
1259
1260 pub fn ref_prefix<'b>(&mut self, prefix: &'b [u8]) -> SafeResult
1268 where
1269 'b: 'a,
1270 {
1271 parse_code(unsafe {
1272 zstd_sys::ZSTD_DCtx_refPrefix(
1273 self.0.as_ptr(),
1274 ptr_void(prefix),
1275 prefix.len(),
1276 )
1277 })
1278 }
1279
1280 pub fn set_parameter(&mut self, param: DParameter) -> SafeResult {
1282 #[cfg(feature = "experimental")]
1283 use zstd_sys::ZSTD_dParameter::{
1284 ZSTD_d_experimentalParam1 as ZSTD_d_format,
1285 ZSTD_d_experimentalParam2 as ZSTD_d_stableOutBuffer,
1286 ZSTD_d_experimentalParam3 as ZSTD_d_forceIgnoreChecksum,
1287 ZSTD_d_experimentalParam4 as ZSTD_d_refMultipleDDicts,
1288 };
1289
1290 use zstd_sys::ZSTD_dParameter::*;
1291 use DParameter::*;
1292
1293 let (param, value) = match param {
1294 #[cfg(feature = "experimental")]
1295 Format(format) => (ZSTD_d_format, format as c_int),
1296 #[cfg(feature = "experimental")]
1297 StableOutBuffer(stable) => {
1298 (ZSTD_d_stableOutBuffer, stable as c_int)
1299 }
1300 #[cfg(feature = "experimental")]
1301 ForceIgnoreChecksum(force) => {
1302 (ZSTD_d_forceIgnoreChecksum, force as c_int)
1303 }
1304 #[cfg(feature = "experimental")]
1305 RefMultipleDDicts(value) => {
1306 (ZSTD_d_refMultipleDDicts, value as c_int)
1307 }
1308
1309 WindowLogMax(value) => (ZSTD_d_windowLogMax, value as c_int),
1310 };
1311
1312 parse_code(unsafe {
1313 zstd_sys::ZSTD_DCtx_setParameter(self.0.as_ptr(), param, value)
1314 })
1315 }
1316
1317 pub fn decompress_stream<C: WriteBuf + ?Sized>(
1329 &mut self,
1330 output: &mut OutBuffer<'_, C>,
1331 input: &mut InBuffer<'_>,
1332 ) -> SafeResult {
1333 self.2.guard()?;
1334 let mut output = output.wrap();
1335 let mut input = input.wrap();
1336 let code = unsafe {
1337 zstd_sys::ZSTD_decompressStream(
1338 self.0.as_ptr(),
1339 ptr_mut(&mut output),
1340 ptr_mut(&mut input),
1341 )
1342 };
1343 self.2.record(parse_code(code))
1344 }
1345
1346 pub fn in_size() -> usize {
1350 unsafe { zstd_sys::ZSTD_DStreamInSize() }
1351 }
1352
1353 pub fn out_size() -> usize {
1357 unsafe { zstd_sys::ZSTD_DStreamOutSize() }
1358 }
1359
1360 pub fn sizeof(&self) -> usize {
1362 unsafe { zstd_sys::ZSTD_sizeof_DCtx(self.0.as_ptr()) }
1363 }
1364
1365 #[cfg(feature = "experimental")]
1373 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1374 #[deprecated(
1375 note = "The block API is deprecated; use decompress_stream instead."
1376 )]
1377 pub unsafe fn decompress_block<C: WriteBuf + ?Sized>(
1378 &mut self,
1379 dst: &mut C,
1380 src: &[u8],
1381 ) -> SafeResult {
1382 unsafe {
1383 dst.write_from(|buffer, capacity| {
1384 parse_code(zstd_sys::ZSTD_decompressBlock(
1385 self.0.as_ptr(),
1386 buffer,
1387 capacity,
1388 ptr_void(src),
1389 src.len(),
1390 ))
1391 })
1392 }
1393 }
1394
1395 #[cfg(feature = "experimental")]
1403 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1404 #[deprecated(
1405 note = "The block API is deprecated; use decompress_stream instead."
1406 )]
1407 pub unsafe fn insert_block(&mut self, block: &[u8]) -> usize {
1408 unsafe {
1409 zstd_sys::ZSTD_insertBlock(
1410 self.0.as_ptr(),
1411 ptr_void(block),
1412 block.len(),
1413 )
1414 }
1415 }
1416
1417 #[cfg(feature = "experimental")]
1423 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1424 #[deprecated(
1425 note = "Context copying is deprecated by zstd; create a new context and configure it instead."
1426 )]
1427 pub fn try_clone(&self) -> Result<Self, ErrorCode> {
1428 self.2.guard()?;
1430 let context = Self::try_create().ok_or(MEMORY_ALLOCATION_ERROR)?;
1434
1435 unsafe {
1437 zstd_sys::ZSTD_copyDCtx(context.0.as_ptr(), self.0.as_ptr())
1438 };
1439
1440 Ok(context)
1441 }
1442}
1443
1444impl Drop for DCtx<'_> {
1445 fn drop(&mut self) {
1446 unsafe {
1447 zstd_sys::ZSTD_freeDCtx(self.0.as_ptr());
1448 }
1449 }
1450}
1451
1452unsafe impl Send for DCtx<'_> {}
1454unsafe impl Sync for DCtx<'_> {}
1457
1458pub struct CDict<'a>(NonNull<zstd_sys::ZSTD_CDict>, PhantomData<&'a ()>);
1464
1465impl CDict<'static> {
1466 pub fn create(
1476 dict_buffer: &[u8],
1477 compression_level: CompressionLevel,
1478 ) -> Self {
1479 Self::try_create(dict_buffer, compression_level)
1480 .expect("zstd returned null pointer when creating dict")
1481 }
1482
1483 pub fn try_create(
1489 dict_buffer: &[u8],
1490 compression_level: CompressionLevel,
1491 ) -> Option<Self> {
1492 #[cfg(feature = "with-rust-allocator")]
1493 let ptr = unsafe {
1494 rust_allocator::create_cdict(
1495 dict_buffer,
1496 compression_level,
1497 zstd_sys::ZSTD_dictLoadMethod_e::ZSTD_dlm_byCopy,
1498 )
1499 };
1500 #[cfg(not(feature = "with-rust-allocator"))]
1501 let ptr = unsafe {
1502 zstd_sys::ZSTD_createCDict(
1503 ptr_void(dict_buffer),
1504 dict_buffer.len(),
1505 compression_level,
1506 )
1507 };
1508 Some(CDict(NonNull::new(ptr)?, PhantomData))
1509 }
1510}
1511
1512impl<'a> CDict<'a> {
1513 #[cfg(feature = "experimental")]
1519 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1520 pub fn create_by_reference(
1521 dict_buffer: &'a [u8],
1522 compression_level: CompressionLevel,
1523 ) -> Self {
1524 Self::try_create_by_reference(dict_buffer, compression_level)
1525 .expect("zstd returned null pointer")
1526 }
1527
1528 #[cfg(feature = "experimental")]
1534 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1535 pub fn try_create_by_reference(
1536 dict_buffer: &'a [u8],
1537 compression_level: CompressionLevel,
1538 ) -> Option<Self> {
1539 #[cfg(feature = "with-rust-allocator")]
1540 let ptr = unsafe {
1541 rust_allocator::create_cdict(
1542 dict_buffer,
1543 compression_level,
1544 zstd_sys::ZSTD_dictLoadMethod_e::ZSTD_dlm_byRef,
1545 )
1546 };
1547 #[cfg(not(feature = "with-rust-allocator"))]
1548 let ptr = unsafe {
1549 zstd_sys::ZSTD_createCDict_byReference(
1550 ptr_void(dict_buffer),
1551 dict_buffer.len(),
1552 compression_level,
1553 )
1554 };
1555 Some(CDict(NonNull::new(ptr)?, PhantomData))
1556 }
1557
1558 pub fn sizeof(&self) -> usize {
1562 unsafe { zstd_sys::ZSTD_sizeof_CDict(self.0.as_ptr()) }
1563 }
1564
1565 pub fn get_dict_id(&self) -> Option<NonZeroU32> {
1569 NonZeroU32::new(unsafe {
1570 zstd_sys::ZSTD_getDictID_fromCDict(self.0.as_ptr()) as u32
1571 })
1572 }
1573}
1574
1575pub fn create_cdict(
1577 dict_buffer: &[u8],
1578 compression_level: CompressionLevel,
1579) -> CDict<'static> {
1580 CDict::create(dict_buffer, compression_level)
1581}
1582
1583impl<'a> Drop for CDict<'a> {
1584 fn drop(&mut self) {
1585 unsafe {
1586 zstd_sys::ZSTD_freeCDict(self.0.as_ptr());
1587 }
1588 }
1589}
1590
1591unsafe impl<'a> Send for CDict<'a> {}
1595unsafe impl<'a> Sync for CDict<'a> {}
1596
1597pub fn compress_using_cdict(
1599 cctx: &mut CCtx<'_>,
1600 dst: &mut [u8],
1601 src: &[u8],
1602 cdict: &CDict<'_>,
1603) -> SafeResult {
1604 cctx.compress_using_cdict(dst, src, cdict)
1605}
1606
1607pub struct DDict<'a>(NonNull<zstd_sys::ZSTD_DDict>, PhantomData<&'a ()>);
1609
1610impl DDict<'static> {
1611 pub fn create(dict_buffer: &[u8]) -> Self {
1619 Self::try_create(dict_buffer)
1620 .expect("zstd returned null pointer when creating dict")
1621 }
1622
1623 pub fn try_create(dict_buffer: &[u8]) -> Option<Self> {
1629 #[cfg(feature = "with-rust-allocator")]
1630 let ptr = unsafe {
1631 rust_allocator::create_ddict(
1632 dict_buffer,
1633 zstd_sys::ZSTD_dictLoadMethod_e::ZSTD_dlm_byCopy,
1634 )
1635 };
1636 #[cfg(not(feature = "with-rust-allocator"))]
1637 let ptr = unsafe {
1638 zstd_sys::ZSTD_createDDict(
1639 ptr_void(dict_buffer),
1640 dict_buffer.len(),
1641 )
1642 };
1643 Some(DDict(NonNull::new(ptr)?, PhantomData))
1644 }
1645}
1646
1647impl<'a> DDict<'a> {
1648 pub fn sizeof(&self) -> usize {
1649 unsafe { zstd_sys::ZSTD_sizeof_DDict(self.0.as_ptr()) }
1650 }
1651
1652 #[cfg(feature = "experimental")]
1660 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1661 pub fn create_by_reference(dict_buffer: &'a [u8]) -> Self {
1662 Self::try_create_by_reference(dict_buffer)
1663 .expect("zstd returned null pointer")
1664 }
1665
1666 #[cfg(feature = "experimental")]
1672 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1673 pub fn try_create_by_reference(dict_buffer: &'a [u8]) -> Option<Self> {
1674 #[cfg(feature = "with-rust-allocator")]
1675 let ptr = unsafe {
1676 rust_allocator::create_ddict(
1677 dict_buffer,
1678 zstd_sys::ZSTD_dictLoadMethod_e::ZSTD_dlm_byRef,
1679 )
1680 };
1681 #[cfg(not(feature = "with-rust-allocator"))]
1682 let ptr = unsafe {
1683 zstd_sys::ZSTD_createDDict_byReference(
1684 ptr_void(dict_buffer),
1685 dict_buffer.len(),
1686 )
1687 };
1688 Some(DDict(NonNull::new(ptr)?, PhantomData))
1689 }
1690
1691 pub fn get_dict_id(&self) -> Option<NonZeroU32> {
1695 NonZeroU32::new(unsafe {
1696 zstd_sys::ZSTD_getDictID_fromDDict(self.0.as_ptr()) as u32
1697 })
1698 }
1699}
1700
1701pub fn create_ddict(dict_buffer: &[u8]) -> DDict<'static> {
1705 DDict::create(dict_buffer)
1706}
1707
1708impl<'a> Drop for DDict<'a> {
1709 fn drop(&mut self) {
1710 unsafe {
1711 zstd_sys::ZSTD_freeDDict(self.0.as_ptr());
1712 }
1713 }
1714}
1715
1716unsafe impl<'a> Send for DDict<'a> {}
1719unsafe impl<'a> Sync for DDict<'a> {}
1720
1721#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1723#[cfg_attr(
1724 feature = "doc-cfg",
1725 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1726)]
1727pub struct ThreadPool(NonNull<zstd_sys::ZSTD_threadPool>);
1728
1729#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1730#[cfg_attr(
1731 feature = "doc-cfg",
1732 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1733)]
1734impl ThreadPool {
1735 pub fn new(num_threads: usize) -> Self {
1741 Self::try_new(num_threads)
1742 .expect("zstd returned null pointer when creating thread pool")
1743 }
1744
1745 pub fn try_new(num_threads: usize) -> Option<Self> {
1747 Some(Self(NonNull::new(unsafe {
1748 zstd_sys::ZSTD_createThreadPool(num_threads)
1749 })?))
1750 }
1751}
1752
1753#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1754#[cfg_attr(
1755 feature = "doc-cfg",
1756 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1757)]
1758impl Drop for ThreadPool {
1759 fn drop(&mut self) {
1760 unsafe {
1761 zstd_sys::ZSTD_freeThreadPool(self.0.as_ptr());
1762 }
1763 }
1764}
1765
1766#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1767#[cfg_attr(
1768 feature = "doc-cfg",
1769 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1770)]
1771unsafe impl Send for ThreadPool {}
1774#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1775#[cfg_attr(
1776 feature = "doc-cfg",
1777 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1778)]
1779unsafe impl Sync for ThreadPool {}
1783
1784pub fn decompress_using_ddict(
1786 dctx: &mut DCtx<'_>,
1787 dst: &mut [u8],
1788 src: &[u8],
1789 ddict: &DDict<'_>,
1790) -> SafeResult {
1791 dctx.decompress_using_ddict(dst, src, ddict)
1792}
1793
1794pub type CStream<'a> = CCtx<'a>;
1798
1799pub fn create_cstream<'a>() -> CStream<'a> {
1803 CCtx::create()
1804}
1805
1806pub fn init_cstream(
1808 zcs: &mut CStream<'_>,
1809 compression_level: CompressionLevel,
1810) -> SafeResult {
1811 zcs.init(compression_level)
1812}
1813
1814#[derive(Debug)]
1815pub struct InBuffer<'a> {
1821 pub src: &'a [u8],
1822 pub pos: usize,
1823}
1824
1825pub unsafe trait WriteBuf {
1857 fn as_slice(&self) -> &[u8];
1859
1860 fn capacity(&self) -> usize;
1862
1863 fn as_mut_ptr(&mut self) -> *mut u8;
1865
1866 unsafe fn filled_until(&mut self, n: usize);
1872
1873 unsafe fn write_from<F>(&mut self, f: F) -> SafeResult
1885 where
1886 F: FnOnce(*mut c_void, usize) -> SafeResult,
1887 {
1888 let res = f(ptr_mut_void(self), self.capacity());
1889 if let Ok(n) = res {
1890 self.filled_until(n);
1891 }
1892 res
1893 }
1894}
1895
1896#[cfg(feature = "std")]
1904fn cursor_position<T>(cursor: &std::io::Cursor<T>) -> usize {
1905 use core::convert::TryFrom;
1906
1907 usize::try_from(cursor.position()).unwrap_or(usize::MAX)
1908}
1909
1910#[cfg(feature = "std")]
1911#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "std")))]
1912unsafe impl<T> WriteBuf for std::io::Cursor<T>
1913where
1914 T: WriteBuf,
1915{
1916 fn as_slice(&self) -> &[u8] {
1917 &self.get_ref().as_slice()[cursor_position(self)..]
1918 }
1919
1920 fn capacity(&self) -> usize {
1921 self.get_ref()
1922 .capacity()
1923 .saturating_sub(cursor_position(self))
1924 }
1925
1926 fn as_mut_ptr(&mut self) -> *mut u8 {
1927 let start = cursor_position(self);
1928 assert!(start <= self.get_ref().capacity());
1929 unsafe { self.get_mut().as_mut_ptr().add(start) }
1931 }
1932
1933 unsafe fn filled_until(&mut self, n: usize) {
1934 if n == 0 {
1936 return;
1937 }
1938
1939 let position = cursor_position(self);
1943 assert!(position <= self.get_ref().capacity());
1947 let initialized = self.get_ref().as_slice().len();
1948 if let Some(uninitialized) = position.checked_sub(initialized) {
1949 unsafe {
1961 self.get_mut()
1962 .as_mut_ptr()
1963 .add(initialized)
1964 .write_bytes(0u8, uninitialized)
1965 };
1966 }
1967
1968 let start = position;
1969 assert!(start + n <= self.get_ref().capacity());
1970 self.get_mut().filled_until(start + n);
1971 }
1972}
1973
1974#[cfg(feature = "std")]
1975#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "std")))]
1976unsafe impl WriteBuf for &mut std::vec::Vec<u8> {
1977 fn as_slice(&self) -> &[u8] {
1978 std::vec::Vec::as_slice(self)
1979 }
1980
1981 fn capacity(&self) -> usize {
1982 std::vec::Vec::capacity(self)
1983 }
1984
1985 fn as_mut_ptr(&mut self) -> *mut u8 {
1986 std::vec::Vec::as_mut_ptr(self)
1987 }
1988
1989 unsafe fn filled_until(&mut self, n: usize) {
1990 std::vec::Vec::set_len(self, n)
1991 }
1992}
1993
1994#[cfg(feature = "std")]
1995#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "std")))]
1996unsafe impl WriteBuf for std::vec::Vec<u8> {
1997 fn as_slice(&self) -> &[u8] {
1998 &self[..]
1999 }
2000 fn capacity(&self) -> usize {
2001 self.capacity()
2002 }
2003 fn as_mut_ptr(&mut self) -> *mut u8 {
2004 self.as_mut_ptr()
2005 }
2006 unsafe fn filled_until(&mut self, n: usize) {
2007 self.set_len(n);
2008 }
2009}
2010
2011#[cfg(feature = "arrays")]
2012#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "arrays")))]
2013unsafe impl<const N: usize> WriteBuf for [u8; N] {
2014 fn as_slice(&self) -> &[u8] {
2015 self
2016 }
2017 fn capacity(&self) -> usize {
2018 self.len()
2019 }
2020
2021 fn as_mut_ptr(&mut self) -> *mut u8 {
2022 self[..].as_mut_ptr()
2023 }
2024
2025 unsafe fn filled_until(&mut self, _n: usize) {
2026 }
2028}
2029
2030unsafe impl WriteBuf for [u8] {
2031 fn as_slice(&self) -> &[u8] {
2032 self
2033 }
2034 fn capacity(&self) -> usize {
2035 self.len()
2036 }
2037
2038 fn as_mut_ptr(&mut self) -> *mut u8 {
2039 self.as_mut_ptr()
2040 }
2041
2042 unsafe fn filled_until(&mut self, _n: usize) {
2043 }
2045}
2046
2047#[derive(Debug)]
2066pub struct OutBuffer<'a, C: WriteBuf + ?Sized> {
2078 dst: &'a mut C,
2079 pos: usize,
2080}
2081
2082fn ptr_mut<B>(ptr_void: &mut B) -> *mut B {
2084 ptr_void as *mut B
2085}
2086
2087struct OutBufferWrapper<'a, 'b, C: WriteBuf + ?Sized> {
2091 buf: zstd_sys::ZSTD_outBuffer,
2092 parent: &'a mut OutBuffer<'b, C>,
2093}
2094
2095impl<'a, 'b: 'a, C: WriteBuf + ?Sized> Deref for OutBufferWrapper<'a, 'b, C> {
2096 type Target = zstd_sys::ZSTD_outBuffer;
2097
2098 fn deref(&self) -> &Self::Target {
2099 &self.buf
2100 }
2101}
2102
2103impl<'a, 'b: 'a, C: WriteBuf + ?Sized> DerefMut
2104 for OutBufferWrapper<'a, 'b, C>
2105{
2106 fn deref_mut(&mut self) -> &mut Self::Target {
2107 &mut self.buf
2108 }
2109}
2110
2111impl<'a, C: WriteBuf + ?Sized> OutBuffer<'a, C> {
2112 pub fn around(dst: &'a mut C) -> Self {
2116 OutBuffer { dst, pos: 0 }
2117 }
2118
2119 pub fn around_pos(dst: &'a mut C, pos: usize) -> Self {
2125 if pos > dst.capacity() {
2126 panic!("Given position outside of the buffer bounds.");
2127 }
2128
2129 OutBuffer { dst, pos }
2130 }
2131
2132 pub fn pos(&self) -> usize {
2136 assert!(self.pos <= self.dst.capacity());
2137 self.pos
2138 }
2139
2140 pub fn capacity(&self) -> usize {
2142 self.dst.capacity()
2143 }
2144
2145 pub unsafe fn set_pos(&mut self, pos: usize) {
2155 if pos > self.dst.capacity() {
2156 panic!("Given position outside of the buffer bounds.");
2157 }
2158
2159 self.dst.filled_until(pos);
2160
2161 self.pos = pos;
2162 }
2163
2164 fn wrap<'b>(&'b mut self) -> OutBufferWrapper<'b, 'a, C> {
2165 OutBufferWrapper {
2166 buf: zstd_sys::ZSTD_outBuffer {
2167 dst: ptr_mut_void(self.dst),
2168 size: self.dst.capacity(),
2169 pos: self.pos,
2170 },
2171 parent: self,
2172 }
2173 }
2174
2175 pub fn as_slice<'b>(&'b self) -> &'a [u8]
2177 where
2178 'b: 'a,
2179 {
2180 let pos = self.pos;
2181 &self.dst.as_slice()[..pos]
2182 }
2183
2184 pub fn as_mut_ptr(&mut self) -> *mut u8 {
2186 self.dst.as_mut_ptr()
2187 }
2188}
2189
2190impl<'a, 'b, C: WriteBuf + ?Sized> Drop for OutBufferWrapper<'a, 'b, C> {
2191 fn drop(&mut self) {
2192 unsafe { self.parent.set_pos(self.buf.pos) };
2194 }
2195}
2196
2197struct InBufferWrapper<'a, 'b> {
2198 buf: zstd_sys::ZSTD_inBuffer,
2199 parent: &'a mut InBuffer<'b>,
2200}
2201
2202impl<'a, 'b: 'a> Deref for InBufferWrapper<'a, 'b> {
2203 type Target = zstd_sys::ZSTD_inBuffer;
2204
2205 fn deref(&self) -> &Self::Target {
2206 &self.buf
2207 }
2208}
2209
2210impl<'a, 'b: 'a> DerefMut for InBufferWrapper<'a, 'b> {
2211 fn deref_mut(&mut self) -> &mut Self::Target {
2212 &mut self.buf
2213 }
2214}
2215
2216impl<'a> InBuffer<'a> {
2217 pub fn around(src: &'a [u8]) -> Self {
2221 InBuffer { src, pos: 0 }
2222 }
2223
2224 pub fn pos(&self) -> usize {
2226 self.pos
2227 }
2228
2229 pub fn set_pos(&mut self, pos: usize) {
2235 if pos > self.src.len() {
2236 panic!("Given position outside of the buffer bounds.");
2237 }
2238 self.pos = pos;
2239 }
2240
2241 fn wrap<'b>(&'b mut self) -> InBufferWrapper<'b, 'a> {
2242 InBufferWrapper {
2243 buf: zstd_sys::ZSTD_inBuffer {
2244 src: ptr_void(self.src),
2245 size: self.src.len(),
2246 pos: self.pos,
2247 },
2248 parent: self,
2249 }
2250 }
2251}
2252
2253impl<'a, 'b> Drop for InBufferWrapper<'a, 'b> {
2254 fn drop(&mut self) {
2255 self.parent.set_pos(self.buf.pos);
2256 }
2257}
2258
2259pub type DStream<'a> = DCtx<'a>;
2263
2264pub fn find_frame_compressed_size(src: &[u8]) -> SafeResult {
2274 let code = unsafe {
2275 zstd_sys::ZSTD_findFrameCompressedSize(ptr_void(src), src.len())
2276 };
2277 parse_code(code)
2278}
2279
2280pub fn get_frame_content_size(
2290 src: &[u8],
2291) -> Result<Option<u64>, ContentSizeError> {
2292 parse_content_size(unsafe {
2293 zstd_sys::ZSTD_getFrameContentSize(ptr_void(src), src.len())
2294 })
2295}
2296
2297#[cfg(feature = "experimental")]
2301#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2302pub fn find_decompressed_size(
2303 src: &[u8],
2304) -> Result<Option<u64>, ContentSizeError> {
2305 parse_content_size(unsafe {
2306 zstd_sys::ZSTD_findDecompressedSize(ptr_void(src), src.len())
2307 })
2308}
2309
2310#[cfg(feature = "experimental")]
2312#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2313pub fn is_frame(buffer: &[u8]) -> bool {
2314 unsafe { zstd_sys::ZSTD_isFrame(ptr_void(buffer), buffer.len()) > 0 }
2315}
2316
2317pub fn get_dict_id_from_dict(dict: &[u8]) -> Option<NonZeroU32> {
2321 NonZeroU32::new(unsafe {
2322 zstd_sys::ZSTD_getDictID_fromDict(ptr_void(dict), dict.len()) as u32
2323 })
2324}
2325
2326pub fn get_dict_id_from_frame(src: &[u8]) -> Option<NonZeroU32> {
2335 NonZeroU32::new(unsafe {
2336 zstd_sys::ZSTD_getDictID_fromFrame(ptr_void(src), src.len()) as u32
2337 })
2338}
2339
2340#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2342pub enum ResetDirective {
2343 SessionOnly,
2351
2352 Parameters,
2358
2359 SessionAndParameters,
2363}
2364
2365impl ResetDirective {
2366 fn resets_session(self) -> bool {
2372 matches!(
2373 self,
2374 ResetDirective::SessionOnly | ResetDirective::SessionAndParameters
2375 )
2376 }
2377
2378 fn as_sys(self) -> zstd_sys::ZSTD_ResetDirective {
2379 match self {
2380 ResetDirective::SessionOnly => zstd_sys::ZSTD_ResetDirective::ZSTD_reset_session_only,
2381 ResetDirective::Parameters => zstd_sys::ZSTD_ResetDirective::ZSTD_reset_parameters,
2382 ResetDirective::SessionAndParameters => zstd_sys::ZSTD_ResetDirective::ZSTD_reset_session_and_parameters,
2383 }
2384 }
2385}
2386
2387#[cfg(feature = "experimental")]
2388#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2389#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2390#[repr(u32)]
2391pub enum FrameFormat {
2392 One = zstd_sys::ZSTD_format_e::ZSTD_f_zstd1 as u32,
2394
2395 Magicless = zstd_sys::ZSTD_format_e::ZSTD_f_zstd1_magicless as u32,
2397}
2398
2399#[cfg(feature = "experimental")]
2400#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2401#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2402#[repr(u32)]
2403pub enum DictAttachPref {
2404 DefaultAttach =
2405 zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictDefaultAttach as u32,
2406 ForceAttach = zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictForceAttach as u32,
2407 ForceCopy = zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictForceCopy as u32,
2408 ForceLoad = zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictForceLoad as u32,
2409}
2410
2411#[cfg(feature = "experimental")]
2412#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2413#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2414#[repr(u32)]
2415pub enum ParamSwitch {
2416 Auto = zstd_sys::ZSTD_ParamSwitch_e::ZSTD_ps_auto as u32,
2417 Enable = zstd_sys::ZSTD_ParamSwitch_e::ZSTD_ps_enable as u32,
2418 Disable = zstd_sys::ZSTD_ParamSwitch_e::ZSTD_ps_disable as u32,
2419}
2420
2421#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2423#[non_exhaustive]
2424pub enum CParameter {
2425 #[cfg(feature = "experimental")]
2426 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2427 RSyncable(bool),
2428
2429 #[cfg(feature = "experimental")]
2430 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2431 Format(FrameFormat),
2432
2433 #[cfg(feature = "experimental")]
2434 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2435 ForceMaxWindow(bool),
2436
2437 #[cfg(feature = "experimental")]
2438 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2439 ForceAttachDict(DictAttachPref),
2440
2441 #[cfg(feature = "experimental")]
2442 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2443 LiteralCompressionMode(ParamSwitch),
2444
2445 #[cfg(feature = "experimental")]
2446 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2447 SrcSizeHint(u32),
2448
2449 #[cfg(feature = "experimental")]
2450 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2451 EnableDedicatedDictSearch(bool),
2452
2453 #[cfg(feature = "experimental")]
2454 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2455 StableInBuffer(bool),
2456
2457 #[cfg(feature = "experimental")]
2458 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2459 StableOutBuffer(bool),
2460
2461 #[cfg(feature = "experimental")]
2462 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2463 BlockDelimiters(bool),
2464
2465 #[cfg(feature = "experimental")]
2466 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2467 ValidateSequences(bool),
2468
2469 #[cfg(feature = "experimental")]
2470 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2471 UseBlockSplitter(ParamSwitch),
2472
2473 #[cfg(feature = "experimental")]
2474 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2475 UseRowMatchFinder(ParamSwitch),
2476
2477 #[cfg(feature = "experimental")]
2478 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2479 DeterministicRefPrefix(bool),
2480
2481 #[cfg(feature = "experimental")]
2482 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2483 PrefetchCDictTables(ParamSwitch),
2484
2485 #[cfg(feature = "experimental")]
2486 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2487 EnableSeqProducerFallback(bool),
2488
2489 #[cfg(feature = "experimental")]
2490 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2491 MaxBlockSize(u32),
2492
2493 #[cfg(feature = "experimental")]
2494 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2495 SearchForExternalRepcodes(ParamSwitch),
2496
2497 TargetCBlockSize(u32),
2504
2505 CompressionLevel(CompressionLevel),
2509
2510 WindowLog(u32),
2514
2515 HashLog(u32),
2516
2517 ChainLog(u32),
2518
2519 SearchLog(u32),
2520
2521 MinMatch(u32),
2522
2523 TargetLength(u32),
2524
2525 Strategy(Strategy),
2526
2527 EnableLongDistanceMatching(bool),
2528
2529 LdmHashLog(u32),
2530
2531 LdmMinMatch(u32),
2532
2533 LdmBucketSizeLog(u32),
2534
2535 LdmHashRateLog(u32),
2536
2537 ContentSizeFlag(bool),
2538
2539 ChecksumFlag(bool),
2540
2541 DictIdFlag(bool),
2542
2543 NbWorkers(u32),
2552
2553 JobSize(u32),
2561
2562 OverlapSizeLog(u32),
2574}
2575
2576#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2578#[non_exhaustive]
2579pub enum DParameter {
2580 WindowLogMax(u32),
2581
2582 #[cfg(feature = "experimental")]
2583 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2584 Format(FrameFormat),
2586
2587 #[cfg(feature = "experimental")]
2588 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2589 StableOutBuffer(bool),
2590
2591 #[cfg(feature = "experimental")]
2592 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2593 ForceIgnoreChecksum(bool),
2594
2595 #[cfg(feature = "experimental")]
2596 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2597 RefMultipleDDicts(bool),
2598}
2599
2600#[cfg(feature = "zdict_builder")]
2602#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "zdict_builder")))]
2603pub fn train_from_buffer<C: WriteBuf + ?Sized>(
2604 dict_buffer: &mut C,
2605 samples_buffer: &[u8],
2606 samples_sizes: &[usize],
2607) -> SafeResult {
2608 assert_eq!(samples_buffer.len(), samples_sizes.iter().sum());
2609
2610 unsafe {
2611 dict_buffer.write_from(|buffer, capacity| {
2612 parse_code(zstd_sys::ZDICT_trainFromBuffer(
2613 buffer,
2614 capacity,
2615 ptr_void(samples_buffer),
2616 samples_sizes.as_ptr(),
2617 samples_sizes.len() as u32,
2618 ))
2619 })
2620 }
2621}
2622
2623#[cfg(feature = "zdict_builder")]
2625#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "zdict_builder")))]
2626pub fn get_dict_id(dict_buffer: &[u8]) -> Option<NonZeroU32> {
2627 NonZeroU32::new(unsafe {
2628 zstd_sys::ZDICT_getDictID(ptr_void(dict_buffer), dict_buffer.len())
2629 })
2630}
2631
2632#[cfg(feature = "experimental")]
2634#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2635#[deprecated(
2636 note = "The block API is deprecated; use the normal compression API instead."
2637)]
2638pub fn get_block_size(cctx: &CCtx) -> usize {
2639 unsafe { zstd_sys::ZSTD_getBlockSize(cctx.0.as_ptr()) }
2640}
2641
2642#[cfg(feature = "experimental")]
2644#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2645pub fn decompress_bound(data: &[u8]) -> Result<u64, ErrorCode> {
2646 let bound =
2647 unsafe { zstd_sys::ZSTD_decompressBound(ptr_void(data), data.len()) };
2648 if is_error(bound as usize) {
2649 Err(bound as usize)
2650 } else {
2651 Ok(bound)
2652 }
2653}
2654
2655#[cfg(feature = "experimental")]
2658#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2659pub fn sequence_bound(src_size: usize) -> usize {
2660 unsafe { zstd_sys::ZSTD_sequenceBound(src_size) }
2662}
2663
2664#[cfg(feature = "experimental")]
2670#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2671pub fn decompression_margin(
2672 compressed_data: &[u8],
2673) -> Result<usize, ErrorCode> {
2674 parse_code(unsafe {
2675 zstd_sys::ZSTD_decompressionMargin(
2676 ptr_void(compressed_data),
2677 compressed_data.len(),
2678 )
2679 })
2680}