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
39use core::ffi::{c_char, c_int, c_ulonglong, c_void};
42
43use core::marker::PhantomData;
44use core::num::{NonZeroU32, NonZeroU64};
45use core::ops::{Deref, DerefMut};
46use core::ptr::NonNull;
47use core::str;
48
49include!("constants.rs");
50
51#[cfg(feature = "experimental")]
52include!("constants_experimental.rs");
53
54#[cfg(feature = "seekable")]
55include!("constants_seekable.rs");
56
57pub type CompressionLevel = i32;
59
60pub type ErrorCode = usize;
62
63pub type SafeResult = Result<usize, ErrorCode>;
67
68#[derive(Debug)]
72pub struct ContentSizeError;
73
74impl core::fmt::Display for ContentSizeError {
75 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
76 f.write_str("Could not get content size")
77 }
78}
79
80fn is_error(code: usize) -> bool {
82 unsafe { zstd_sys::ZSTD_isError(code) != 0 }
84}
85
86fn parse_code(code: usize) -> SafeResult {
91 if !is_error(code) {
92 Ok(code)
93 } else {
94 Err(code)
95 }
96}
97
98fn parse_content_size(
102 content_size: u64,
103) -> Result<Option<u64>, ContentSizeError> {
104 match content_size {
105 CONTENTSIZE_ERROR => Err(ContentSizeError),
106 CONTENTSIZE_UNKNOWN => Ok(None),
107 other => Ok(Some(other)),
108 }
109}
110
111fn ptr_void(src: &[u8]) -> *const c_void {
112 src.as_ptr() as *const c_void
113}
114
115fn ptr_mut_void(dst: &mut (impl WriteBuf + ?Sized)) -> *mut c_void {
116 dst.as_mut_ptr() as *mut c_void
117}
118
119pub fn version_number() -> u32 {
124 unsafe { zstd_sys::ZSTD_versionNumber() as u32 }
126}
127
128pub fn version_string() -> &'static str {
132 unsafe { c_char_to_str(zstd_sys::ZSTD_versionString()) }
134}
135
136pub fn min_c_level() -> CompressionLevel {
140 unsafe { zstd_sys::ZSTD_minCLevel() as CompressionLevel }
142}
143
144pub fn max_c_level() -> CompressionLevel {
146 unsafe { zstd_sys::ZSTD_maxCLevel() as CompressionLevel }
148}
149
150pub fn compress<C: WriteBuf + ?Sized>(
158 dst: &mut C,
159 src: &[u8],
160 compression_level: CompressionLevel,
161) -> SafeResult {
162 unsafe {
164 dst.write_from(|buffer, capacity| {
165 parse_code(zstd_sys::ZSTD_compress(
166 buffer,
167 capacity,
168 ptr_void(src),
169 src.len(),
170 compression_level,
171 ))
172 })
173 }
174}
175
176pub fn decompress<C: WriteBuf + ?Sized>(
185 dst: &mut C,
186 src: &[u8],
187) -> SafeResult {
188 unsafe {
190 dst.write_from(|buffer, capacity| {
191 parse_code(zstd_sys::ZSTD_decompress(
192 buffer,
193 capacity,
194 ptr_void(src),
195 src.len(),
196 ))
197 })
198 }
199}
200
201#[deprecated(note = "Use ZSTD_getFrameContentSize instead")]
205pub fn get_decompressed_size(src: &[u8]) -> Option<NonZeroU64> {
206 NonZeroU64::new(unsafe {
208 zstd_sys::ZSTD_getDecompressedSize(ptr_void(src), src.len()) as u64
209 })
210}
211
212pub fn compress_bound(src_size: usize) -> usize {
214 unsafe { zstd_sys::ZSTD_compressBound(src_size) }
216}
217
218pub struct CCtx<'a>(NonNull<zstd_sys::ZSTD_CCtx>, PhantomData<&'a ()>);
223
224impl Default for CCtx<'_> {
225 fn default() -> Self {
226 CCtx::create()
227 }
228}
229
230impl<'a> CCtx<'a> {
231 pub fn try_create() -> Option<Self> {
235 Some(CCtx(
237 NonNull::new(unsafe { zstd_sys::ZSTD_createCCtx() })?,
238 PhantomData,
239 ))
240 }
241
242 pub fn create() -> Self {
248 Self::try_create()
249 .expect("zstd returned null pointer when creating new context")
250 }
251
252 pub fn compress<C: WriteBuf + ?Sized>(
254 &mut self,
255 dst: &mut C,
256 src: &[u8],
257 compression_level: CompressionLevel,
258 ) -> SafeResult {
259 unsafe {
261 dst.write_from(|buffer, capacity| {
262 parse_code(zstd_sys::ZSTD_compressCCtx(
263 self.0.as_ptr(),
264 buffer,
265 capacity,
266 ptr_void(src),
267 src.len(),
268 compression_level,
269 ))
270 })
271 }
272 }
273
274 pub fn compress2<C: WriteBuf + ?Sized>(
276 &mut self,
277 dst: &mut C,
278 src: &[u8],
279 ) -> SafeResult {
280 unsafe {
282 dst.write_from(|buffer, capacity| {
283 parse_code(zstd_sys::ZSTD_compress2(
284 self.0.as_ptr(),
285 buffer,
286 capacity,
287 ptr_void(src),
288 src.len(),
289 ))
290 })
291 }
292 }
293
294 pub fn compress_using_dict<C: WriteBuf + ?Sized>(
296 &mut self,
297 dst: &mut C,
298 src: &[u8],
299 dict: &[u8],
300 compression_level: CompressionLevel,
301 ) -> SafeResult {
302 unsafe {
304 dst.write_from(|buffer, capacity| {
305 parse_code(zstd_sys::ZSTD_compress_usingDict(
306 self.0.as_ptr(),
307 buffer,
308 capacity,
309 ptr_void(src),
310 src.len(),
311 ptr_void(dict),
312 dict.len(),
313 compression_level,
314 ))
315 })
316 }
317 }
318
319 pub fn compress_using_cdict<C: WriteBuf + ?Sized>(
321 &mut self,
322 dst: &mut C,
323 src: &[u8],
324 cdict: &CDict<'_>,
325 ) -> SafeResult {
326 unsafe {
328 dst.write_from(|buffer, capacity| {
329 parse_code(zstd_sys::ZSTD_compress_usingCDict(
330 self.0.as_ptr(),
331 buffer,
332 capacity,
333 ptr_void(src),
334 src.len(),
335 cdict.0.as_ptr(),
336 ))
337 })
338 }
339 }
340
341 pub fn init(&mut self, compression_level: CompressionLevel) -> SafeResult {
347 let code = unsafe {
349 zstd_sys::ZSTD_initCStream(self.0.as_ptr(), compression_level)
350 };
351 parse_code(code)
352 }
353
354 #[cfg(feature = "experimental")]
356 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
357 #[deprecated]
358 pub fn init_src_size(
359 &mut self,
360 compression_level: CompressionLevel,
361 pledged_src_size: u64,
362 ) -> SafeResult {
363 let code = unsafe {
365 zstd_sys::ZSTD_initCStream_srcSize(
366 self.0.as_ptr(),
367 compression_level as c_int,
368 pledged_src_size as c_ulonglong,
369 )
370 };
371 parse_code(code)
372 }
373
374 #[cfg(feature = "experimental")]
376 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
377 #[deprecated]
378 pub fn init_using_dict(
379 &mut self,
380 dict: &[u8],
381 compression_level: CompressionLevel,
382 ) -> SafeResult {
383 let code = unsafe {
385 zstd_sys::ZSTD_initCStream_usingDict(
386 self.0.as_ptr(),
387 ptr_void(dict),
388 dict.len(),
389 compression_level,
390 )
391 };
392 parse_code(code)
393 }
394
395 #[cfg(feature = "experimental")]
397 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
398 #[deprecated]
399 pub fn init_using_cdict<'b>(&mut self, cdict: &CDict<'b>) -> SafeResult
400 where
401 'b: 'a, {
403 let code = unsafe {
405 zstd_sys::ZSTD_initCStream_usingCDict(
406 self.0.as_ptr(),
407 cdict.0.as_ptr(),
408 )
409 };
410 parse_code(code)
411 }
412
413 pub fn load_dictionary(&mut self, dict: &[u8]) -> SafeResult {
423 parse_code(unsafe {
425 zstd_sys::ZSTD_CCtx_loadDictionary(
426 self.0.as_ptr(),
427 ptr_void(dict),
428 dict.len(),
429 )
430 })
431 }
432
433 pub fn ref_cdict<'b>(&mut self, cdict: &CDict<'b>) -> SafeResult
437 where
438 'b: 'a,
439 {
440 parse_code(unsafe {
442 zstd_sys::ZSTD_CCtx_refCDict(self.0.as_ptr(), cdict.0.as_ptr())
443 })
444 }
445
446 pub fn disable_dictionary(&mut self) -> SafeResult {
450 parse_code(unsafe {
452 zstd_sys::ZSTD_CCtx_loadDictionary(
453 self.0.as_ptr(),
454 core::ptr::null(),
455 0,
456 )
457 })
458 }
459
460 pub fn ref_prefix<'b>(&mut self, prefix: &'b [u8]) -> SafeResult
466 where
467 'b: 'a,
468 {
469 parse_code(unsafe {
471 zstd_sys::ZSTD_CCtx_refPrefix(
472 self.0.as_ptr(),
473 ptr_void(prefix),
474 prefix.len(),
475 )
476 })
477 }
478
479 pub fn compress_stream<C: WriteBuf + ?Sized>(
491 &mut self,
492 output: &mut OutBuffer<'_, C>,
493 input: &mut InBuffer<'_>,
494 ) -> SafeResult {
495 let mut output = output.wrap();
496 let mut input = input.wrap();
497 let code = unsafe {
499 zstd_sys::ZSTD_compressStream(
500 self.0.as_ptr(),
501 ptr_mut(&mut output),
502 ptr_mut(&mut input),
503 )
504 };
505 parse_code(code)
506 }
507
508 pub fn compress_stream2<C: WriteBuf + ?Sized>(
524 &mut self,
525 output: &mut OutBuffer<'_, C>,
526 input: &mut InBuffer<'_>,
527 end_op: zstd_sys::ZSTD_EndDirective,
528 ) -> SafeResult {
529 let mut output = output.wrap();
530 let mut input = input.wrap();
531 parse_code(unsafe {
533 zstd_sys::ZSTD_compressStream2(
534 self.0.as_ptr(),
535 ptr_mut(&mut output),
536 ptr_mut(&mut input),
537 end_op,
538 )
539 })
540 }
541
542 pub fn flush_stream<C: WriteBuf + ?Sized>(
548 &mut self,
549 output: &mut OutBuffer<'_, C>,
550 ) -> SafeResult {
551 let mut output = output.wrap();
552 let code = unsafe {
554 zstd_sys::ZSTD_flushStream(self.0.as_ptr(), ptr_mut(&mut output))
555 };
556 parse_code(code)
557 }
558
559 pub fn end_stream<C: WriteBuf + ?Sized>(
565 &mut self,
566 output: &mut OutBuffer<'_, C>,
567 ) -> SafeResult {
568 let mut output = output.wrap();
569 let code = unsafe {
571 zstd_sys::ZSTD_endStream(self.0.as_ptr(), ptr_mut(&mut output))
572 };
573 parse_code(code)
574 }
575
576 pub fn sizeof(&self) -> usize {
580 unsafe { zstd_sys::ZSTD_sizeof_CCtx(self.0.as_ptr()) }
582 }
583
584 pub fn reset(&mut self, reset: ResetDirective) -> SafeResult {
590 parse_code(unsafe {
592 zstd_sys::ZSTD_CCtx_reset(self.0.as_ptr(), reset.as_sys())
593 })
594 }
595
596 pub fn set_parameter(&mut self, param: CParameter) -> SafeResult {
600 #[cfg(feature = "experimental")]
603 use zstd_sys::ZSTD_cParameter::{
604 ZSTD_c_experimentalParam1 as ZSTD_c_rsyncable,
605 ZSTD_c_experimentalParam10 as ZSTD_c_stableOutBuffer,
606 ZSTD_c_experimentalParam11 as ZSTD_c_blockDelimiters,
607 ZSTD_c_experimentalParam12 as ZSTD_c_validateSequences,
608 ZSTD_c_experimentalParam13 as ZSTD_c_useBlockSplitter,
609 ZSTD_c_experimentalParam14 as ZSTD_c_useRowMatchFinder,
610 ZSTD_c_experimentalParam15 as ZSTD_c_deterministicRefPrefix,
611 ZSTD_c_experimentalParam16 as ZSTD_c_prefetchCDictTables,
612 ZSTD_c_experimentalParam17 as ZSTD_c_enableSeqProducerFallback,
613 ZSTD_c_experimentalParam18 as ZSTD_c_maxBlockSize,
614 ZSTD_c_experimentalParam19 as ZSTD_c_searchForExternalRepcodes,
615 ZSTD_c_experimentalParam2 as ZSTD_c_format,
616 ZSTD_c_experimentalParam3 as ZSTD_c_forceMaxWindow,
617 ZSTD_c_experimentalParam4 as ZSTD_c_forceAttachDict,
618 ZSTD_c_experimentalParam5 as ZSTD_c_literalCompressionMode,
619 ZSTD_c_experimentalParam7 as ZSTD_c_srcSizeHint,
620 ZSTD_c_experimentalParam8 as ZSTD_c_enableDedicatedDictSearch,
621 ZSTD_c_experimentalParam9 as ZSTD_c_stableInBuffer,
622 };
623
624 use zstd_sys::ZSTD_cParameter::*;
625 use CParameter::*;
626
627 let (param, value) = match param {
628 #[cfg(feature = "experimental")]
629 RSyncable(rsyncable) => (ZSTD_c_rsyncable, rsyncable as c_int),
630 #[cfg(feature = "experimental")]
631 Format(format) => (ZSTD_c_format, format as c_int),
632 #[cfg(feature = "experimental")]
633 ForceMaxWindow(force) => (ZSTD_c_forceMaxWindow, force as c_int),
634 #[cfg(feature = "experimental")]
635 ForceAttachDict(force) => (ZSTD_c_forceAttachDict, force as c_int),
636 #[cfg(feature = "experimental")]
637 LiteralCompressionMode(mode) => {
638 (ZSTD_c_literalCompressionMode, mode as c_int)
639 }
640 #[cfg(feature = "experimental")]
641 SrcSizeHint(value) => (ZSTD_c_srcSizeHint, value as c_int),
642 #[cfg(feature = "experimental")]
643 EnableDedicatedDictSearch(enable) => {
644 (ZSTD_c_enableDedicatedDictSearch, enable as c_int)
645 }
646 #[cfg(feature = "experimental")]
647 StableInBuffer(stable) => (ZSTD_c_stableInBuffer, stable as c_int),
648 #[cfg(feature = "experimental")]
649 StableOutBuffer(stable) => {
650 (ZSTD_c_stableOutBuffer, stable as c_int)
651 }
652 #[cfg(feature = "experimental")]
653 BlockDelimiters(value) => (ZSTD_c_blockDelimiters, value as c_int),
654 #[cfg(feature = "experimental")]
655 ValidateSequences(validate) => {
656 (ZSTD_c_validateSequences, validate as c_int)
657 }
658 #[cfg(feature = "experimental")]
659 UseBlockSplitter(split) => {
660 (ZSTD_c_useBlockSplitter, split as c_int)
661 }
662 #[cfg(feature = "experimental")]
663 UseRowMatchFinder(mode) => {
664 (ZSTD_c_useRowMatchFinder, mode as c_int)
665 }
666 #[cfg(feature = "experimental")]
667 DeterministicRefPrefix(deterministic) => {
668 (ZSTD_c_deterministicRefPrefix, deterministic as c_int)
669 }
670 #[cfg(feature = "experimental")]
671 PrefetchCDictTables(prefetch) => {
672 (ZSTD_c_prefetchCDictTables, prefetch as c_int)
673 }
674 #[cfg(feature = "experimental")]
675 EnableSeqProducerFallback(enable) => {
676 (ZSTD_c_enableSeqProducerFallback, enable as c_int)
677 }
678 #[cfg(feature = "experimental")]
679 MaxBlockSize(value) => (ZSTD_c_maxBlockSize, value as c_int),
680 #[cfg(feature = "experimental")]
681 SearchForExternalRepcodes(value) => {
682 (ZSTD_c_searchForExternalRepcodes, value as c_int)
683 }
684 TargetCBlockSize(value) => {
685 (ZSTD_c_targetCBlockSize, value as c_int)
686 }
687 CompressionLevel(level) => (ZSTD_c_compressionLevel, level),
688 WindowLog(value) => (ZSTD_c_windowLog, value as c_int),
689 HashLog(value) => (ZSTD_c_hashLog, value as c_int),
690 ChainLog(value) => (ZSTD_c_chainLog, value as c_int),
691 SearchLog(value) => (ZSTD_c_searchLog, value as c_int),
692 MinMatch(value) => (ZSTD_c_minMatch, value as c_int),
693 TargetLength(value) => (ZSTD_c_targetLength, value as c_int),
694 Strategy(strategy) => (ZSTD_c_strategy, strategy as c_int),
695 EnableLongDistanceMatching(flag) => {
696 (ZSTD_c_enableLongDistanceMatching, flag as c_int)
697 }
698 LdmHashLog(value) => (ZSTD_c_ldmHashLog, value as c_int),
699 LdmMinMatch(value) => (ZSTD_c_ldmMinMatch, value as c_int),
700 LdmBucketSizeLog(value) => {
701 (ZSTD_c_ldmBucketSizeLog, value as c_int)
702 }
703 LdmHashRateLog(value) => (ZSTD_c_ldmHashRateLog, value as c_int),
704 ContentSizeFlag(flag) => (ZSTD_c_contentSizeFlag, flag as c_int),
705 ChecksumFlag(flag) => (ZSTD_c_checksumFlag, flag as c_int),
706 DictIdFlag(flag) => (ZSTD_c_dictIDFlag, flag as c_int),
707
708 NbWorkers(value) => (ZSTD_c_nbWorkers, value as c_int),
709
710 JobSize(value) => (ZSTD_c_jobSize, value as c_int),
711
712 OverlapSizeLog(value) => (ZSTD_c_overlapLog, value as c_int),
713 };
714
715 parse_code(unsafe {
717 zstd_sys::ZSTD_CCtx_setParameter(self.0.as_ptr(), param, value)
718 })
719 }
720
721 pub fn set_pledged_src_size(
730 &mut self,
731 pledged_src_size: Option<u64>,
732 ) -> SafeResult {
733 parse_code(unsafe {
735 zstd_sys::ZSTD_CCtx_setPledgedSrcSize(
736 self.0.as_ptr(),
737 pledged_src_size.unwrap_or(CONTENTSIZE_UNKNOWN) as c_ulonglong,
738 )
739 })
740 }
741
742 #[cfg(feature = "experimental")]
747 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
748 pub fn try_clone(
749 &self,
750 pledged_src_size: Option<u64>,
751 ) -> Result<Self, ErrorCode> {
752 let context = NonNull::new(unsafe { zstd_sys::ZSTD_createCCtx() })
754 .ok_or(0usize)?;
755
756 parse_code(unsafe {
758 zstd_sys::ZSTD_copyCCtx(
759 context.as_ptr(),
760 self.0.as_ptr(),
761 pledged_src_size.unwrap_or(CONTENTSIZE_UNKNOWN),
762 )
763 })?;
764
765 Ok(CCtx(context, self.1))
766 }
767
768 #[cfg(feature = "experimental")]
770 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
771 pub fn get_block_size(&self) -> usize {
772 unsafe { zstd_sys::ZSTD_getBlockSize(self.0.as_ptr()) }
774 }
775
776 #[cfg(feature = "experimental")]
778 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
779 pub fn compress_block<C: WriteBuf + ?Sized>(
780 &mut self,
781 dst: &mut C,
782 src: &[u8],
783 ) -> SafeResult {
784 unsafe {
786 dst.write_from(|buffer, capacity| {
787 parse_code(zstd_sys::ZSTD_compressBlock(
788 self.0.as_ptr(),
789 buffer,
790 capacity,
791 ptr_void(src),
792 src.len(),
793 ))
794 })
795 }
796 }
797
798 pub fn in_size() -> usize {
802 unsafe { zstd_sys::ZSTD_CStreamInSize() }
804 }
805
806 pub fn out_size() -> usize {
810 unsafe { zstd_sys::ZSTD_CStreamOutSize() }
812 }
813
814 #[cfg(all(feature = "experimental", feature = "zstdmt"))]
818 #[cfg_attr(
819 feature = "doc-cfg",
820 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
821 )]
822 pub fn ref_thread_pool<'b>(&mut self, pool: &'b ThreadPool) -> SafeResult
823 where
824 'b: 'a,
825 {
826 parse_code(unsafe {
827 zstd_sys::ZSTD_CCtx_refThreadPool(self.0.as_ptr(), pool.0.as_ptr())
828 })
829 }
830
831 #[cfg(all(feature = "experimental", feature = "zstdmt"))]
833 #[cfg_attr(
834 feature = "doc-cfg",
835 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
836 )]
837 pub fn disable_thread_pool(&mut self) -> SafeResult {
838 parse_code(unsafe {
839 zstd_sys::ZSTD_CCtx_refThreadPool(
840 self.0.as_ptr(),
841 core::ptr::null_mut(),
842 )
843 })
844 }
845}
846
847impl<'a> Drop for CCtx<'a> {
848 fn drop(&mut self) {
849 unsafe {
851 zstd_sys::ZSTD_freeCCtx(self.0.as_ptr());
852 }
853 }
854}
855
856unsafe impl Send for CCtx<'_> {}
857unsafe impl Sync for CCtx<'_> {}
859
860unsafe fn c_char_to_str(text: *const c_char) -> &'static str {
861 core::ffi::CStr::from_ptr(text)
862 .to_str()
863 .expect("bad error message from zstd")
864}
865
866pub fn get_error_name(code: usize) -> &'static str {
868 unsafe {
869 let name = zstd_sys::ZSTD_getErrorName(code);
871 c_char_to_str(name)
872 }
873}
874
875pub struct DCtx<'a>(NonNull<zstd_sys::ZSTD_DCtx>, PhantomData<&'a ()>);
883
884impl Default for DCtx<'_> {
885 fn default() -> Self {
886 DCtx::create()
887 }
888}
889
890impl<'a> DCtx<'a> {
891 pub fn try_create() -> Option<Self> {
895 Some(DCtx(
896 NonNull::new(unsafe { zstd_sys::ZSTD_createDCtx() })?,
897 PhantomData,
898 ))
899 }
900
901 pub fn create() -> Self {
907 Self::try_create()
908 .expect("zstd returned null pointer when creating new context")
909 }
910
911 pub fn decompress<C: WriteBuf + ?Sized>(
918 &mut self,
919 dst: &mut C,
920 src: &[u8],
921 ) -> SafeResult {
922 unsafe {
923 dst.write_from(|buffer, capacity| {
924 parse_code(zstd_sys::ZSTD_decompressDCtx(
925 self.0.as_ptr(),
926 buffer,
927 capacity,
928 ptr_void(src),
929 src.len(),
930 ))
931 })
932 }
933 }
934
935 pub fn decompress_using_dict<C: WriteBuf + ?Sized>(
944 &mut self,
945 dst: &mut C,
946 src: &[u8],
947 dict: &[u8],
948 ) -> SafeResult {
949 unsafe {
950 dst.write_from(|buffer, capacity| {
951 parse_code(zstd_sys::ZSTD_decompress_usingDict(
952 self.0.as_ptr(),
953 buffer,
954 capacity,
955 ptr_void(src),
956 src.len(),
957 ptr_void(dict),
958 dict.len(),
959 ))
960 })
961 }
962 }
963
964 pub fn decompress_using_ddict<C: WriteBuf + ?Sized>(
970 &mut self,
971 dst: &mut C,
972 src: &[u8],
973 ddict: &DDict<'_>,
974 ) -> SafeResult {
975 unsafe {
976 dst.write_from(|buffer, capacity| {
977 parse_code(zstd_sys::ZSTD_decompress_usingDDict(
978 self.0.as_ptr(),
979 buffer,
980 capacity,
981 ptr_void(src),
982 src.len(),
983 ddict.0.as_ptr(),
984 ))
985 })
986 }
987 }
988
989 pub fn init(&mut self) -> SafeResult {
997 let code = unsafe { zstd_sys::ZSTD_initDStream(self.0.as_ptr()) };
998 parse_code(code)
999 }
1000
1001 #[cfg(feature = "experimental")]
1003 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1004 #[deprecated]
1005 pub fn init_using_dict(&mut self, dict: &[u8]) -> SafeResult {
1006 let code = unsafe {
1007 zstd_sys::ZSTD_initDStream_usingDict(
1008 self.0.as_ptr(),
1009 ptr_void(dict),
1010 dict.len(),
1011 )
1012 };
1013 parse_code(code)
1014 }
1015
1016 #[cfg(feature = "experimental")]
1018 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1019 #[deprecated]
1020 pub fn init_using_ddict<'b>(&mut self, ddict: &DDict<'b>) -> SafeResult
1021 where
1022 'b: 'a,
1023 {
1024 let code = unsafe {
1025 zstd_sys::ZSTD_initDStream_usingDDict(
1026 self.0.as_ptr(),
1027 ddict.0.as_ptr(),
1028 )
1029 };
1030 parse_code(code)
1031 }
1032
1033 pub fn reset(&mut self, reset: ResetDirective) -> SafeResult {
1039 parse_code(unsafe {
1040 zstd_sys::ZSTD_DCtx_reset(self.0.as_ptr(), reset.as_sys())
1041 })
1042 }
1043
1044 pub fn load_dictionary(&mut self, dict: &[u8]) -> SafeResult {
1056 parse_code(unsafe {
1057 zstd_sys::ZSTD_DCtx_loadDictionary(
1058 self.0.as_ptr(),
1059 ptr_void(dict),
1060 dict.len(),
1061 )
1062 })
1063 }
1064
1065 pub fn disable_dictionary(&mut self) -> SafeResult {
1069 parse_code(unsafe {
1070 zstd_sys::ZSTD_DCtx_loadDictionary(
1071 self.0.as_ptr(),
1072 core::ptr::null(),
1073 0,
1074 )
1075 })
1076 }
1077
1078 pub fn ref_ddict<'b>(&mut self, ddict: &DDict<'b>) -> SafeResult
1086 where
1087 'b: 'a,
1088 {
1089 parse_code(unsafe {
1090 zstd_sys::ZSTD_DCtx_refDDict(self.0.as_ptr(), ddict.0.as_ptr())
1091 })
1092 }
1093
1094 pub fn ref_prefix<'b>(&mut self, prefix: &'b [u8]) -> SafeResult
1102 where
1103 'b: 'a,
1104 {
1105 parse_code(unsafe {
1106 zstd_sys::ZSTD_DCtx_refPrefix(
1107 self.0.as_ptr(),
1108 ptr_void(prefix),
1109 prefix.len(),
1110 )
1111 })
1112 }
1113
1114 pub fn set_parameter(&mut self, param: DParameter) -> SafeResult {
1116 #[cfg(feature = "experimental")]
1117 use zstd_sys::ZSTD_dParameter::{
1118 ZSTD_d_experimentalParam1 as ZSTD_d_format,
1119 ZSTD_d_experimentalParam2 as ZSTD_d_stableOutBuffer,
1120 ZSTD_d_experimentalParam3 as ZSTD_d_forceIgnoreChecksum,
1121 ZSTD_d_experimentalParam4 as ZSTD_d_refMultipleDDicts,
1122 };
1123
1124 use zstd_sys::ZSTD_dParameter::*;
1125 use DParameter::*;
1126
1127 let (param, value) = match param {
1128 #[cfg(feature = "experimental")]
1129 Format(format) => (ZSTD_d_format, format as c_int),
1130 #[cfg(feature = "experimental")]
1131 StableOutBuffer(stable) => {
1132 (ZSTD_d_stableOutBuffer, stable as c_int)
1133 }
1134 #[cfg(feature = "experimental")]
1135 ForceIgnoreChecksum(force) => {
1136 (ZSTD_d_forceIgnoreChecksum, force as c_int)
1137 }
1138 #[cfg(feature = "experimental")]
1139 RefMultipleDDicts(value) => {
1140 (ZSTD_d_refMultipleDDicts, value as c_int)
1141 }
1142
1143 WindowLogMax(value) => (ZSTD_d_windowLogMax, value as c_int),
1144 };
1145
1146 parse_code(unsafe {
1147 zstd_sys::ZSTD_DCtx_setParameter(self.0.as_ptr(), param, value)
1148 })
1149 }
1150
1151 pub fn decompress_stream<C: WriteBuf + ?Sized>(
1163 &mut self,
1164 output: &mut OutBuffer<'_, C>,
1165 input: &mut InBuffer<'_>,
1166 ) -> SafeResult {
1167 let mut output = output.wrap();
1168 let mut input = input.wrap();
1169 let code = unsafe {
1170 zstd_sys::ZSTD_decompressStream(
1171 self.0.as_ptr(),
1172 ptr_mut(&mut output),
1173 ptr_mut(&mut input),
1174 )
1175 };
1176 parse_code(code)
1177 }
1178
1179 pub fn in_size() -> usize {
1183 unsafe { zstd_sys::ZSTD_DStreamInSize() }
1184 }
1185
1186 pub fn out_size() -> usize {
1190 unsafe { zstd_sys::ZSTD_DStreamOutSize() }
1191 }
1192
1193 pub fn sizeof(&self) -> usize {
1195 unsafe { zstd_sys::ZSTD_sizeof_DCtx(self.0.as_ptr()) }
1196 }
1197
1198 #[cfg(feature = "experimental")]
1200 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1201 pub fn decompress_block<C: WriteBuf + ?Sized>(
1202 &mut self,
1203 dst: &mut C,
1204 src: &[u8],
1205 ) -> SafeResult {
1206 unsafe {
1207 dst.write_from(|buffer, capacity| {
1208 parse_code(zstd_sys::ZSTD_decompressBlock(
1209 self.0.as_ptr(),
1210 buffer,
1211 capacity,
1212 ptr_void(src),
1213 src.len(),
1214 ))
1215 })
1216 }
1217 }
1218
1219 #[cfg(feature = "experimental")]
1221 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1222 pub fn insert_block(&mut self, block: &[u8]) -> usize {
1223 unsafe {
1224 zstd_sys::ZSTD_insertBlock(
1225 self.0.as_ptr(),
1226 ptr_void(block),
1227 block.len(),
1228 )
1229 }
1230 }
1231
1232 #[cfg(feature = "experimental")]
1237 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1238 pub fn try_clone(&self) -> Result<Self, ErrorCode> {
1239 let context = NonNull::new(unsafe { zstd_sys::ZSTD_createDCtx() })
1240 .ok_or(0usize)?;
1241
1242 unsafe { zstd_sys::ZSTD_copyDCtx(context.as_ptr(), self.0.as_ptr()) };
1243
1244 Ok(DCtx(context, self.1))
1245 }
1246}
1247
1248impl Drop for DCtx<'_> {
1249 fn drop(&mut self) {
1250 unsafe {
1251 zstd_sys::ZSTD_freeDCtx(self.0.as_ptr());
1252 }
1253 }
1254}
1255
1256unsafe impl Send for DCtx<'_> {}
1257unsafe impl Sync for DCtx<'_> {}
1259
1260pub struct CDict<'a>(NonNull<zstd_sys::ZSTD_CDict>, PhantomData<&'a ()>);
1262
1263impl CDict<'static> {
1264 pub fn create(
1274 dict_buffer: &[u8],
1275 compression_level: CompressionLevel,
1276 ) -> Self {
1277 Self::try_create(dict_buffer, compression_level)
1278 .expect("zstd returned null pointer when creating dict")
1279 }
1280
1281 pub fn try_create(
1287 dict_buffer: &[u8],
1288 compression_level: CompressionLevel,
1289 ) -> Option<Self> {
1290 Some(CDict(
1291 NonNull::new(unsafe {
1292 zstd_sys::ZSTD_createCDict(
1293 ptr_void(dict_buffer),
1294 dict_buffer.len(),
1295 compression_level,
1296 )
1297 })?,
1298 PhantomData,
1299 ))
1300 }
1301}
1302
1303impl<'a> CDict<'a> {
1304 #[cfg(feature = "experimental")]
1305 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1306 pub fn create_by_reference(
1307 dict_buffer: &'a [u8],
1308 compression_level: CompressionLevel,
1309 ) -> Self {
1310 CDict(
1311 NonNull::new(unsafe {
1312 zstd_sys::ZSTD_createCDict_byReference(
1313 ptr_void(dict_buffer),
1314 dict_buffer.len(),
1315 compression_level,
1316 )
1317 })
1318 .expect("zstd returned null pointer"),
1319 PhantomData,
1320 )
1321 }
1322
1323 pub fn sizeof(&self) -> usize {
1327 unsafe { zstd_sys::ZSTD_sizeof_CDict(self.0.as_ptr()) }
1328 }
1329
1330 pub fn get_dict_id(&self) -> Option<NonZeroU32> {
1334 NonZeroU32::new(unsafe {
1335 zstd_sys::ZSTD_getDictID_fromCDict(self.0.as_ptr()) as u32
1336 })
1337 }
1338}
1339
1340pub fn create_cdict(
1342 dict_buffer: &[u8],
1343 compression_level: CompressionLevel,
1344) -> CDict<'static> {
1345 CDict::create(dict_buffer, compression_level)
1346}
1347
1348impl<'a> Drop for CDict<'a> {
1349 fn drop(&mut self) {
1350 unsafe {
1351 zstd_sys::ZSTD_freeCDict(self.0.as_ptr());
1352 }
1353 }
1354}
1355
1356unsafe impl<'a> Send for CDict<'a> {}
1357unsafe impl<'a> Sync for CDict<'a> {}
1358
1359pub fn compress_using_cdict(
1361 cctx: &mut CCtx<'_>,
1362 dst: &mut [u8],
1363 src: &[u8],
1364 cdict: &CDict<'_>,
1365) -> SafeResult {
1366 cctx.compress_using_cdict(dst, src, cdict)
1367}
1368
1369pub struct DDict<'a>(NonNull<zstd_sys::ZSTD_DDict>, PhantomData<&'a ()>);
1371
1372impl DDict<'static> {
1373 pub fn create(dict_buffer: &[u8]) -> Self {
1374 Self::try_create(dict_buffer)
1375 .expect("zstd returned null pointer when creating dict")
1376 }
1377
1378 pub fn try_create(dict_buffer: &[u8]) -> Option<Self> {
1379 Some(DDict(
1380 NonNull::new(unsafe {
1381 zstd_sys::ZSTD_createDDict(
1382 ptr_void(dict_buffer),
1383 dict_buffer.len(),
1384 )
1385 })?,
1386 PhantomData,
1387 ))
1388 }
1389}
1390
1391impl<'a> DDict<'a> {
1392 pub fn sizeof(&self) -> usize {
1393 unsafe { zstd_sys::ZSTD_sizeof_DDict(self.0.as_ptr()) }
1394 }
1395
1396 #[cfg(feature = "experimental")]
1400 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1401 pub fn create_by_reference(dict_buffer: &'a [u8]) -> Self {
1402 DDict(
1403 NonNull::new(unsafe {
1404 zstd_sys::ZSTD_createDDict_byReference(
1405 ptr_void(dict_buffer),
1406 dict_buffer.len(),
1407 )
1408 })
1409 .expect("zstd returned null pointer"),
1410 PhantomData,
1411 )
1412 }
1413
1414 pub fn get_dict_id(&self) -> Option<NonZeroU32> {
1418 NonZeroU32::new(unsafe {
1419 zstd_sys::ZSTD_getDictID_fromDDict(self.0.as_ptr()) as u32
1420 })
1421 }
1422}
1423
1424pub fn create_ddict(dict_buffer: &[u8]) -> DDict<'static> {
1428 DDict::create(dict_buffer)
1429}
1430
1431impl<'a> Drop for DDict<'a> {
1432 fn drop(&mut self) {
1433 unsafe {
1434 zstd_sys::ZSTD_freeDDict(self.0.as_ptr());
1435 }
1436 }
1437}
1438
1439unsafe impl<'a> Send for DDict<'a> {}
1440unsafe impl<'a> Sync for DDict<'a> {}
1441
1442#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1444#[cfg_attr(
1445 feature = "doc-cfg",
1446 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1447)]
1448pub struct ThreadPool(NonNull<zstd_sys::ZSTD_threadPool>);
1449
1450#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1451#[cfg_attr(
1452 feature = "doc-cfg",
1453 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1454)]
1455impl ThreadPool {
1456 pub fn new(num_threads: usize) -> Self {
1462 Self::try_new(num_threads)
1463 .expect("zstd returned null pointer when creating thread pool")
1464 }
1465
1466 pub fn try_new(num_threads: usize) -> Option<Self> {
1468 Some(Self(NonNull::new(unsafe {
1469 zstd_sys::ZSTD_createThreadPool(num_threads)
1470 })?))
1471 }
1472}
1473
1474#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1475#[cfg_attr(
1476 feature = "doc-cfg",
1477 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1478)]
1479impl Drop for ThreadPool {
1480 fn drop(&mut self) {
1481 unsafe {
1482 zstd_sys::ZSTD_freeThreadPool(self.0.as_ptr());
1483 }
1484 }
1485}
1486
1487#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1488#[cfg_attr(
1489 feature = "doc-cfg",
1490 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1491)]
1492unsafe impl Send for ThreadPool {}
1493#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1494#[cfg_attr(
1495 feature = "doc-cfg",
1496 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1497)]
1498unsafe impl Sync for ThreadPool {}
1499
1500pub fn decompress_using_ddict(
1502 dctx: &mut DCtx<'_>,
1503 dst: &mut [u8],
1504 src: &[u8],
1505 ddict: &DDict<'_>,
1506) -> SafeResult {
1507 dctx.decompress_using_ddict(dst, src, ddict)
1508}
1509
1510pub type CStream<'a> = CCtx<'a>;
1514
1515pub fn create_cstream<'a>() -> CStream<'a> {
1519 CCtx::create()
1520}
1521
1522pub fn init_cstream(
1524 zcs: &mut CStream<'_>,
1525 compression_level: CompressionLevel,
1526) -> SafeResult {
1527 zcs.init(compression_level)
1528}
1529
1530#[derive(Debug)]
1531pub struct InBuffer<'a> {
1537 pub src: &'a [u8],
1538 pub pos: usize,
1539}
1540
1541pub unsafe trait WriteBuf {
1561 fn as_slice(&self) -> &[u8];
1563
1564 fn capacity(&self) -> usize;
1566
1567 fn as_mut_ptr(&mut self) -> *mut u8;
1569
1570 unsafe fn filled_until(&mut self, n: usize);
1575
1576 unsafe fn write_from<F>(&mut self, f: F) -> SafeResult
1587 where
1588 F: FnOnce(*mut c_void, usize) -> SafeResult,
1589 {
1590 let res = f(ptr_mut_void(self), self.capacity());
1591 if let Ok(n) = res {
1592 self.filled_until(n);
1593 }
1594 res
1595 }
1596}
1597
1598#[cfg(feature = "std")]
1599#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "std")))]
1600unsafe impl<T> WriteBuf for std::io::Cursor<T>
1601where
1602 T: WriteBuf,
1603{
1604 fn as_slice(&self) -> &[u8] {
1605 &self.get_ref().as_slice()[self.position() as usize..]
1606 }
1607
1608 fn capacity(&self) -> usize {
1609 self.get_ref()
1610 .capacity()
1611 .saturating_sub(self.position() as usize)
1612 }
1613
1614 fn as_mut_ptr(&mut self) -> *mut u8 {
1615 let start = self.position() as usize;
1616 assert!(start <= self.get_ref().capacity());
1617 unsafe { self.get_mut().as_mut_ptr().add(start) }
1619 }
1620
1621 unsafe fn filled_until(&mut self, n: usize) {
1622 if n == 0 {
1624 return;
1625 }
1626
1627 let position = self.position() as usize;
1631 let initialized = self.get_ref().as_slice().len();
1632 if let Some(uninitialized) = position.checked_sub(initialized) {
1633 unsafe {
1645 self.get_mut()
1646 .as_mut_ptr()
1647 .add(initialized)
1648 .write_bytes(0u8, uninitialized)
1649 };
1650 }
1651
1652 let start = self.position() as usize;
1653 assert!(start + n <= self.get_ref().capacity());
1654 self.get_mut().filled_until(start + n);
1655 }
1656}
1657
1658#[cfg(feature = "std")]
1659#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "std")))]
1660unsafe impl<'a> WriteBuf for &'a mut std::vec::Vec<u8> {
1661 fn as_slice(&self) -> &[u8] {
1662 std::vec::Vec::as_slice(self)
1663 }
1664
1665 fn capacity(&self) -> usize {
1666 std::vec::Vec::capacity(self)
1667 }
1668
1669 fn as_mut_ptr(&mut self) -> *mut u8 {
1670 std::vec::Vec::as_mut_ptr(self)
1671 }
1672
1673 unsafe fn filled_until(&mut self, n: usize) {
1674 std::vec::Vec::set_len(self, n)
1675 }
1676}
1677
1678#[cfg(feature = "std")]
1679#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "std")))]
1680unsafe impl WriteBuf for std::vec::Vec<u8> {
1681 fn as_slice(&self) -> &[u8] {
1682 &self[..]
1683 }
1684 fn capacity(&self) -> usize {
1685 self.capacity()
1686 }
1687 fn as_mut_ptr(&mut self) -> *mut u8 {
1688 self.as_mut_ptr()
1689 }
1690 unsafe fn filled_until(&mut self, n: usize) {
1691 self.set_len(n);
1692 }
1693}
1694
1695#[cfg(feature = "arrays")]
1696#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "arrays")))]
1697unsafe impl<const N: usize> WriteBuf for [u8; N] {
1698 fn as_slice(&self) -> &[u8] {
1699 self
1700 }
1701 fn capacity(&self) -> usize {
1702 self.len()
1703 }
1704
1705 fn as_mut_ptr(&mut self) -> *mut u8 {
1706 (&mut self[..]).as_mut_ptr()
1707 }
1708
1709 unsafe fn filled_until(&mut self, _n: usize) {
1710 }
1712}
1713
1714unsafe impl WriteBuf for [u8] {
1715 fn as_slice(&self) -> &[u8] {
1716 self
1717 }
1718 fn capacity(&self) -> usize {
1719 self.len()
1720 }
1721
1722 fn as_mut_ptr(&mut self) -> *mut u8 {
1723 self.as_mut_ptr()
1724 }
1725
1726 unsafe fn filled_until(&mut self, _n: usize) {
1727 }
1729}
1730
1731#[derive(Debug)]
1750pub struct OutBuffer<'a, C: WriteBuf + ?Sized> {
1762 dst: &'a mut C,
1763 pos: usize,
1764}
1765
1766fn ptr_mut<B>(ptr_void: &mut B) -> *mut B {
1768 ptr_void as *mut B
1769}
1770
1771struct OutBufferWrapper<'a, 'b, C: WriteBuf + ?Sized> {
1775 buf: zstd_sys::ZSTD_outBuffer,
1776 parent: &'a mut OutBuffer<'b, C>,
1777}
1778
1779impl<'a, 'b: 'a, C: WriteBuf + ?Sized> Deref for OutBufferWrapper<'a, 'b, C> {
1780 type Target = zstd_sys::ZSTD_outBuffer;
1781
1782 fn deref(&self) -> &Self::Target {
1783 &self.buf
1784 }
1785}
1786
1787impl<'a, 'b: 'a, C: WriteBuf + ?Sized> DerefMut
1788 for OutBufferWrapper<'a, 'b, C>
1789{
1790 fn deref_mut(&mut self) -> &mut Self::Target {
1791 &mut self.buf
1792 }
1793}
1794
1795impl<'a, C: WriteBuf + ?Sized> OutBuffer<'a, C> {
1796 pub fn around(dst: &'a mut C) -> Self {
1800 OutBuffer { dst, pos: 0 }
1801 }
1802
1803 pub fn around_pos(dst: &'a mut C, pos: usize) -> Self {
1809 if pos > dst.capacity() {
1810 panic!("Given position outside of the buffer bounds.");
1811 }
1812
1813 OutBuffer { dst, pos }
1814 }
1815
1816 pub fn pos(&self) -> usize {
1820 assert!(self.pos <= self.dst.capacity());
1821 self.pos
1822 }
1823
1824 pub fn capacity(&self) -> usize {
1826 self.dst.capacity()
1827 }
1828
1829 pub unsafe fn set_pos(&mut self, pos: usize) {
1839 if pos > self.dst.capacity() {
1840 panic!("Given position outside of the buffer bounds.");
1841 }
1842
1843 self.dst.filled_until(pos);
1844
1845 self.pos = pos;
1846 }
1847
1848 fn wrap<'b>(&'b mut self) -> OutBufferWrapper<'b, 'a, C> {
1849 OutBufferWrapper {
1850 buf: zstd_sys::ZSTD_outBuffer {
1851 dst: ptr_mut_void(self.dst),
1852 size: self.dst.capacity(),
1853 pos: self.pos,
1854 },
1855 parent: self,
1856 }
1857 }
1858
1859 pub fn as_slice<'b>(&'b self) -> &'a [u8]
1861 where
1862 'b: 'a,
1863 {
1864 let pos = self.pos;
1865 &self.dst.as_slice()[..pos]
1866 }
1867
1868 pub fn as_mut_ptr(&mut self) -> *mut u8 {
1870 self.dst.as_mut_ptr()
1871 }
1872}
1873
1874impl<'a, 'b, C: WriteBuf + ?Sized> Drop for OutBufferWrapper<'a, 'b, C> {
1875 fn drop(&mut self) {
1876 unsafe { self.parent.set_pos(self.buf.pos) };
1878 }
1879}
1880
1881struct InBufferWrapper<'a, 'b> {
1882 buf: zstd_sys::ZSTD_inBuffer,
1883 parent: &'a mut InBuffer<'b>,
1884}
1885
1886impl<'a, 'b: 'a> Deref for InBufferWrapper<'a, 'b> {
1887 type Target = zstd_sys::ZSTD_inBuffer;
1888
1889 fn deref(&self) -> &Self::Target {
1890 &self.buf
1891 }
1892}
1893
1894impl<'a, 'b: 'a> DerefMut for InBufferWrapper<'a, 'b> {
1895 fn deref_mut(&mut self) -> &mut Self::Target {
1896 &mut self.buf
1897 }
1898}
1899
1900impl<'a> InBuffer<'a> {
1901 pub fn around(src: &'a [u8]) -> Self {
1905 InBuffer { src, pos: 0 }
1906 }
1907
1908 pub fn pos(&self) -> usize {
1910 self.pos
1911 }
1912
1913 pub fn set_pos(&mut self, pos: usize) {
1919 if pos > self.src.len() {
1920 panic!("Given position outside of the buffer bounds.");
1921 }
1922 self.pos = pos;
1923 }
1924
1925 fn wrap<'b>(&'b mut self) -> InBufferWrapper<'b, 'a> {
1926 InBufferWrapper {
1927 buf: zstd_sys::ZSTD_inBuffer {
1928 src: ptr_void(self.src),
1929 size: self.src.len(),
1930 pos: self.pos,
1931 },
1932 parent: self,
1933 }
1934 }
1935}
1936
1937impl<'a, 'b> Drop for InBufferWrapper<'a, 'b> {
1938 fn drop(&mut self) {
1939 self.parent.set_pos(self.buf.pos);
1940 }
1941}
1942
1943pub type DStream<'a> = DCtx<'a>;
1947
1948pub fn find_frame_compressed_size(src: &[u8]) -> SafeResult {
1958 let code = unsafe {
1959 zstd_sys::ZSTD_findFrameCompressedSize(ptr_void(src), src.len())
1960 };
1961 parse_code(code)
1962}
1963
1964pub fn get_frame_content_size(
1974 src: &[u8],
1975) -> Result<Option<u64>, ContentSizeError> {
1976 parse_content_size(unsafe {
1977 zstd_sys::ZSTD_getFrameContentSize(ptr_void(src), src.len())
1978 })
1979}
1980
1981#[cfg(feature = "experimental")]
1985#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1986pub fn find_decompressed_size(
1987 src: &[u8],
1988) -> Result<Option<u64>, ContentSizeError> {
1989 parse_content_size(unsafe {
1990 zstd_sys::ZSTD_findDecompressedSize(ptr_void(src), src.len())
1991 })
1992}
1993
1994#[cfg(feature = "experimental")]
1996#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1997pub fn is_frame(buffer: &[u8]) -> bool {
1998 unsafe { zstd_sys::ZSTD_isFrame(ptr_void(buffer), buffer.len()) > 0 }
1999}
2000
2001pub fn get_dict_id_from_dict(dict: &[u8]) -> Option<NonZeroU32> {
2005 NonZeroU32::new(unsafe {
2006 zstd_sys::ZSTD_getDictID_fromDict(ptr_void(dict), dict.len()) as u32
2007 })
2008}
2009
2010pub fn get_dict_id_from_frame(src: &[u8]) -> Option<NonZeroU32> {
2019 NonZeroU32::new(unsafe {
2020 zstd_sys::ZSTD_getDictID_fromFrame(ptr_void(src), src.len()) as u32
2021 })
2022}
2023
2024pub enum ResetDirective {
2026 SessionOnly,
2034
2035 Parameters,
2041
2042 SessionAndParameters,
2046}
2047
2048impl ResetDirective {
2049 fn as_sys(self) -> zstd_sys::ZSTD_ResetDirective {
2050 match self {
2051 ResetDirective::SessionOnly => zstd_sys::ZSTD_ResetDirective::ZSTD_reset_session_only,
2052 ResetDirective::Parameters => zstd_sys::ZSTD_ResetDirective::ZSTD_reset_parameters,
2053 ResetDirective::SessionAndParameters => zstd_sys::ZSTD_ResetDirective::ZSTD_reset_session_and_parameters,
2054 }
2055 }
2056}
2057
2058#[cfg(feature = "experimental")]
2059#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2060#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2061#[repr(u32)]
2062pub enum FrameFormat {
2063 One = zstd_sys::ZSTD_format_e::ZSTD_f_zstd1 as u32,
2065
2066 Magicless = zstd_sys::ZSTD_format_e::ZSTD_f_zstd1_magicless as u32,
2068}
2069
2070#[cfg(feature = "experimental")]
2071#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2072#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2073#[repr(u32)]
2074pub enum DictAttachPref {
2075 DefaultAttach =
2076 zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictDefaultAttach as u32,
2077 ForceAttach = zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictForceAttach as u32,
2078 ForceCopy = zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictForceCopy as u32,
2079 ForceLoad = zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictForceLoad as u32,
2080}
2081
2082#[cfg(feature = "experimental")]
2083#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2084#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2085#[repr(u32)]
2086pub enum ParamSwitch {
2087 Auto = zstd_sys::ZSTD_ParamSwitch_e::ZSTD_ps_auto as u32,
2088 Enable = zstd_sys::ZSTD_ParamSwitch_e::ZSTD_ps_enable as u32,
2089 Disable = zstd_sys::ZSTD_ParamSwitch_e::ZSTD_ps_disable as u32,
2090}
2091
2092#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2094#[non_exhaustive]
2095pub enum CParameter {
2096 #[cfg(feature = "experimental")]
2097 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2098 RSyncable(bool),
2099
2100 #[cfg(feature = "experimental")]
2101 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2102 Format(FrameFormat),
2103
2104 #[cfg(feature = "experimental")]
2105 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2106 ForceMaxWindow(bool),
2107
2108 #[cfg(feature = "experimental")]
2109 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2110 ForceAttachDict(DictAttachPref),
2111
2112 #[cfg(feature = "experimental")]
2113 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2114 LiteralCompressionMode(ParamSwitch),
2115
2116 #[cfg(feature = "experimental")]
2117 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2118 SrcSizeHint(u32),
2119
2120 #[cfg(feature = "experimental")]
2121 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2122 EnableDedicatedDictSearch(bool),
2123
2124 #[cfg(feature = "experimental")]
2125 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2126 StableInBuffer(bool),
2127
2128 #[cfg(feature = "experimental")]
2129 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2130 StableOutBuffer(bool),
2131
2132 #[cfg(feature = "experimental")]
2133 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2134 BlockDelimiters(bool),
2135
2136 #[cfg(feature = "experimental")]
2137 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2138 ValidateSequences(bool),
2139
2140 #[cfg(feature = "experimental")]
2141 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2142 UseBlockSplitter(ParamSwitch),
2143
2144 #[cfg(feature = "experimental")]
2145 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2146 UseRowMatchFinder(ParamSwitch),
2147
2148 #[cfg(feature = "experimental")]
2149 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2150 DeterministicRefPrefix(bool),
2151
2152 #[cfg(feature = "experimental")]
2153 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2154 PrefetchCDictTables(ParamSwitch),
2155
2156 #[cfg(feature = "experimental")]
2157 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2158 EnableSeqProducerFallback(bool),
2159
2160 #[cfg(feature = "experimental")]
2161 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2162 MaxBlockSize(u32),
2163
2164 #[cfg(feature = "experimental")]
2165 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2166 SearchForExternalRepcodes(ParamSwitch),
2167
2168 TargetCBlockSize(u32),
2175
2176 CompressionLevel(CompressionLevel),
2180
2181 WindowLog(u32),
2185
2186 HashLog(u32),
2187
2188 ChainLog(u32),
2189
2190 SearchLog(u32),
2191
2192 MinMatch(u32),
2193
2194 TargetLength(u32),
2195
2196 Strategy(Strategy),
2197
2198 EnableLongDistanceMatching(bool),
2199
2200 LdmHashLog(u32),
2201
2202 LdmMinMatch(u32),
2203
2204 LdmBucketSizeLog(u32),
2205
2206 LdmHashRateLog(u32),
2207
2208 ContentSizeFlag(bool),
2209
2210 ChecksumFlag(bool),
2211
2212 DictIdFlag(bool),
2213
2214 NbWorkers(u32),
2223
2224 JobSize(u32),
2232
2233 OverlapSizeLog(u32),
2245}
2246
2247#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2249#[non_exhaustive]
2250pub enum DParameter {
2251 WindowLogMax(u32),
2252
2253 #[cfg(feature = "experimental")]
2254 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2255 Format(FrameFormat),
2257
2258 #[cfg(feature = "experimental")]
2259 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2260 StableOutBuffer(bool),
2261
2262 #[cfg(feature = "experimental")]
2263 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2264 ForceIgnoreChecksum(bool),
2265
2266 #[cfg(feature = "experimental")]
2267 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2268 RefMultipleDDicts(bool),
2269}
2270
2271#[cfg(feature = "zdict_builder")]
2273#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "zdict_builder")))]
2274pub fn train_from_buffer<C: WriteBuf + ?Sized>(
2275 dict_buffer: &mut C,
2276 samples_buffer: &[u8],
2277 samples_sizes: &[usize],
2278) -> SafeResult {
2279 assert_eq!(samples_buffer.len(), samples_sizes.iter().sum());
2280
2281 unsafe {
2282 dict_buffer.write_from(|buffer, capacity| {
2283 parse_code(zstd_sys::ZDICT_trainFromBuffer(
2284 buffer,
2285 capacity,
2286 ptr_void(samples_buffer),
2287 samples_sizes.as_ptr(),
2288 samples_sizes.len() as u32,
2289 ))
2290 })
2291 }
2292}
2293
2294#[cfg(feature = "zdict_builder")]
2296#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "zdict_builder")))]
2297pub fn get_dict_id(dict_buffer: &[u8]) -> Option<NonZeroU32> {
2298 NonZeroU32::new(unsafe {
2299 zstd_sys::ZDICT_getDictID(ptr_void(dict_buffer), dict_buffer.len())
2300 })
2301}
2302
2303#[cfg(feature = "experimental")]
2305#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2306pub fn get_block_size(cctx: &CCtx) -> usize {
2307 unsafe { zstd_sys::ZSTD_getBlockSize(cctx.0.as_ptr()) }
2308}
2309
2310#[cfg(feature = "experimental")]
2312#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2313pub fn decompress_bound(data: &[u8]) -> Result<u64, ErrorCode> {
2314 let bound =
2315 unsafe { zstd_sys::ZSTD_decompressBound(ptr_void(data), data.len()) };
2316 if is_error(bound as usize) {
2317 Err(bound as usize)
2318 } else {
2319 Ok(bound)
2320 }
2321}
2322
2323#[cfg(feature = "experimental")]
2326#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2327pub fn sequence_bound(src_size: usize) -> usize {
2328 unsafe { zstd_sys::ZSTD_sequenceBound(src_size) }
2330}
2331
2332#[cfg(feature = "experimental")]
2338#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2339pub fn decompression_margin(
2340 compressed_data: &[u8],
2341) -> Result<usize, ErrorCode> {
2342 parse_code(unsafe {
2343 zstd_sys::ZSTD_decompressionMargin(
2344 ptr_void(compressed_data),
2345 compressed_data.len(),
2346 )
2347 })
2348}