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 = "seekable")]
31pub mod seekable;
32
33pub use zstd_sys;
35
36pub use zstd_sys::ZSTD_strategy as Strategy;
38
39#[cfg(feature = "experimental")]
41#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
42pub use zstd_sys::ZSTD_frameProgression as FrameProgression;
43
44use core::ffi::{c_char, c_int, c_ulonglong, c_void};
47
48use core::marker::PhantomData;
49use core::num::{NonZeroU32, NonZeroU64};
50use core::ops::{Deref, DerefMut};
51use core::ptr::NonNull;
52use core::str;
53
54include!("constants.rs");
55
56#[cfg(feature = "experimental")]
57include!("constants_experimental.rs");
58
59#[cfg(feature = "seekable")]
60include!("constants_seekable.rs");
61
62pub type CompressionLevel = i32;
64
65pub type ErrorCode = usize;
67
68pub type SafeResult = Result<usize, ErrorCode>;
72
73#[derive(Debug)]
77pub struct ContentSizeError;
78
79impl core::fmt::Display for ContentSizeError {
80 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
81 f.write_str("Could not get content size")
82 }
83}
84
85fn is_error(code: usize) -> bool {
87 unsafe { zstd_sys::ZSTD_isError(code) != 0 }
89}
90
91fn parse_code(code: usize) -> SafeResult {
96 if !is_error(code) {
97 Ok(code)
98 } else {
99 Err(code)
100 }
101}
102
103fn parse_content_size(
107 content_size: u64,
108) -> Result<Option<u64>, ContentSizeError> {
109 match content_size {
110 CONTENTSIZE_ERROR => Err(ContentSizeError),
111 CONTENTSIZE_UNKNOWN => Ok(None),
112 other => Ok(Some(other)),
113 }
114}
115
116fn ptr_void(src: &[u8]) -> *const c_void {
117 src.as_ptr() as *const c_void
118}
119
120fn ptr_mut_void(dst: &mut (impl WriteBuf + ?Sized)) -> *mut c_void {
121 dst.as_mut_ptr() as *mut c_void
122}
123
124pub fn version_number() -> u32 {
129 unsafe { zstd_sys::ZSTD_versionNumber() as u32 }
131}
132
133pub fn version_string() -> &'static str {
137 unsafe { c_char_to_str(zstd_sys::ZSTD_versionString()) }
139}
140
141pub fn min_c_level() -> CompressionLevel {
145 unsafe { zstd_sys::ZSTD_minCLevel() as CompressionLevel }
147}
148
149pub fn max_c_level() -> CompressionLevel {
151 unsafe { zstd_sys::ZSTD_maxCLevel() as CompressionLevel }
153}
154
155pub fn compress<C: WriteBuf + ?Sized>(
163 dst: &mut C,
164 src: &[u8],
165 compression_level: CompressionLevel,
166) -> SafeResult {
167 unsafe {
169 dst.write_from(|buffer, capacity| {
170 parse_code(zstd_sys::ZSTD_compress(
171 buffer,
172 capacity,
173 ptr_void(src),
174 src.len(),
175 compression_level,
176 ))
177 })
178 }
179}
180
181pub fn decompress<C: WriteBuf + ?Sized>(
190 dst: &mut C,
191 src: &[u8],
192) -> SafeResult {
193 unsafe {
195 dst.write_from(|buffer, capacity| {
196 parse_code(zstd_sys::ZSTD_decompress(
197 buffer,
198 capacity,
199 ptr_void(src),
200 src.len(),
201 ))
202 })
203 }
204}
205
206#[deprecated(note = "Use ZSTD_getFrameContentSize instead")]
210pub fn get_decompressed_size(src: &[u8]) -> Option<NonZeroU64> {
211 NonZeroU64::new(unsafe {
213 zstd_sys::ZSTD_getDecompressedSize(ptr_void(src), src.len()) as u64
214 })
215}
216
217pub fn compress_bound(src_size: usize) -> usize {
219 unsafe { zstd_sys::ZSTD_compressBound(src_size) }
221}
222
223#[derive(Clone, Debug, Default)]
233struct Poison(Option<ErrorCode>);
234
235impl Poison {
236 fn guard(&self) -> Result<(), ErrorCode> {
238 match self.0 {
239 Some(code) => Err(code),
240 None => Ok(()),
241 }
242 }
243
244 fn record(&mut self, res: SafeResult) -> SafeResult {
246 if let Err(code) = res {
247 self.0 = Some(code);
248 }
249 res
250 }
251
252 fn clear(&mut self) {
254 self.0 = None;
255 }
256}
257
258pub struct CCtx<'a>(NonNull<zstd_sys::ZSTD_CCtx>, PhantomData<&'a ()>, Poison);
263
264impl Default for CCtx<'_> {
265 fn default() -> Self {
266 CCtx::create()
267 }
268}
269
270impl<'a> CCtx<'a> {
271 pub fn try_create() -> Option<Self> {
275 Some(CCtx(
277 NonNull::new(unsafe { zstd_sys::ZSTD_createCCtx() })?,
278 PhantomData,
279 Poison::default(),
280 ))
281 }
282
283 pub fn create() -> Self {
289 Self::try_create()
290 .expect("zstd returned null pointer when creating new context")
291 }
292
293 pub fn compress<C: WriteBuf + ?Sized>(
295 &mut self,
296 dst: &mut C,
297 src: &[u8],
298 compression_level: CompressionLevel,
299 ) -> SafeResult {
300 self.2.clear();
301 unsafe {
303 dst.write_from(|buffer, capacity| {
304 parse_code(zstd_sys::ZSTD_compressCCtx(
305 self.0.as_ptr(),
306 buffer,
307 capacity,
308 ptr_void(src),
309 src.len(),
310 compression_level,
311 ))
312 })
313 }
314 }
315
316 pub fn compress2<C: WriteBuf + ?Sized>(
318 &mut self,
319 dst: &mut C,
320 src: &[u8],
321 ) -> SafeResult {
322 self.2.clear();
323 unsafe {
325 dst.write_from(|buffer, capacity| {
326 parse_code(zstd_sys::ZSTD_compress2(
327 self.0.as_ptr(),
328 buffer,
329 capacity,
330 ptr_void(src),
331 src.len(),
332 ))
333 })
334 }
335 }
336
337 pub fn compress_using_dict<C: WriteBuf + ?Sized>(
339 &mut self,
340 dst: &mut C,
341 src: &[u8],
342 dict: &[u8],
343 compression_level: CompressionLevel,
344 ) -> SafeResult {
345 self.2.clear();
346 unsafe {
348 dst.write_from(|buffer, capacity| {
349 parse_code(zstd_sys::ZSTD_compress_usingDict(
350 self.0.as_ptr(),
351 buffer,
352 capacity,
353 ptr_void(src),
354 src.len(),
355 ptr_void(dict),
356 dict.len(),
357 compression_level,
358 ))
359 })
360 }
361 }
362
363 pub fn compress_using_cdict<C: WriteBuf + ?Sized>(
365 &mut self,
366 dst: &mut C,
367 src: &[u8],
368 cdict: &CDict<'_>,
369 ) -> SafeResult {
370 self.2.clear();
371 unsafe {
373 dst.write_from(|buffer, capacity| {
374 parse_code(zstd_sys::ZSTD_compress_usingCDict(
375 self.0.as_ptr(),
376 buffer,
377 capacity,
378 ptr_void(src),
379 src.len(),
380 cdict.0.as_ptr(),
381 ))
382 })
383 }
384 }
385
386 pub fn init(&mut self, compression_level: CompressionLevel) -> SafeResult {
392 self.2.clear();
393 let code = unsafe {
395 zstd_sys::ZSTD_initCStream(self.0.as_ptr(), compression_level)
396 };
397 self.2.record(parse_code(code))
398 }
399
400 #[cfg(feature = "experimental")]
402 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
403 #[deprecated]
404 pub fn init_src_size(
405 &mut self,
406 compression_level: CompressionLevel,
407 pledged_src_size: u64,
408 ) -> SafeResult {
409 self.2.clear();
410 let code = unsafe {
412 zstd_sys::ZSTD_initCStream_srcSize(
413 self.0.as_ptr(),
414 compression_level as c_int,
415 pledged_src_size as c_ulonglong,
416 )
417 };
418 parse_code(code)
419 }
420
421 #[cfg(feature = "experimental")]
423 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
424 #[deprecated]
425 pub fn init_using_dict(
426 &mut self,
427 dict: &[u8],
428 compression_level: CompressionLevel,
429 ) -> SafeResult {
430 self.2.clear();
431 self.2.clear();
432 let code = unsafe {
434 zstd_sys::ZSTD_initCStream_usingDict(
435 self.0.as_ptr(),
436 ptr_void(dict),
437 dict.len(),
438 compression_level,
439 )
440 };
441 parse_code(code)
442 }
443
444 #[cfg(feature = "experimental")]
446 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
447 #[deprecated]
448 pub fn init_using_cdict<'b>(&mut self, cdict: &CDict<'b>) -> SafeResult
449 where
450 'b: 'a, {
452 let code = unsafe {
454 zstd_sys::ZSTD_initCStream_usingCDict(
455 self.0.as_ptr(),
456 cdict.0.as_ptr(),
457 )
458 };
459 parse_code(code)
460 }
461
462 pub fn load_dictionary(&mut self, dict: &[u8]) -> SafeResult {
472 parse_code(unsafe {
474 zstd_sys::ZSTD_CCtx_loadDictionary(
475 self.0.as_ptr(),
476 ptr_void(dict),
477 dict.len(),
478 )
479 })
480 }
481
482 pub fn ref_cdict<'b>(&mut self, cdict: &'a CDict<'b>) -> SafeResult
486 where
487 'b: 'a,
488 {
489 parse_code(unsafe {
491 zstd_sys::ZSTD_CCtx_refCDict(self.0.as_ptr(), cdict.0.as_ptr())
492 })
493 }
494
495 pub fn disable_dictionary(&mut self) -> SafeResult {
499 parse_code(unsafe {
501 zstd_sys::ZSTD_CCtx_loadDictionary(
502 self.0.as_ptr(),
503 core::ptr::null(),
504 0,
505 )
506 })
507 }
508
509 pub fn ref_prefix<'b>(&mut self, prefix: &'b [u8]) -> SafeResult
515 where
516 'b: 'a,
517 {
518 parse_code(unsafe {
520 zstd_sys::ZSTD_CCtx_refPrefix(
521 self.0.as_ptr(),
522 ptr_void(prefix),
523 prefix.len(),
524 )
525 })
526 }
527
528 pub fn compress_stream<C: WriteBuf + ?Sized>(
540 &mut self,
541 output: &mut OutBuffer<'_, C>,
542 input: &mut InBuffer<'_>,
543 ) -> SafeResult {
544 self.2.guard()?;
545 let mut output = output.wrap();
546 let mut input = input.wrap();
547 let code = unsafe {
549 zstd_sys::ZSTD_compressStream(
550 self.0.as_ptr(),
551 ptr_mut(&mut output),
552 ptr_mut(&mut input),
553 )
554 };
555 self.2.record(parse_code(code))
556 }
557
558 pub fn compress_stream2<C: WriteBuf + ?Sized>(
574 &mut self,
575 output: &mut OutBuffer<'_, C>,
576 input: &mut InBuffer<'_>,
577 end_op: zstd_sys::ZSTD_EndDirective,
578 ) -> SafeResult {
579 self.2.guard()?;
580 let mut output = output.wrap();
581 let mut input = input.wrap();
582 let code = unsafe {
584 zstd_sys::ZSTD_compressStream2(
585 self.0.as_ptr(),
586 ptr_mut(&mut output),
587 ptr_mut(&mut input),
588 end_op,
589 )
590 };
591 self.2.record(parse_code(code))
592 }
593
594 pub fn flush_stream<C: WriteBuf + ?Sized>(
600 &mut self,
601 output: &mut OutBuffer<'_, C>,
602 ) -> SafeResult {
603 self.2.guard()?;
604 let mut output = output.wrap();
605 let code = unsafe {
607 zstd_sys::ZSTD_flushStream(self.0.as_ptr(), ptr_mut(&mut output))
608 };
609 self.2.record(parse_code(code))
610 }
611
612 pub fn end_stream<C: WriteBuf + ?Sized>(
618 &mut self,
619 output: &mut OutBuffer<'_, C>,
620 ) -> SafeResult {
621 self.2.guard()?;
622 let mut output = output.wrap();
623 let code = unsafe {
625 zstd_sys::ZSTD_endStream(self.0.as_ptr(), ptr_mut(&mut output))
626 };
627 self.2.record(parse_code(code))
628 }
629
630 pub fn sizeof(&self) -> usize {
634 unsafe { zstd_sys::ZSTD_sizeof_CCtx(self.0.as_ptr()) }
636 }
637
638 pub fn reset(&mut self, reset: ResetDirective) -> SafeResult {
644 let res = parse_code(unsafe {
646 zstd_sys::ZSTD_CCtx_reset(self.0.as_ptr(), reset.as_sys())
647 });
648 if res.is_ok() && reset.resets_session() {
649 self.2.clear();
650 }
651 res
652 }
653
654 pub fn set_parameter(&mut self, param: CParameter) -> SafeResult {
658 #[cfg(feature = "experimental")]
661 use zstd_sys::ZSTD_cParameter::{
662 ZSTD_c_experimentalParam1 as ZSTD_c_rsyncable,
663 ZSTD_c_experimentalParam10 as ZSTD_c_stableOutBuffer,
664 ZSTD_c_experimentalParam11 as ZSTD_c_blockDelimiters,
665 ZSTD_c_experimentalParam12 as ZSTD_c_validateSequences,
666 ZSTD_c_experimentalParam13 as ZSTD_c_useBlockSplitter,
667 ZSTD_c_experimentalParam14 as ZSTD_c_useRowMatchFinder,
668 ZSTD_c_experimentalParam15 as ZSTD_c_deterministicRefPrefix,
669 ZSTD_c_experimentalParam16 as ZSTD_c_prefetchCDictTables,
670 ZSTD_c_experimentalParam17 as ZSTD_c_enableSeqProducerFallback,
671 ZSTD_c_experimentalParam18 as ZSTD_c_maxBlockSize,
672 ZSTD_c_experimentalParam19 as ZSTD_c_searchForExternalRepcodes,
673 ZSTD_c_experimentalParam2 as ZSTD_c_format,
674 ZSTD_c_experimentalParam3 as ZSTD_c_forceMaxWindow,
675 ZSTD_c_experimentalParam4 as ZSTD_c_forceAttachDict,
676 ZSTD_c_experimentalParam5 as ZSTD_c_literalCompressionMode,
677 ZSTD_c_experimentalParam7 as ZSTD_c_srcSizeHint,
678 ZSTD_c_experimentalParam8 as ZSTD_c_enableDedicatedDictSearch,
679 ZSTD_c_experimentalParam9 as ZSTD_c_stableInBuffer,
680 };
681
682 use zstd_sys::ZSTD_cParameter::*;
683 use CParameter::*;
684
685 let (param, value) = match param {
686 #[cfg(feature = "experimental")]
687 RSyncable(rsyncable) => (ZSTD_c_rsyncable, rsyncable as c_int),
688 #[cfg(feature = "experimental")]
689 Format(format) => (ZSTD_c_format, format as c_int),
690 #[cfg(feature = "experimental")]
691 ForceMaxWindow(force) => (ZSTD_c_forceMaxWindow, force as c_int),
692 #[cfg(feature = "experimental")]
693 ForceAttachDict(force) => (ZSTD_c_forceAttachDict, force as c_int),
694 #[cfg(feature = "experimental")]
695 LiteralCompressionMode(mode) => {
696 (ZSTD_c_literalCompressionMode, mode as c_int)
697 }
698 #[cfg(feature = "experimental")]
699 SrcSizeHint(value) => (ZSTD_c_srcSizeHint, value as c_int),
700 #[cfg(feature = "experimental")]
701 EnableDedicatedDictSearch(enable) => {
702 (ZSTD_c_enableDedicatedDictSearch, enable as c_int)
703 }
704 #[cfg(feature = "experimental")]
705 StableInBuffer(stable) => (ZSTD_c_stableInBuffer, stable as c_int),
706 #[cfg(feature = "experimental")]
707 StableOutBuffer(stable) => {
708 (ZSTD_c_stableOutBuffer, stable as c_int)
709 }
710 #[cfg(feature = "experimental")]
711 BlockDelimiters(value) => (ZSTD_c_blockDelimiters, value as c_int),
712 #[cfg(feature = "experimental")]
713 ValidateSequences(validate) => {
714 (ZSTD_c_validateSequences, validate as c_int)
715 }
716 #[cfg(feature = "experimental")]
717 UseBlockSplitter(split) => {
718 (ZSTD_c_useBlockSplitter, split as c_int)
719 }
720 #[cfg(feature = "experimental")]
721 UseRowMatchFinder(mode) => {
722 (ZSTD_c_useRowMatchFinder, mode as c_int)
723 }
724 #[cfg(feature = "experimental")]
725 DeterministicRefPrefix(deterministic) => {
726 (ZSTD_c_deterministicRefPrefix, deterministic as c_int)
727 }
728 #[cfg(feature = "experimental")]
729 PrefetchCDictTables(prefetch) => {
730 (ZSTD_c_prefetchCDictTables, prefetch as c_int)
731 }
732 #[cfg(feature = "experimental")]
733 EnableSeqProducerFallback(enable) => {
734 (ZSTD_c_enableSeqProducerFallback, enable as c_int)
735 }
736 #[cfg(feature = "experimental")]
737 MaxBlockSize(value) => (ZSTD_c_maxBlockSize, value as c_int),
738 #[cfg(feature = "experimental")]
739 SearchForExternalRepcodes(value) => {
740 (ZSTD_c_searchForExternalRepcodes, value as c_int)
741 }
742 TargetCBlockSize(value) => {
743 (ZSTD_c_targetCBlockSize, value as c_int)
744 }
745 CompressionLevel(level) => (ZSTD_c_compressionLevel, level),
746 WindowLog(value) => (ZSTD_c_windowLog, value as c_int),
747 HashLog(value) => (ZSTD_c_hashLog, value as c_int),
748 ChainLog(value) => (ZSTD_c_chainLog, value as c_int),
749 SearchLog(value) => (ZSTD_c_searchLog, value as c_int),
750 MinMatch(value) => (ZSTD_c_minMatch, value as c_int),
751 TargetLength(value) => (ZSTD_c_targetLength, value as c_int),
752 Strategy(strategy) => (ZSTD_c_strategy, strategy as c_int),
753 EnableLongDistanceMatching(flag) => {
754 (ZSTD_c_enableLongDistanceMatching, flag as c_int)
755 }
756 LdmHashLog(value) => (ZSTD_c_ldmHashLog, value as c_int),
757 LdmMinMatch(value) => (ZSTD_c_ldmMinMatch, value as c_int),
758 LdmBucketSizeLog(value) => {
759 (ZSTD_c_ldmBucketSizeLog, value as c_int)
760 }
761 LdmHashRateLog(value) => (ZSTD_c_ldmHashRateLog, value as c_int),
762 ContentSizeFlag(flag) => (ZSTD_c_contentSizeFlag, flag as c_int),
763 ChecksumFlag(flag) => (ZSTD_c_checksumFlag, flag as c_int),
764 DictIdFlag(flag) => (ZSTD_c_dictIDFlag, flag as c_int),
765
766 NbWorkers(value) => (ZSTD_c_nbWorkers, value as c_int),
767
768 JobSize(value) => (ZSTD_c_jobSize, value as c_int),
769
770 OverlapSizeLog(value) => (ZSTD_c_overlapLog, value as c_int),
771 };
772
773 parse_code(unsafe {
775 zstd_sys::ZSTD_CCtx_setParameter(self.0.as_ptr(), param, value)
776 })
777 }
778
779 pub fn set_pledged_src_size(
788 &mut self,
789 pledged_src_size: Option<u64>,
790 ) -> SafeResult {
791 parse_code(unsafe {
793 zstd_sys::ZSTD_CCtx_setPledgedSrcSize(
794 self.0.as_ptr(),
795 pledged_src_size.unwrap_or(CONTENTSIZE_UNKNOWN) as c_ulonglong,
796 )
797 })
798 }
799
800 #[cfg(feature = "experimental")]
805 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
806 pub fn try_clone(
807 &self,
808 pledged_src_size: Option<u64>,
809 ) -> Result<Self, ErrorCode> {
810 let context = NonNull::new(unsafe { zstd_sys::ZSTD_createCCtx() })
812 .ok_or(0usize)?;
813
814 parse_code(unsafe {
816 zstd_sys::ZSTD_copyCCtx(
817 context.as_ptr(),
818 self.0.as_ptr(),
819 pledged_src_size.unwrap_or(CONTENTSIZE_UNKNOWN),
820 )
821 })?;
822
823 Ok(CCtx(context, self.1, self.2.clone()))
824 }
825
826 #[cfg(feature = "experimental")]
828 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
829 pub fn get_block_size(&self) -> usize {
830 unsafe { zstd_sys::ZSTD_getBlockSize(self.0.as_ptr()) }
832 }
833
834 #[cfg(feature = "experimental")]
842 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
843 pub unsafe fn compress_block<C: WriteBuf + ?Sized>(
844 &mut self,
845 dst: &mut C,
846 src: &[u8],
847 ) -> SafeResult {
848 unsafe {
850 dst.write_from(|buffer, capacity| {
851 parse_code(zstd_sys::ZSTD_compressBlock(
852 self.0.as_ptr(),
853 buffer,
854 capacity,
855 ptr_void(src),
856 src.len(),
857 ))
858 })
859 }
860 }
861
862 pub fn in_size() -> usize {
866 unsafe { zstd_sys::ZSTD_CStreamInSize() }
868 }
869
870 pub fn out_size() -> usize {
874 unsafe { zstd_sys::ZSTD_CStreamOutSize() }
876 }
877
878 #[cfg(all(feature = "experimental", feature = "zstdmt"))]
882 #[cfg_attr(
883 feature = "doc-cfg",
884 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
885 )]
886 pub fn ref_thread_pool<'b>(&mut self, pool: &'b ThreadPool) -> SafeResult
887 where
888 'b: 'a,
889 {
890 parse_code(unsafe {
891 zstd_sys::ZSTD_CCtx_refThreadPool(self.0.as_ptr(), pool.0.as_ptr())
892 })
893 }
894
895 #[cfg(all(feature = "experimental", feature = "zstdmt"))]
897 #[cfg_attr(
898 feature = "doc-cfg",
899 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
900 )]
901 pub fn disable_thread_pool(&mut self) -> SafeResult {
902 parse_code(unsafe {
903 zstd_sys::ZSTD_CCtx_refThreadPool(
904 self.0.as_ptr(),
905 core::ptr::null_mut(),
906 )
907 })
908 }
909
910 #[cfg(feature = "experimental")]
911 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
912 pub fn get_frame_progression(&self) -> FrameProgression {
913 unsafe { zstd_sys::ZSTD_getFrameProgression(self.0.as_ptr()) }
915 }
916}
917
918impl<'a> Drop for CCtx<'a> {
919 fn drop(&mut self) {
920 unsafe {
922 zstd_sys::ZSTD_freeCCtx(self.0.as_ptr());
923 }
924 }
925}
926
927unsafe impl Send for CCtx<'_> {}
930unsafe impl Sync for CCtx<'_> {}
933
934unsafe fn c_char_to_str(text: *const c_char) -> &'static str {
942 core::ffi::CStr::from_ptr(text)
944 .to_str()
945 .expect("bad error message from zstd")
946}
947
948pub fn get_error_name(code: usize) -> &'static str {
950 unsafe {
951 let name = zstd_sys::ZSTD_getErrorName(code);
953 c_char_to_str(name)
954 }
955}
956
957pub struct DCtx<'a>(NonNull<zstd_sys::ZSTD_DCtx>, PhantomData<&'a ()>, Poison);
965
966impl Default for DCtx<'_> {
967 fn default() -> Self {
968 DCtx::create()
969 }
970}
971
972impl<'a> DCtx<'a> {
973 pub fn try_create() -> Option<Self> {
977 Some(DCtx(
978 NonNull::new(unsafe { zstd_sys::ZSTD_createDCtx() })?,
979 PhantomData,
980 Poison::default(),
981 ))
982 }
983
984 pub fn create() -> Self {
990 Self::try_create()
991 .expect("zstd returned null pointer when creating new context")
992 }
993
994 pub fn decompress<C: WriteBuf + ?Sized>(
1001 &mut self,
1002 dst: &mut C,
1003 src: &[u8],
1004 ) -> SafeResult {
1005 self.2.clear();
1006 unsafe {
1007 dst.write_from(|buffer, capacity| {
1008 parse_code(zstd_sys::ZSTD_decompressDCtx(
1009 self.0.as_ptr(),
1010 buffer,
1011 capacity,
1012 ptr_void(src),
1013 src.len(),
1014 ))
1015 })
1016 }
1017 }
1018
1019 pub fn decompress_using_dict<C: WriteBuf + ?Sized>(
1028 &mut self,
1029 dst: &mut C,
1030 src: &[u8],
1031 dict: &[u8],
1032 ) -> SafeResult {
1033 self.2.clear();
1034 unsafe {
1035 dst.write_from(|buffer, capacity| {
1036 parse_code(zstd_sys::ZSTD_decompress_usingDict(
1037 self.0.as_ptr(),
1038 buffer,
1039 capacity,
1040 ptr_void(src),
1041 src.len(),
1042 ptr_void(dict),
1043 dict.len(),
1044 ))
1045 })
1046 }
1047 }
1048
1049 pub fn decompress_using_ddict<C: WriteBuf + ?Sized>(
1055 &mut self,
1056 dst: &mut C,
1057 src: &[u8],
1058 ddict: &DDict<'_>,
1059 ) -> SafeResult {
1060 self.2.clear();
1061 unsafe {
1062 dst.write_from(|buffer, capacity| {
1063 parse_code(zstd_sys::ZSTD_decompress_usingDDict(
1064 self.0.as_ptr(),
1065 buffer,
1066 capacity,
1067 ptr_void(src),
1068 src.len(),
1069 ddict.0.as_ptr(),
1070 ))
1071 })
1072 }
1073 }
1074
1075 pub fn init(&mut self) -> SafeResult {
1083 self.2.clear();
1084 let code = unsafe { zstd_sys::ZSTD_initDStream(self.0.as_ptr()) };
1085 self.2.record(parse_code(code))
1086 }
1087
1088 #[cfg(feature = "experimental")]
1090 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1091 #[deprecated]
1092 pub fn init_using_dict(&mut self, dict: &[u8]) -> SafeResult {
1093 self.2.clear();
1094 self.2.clear();
1095 let code = unsafe {
1096 zstd_sys::ZSTD_initDStream_usingDict(
1097 self.0.as_ptr(),
1098 ptr_void(dict),
1099 dict.len(),
1100 )
1101 };
1102 parse_code(code)
1103 }
1104
1105 #[cfg(feature = "experimental")]
1107 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1108 #[deprecated]
1109 pub fn init_using_ddict<'b>(&mut self, ddict: &DDict<'b>) -> SafeResult
1110 where
1111 'b: 'a,
1112 {
1113 let code = unsafe {
1114 zstd_sys::ZSTD_initDStream_usingDDict(
1115 self.0.as_ptr(),
1116 ddict.0.as_ptr(),
1117 )
1118 };
1119 parse_code(code)
1120 }
1121
1122 pub fn reset(&mut self, reset: ResetDirective) -> SafeResult {
1128 let res = parse_code(unsafe {
1129 zstd_sys::ZSTD_DCtx_reset(self.0.as_ptr(), reset.as_sys())
1130 });
1131 if res.is_ok() && reset.resets_session() {
1132 self.2.clear();
1133 }
1134 res
1135 }
1136
1137 pub fn load_dictionary(&mut self, dict: &[u8]) -> SafeResult {
1149 parse_code(unsafe {
1150 zstd_sys::ZSTD_DCtx_loadDictionary(
1151 self.0.as_ptr(),
1152 ptr_void(dict),
1153 dict.len(),
1154 )
1155 })
1156 }
1157
1158 pub fn disable_dictionary(&mut self) -> SafeResult {
1162 parse_code(unsafe {
1163 zstd_sys::ZSTD_DCtx_loadDictionary(
1164 self.0.as_ptr(),
1165 core::ptr::null(),
1166 0,
1167 )
1168 })
1169 }
1170
1171 pub fn ref_ddict<'b>(&mut self, ddict: &'a DDict<'b>) -> SafeResult
1181 where
1182 'b: 'a,
1183 {
1184 parse_code(unsafe {
1185 zstd_sys::ZSTD_DCtx_refDDict(self.0.as_ptr(), ddict.0.as_ptr())
1186 })
1187 }
1188
1189 pub fn ref_prefix<'b>(&mut self, prefix: &'b [u8]) -> SafeResult
1197 where
1198 'b: 'a,
1199 {
1200 parse_code(unsafe {
1201 zstd_sys::ZSTD_DCtx_refPrefix(
1202 self.0.as_ptr(),
1203 ptr_void(prefix),
1204 prefix.len(),
1205 )
1206 })
1207 }
1208
1209 pub fn set_parameter(&mut self, param: DParameter) -> SafeResult {
1211 #[cfg(feature = "experimental")]
1212 use zstd_sys::ZSTD_dParameter::{
1213 ZSTD_d_experimentalParam1 as ZSTD_d_format,
1214 ZSTD_d_experimentalParam2 as ZSTD_d_stableOutBuffer,
1215 ZSTD_d_experimentalParam3 as ZSTD_d_forceIgnoreChecksum,
1216 ZSTD_d_experimentalParam4 as ZSTD_d_refMultipleDDicts,
1217 };
1218
1219 use zstd_sys::ZSTD_dParameter::*;
1220 use DParameter::*;
1221
1222 let (param, value) = match param {
1223 #[cfg(feature = "experimental")]
1224 Format(format) => (ZSTD_d_format, format as c_int),
1225 #[cfg(feature = "experimental")]
1226 StableOutBuffer(stable) => {
1227 (ZSTD_d_stableOutBuffer, stable as c_int)
1228 }
1229 #[cfg(feature = "experimental")]
1230 ForceIgnoreChecksum(force) => {
1231 (ZSTD_d_forceIgnoreChecksum, force as c_int)
1232 }
1233 #[cfg(feature = "experimental")]
1234 RefMultipleDDicts(value) => {
1235 (ZSTD_d_refMultipleDDicts, value as c_int)
1236 }
1237
1238 WindowLogMax(value) => (ZSTD_d_windowLogMax, value as c_int),
1239 };
1240
1241 parse_code(unsafe {
1242 zstd_sys::ZSTD_DCtx_setParameter(self.0.as_ptr(), param, value)
1243 })
1244 }
1245
1246 pub fn decompress_stream<C: WriteBuf + ?Sized>(
1258 &mut self,
1259 output: &mut OutBuffer<'_, C>,
1260 input: &mut InBuffer<'_>,
1261 ) -> SafeResult {
1262 self.2.guard()?;
1263 let mut output = output.wrap();
1264 let mut input = input.wrap();
1265 let code = unsafe {
1266 zstd_sys::ZSTD_decompressStream(
1267 self.0.as_ptr(),
1268 ptr_mut(&mut output),
1269 ptr_mut(&mut input),
1270 )
1271 };
1272 self.2.record(parse_code(code))
1273 }
1274
1275 pub fn in_size() -> usize {
1279 unsafe { zstd_sys::ZSTD_DStreamInSize() }
1280 }
1281
1282 pub fn out_size() -> usize {
1286 unsafe { zstd_sys::ZSTD_DStreamOutSize() }
1287 }
1288
1289 pub fn sizeof(&self) -> usize {
1291 unsafe { zstd_sys::ZSTD_sizeof_DCtx(self.0.as_ptr()) }
1292 }
1293
1294 #[cfg(feature = "experimental")]
1302 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1303 pub unsafe fn decompress_block<C: WriteBuf + ?Sized>(
1304 &mut self,
1305 dst: &mut C,
1306 src: &[u8],
1307 ) -> SafeResult {
1308 unsafe {
1309 dst.write_from(|buffer, capacity| {
1310 parse_code(zstd_sys::ZSTD_decompressBlock(
1311 self.0.as_ptr(),
1312 buffer,
1313 capacity,
1314 ptr_void(src),
1315 src.len(),
1316 ))
1317 })
1318 }
1319 }
1320
1321 #[cfg(feature = "experimental")]
1329 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1330 pub unsafe fn insert_block(&mut self, block: &[u8]) -> usize {
1331 unsafe {
1332 zstd_sys::ZSTD_insertBlock(
1333 self.0.as_ptr(),
1334 ptr_void(block),
1335 block.len(),
1336 )
1337 }
1338 }
1339
1340 #[cfg(feature = "experimental")]
1345 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1346 pub fn try_clone(&self) -> Result<Self, ErrorCode> {
1347 let context = NonNull::new(unsafe { zstd_sys::ZSTD_createDCtx() })
1348 .ok_or(0usize)?;
1349
1350 unsafe { zstd_sys::ZSTD_copyDCtx(context.as_ptr(), self.0.as_ptr()) };
1351
1352 Ok(DCtx(context, self.1, self.2.clone()))
1353 }
1354}
1355
1356impl Drop for DCtx<'_> {
1357 fn drop(&mut self) {
1358 unsafe {
1359 zstd_sys::ZSTD_freeDCtx(self.0.as_ptr());
1360 }
1361 }
1362}
1363
1364unsafe impl Send for DCtx<'_> {}
1366unsafe impl Sync for DCtx<'_> {}
1369
1370pub struct CDict<'a>(NonNull<zstd_sys::ZSTD_CDict>, PhantomData<&'a ()>);
1372
1373impl CDict<'static> {
1374 pub fn create(
1384 dict_buffer: &[u8],
1385 compression_level: CompressionLevel,
1386 ) -> Self {
1387 Self::try_create(dict_buffer, compression_level)
1388 .expect("zstd returned null pointer when creating dict")
1389 }
1390
1391 pub fn try_create(
1397 dict_buffer: &[u8],
1398 compression_level: CompressionLevel,
1399 ) -> Option<Self> {
1400 Some(CDict(
1401 NonNull::new(unsafe {
1402 zstd_sys::ZSTD_createCDict(
1403 ptr_void(dict_buffer),
1404 dict_buffer.len(),
1405 compression_level,
1406 )
1407 })?,
1408 PhantomData,
1409 ))
1410 }
1411}
1412
1413impl<'a> CDict<'a> {
1414 #[cfg(feature = "experimental")]
1415 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1416 pub fn create_by_reference(
1417 dict_buffer: &'a [u8],
1418 compression_level: CompressionLevel,
1419 ) -> Self {
1420 CDict(
1421 NonNull::new(unsafe {
1422 zstd_sys::ZSTD_createCDict_byReference(
1423 ptr_void(dict_buffer),
1424 dict_buffer.len(),
1425 compression_level,
1426 )
1427 })
1428 .expect("zstd returned null pointer"),
1429 PhantomData,
1430 )
1431 }
1432
1433 pub fn sizeof(&self) -> usize {
1437 unsafe { zstd_sys::ZSTD_sizeof_CDict(self.0.as_ptr()) }
1438 }
1439
1440 pub fn get_dict_id(&self) -> Option<NonZeroU32> {
1444 NonZeroU32::new(unsafe {
1445 zstd_sys::ZSTD_getDictID_fromCDict(self.0.as_ptr()) as u32
1446 })
1447 }
1448}
1449
1450pub fn create_cdict(
1452 dict_buffer: &[u8],
1453 compression_level: CompressionLevel,
1454) -> CDict<'static> {
1455 CDict::create(dict_buffer, compression_level)
1456}
1457
1458impl<'a> Drop for CDict<'a> {
1459 fn drop(&mut self) {
1460 unsafe {
1461 zstd_sys::ZSTD_freeCDict(self.0.as_ptr());
1462 }
1463 }
1464}
1465
1466unsafe impl<'a> Send for CDict<'a> {}
1470unsafe impl<'a> Sync for CDict<'a> {}
1471
1472pub fn compress_using_cdict(
1474 cctx: &mut CCtx<'_>,
1475 dst: &mut [u8],
1476 src: &[u8],
1477 cdict: &CDict<'_>,
1478) -> SafeResult {
1479 cctx.compress_using_cdict(dst, src, cdict)
1480}
1481
1482pub struct DDict<'a>(NonNull<zstd_sys::ZSTD_DDict>, PhantomData<&'a ()>);
1484
1485impl DDict<'static> {
1486 pub fn create(dict_buffer: &[u8]) -> Self {
1487 Self::try_create(dict_buffer)
1488 .expect("zstd returned null pointer when creating dict")
1489 }
1490
1491 pub fn try_create(dict_buffer: &[u8]) -> Option<Self> {
1492 Some(DDict(
1493 NonNull::new(unsafe {
1494 zstd_sys::ZSTD_createDDict(
1495 ptr_void(dict_buffer),
1496 dict_buffer.len(),
1497 )
1498 })?,
1499 PhantomData,
1500 ))
1501 }
1502}
1503
1504impl<'a> DDict<'a> {
1505 pub fn sizeof(&self) -> usize {
1506 unsafe { zstd_sys::ZSTD_sizeof_DDict(self.0.as_ptr()) }
1507 }
1508
1509 #[cfg(feature = "experimental")]
1513 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1514 pub fn create_by_reference(dict_buffer: &'a [u8]) -> Self {
1515 DDict(
1516 NonNull::new(unsafe {
1517 zstd_sys::ZSTD_createDDict_byReference(
1518 ptr_void(dict_buffer),
1519 dict_buffer.len(),
1520 )
1521 })
1522 .expect("zstd returned null pointer"),
1523 PhantomData,
1524 )
1525 }
1526
1527 pub fn get_dict_id(&self) -> Option<NonZeroU32> {
1531 NonZeroU32::new(unsafe {
1532 zstd_sys::ZSTD_getDictID_fromDDict(self.0.as_ptr()) as u32
1533 })
1534 }
1535}
1536
1537pub fn create_ddict(dict_buffer: &[u8]) -> DDict<'static> {
1541 DDict::create(dict_buffer)
1542}
1543
1544impl<'a> Drop for DDict<'a> {
1545 fn drop(&mut self) {
1546 unsafe {
1547 zstd_sys::ZSTD_freeDDict(self.0.as_ptr());
1548 }
1549 }
1550}
1551
1552unsafe impl<'a> Send for DDict<'a> {}
1555unsafe impl<'a> Sync for DDict<'a> {}
1556
1557#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1559#[cfg_attr(
1560 feature = "doc-cfg",
1561 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1562)]
1563pub struct ThreadPool(NonNull<zstd_sys::ZSTD_threadPool>);
1564
1565#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1566#[cfg_attr(
1567 feature = "doc-cfg",
1568 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1569)]
1570impl ThreadPool {
1571 pub fn new(num_threads: usize) -> Self {
1577 Self::try_new(num_threads)
1578 .expect("zstd returned null pointer when creating thread pool")
1579 }
1580
1581 pub fn try_new(num_threads: usize) -> Option<Self> {
1583 Some(Self(NonNull::new(unsafe {
1584 zstd_sys::ZSTD_createThreadPool(num_threads)
1585 })?))
1586 }
1587}
1588
1589#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1590#[cfg_attr(
1591 feature = "doc-cfg",
1592 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1593)]
1594impl Drop for ThreadPool {
1595 fn drop(&mut self) {
1596 unsafe {
1597 zstd_sys::ZSTD_freeThreadPool(self.0.as_ptr());
1598 }
1599 }
1600}
1601
1602#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1603#[cfg_attr(
1604 feature = "doc-cfg",
1605 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1606)]
1607unsafe impl Send for ThreadPool {}
1610#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1611#[cfg_attr(
1612 feature = "doc-cfg",
1613 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1614)]
1615unsafe impl Sync for ThreadPool {}
1619
1620pub fn decompress_using_ddict(
1622 dctx: &mut DCtx<'_>,
1623 dst: &mut [u8],
1624 src: &[u8],
1625 ddict: &DDict<'_>,
1626) -> SafeResult {
1627 dctx.decompress_using_ddict(dst, src, ddict)
1628}
1629
1630pub type CStream<'a> = CCtx<'a>;
1634
1635pub fn create_cstream<'a>() -> CStream<'a> {
1639 CCtx::create()
1640}
1641
1642pub fn init_cstream(
1644 zcs: &mut CStream<'_>,
1645 compression_level: CompressionLevel,
1646) -> SafeResult {
1647 zcs.init(compression_level)
1648}
1649
1650#[derive(Debug)]
1651pub struct InBuffer<'a> {
1657 pub src: &'a [u8],
1658 pub pos: usize,
1659}
1660
1661pub unsafe trait WriteBuf {
1681 fn as_slice(&self) -> &[u8];
1683
1684 fn capacity(&self) -> usize;
1686
1687 fn as_mut_ptr(&mut self) -> *mut u8;
1689
1690 unsafe fn filled_until(&mut self, n: usize);
1695
1696 unsafe fn write_from<F>(&mut self, f: F) -> SafeResult
1707 where
1708 F: FnOnce(*mut c_void, usize) -> SafeResult,
1709 {
1710 let res = f(ptr_mut_void(self), self.capacity());
1711 if let Ok(n) = res {
1712 self.filled_until(n);
1713 }
1714 res
1715 }
1716}
1717
1718#[cfg(feature = "std")]
1726fn cursor_position<T>(cursor: &std::io::Cursor<T>) -> usize {
1727 use core::convert::TryFrom;
1728
1729 usize::try_from(cursor.position()).unwrap_or(usize::MAX)
1730}
1731
1732#[cfg(feature = "std")]
1733#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "std")))]
1734unsafe impl<T> WriteBuf for std::io::Cursor<T>
1735where
1736 T: WriteBuf,
1737{
1738 fn as_slice(&self) -> &[u8] {
1739 &self.get_ref().as_slice()[cursor_position(self)..]
1740 }
1741
1742 fn capacity(&self) -> usize {
1743 self.get_ref()
1744 .capacity()
1745 .saturating_sub(cursor_position(self))
1746 }
1747
1748 fn as_mut_ptr(&mut self) -> *mut u8 {
1749 let start = cursor_position(self);
1750 assert!(start <= self.get_ref().capacity());
1751 unsafe { self.get_mut().as_mut_ptr().add(start) }
1753 }
1754
1755 unsafe fn filled_until(&mut self, n: usize) {
1756 if n == 0 {
1758 return;
1759 }
1760
1761 let position = cursor_position(self);
1765 assert!(position <= self.get_ref().capacity());
1769 let initialized = self.get_ref().as_slice().len();
1770 if let Some(uninitialized) = position.checked_sub(initialized) {
1771 unsafe {
1783 self.get_mut()
1784 .as_mut_ptr()
1785 .add(initialized)
1786 .write_bytes(0u8, uninitialized)
1787 };
1788 }
1789
1790 let start = position;
1791 assert!(start + n <= self.get_ref().capacity());
1792 self.get_mut().filled_until(start + n);
1793 }
1794}
1795
1796#[cfg(feature = "std")]
1797#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "std")))]
1798unsafe impl<'a> WriteBuf for &'a mut std::vec::Vec<u8> {
1799 fn as_slice(&self) -> &[u8] {
1800 std::vec::Vec::as_slice(self)
1801 }
1802
1803 fn capacity(&self) -> usize {
1804 std::vec::Vec::capacity(self)
1805 }
1806
1807 fn as_mut_ptr(&mut self) -> *mut u8 {
1808 std::vec::Vec::as_mut_ptr(self)
1809 }
1810
1811 unsafe fn filled_until(&mut self, n: usize) {
1812 std::vec::Vec::set_len(self, n)
1813 }
1814}
1815
1816#[cfg(feature = "std")]
1817#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "std")))]
1818unsafe impl WriteBuf for std::vec::Vec<u8> {
1819 fn as_slice(&self) -> &[u8] {
1820 &self[..]
1821 }
1822 fn capacity(&self) -> usize {
1823 self.capacity()
1824 }
1825 fn as_mut_ptr(&mut self) -> *mut u8 {
1826 self.as_mut_ptr()
1827 }
1828 unsafe fn filled_until(&mut self, n: usize) {
1829 self.set_len(n);
1830 }
1831}
1832
1833#[cfg(feature = "arrays")]
1834#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "arrays")))]
1835unsafe impl<const N: usize> WriteBuf for [u8; N] {
1836 fn as_slice(&self) -> &[u8] {
1837 self
1838 }
1839 fn capacity(&self) -> usize {
1840 self.len()
1841 }
1842
1843 fn as_mut_ptr(&mut self) -> *mut u8 {
1844 (&mut self[..]).as_mut_ptr()
1845 }
1846
1847 unsafe fn filled_until(&mut self, _n: usize) {
1848 }
1850}
1851
1852unsafe impl WriteBuf for [u8] {
1853 fn as_slice(&self) -> &[u8] {
1854 self
1855 }
1856 fn capacity(&self) -> usize {
1857 self.len()
1858 }
1859
1860 fn as_mut_ptr(&mut self) -> *mut u8 {
1861 self.as_mut_ptr()
1862 }
1863
1864 unsafe fn filled_until(&mut self, _n: usize) {
1865 }
1867}
1868
1869#[derive(Debug)]
1888pub struct OutBuffer<'a, C: WriteBuf + ?Sized> {
1900 dst: &'a mut C,
1901 pos: usize,
1902}
1903
1904fn ptr_mut<B>(ptr_void: &mut B) -> *mut B {
1906 ptr_void as *mut B
1907}
1908
1909struct OutBufferWrapper<'a, 'b, C: WriteBuf + ?Sized> {
1913 buf: zstd_sys::ZSTD_outBuffer,
1914 parent: &'a mut OutBuffer<'b, C>,
1915}
1916
1917impl<'a, 'b: 'a, C: WriteBuf + ?Sized> Deref for OutBufferWrapper<'a, 'b, C> {
1918 type Target = zstd_sys::ZSTD_outBuffer;
1919
1920 fn deref(&self) -> &Self::Target {
1921 &self.buf
1922 }
1923}
1924
1925impl<'a, 'b: 'a, C: WriteBuf + ?Sized> DerefMut
1926 for OutBufferWrapper<'a, 'b, C>
1927{
1928 fn deref_mut(&mut self) -> &mut Self::Target {
1929 &mut self.buf
1930 }
1931}
1932
1933impl<'a, C: WriteBuf + ?Sized> OutBuffer<'a, C> {
1934 pub fn around(dst: &'a mut C) -> Self {
1938 OutBuffer { dst, pos: 0 }
1939 }
1940
1941 pub fn around_pos(dst: &'a mut C, pos: usize) -> Self {
1947 if pos > dst.capacity() {
1948 panic!("Given position outside of the buffer bounds.");
1949 }
1950
1951 OutBuffer { dst, pos }
1952 }
1953
1954 pub fn pos(&self) -> usize {
1958 assert!(self.pos <= self.dst.capacity());
1959 self.pos
1960 }
1961
1962 pub fn capacity(&self) -> usize {
1964 self.dst.capacity()
1965 }
1966
1967 pub unsafe fn set_pos(&mut self, pos: usize) {
1977 if pos > self.dst.capacity() {
1978 panic!("Given position outside of the buffer bounds.");
1979 }
1980
1981 self.dst.filled_until(pos);
1982
1983 self.pos = pos;
1984 }
1985
1986 fn wrap<'b>(&'b mut self) -> OutBufferWrapper<'b, 'a, C> {
1987 OutBufferWrapper {
1988 buf: zstd_sys::ZSTD_outBuffer {
1989 dst: ptr_mut_void(self.dst),
1990 size: self.dst.capacity(),
1991 pos: self.pos,
1992 },
1993 parent: self,
1994 }
1995 }
1996
1997 pub fn as_slice<'b>(&'b self) -> &'a [u8]
1999 where
2000 'b: 'a,
2001 {
2002 let pos = self.pos;
2003 &self.dst.as_slice()[..pos]
2004 }
2005
2006 pub fn as_mut_ptr(&mut self) -> *mut u8 {
2008 self.dst.as_mut_ptr()
2009 }
2010}
2011
2012impl<'a, 'b, C: WriteBuf + ?Sized> Drop for OutBufferWrapper<'a, 'b, C> {
2013 fn drop(&mut self) {
2014 unsafe { self.parent.set_pos(self.buf.pos) };
2016 }
2017}
2018
2019struct InBufferWrapper<'a, 'b> {
2020 buf: zstd_sys::ZSTD_inBuffer,
2021 parent: &'a mut InBuffer<'b>,
2022}
2023
2024impl<'a, 'b: 'a> Deref for InBufferWrapper<'a, 'b> {
2025 type Target = zstd_sys::ZSTD_inBuffer;
2026
2027 fn deref(&self) -> &Self::Target {
2028 &self.buf
2029 }
2030}
2031
2032impl<'a, 'b: 'a> DerefMut for InBufferWrapper<'a, 'b> {
2033 fn deref_mut(&mut self) -> &mut Self::Target {
2034 &mut self.buf
2035 }
2036}
2037
2038impl<'a> InBuffer<'a> {
2039 pub fn around(src: &'a [u8]) -> Self {
2043 InBuffer { src, pos: 0 }
2044 }
2045
2046 pub fn pos(&self) -> usize {
2048 self.pos
2049 }
2050
2051 pub fn set_pos(&mut self, pos: usize) {
2057 if pos > self.src.len() {
2058 panic!("Given position outside of the buffer bounds.");
2059 }
2060 self.pos = pos;
2061 }
2062
2063 fn wrap<'b>(&'b mut self) -> InBufferWrapper<'b, 'a> {
2064 InBufferWrapper {
2065 buf: zstd_sys::ZSTD_inBuffer {
2066 src: ptr_void(self.src),
2067 size: self.src.len(),
2068 pos: self.pos,
2069 },
2070 parent: self,
2071 }
2072 }
2073}
2074
2075impl<'a, 'b> Drop for InBufferWrapper<'a, 'b> {
2076 fn drop(&mut self) {
2077 self.parent.set_pos(self.buf.pos);
2078 }
2079}
2080
2081pub type DStream<'a> = DCtx<'a>;
2085
2086pub fn find_frame_compressed_size(src: &[u8]) -> SafeResult {
2096 let code = unsafe {
2097 zstd_sys::ZSTD_findFrameCompressedSize(ptr_void(src), src.len())
2098 };
2099 parse_code(code)
2100}
2101
2102pub fn get_frame_content_size(
2112 src: &[u8],
2113) -> Result<Option<u64>, ContentSizeError> {
2114 parse_content_size(unsafe {
2115 zstd_sys::ZSTD_getFrameContentSize(ptr_void(src), src.len())
2116 })
2117}
2118
2119#[cfg(feature = "experimental")]
2123#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2124pub fn find_decompressed_size(
2125 src: &[u8],
2126) -> Result<Option<u64>, ContentSizeError> {
2127 parse_content_size(unsafe {
2128 zstd_sys::ZSTD_findDecompressedSize(ptr_void(src), src.len())
2129 })
2130}
2131
2132#[cfg(feature = "experimental")]
2134#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2135pub fn is_frame(buffer: &[u8]) -> bool {
2136 unsafe { zstd_sys::ZSTD_isFrame(ptr_void(buffer), buffer.len()) > 0 }
2137}
2138
2139pub fn get_dict_id_from_dict(dict: &[u8]) -> Option<NonZeroU32> {
2143 NonZeroU32::new(unsafe {
2144 zstd_sys::ZSTD_getDictID_fromDict(ptr_void(dict), dict.len()) as u32
2145 })
2146}
2147
2148pub fn get_dict_id_from_frame(src: &[u8]) -> Option<NonZeroU32> {
2157 NonZeroU32::new(unsafe {
2158 zstd_sys::ZSTD_getDictID_fromFrame(ptr_void(src), src.len()) as u32
2159 })
2160}
2161
2162#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2164pub enum ResetDirective {
2165 SessionOnly,
2173
2174 Parameters,
2180
2181 SessionAndParameters,
2185}
2186
2187impl ResetDirective {
2188 fn resets_session(self) -> bool {
2194 matches!(
2195 self,
2196 ResetDirective::SessionOnly | ResetDirective::SessionAndParameters
2197 )
2198 }
2199
2200 fn as_sys(self) -> zstd_sys::ZSTD_ResetDirective {
2201 match self {
2202 ResetDirective::SessionOnly => zstd_sys::ZSTD_ResetDirective::ZSTD_reset_session_only,
2203 ResetDirective::Parameters => zstd_sys::ZSTD_ResetDirective::ZSTD_reset_parameters,
2204 ResetDirective::SessionAndParameters => zstd_sys::ZSTD_ResetDirective::ZSTD_reset_session_and_parameters,
2205 }
2206 }
2207}
2208
2209#[cfg(feature = "experimental")]
2210#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2211#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2212#[repr(u32)]
2213pub enum FrameFormat {
2214 One = zstd_sys::ZSTD_format_e::ZSTD_f_zstd1 as u32,
2216
2217 Magicless = zstd_sys::ZSTD_format_e::ZSTD_f_zstd1_magicless as u32,
2219}
2220
2221#[cfg(feature = "experimental")]
2222#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2223#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2224#[repr(u32)]
2225pub enum DictAttachPref {
2226 DefaultAttach =
2227 zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictDefaultAttach as u32,
2228 ForceAttach = zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictForceAttach as u32,
2229 ForceCopy = zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictForceCopy as u32,
2230 ForceLoad = zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictForceLoad as u32,
2231}
2232
2233#[cfg(feature = "experimental")]
2234#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2235#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2236#[repr(u32)]
2237pub enum ParamSwitch {
2238 Auto = zstd_sys::ZSTD_ParamSwitch_e::ZSTD_ps_auto as u32,
2239 Enable = zstd_sys::ZSTD_ParamSwitch_e::ZSTD_ps_enable as u32,
2240 Disable = zstd_sys::ZSTD_ParamSwitch_e::ZSTD_ps_disable as u32,
2241}
2242
2243#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2245#[non_exhaustive]
2246pub enum CParameter {
2247 #[cfg(feature = "experimental")]
2248 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2249 RSyncable(bool),
2250
2251 #[cfg(feature = "experimental")]
2252 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2253 Format(FrameFormat),
2254
2255 #[cfg(feature = "experimental")]
2256 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2257 ForceMaxWindow(bool),
2258
2259 #[cfg(feature = "experimental")]
2260 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2261 ForceAttachDict(DictAttachPref),
2262
2263 #[cfg(feature = "experimental")]
2264 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2265 LiteralCompressionMode(ParamSwitch),
2266
2267 #[cfg(feature = "experimental")]
2268 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2269 SrcSizeHint(u32),
2270
2271 #[cfg(feature = "experimental")]
2272 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2273 EnableDedicatedDictSearch(bool),
2274
2275 #[cfg(feature = "experimental")]
2276 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2277 StableInBuffer(bool),
2278
2279 #[cfg(feature = "experimental")]
2280 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2281 StableOutBuffer(bool),
2282
2283 #[cfg(feature = "experimental")]
2284 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2285 BlockDelimiters(bool),
2286
2287 #[cfg(feature = "experimental")]
2288 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2289 ValidateSequences(bool),
2290
2291 #[cfg(feature = "experimental")]
2292 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2293 UseBlockSplitter(ParamSwitch),
2294
2295 #[cfg(feature = "experimental")]
2296 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2297 UseRowMatchFinder(ParamSwitch),
2298
2299 #[cfg(feature = "experimental")]
2300 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2301 DeterministicRefPrefix(bool),
2302
2303 #[cfg(feature = "experimental")]
2304 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2305 PrefetchCDictTables(ParamSwitch),
2306
2307 #[cfg(feature = "experimental")]
2308 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2309 EnableSeqProducerFallback(bool),
2310
2311 #[cfg(feature = "experimental")]
2312 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2313 MaxBlockSize(u32),
2314
2315 #[cfg(feature = "experimental")]
2316 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2317 SearchForExternalRepcodes(ParamSwitch),
2318
2319 TargetCBlockSize(u32),
2326
2327 CompressionLevel(CompressionLevel),
2331
2332 WindowLog(u32),
2336
2337 HashLog(u32),
2338
2339 ChainLog(u32),
2340
2341 SearchLog(u32),
2342
2343 MinMatch(u32),
2344
2345 TargetLength(u32),
2346
2347 Strategy(Strategy),
2348
2349 EnableLongDistanceMatching(bool),
2350
2351 LdmHashLog(u32),
2352
2353 LdmMinMatch(u32),
2354
2355 LdmBucketSizeLog(u32),
2356
2357 LdmHashRateLog(u32),
2358
2359 ContentSizeFlag(bool),
2360
2361 ChecksumFlag(bool),
2362
2363 DictIdFlag(bool),
2364
2365 NbWorkers(u32),
2374
2375 JobSize(u32),
2383
2384 OverlapSizeLog(u32),
2396}
2397
2398#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2400#[non_exhaustive]
2401pub enum DParameter {
2402 WindowLogMax(u32),
2403
2404 #[cfg(feature = "experimental")]
2405 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2406 Format(FrameFormat),
2408
2409 #[cfg(feature = "experimental")]
2410 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2411 StableOutBuffer(bool),
2412
2413 #[cfg(feature = "experimental")]
2414 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2415 ForceIgnoreChecksum(bool),
2416
2417 #[cfg(feature = "experimental")]
2418 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2419 RefMultipleDDicts(bool),
2420}
2421
2422#[cfg(feature = "zdict_builder")]
2424#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "zdict_builder")))]
2425pub fn train_from_buffer<C: WriteBuf + ?Sized>(
2426 dict_buffer: &mut C,
2427 samples_buffer: &[u8],
2428 samples_sizes: &[usize],
2429) -> SafeResult {
2430 assert_eq!(samples_buffer.len(), samples_sizes.iter().sum());
2431
2432 unsafe {
2433 dict_buffer.write_from(|buffer, capacity| {
2434 parse_code(zstd_sys::ZDICT_trainFromBuffer(
2435 buffer,
2436 capacity,
2437 ptr_void(samples_buffer),
2438 samples_sizes.as_ptr(),
2439 samples_sizes.len() as u32,
2440 ))
2441 })
2442 }
2443}
2444
2445#[cfg(feature = "zdict_builder")]
2447#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "zdict_builder")))]
2448pub fn get_dict_id(dict_buffer: &[u8]) -> Option<NonZeroU32> {
2449 NonZeroU32::new(unsafe {
2450 zstd_sys::ZDICT_getDictID(ptr_void(dict_buffer), dict_buffer.len())
2451 })
2452}
2453
2454#[cfg(feature = "experimental")]
2456#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2457pub fn get_block_size(cctx: &CCtx) -> usize {
2458 unsafe { zstd_sys::ZSTD_getBlockSize(cctx.0.as_ptr()) }
2459}
2460
2461#[cfg(feature = "experimental")]
2463#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2464pub fn decompress_bound(data: &[u8]) -> Result<u64, ErrorCode> {
2465 let bound =
2466 unsafe { zstd_sys::ZSTD_decompressBound(ptr_void(data), data.len()) };
2467 if is_error(bound as usize) {
2468 Err(bound as usize)
2469 } else {
2470 Ok(bound)
2471 }
2472}
2473
2474#[cfg(feature = "experimental")]
2477#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2478pub fn sequence_bound(src_size: usize) -> usize {
2479 unsafe { zstd_sys::ZSTD_sequenceBound(src_size) }
2481}
2482
2483#[cfg(feature = "experimental")]
2489#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2490pub fn decompression_margin(
2491 compressed_data: &[u8],
2492) -> Result<usize, ErrorCode> {
2493 parse_code(unsafe {
2494 zstd_sys::ZSTD_decompressionMargin(
2495 ptr_void(compressed_data),
2496 compressed_data.len(),
2497 )
2498 })
2499}