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
30pub use zstd_sys;
32
33pub use zstd_sys::ZSTD_strategy as Strategy;
35
36use core::ffi::{c_char, c_int, c_ulonglong, c_void};
39
40use core::marker::PhantomData;
41use core::num::{NonZeroU32, NonZeroU64};
42use core::ops::{Deref, DerefMut};
43use core::ptr::NonNull;
44use core::str;
45
46include!("constants.rs");
47
48#[cfg(feature = "experimental")]
49include!("constants_experimental.rs");
50
51pub type CompressionLevel = i32;
53
54pub type ErrorCode = usize;
56
57pub type SafeResult = Result<usize, ErrorCode>;
61
62#[derive(Debug)]
66pub struct ContentSizeError;
67
68impl core::fmt::Display for ContentSizeError {
69 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
70 f.write_str("Could not get content size")
71 }
72}
73
74fn is_error(code: usize) -> bool {
76 unsafe { zstd_sys::ZSTD_isError(code) != 0 }
78}
79
80fn parse_code(code: usize) -> SafeResult {
85 if !is_error(code) {
86 Ok(code)
87 } else {
88 Err(code)
89 }
90}
91
92fn parse_content_size(
96 content_size: u64,
97) -> Result<Option<u64>, ContentSizeError> {
98 match content_size {
99 CONTENTSIZE_ERROR => Err(ContentSizeError),
100 CONTENTSIZE_UNKNOWN => Ok(None),
101 other => Ok(Some(other)),
102 }
103}
104
105fn ptr_void(src: &[u8]) -> *const c_void {
106 src.as_ptr() as *const c_void
107}
108
109fn ptr_mut_void(dst: &mut (impl WriteBuf + ?Sized)) -> *mut c_void {
110 dst.as_mut_ptr() as *mut c_void
111}
112
113pub fn version_number() -> u32 {
118 unsafe { zstd_sys::ZSTD_versionNumber() as u32 }
120}
121
122pub fn version_string() -> &'static str {
126 unsafe { c_char_to_str(zstd_sys::ZSTD_versionString()) }
128}
129
130pub fn min_c_level() -> CompressionLevel {
134 unsafe { zstd_sys::ZSTD_minCLevel() as CompressionLevel }
136}
137
138pub fn max_c_level() -> CompressionLevel {
140 unsafe { zstd_sys::ZSTD_maxCLevel() as CompressionLevel }
142}
143
144pub fn compress<C: WriteBuf + ?Sized>(
152 dst: &mut C,
153 src: &[u8],
154 compression_level: CompressionLevel,
155) -> SafeResult {
156 unsafe {
158 dst.write_from(|buffer, capacity| {
159 parse_code(zstd_sys::ZSTD_compress(
160 buffer,
161 capacity,
162 ptr_void(src),
163 src.len(),
164 compression_level,
165 ))
166 })
167 }
168}
169
170pub fn decompress<C: WriteBuf + ?Sized>(
179 dst: &mut C,
180 src: &[u8],
181) -> SafeResult {
182 unsafe {
184 dst.write_from(|buffer, capacity| {
185 parse_code(zstd_sys::ZSTD_decompress(
186 buffer,
187 capacity,
188 ptr_void(src),
189 src.len(),
190 ))
191 })
192 }
193}
194
195#[deprecated(note = "Use ZSTD_getFrameContentSize instead")]
199pub fn get_decompressed_size(src: &[u8]) -> Option<NonZeroU64> {
200 NonZeroU64::new(unsafe {
202 zstd_sys::ZSTD_getDecompressedSize(ptr_void(src), src.len()) as u64
203 })
204}
205
206pub fn compress_bound(src_size: usize) -> usize {
208 unsafe { zstd_sys::ZSTD_compressBound(src_size) }
210}
211
212pub struct CCtx<'a>(NonNull<zstd_sys::ZSTD_CCtx>, PhantomData<&'a ()>);
217
218impl Default for CCtx<'_> {
219 fn default() -> Self {
220 CCtx::create()
221 }
222}
223
224impl<'a> CCtx<'a> {
225 pub fn try_create() -> Option<Self> {
229 Some(CCtx(
231 NonNull::new(unsafe { zstd_sys::ZSTD_createCCtx() })?,
232 PhantomData,
233 ))
234 }
235
236 pub fn create() -> Self {
242 Self::try_create()
243 .expect("zstd returned null pointer when creating new context")
244 }
245
246 pub fn compress<C: WriteBuf + ?Sized>(
248 &mut self,
249 dst: &mut C,
250 src: &[u8],
251 compression_level: CompressionLevel,
252 ) -> SafeResult {
253 unsafe {
255 dst.write_from(|buffer, capacity| {
256 parse_code(zstd_sys::ZSTD_compressCCtx(
257 self.0.as_ptr(),
258 buffer,
259 capacity,
260 ptr_void(src),
261 src.len(),
262 compression_level,
263 ))
264 })
265 }
266 }
267
268 pub fn compress2<C: WriteBuf + ?Sized>(
270 &mut self,
271 dst: &mut C,
272 src: &[u8],
273 ) -> SafeResult {
274 unsafe {
276 dst.write_from(|buffer, capacity| {
277 parse_code(zstd_sys::ZSTD_compress2(
278 self.0.as_ptr(),
279 buffer,
280 capacity,
281 ptr_void(src),
282 src.len(),
283 ))
284 })
285 }
286 }
287
288 pub fn compress_using_dict<C: WriteBuf + ?Sized>(
290 &mut self,
291 dst: &mut C,
292 src: &[u8],
293 dict: &[u8],
294 compression_level: CompressionLevel,
295 ) -> SafeResult {
296 unsafe {
298 dst.write_from(|buffer, capacity| {
299 parse_code(zstd_sys::ZSTD_compress_usingDict(
300 self.0.as_ptr(),
301 buffer,
302 capacity,
303 ptr_void(src),
304 src.len(),
305 ptr_void(dict),
306 dict.len(),
307 compression_level,
308 ))
309 })
310 }
311 }
312
313 pub fn compress_using_cdict<C: WriteBuf + ?Sized>(
315 &mut self,
316 dst: &mut C,
317 src: &[u8],
318 cdict: &CDict<'_>,
319 ) -> SafeResult {
320 unsafe {
322 dst.write_from(|buffer, capacity| {
323 parse_code(zstd_sys::ZSTD_compress_usingCDict(
324 self.0.as_ptr(),
325 buffer,
326 capacity,
327 ptr_void(src),
328 src.len(),
329 cdict.0.as_ptr(),
330 ))
331 })
332 }
333 }
334
335 pub fn init(&mut self, compression_level: CompressionLevel) -> SafeResult {
341 let code = unsafe {
343 zstd_sys::ZSTD_initCStream(self.0.as_ptr(), compression_level)
344 };
345 parse_code(code)
346 }
347
348 #[cfg(feature = "experimental")]
350 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
351 #[deprecated]
352 pub fn init_src_size(
353 &mut self,
354 compression_level: CompressionLevel,
355 pledged_src_size: u64,
356 ) -> SafeResult {
357 let code = unsafe {
359 zstd_sys::ZSTD_initCStream_srcSize(
360 self.0.as_ptr(),
361 compression_level as c_int,
362 pledged_src_size as c_ulonglong,
363 )
364 };
365 parse_code(code)
366 }
367
368 #[cfg(feature = "experimental")]
370 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
371 #[deprecated]
372 pub fn init_using_dict(
373 &mut self,
374 dict: &[u8],
375 compression_level: CompressionLevel,
376 ) -> SafeResult {
377 let code = unsafe {
379 zstd_sys::ZSTD_initCStream_usingDict(
380 self.0.as_ptr(),
381 ptr_void(dict),
382 dict.len(),
383 compression_level,
384 )
385 };
386 parse_code(code)
387 }
388
389 #[cfg(feature = "experimental")]
391 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
392 #[deprecated]
393 pub fn init_using_cdict<'b>(&mut self, cdict: &CDict<'b>) -> SafeResult
394 where
395 'b: 'a, {
397 let code = unsafe {
399 zstd_sys::ZSTD_initCStream_usingCDict(
400 self.0.as_ptr(),
401 cdict.0.as_ptr(),
402 )
403 };
404 parse_code(code)
405 }
406
407 pub fn load_dictionary(&mut self, dict: &[u8]) -> SafeResult {
417 parse_code(unsafe {
419 zstd_sys::ZSTD_CCtx_loadDictionary(
420 self.0.as_ptr(),
421 ptr_void(dict),
422 dict.len(),
423 )
424 })
425 }
426
427 pub fn ref_cdict<'b>(&mut self, cdict: &CDict<'b>) -> SafeResult
431 where
432 'b: 'a,
433 {
434 parse_code(unsafe {
436 zstd_sys::ZSTD_CCtx_refCDict(self.0.as_ptr(), cdict.0.as_ptr())
437 })
438 }
439
440 pub fn disable_dictionary(&mut self) -> SafeResult {
444 parse_code(unsafe {
446 zstd_sys::ZSTD_CCtx_loadDictionary(
447 self.0.as_ptr(),
448 core::ptr::null(),
449 0,
450 )
451 })
452 }
453
454 pub fn ref_prefix<'b>(&mut self, prefix: &'b [u8]) -> SafeResult
460 where
461 'b: 'a,
462 {
463 parse_code(unsafe {
465 zstd_sys::ZSTD_CCtx_refPrefix(
466 self.0.as_ptr(),
467 ptr_void(prefix),
468 prefix.len(),
469 )
470 })
471 }
472
473 pub fn compress_stream<C: WriteBuf + ?Sized>(
485 &mut self,
486 output: &mut OutBuffer<'_, C>,
487 input: &mut InBuffer<'_>,
488 ) -> SafeResult {
489 let mut output = output.wrap();
490 let mut input = input.wrap();
491 let code = unsafe {
493 zstd_sys::ZSTD_compressStream(
494 self.0.as_ptr(),
495 ptr_mut(&mut output),
496 ptr_mut(&mut input),
497 )
498 };
499 parse_code(code)
500 }
501
502 pub fn compress_stream2<C: WriteBuf + ?Sized>(
518 &mut self,
519 output: &mut OutBuffer<'_, C>,
520 input: &mut InBuffer<'_>,
521 end_op: zstd_sys::ZSTD_EndDirective,
522 ) -> SafeResult {
523 let mut output = output.wrap();
524 let mut input = input.wrap();
525 parse_code(unsafe {
527 zstd_sys::ZSTD_compressStream2(
528 self.0.as_ptr(),
529 ptr_mut(&mut output),
530 ptr_mut(&mut input),
531 end_op,
532 )
533 })
534 }
535
536 pub fn flush_stream<C: WriteBuf + ?Sized>(
542 &mut self,
543 output: &mut OutBuffer<'_, C>,
544 ) -> SafeResult {
545 let mut output = output.wrap();
546 let code = unsafe {
548 zstd_sys::ZSTD_flushStream(self.0.as_ptr(), ptr_mut(&mut output))
549 };
550 parse_code(code)
551 }
552
553 pub fn end_stream<C: WriteBuf + ?Sized>(
559 &mut self,
560 output: &mut OutBuffer<'_, C>,
561 ) -> SafeResult {
562 let mut output = output.wrap();
563 let code = unsafe {
565 zstd_sys::ZSTD_endStream(self.0.as_ptr(), ptr_mut(&mut output))
566 };
567 parse_code(code)
568 }
569
570 pub fn sizeof(&self) -> usize {
574 unsafe { zstd_sys::ZSTD_sizeof_CCtx(self.0.as_ptr()) }
576 }
577
578 pub fn reset(&mut self, reset: ResetDirective) -> SafeResult {
584 parse_code(unsafe {
586 zstd_sys::ZSTD_CCtx_reset(self.0.as_ptr(), reset.as_sys())
587 })
588 }
589
590 pub fn set_parameter(&mut self, param: CParameter) -> SafeResult {
594 #[cfg(feature = "experimental")]
597 use zstd_sys::ZSTD_cParameter::{
598 ZSTD_c_experimentalParam1 as ZSTD_c_rsyncable,
599 ZSTD_c_experimentalParam10 as ZSTD_c_stableOutBuffer,
600 ZSTD_c_experimentalParam11 as ZSTD_c_blockDelimiters,
601 ZSTD_c_experimentalParam12 as ZSTD_c_validateSequences,
602 ZSTD_c_experimentalParam13 as ZSTD_c_useBlockSplitter,
603 ZSTD_c_experimentalParam14 as ZSTD_c_useRowMatchFinder,
604 ZSTD_c_experimentalParam15 as ZSTD_c_deterministicRefPrefix,
605 ZSTD_c_experimentalParam16 as ZSTD_c_prefetchCDictTables,
606 ZSTD_c_experimentalParam17 as ZSTD_c_enableSeqProducerFallback,
607 ZSTD_c_experimentalParam18 as ZSTD_c_maxBlockSize,
608 ZSTD_c_experimentalParam19 as ZSTD_c_searchForExternalRepcodes,
609 ZSTD_c_experimentalParam2 as ZSTD_c_format,
610 ZSTD_c_experimentalParam3 as ZSTD_c_forceMaxWindow,
611 ZSTD_c_experimentalParam4 as ZSTD_c_forceAttachDict,
612 ZSTD_c_experimentalParam5 as ZSTD_c_literalCompressionMode,
613 ZSTD_c_experimentalParam7 as ZSTD_c_srcSizeHint,
614 ZSTD_c_experimentalParam8 as ZSTD_c_enableDedicatedDictSearch,
615 ZSTD_c_experimentalParam9 as ZSTD_c_stableInBuffer,
616 };
617
618 use zstd_sys::ZSTD_cParameter::*;
619 use CParameter::*;
620
621 let (param, value) = match param {
622 #[cfg(feature = "experimental")]
623 RSyncable(rsyncable) => (ZSTD_c_rsyncable, rsyncable as c_int),
624 #[cfg(feature = "experimental")]
625 Format(format) => (ZSTD_c_format, format as c_int),
626 #[cfg(feature = "experimental")]
627 ForceMaxWindow(force) => (ZSTD_c_forceMaxWindow, force as c_int),
628 #[cfg(feature = "experimental")]
629 ForceAttachDict(force) => (ZSTD_c_forceAttachDict, force as c_int),
630 #[cfg(feature = "experimental")]
631 LiteralCompressionMode(mode) => {
632 (ZSTD_c_literalCompressionMode, mode as c_int)
633 }
634 #[cfg(feature = "experimental")]
635 SrcSizeHint(value) => (ZSTD_c_srcSizeHint, value as c_int),
636 #[cfg(feature = "experimental")]
637 EnableDedicatedDictSearch(enable) => {
638 (ZSTD_c_enableDedicatedDictSearch, enable as c_int)
639 }
640 #[cfg(feature = "experimental")]
641 StableInBuffer(stable) => (ZSTD_c_stableInBuffer, stable as c_int),
642 #[cfg(feature = "experimental")]
643 StableOutBuffer(stable) => {
644 (ZSTD_c_stableOutBuffer, stable as c_int)
645 }
646 #[cfg(feature = "experimental")]
647 BlockDelimiters(value) => (ZSTD_c_blockDelimiters, value as c_int),
648 #[cfg(feature = "experimental")]
649 ValidateSequences(validate) => {
650 (ZSTD_c_validateSequences, validate as c_int)
651 }
652 #[cfg(feature = "experimental")]
653 UseBlockSplitter(split) => {
654 (ZSTD_c_useBlockSplitter, split as c_int)
655 }
656 #[cfg(feature = "experimental")]
657 UseRowMatchFinder(mode) => {
658 (ZSTD_c_useRowMatchFinder, mode as c_int)
659 }
660 #[cfg(feature = "experimental")]
661 DeterministicRefPrefix(deterministic) => {
662 (ZSTD_c_deterministicRefPrefix, deterministic as c_int)
663 }
664 #[cfg(feature = "experimental")]
665 PrefetchCDictTables(prefetch) => {
666 (ZSTD_c_prefetchCDictTables, prefetch as c_int)
667 }
668 #[cfg(feature = "experimental")]
669 EnableSeqProducerFallback(enable) => {
670 (ZSTD_c_enableSeqProducerFallback, enable as c_int)
671 }
672 #[cfg(feature = "experimental")]
673 MaxBlockSize(value) => (ZSTD_c_maxBlockSize, value as c_int),
674 #[cfg(feature = "experimental")]
675 SearchForExternalRepcodes(value) => {
676 (ZSTD_c_searchForExternalRepcodes, value as c_int)
677 }
678 TargetCBlockSize(value) => {
679 (ZSTD_c_targetCBlockSize, value as c_int)
680 }
681 CompressionLevel(level) => (ZSTD_c_compressionLevel, level),
682 WindowLog(value) => (ZSTD_c_windowLog, value as c_int),
683 HashLog(value) => (ZSTD_c_hashLog, value as c_int),
684 ChainLog(value) => (ZSTD_c_chainLog, value as c_int),
685 SearchLog(value) => (ZSTD_c_searchLog, value as c_int),
686 MinMatch(value) => (ZSTD_c_minMatch, value as c_int),
687 TargetLength(value) => (ZSTD_c_targetLength, value as c_int),
688 Strategy(strategy) => (ZSTD_c_strategy, strategy as c_int),
689 EnableLongDistanceMatching(flag) => {
690 (ZSTD_c_enableLongDistanceMatching, flag as c_int)
691 }
692 LdmHashLog(value) => (ZSTD_c_ldmHashLog, value as c_int),
693 LdmMinMatch(value) => (ZSTD_c_ldmMinMatch, value as c_int),
694 LdmBucketSizeLog(value) => {
695 (ZSTD_c_ldmBucketSizeLog, value as c_int)
696 }
697 LdmHashRateLog(value) => (ZSTD_c_ldmHashRateLog, value as c_int),
698 ContentSizeFlag(flag) => (ZSTD_c_contentSizeFlag, flag as c_int),
699 ChecksumFlag(flag) => (ZSTD_c_checksumFlag, flag as c_int),
700 DictIdFlag(flag) => (ZSTD_c_dictIDFlag, flag as c_int),
701
702 NbWorkers(value) => (ZSTD_c_nbWorkers, value as c_int),
703
704 JobSize(value) => (ZSTD_c_jobSize, value as c_int),
705
706 OverlapSizeLog(value) => (ZSTD_c_overlapLog, value as c_int),
707 };
708
709 parse_code(unsafe {
711 zstd_sys::ZSTD_CCtx_setParameter(self.0.as_ptr(), param, value)
712 })
713 }
714
715 pub fn set_pledged_src_size(
724 &mut self,
725 pledged_src_size: Option<u64>,
726 ) -> SafeResult {
727 parse_code(unsafe {
729 zstd_sys::ZSTD_CCtx_setPledgedSrcSize(
730 self.0.as_ptr(),
731 pledged_src_size.unwrap_or(CONTENTSIZE_UNKNOWN) as c_ulonglong,
732 )
733 })
734 }
735
736 #[cfg(feature = "experimental")]
741 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
742 pub fn try_clone(
743 &self,
744 pledged_src_size: Option<u64>,
745 ) -> Result<Self, ErrorCode> {
746 let context = NonNull::new(unsafe { zstd_sys::ZSTD_createCCtx() })
748 .ok_or(0usize)?;
749
750 parse_code(unsafe {
752 zstd_sys::ZSTD_copyCCtx(
753 context.as_ptr(),
754 self.0.as_ptr(),
755 pledged_src_size.unwrap_or(CONTENTSIZE_UNKNOWN),
756 )
757 })?;
758
759 Ok(CCtx(context, self.1))
760 }
761
762 #[cfg(feature = "experimental")]
764 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
765 pub fn get_block_size(&self) -> usize {
766 unsafe { zstd_sys::ZSTD_getBlockSize(self.0.as_ptr()) }
768 }
769
770 #[cfg(feature = "experimental")]
772 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
773 pub fn compress_block<C: WriteBuf + ?Sized>(
774 &mut self,
775 dst: &mut C,
776 src: &[u8],
777 ) -> SafeResult {
778 unsafe {
780 dst.write_from(|buffer, capacity| {
781 parse_code(zstd_sys::ZSTD_compressBlock(
782 self.0.as_ptr(),
783 buffer,
784 capacity,
785 ptr_void(src),
786 src.len(),
787 ))
788 })
789 }
790 }
791
792 pub fn in_size() -> usize {
796 unsafe { zstd_sys::ZSTD_CStreamInSize() }
798 }
799
800 pub fn out_size() -> usize {
804 unsafe { zstd_sys::ZSTD_CStreamOutSize() }
806 }
807
808 #[cfg(all(feature = "experimental", feature = "zstdmt"))]
812 #[cfg_attr(
813 feature = "doc-cfg",
814 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
815 )]
816 pub fn ref_thread_pool<'b>(&mut self, pool: &'b ThreadPool) -> SafeResult
817 where
818 'b: 'a,
819 {
820 parse_code(unsafe {
821 zstd_sys::ZSTD_CCtx_refThreadPool(self.0.as_ptr(), pool.0.as_ptr())
822 })
823 }
824
825 #[cfg(all(feature = "experimental", feature = "zstdmt"))]
827 #[cfg_attr(
828 feature = "doc-cfg",
829 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
830 )]
831 pub fn disable_thread_pool(&mut self) -> SafeResult {
832 parse_code(unsafe {
833 zstd_sys::ZSTD_CCtx_refThreadPool(
834 self.0.as_ptr(),
835 core::ptr::null_mut(),
836 )
837 })
838 }
839}
840
841impl<'a> Drop for CCtx<'a> {
842 fn drop(&mut self) {
843 unsafe {
845 zstd_sys::ZSTD_freeCCtx(self.0.as_ptr());
846 }
847 }
848}
849
850unsafe impl Send for CCtx<'_> {}
851unsafe impl Sync for CCtx<'_> {}
853
854unsafe fn c_char_to_str(text: *const c_char) -> &'static str {
855 core::ffi::CStr::from_ptr(text)
856 .to_str()
857 .expect("bad error message from zstd")
858}
859
860pub fn get_error_name(code: usize) -> &'static str {
862 unsafe {
863 let name = zstd_sys::ZSTD_getErrorName(code);
865 c_char_to_str(name)
866 }
867}
868
869pub struct DCtx<'a>(NonNull<zstd_sys::ZSTD_DCtx>, PhantomData<&'a ()>);
877
878impl Default for DCtx<'_> {
879 fn default() -> Self {
880 DCtx::create()
881 }
882}
883
884impl<'a> DCtx<'a> {
885 pub fn try_create() -> Option<Self> {
889 Some(DCtx(
890 NonNull::new(unsafe { zstd_sys::ZSTD_createDCtx() })?,
891 PhantomData,
892 ))
893 }
894
895 pub fn create() -> Self {
901 Self::try_create()
902 .expect("zstd returned null pointer when creating new context")
903 }
904
905 pub fn decompress<C: WriteBuf + ?Sized>(
912 &mut self,
913 dst: &mut C,
914 src: &[u8],
915 ) -> SafeResult {
916 unsafe {
917 dst.write_from(|buffer, capacity| {
918 parse_code(zstd_sys::ZSTD_decompressDCtx(
919 self.0.as_ptr(),
920 buffer,
921 capacity,
922 ptr_void(src),
923 src.len(),
924 ))
925 })
926 }
927 }
928
929 pub fn decompress_using_dict<C: WriteBuf + ?Sized>(
938 &mut self,
939 dst: &mut C,
940 src: &[u8],
941 dict: &[u8],
942 ) -> SafeResult {
943 unsafe {
944 dst.write_from(|buffer, capacity| {
945 parse_code(zstd_sys::ZSTD_decompress_usingDict(
946 self.0.as_ptr(),
947 buffer,
948 capacity,
949 ptr_void(src),
950 src.len(),
951 ptr_void(dict),
952 dict.len(),
953 ))
954 })
955 }
956 }
957
958 pub fn decompress_using_ddict<C: WriteBuf + ?Sized>(
964 &mut self,
965 dst: &mut C,
966 src: &[u8],
967 ddict: &DDict<'_>,
968 ) -> SafeResult {
969 unsafe {
970 dst.write_from(|buffer, capacity| {
971 parse_code(zstd_sys::ZSTD_decompress_usingDDict(
972 self.0.as_ptr(),
973 buffer,
974 capacity,
975 ptr_void(src),
976 src.len(),
977 ddict.0.as_ptr(),
978 ))
979 })
980 }
981 }
982
983 pub fn init(&mut self) -> SafeResult {
991 let code = unsafe { zstd_sys::ZSTD_initDStream(self.0.as_ptr()) };
992 parse_code(code)
993 }
994
995 #[cfg(feature = "experimental")]
997 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
998 #[deprecated]
999 pub fn init_using_dict(&mut self, dict: &[u8]) -> SafeResult {
1000 let code = unsafe {
1001 zstd_sys::ZSTD_initDStream_usingDict(
1002 self.0.as_ptr(),
1003 ptr_void(dict),
1004 dict.len(),
1005 )
1006 };
1007 parse_code(code)
1008 }
1009
1010 #[cfg(feature = "experimental")]
1012 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1013 #[deprecated]
1014 pub fn init_using_ddict<'b>(&mut self, ddict: &DDict<'b>) -> SafeResult
1015 where
1016 'b: 'a,
1017 {
1018 let code = unsafe {
1019 zstd_sys::ZSTD_initDStream_usingDDict(
1020 self.0.as_ptr(),
1021 ddict.0.as_ptr(),
1022 )
1023 };
1024 parse_code(code)
1025 }
1026
1027 pub fn reset(&mut self, reset: ResetDirective) -> SafeResult {
1033 parse_code(unsafe {
1034 zstd_sys::ZSTD_DCtx_reset(self.0.as_ptr(), reset.as_sys())
1035 })
1036 }
1037
1038 pub fn load_dictionary(&mut self, dict: &[u8]) -> SafeResult {
1050 parse_code(unsafe {
1051 zstd_sys::ZSTD_DCtx_loadDictionary(
1052 self.0.as_ptr(),
1053 ptr_void(dict),
1054 dict.len(),
1055 )
1056 })
1057 }
1058
1059 pub fn disable_dictionary(&mut self) -> SafeResult {
1063 parse_code(unsafe {
1064 zstd_sys::ZSTD_DCtx_loadDictionary(
1065 self.0.as_ptr(),
1066 core::ptr::null(),
1067 0,
1068 )
1069 })
1070 }
1071
1072 pub fn ref_ddict<'b>(&mut self, ddict: &DDict<'b>) -> SafeResult
1080 where
1081 'b: 'a,
1082 {
1083 parse_code(unsafe {
1084 zstd_sys::ZSTD_DCtx_refDDict(self.0.as_ptr(), ddict.0.as_ptr())
1085 })
1086 }
1087
1088 pub fn ref_prefix<'b>(&mut self, prefix: &'b [u8]) -> SafeResult
1096 where
1097 'b: 'a,
1098 {
1099 parse_code(unsafe {
1100 zstd_sys::ZSTD_DCtx_refPrefix(
1101 self.0.as_ptr(),
1102 ptr_void(prefix),
1103 prefix.len(),
1104 )
1105 })
1106 }
1107
1108 pub fn set_parameter(&mut self, param: DParameter) -> SafeResult {
1110 #[cfg(feature = "experimental")]
1111 use zstd_sys::ZSTD_dParameter::{
1112 ZSTD_d_experimentalParam1 as ZSTD_d_format,
1113 ZSTD_d_experimentalParam2 as ZSTD_d_stableOutBuffer,
1114 ZSTD_d_experimentalParam3 as ZSTD_d_forceIgnoreChecksum,
1115 ZSTD_d_experimentalParam4 as ZSTD_d_refMultipleDDicts,
1116 };
1117
1118 use zstd_sys::ZSTD_dParameter::*;
1119 use DParameter::*;
1120
1121 let (param, value) = match param {
1122 #[cfg(feature = "experimental")]
1123 Format(format) => (ZSTD_d_format, format as c_int),
1124 #[cfg(feature = "experimental")]
1125 StableOutBuffer(stable) => {
1126 (ZSTD_d_stableOutBuffer, stable as c_int)
1127 }
1128 #[cfg(feature = "experimental")]
1129 ForceIgnoreChecksum(force) => {
1130 (ZSTD_d_forceIgnoreChecksum, force as c_int)
1131 }
1132 #[cfg(feature = "experimental")]
1133 RefMultipleDDicts(value) => {
1134 (ZSTD_d_refMultipleDDicts, value as c_int)
1135 }
1136
1137 WindowLogMax(value) => (ZSTD_d_windowLogMax, value as c_int),
1138 };
1139
1140 parse_code(unsafe {
1141 zstd_sys::ZSTD_DCtx_setParameter(self.0.as_ptr(), param, value)
1142 })
1143 }
1144
1145 pub fn decompress_stream<C: WriteBuf + ?Sized>(
1157 &mut self,
1158 output: &mut OutBuffer<'_, C>,
1159 input: &mut InBuffer<'_>,
1160 ) -> SafeResult {
1161 let mut output = output.wrap();
1162 let mut input = input.wrap();
1163 let code = unsafe {
1164 zstd_sys::ZSTD_decompressStream(
1165 self.0.as_ptr(),
1166 ptr_mut(&mut output),
1167 ptr_mut(&mut input),
1168 )
1169 };
1170 parse_code(code)
1171 }
1172
1173 pub fn in_size() -> usize {
1177 unsafe { zstd_sys::ZSTD_DStreamInSize() }
1178 }
1179
1180 pub fn out_size() -> usize {
1184 unsafe { zstd_sys::ZSTD_DStreamOutSize() }
1185 }
1186
1187 pub fn sizeof(&self) -> usize {
1189 unsafe { zstd_sys::ZSTD_sizeof_DCtx(self.0.as_ptr()) }
1190 }
1191
1192 #[cfg(feature = "experimental")]
1194 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1195 pub fn decompress_block<C: WriteBuf + ?Sized>(
1196 &mut self,
1197 dst: &mut C,
1198 src: &[u8],
1199 ) -> SafeResult {
1200 unsafe {
1201 dst.write_from(|buffer, capacity| {
1202 parse_code(zstd_sys::ZSTD_decompressBlock(
1203 self.0.as_ptr(),
1204 buffer,
1205 capacity,
1206 ptr_void(src),
1207 src.len(),
1208 ))
1209 })
1210 }
1211 }
1212
1213 #[cfg(feature = "experimental")]
1215 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1216 pub fn insert_block(&mut self, block: &[u8]) -> usize {
1217 unsafe {
1218 zstd_sys::ZSTD_insertBlock(
1219 self.0.as_ptr(),
1220 ptr_void(block),
1221 block.len(),
1222 )
1223 }
1224 }
1225
1226 #[cfg(feature = "experimental")]
1231 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1232 pub fn try_clone(&self) -> Result<Self, ErrorCode> {
1233 let context = NonNull::new(unsafe { zstd_sys::ZSTD_createDCtx() })
1234 .ok_or(0usize)?;
1235
1236 unsafe { zstd_sys::ZSTD_copyDCtx(context.as_ptr(), self.0.as_ptr()) };
1237
1238 Ok(DCtx(context, self.1))
1239 }
1240}
1241
1242impl Drop for DCtx<'_> {
1243 fn drop(&mut self) {
1244 unsafe {
1245 zstd_sys::ZSTD_freeDCtx(self.0.as_ptr());
1246 }
1247 }
1248}
1249
1250unsafe impl Send for DCtx<'_> {}
1251unsafe impl Sync for DCtx<'_> {}
1253
1254pub struct CDict<'a>(NonNull<zstd_sys::ZSTD_CDict>, PhantomData<&'a ()>);
1256
1257impl CDict<'static> {
1258 pub fn create(
1268 dict_buffer: &[u8],
1269 compression_level: CompressionLevel,
1270 ) -> Self {
1271 Self::try_create(dict_buffer, compression_level)
1272 .expect("zstd returned null pointer when creating dict")
1273 }
1274
1275 pub fn try_create(
1281 dict_buffer: &[u8],
1282 compression_level: CompressionLevel,
1283 ) -> Option<Self> {
1284 Some(CDict(
1285 NonNull::new(unsafe {
1286 zstd_sys::ZSTD_createCDict(
1287 ptr_void(dict_buffer),
1288 dict_buffer.len(),
1289 compression_level,
1290 )
1291 })?,
1292 PhantomData,
1293 ))
1294 }
1295}
1296
1297impl<'a> CDict<'a> {
1298 #[cfg(feature = "experimental")]
1299 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1300 pub fn create_by_reference(
1301 dict_buffer: &'a [u8],
1302 compression_level: CompressionLevel,
1303 ) -> Self {
1304 CDict(
1305 NonNull::new(unsafe {
1306 zstd_sys::ZSTD_createCDict_byReference(
1307 ptr_void(dict_buffer),
1308 dict_buffer.len(),
1309 compression_level,
1310 )
1311 })
1312 .expect("zstd returned null pointer"),
1313 PhantomData,
1314 )
1315 }
1316
1317 pub fn sizeof(&self) -> usize {
1321 unsafe { zstd_sys::ZSTD_sizeof_CDict(self.0.as_ptr()) }
1322 }
1323
1324 pub fn get_dict_id(&self) -> Option<NonZeroU32> {
1328 NonZeroU32::new(unsafe {
1329 zstd_sys::ZSTD_getDictID_fromCDict(self.0.as_ptr()) as u32
1330 })
1331 }
1332}
1333
1334pub fn create_cdict(
1336 dict_buffer: &[u8],
1337 compression_level: CompressionLevel,
1338) -> CDict<'static> {
1339 CDict::create(dict_buffer, compression_level)
1340}
1341
1342impl<'a> Drop for CDict<'a> {
1343 fn drop(&mut self) {
1344 unsafe {
1345 zstd_sys::ZSTD_freeCDict(self.0.as_ptr());
1346 }
1347 }
1348}
1349
1350unsafe impl<'a> Send for CDict<'a> {}
1351unsafe impl<'a> Sync for CDict<'a> {}
1352
1353pub fn compress_using_cdict(
1355 cctx: &mut CCtx<'_>,
1356 dst: &mut [u8],
1357 src: &[u8],
1358 cdict: &CDict<'_>,
1359) -> SafeResult {
1360 cctx.compress_using_cdict(dst, src, cdict)
1361}
1362
1363pub struct DDict<'a>(NonNull<zstd_sys::ZSTD_DDict>, PhantomData<&'a ()>);
1365
1366impl DDict<'static> {
1367 pub fn create(dict_buffer: &[u8]) -> Self {
1368 Self::try_create(dict_buffer)
1369 .expect("zstd returned null pointer when creating dict")
1370 }
1371
1372 pub fn try_create(dict_buffer: &[u8]) -> Option<Self> {
1373 Some(DDict(
1374 NonNull::new(unsafe {
1375 zstd_sys::ZSTD_createDDict(
1376 ptr_void(dict_buffer),
1377 dict_buffer.len(),
1378 )
1379 })?,
1380 PhantomData,
1381 ))
1382 }
1383}
1384
1385impl<'a> DDict<'a> {
1386 pub fn sizeof(&self) -> usize {
1387 unsafe { zstd_sys::ZSTD_sizeof_DDict(self.0.as_ptr()) }
1388 }
1389
1390 #[cfg(feature = "experimental")]
1394 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1395 pub fn create_by_reference(dict_buffer: &'a [u8]) -> Self {
1396 DDict(
1397 NonNull::new(unsafe {
1398 zstd_sys::ZSTD_createDDict_byReference(
1399 ptr_void(dict_buffer),
1400 dict_buffer.len(),
1401 )
1402 })
1403 .expect("zstd returned null pointer"),
1404 PhantomData,
1405 )
1406 }
1407
1408 pub fn get_dict_id(&self) -> Option<NonZeroU32> {
1412 NonZeroU32::new(unsafe {
1413 zstd_sys::ZSTD_getDictID_fromDDict(self.0.as_ptr()) as u32
1414 })
1415 }
1416}
1417
1418pub fn create_ddict(dict_buffer: &[u8]) -> DDict<'static> {
1422 DDict::create(dict_buffer)
1423}
1424
1425impl<'a> Drop for DDict<'a> {
1426 fn drop(&mut self) {
1427 unsafe {
1428 zstd_sys::ZSTD_freeDDict(self.0.as_ptr());
1429 }
1430 }
1431}
1432
1433unsafe impl<'a> Send for DDict<'a> {}
1434unsafe impl<'a> Sync for DDict<'a> {}
1435
1436#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1438#[cfg_attr(
1439 feature = "doc-cfg",
1440 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1441)]
1442pub struct ThreadPool(NonNull<zstd_sys::ZSTD_threadPool>);
1443
1444#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1445#[cfg_attr(
1446 feature = "doc-cfg",
1447 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1448)]
1449impl ThreadPool {
1450 pub fn new(num_threads: usize) -> Self {
1456 Self::try_new(num_threads)
1457 .expect("zstd returned null pointer when creating thread pool")
1458 }
1459
1460 pub fn try_new(num_threads: usize) -> Option<Self> {
1462 Some(Self(NonNull::new(unsafe {
1463 zstd_sys::ZSTD_createThreadPool(num_threads)
1464 })?))
1465 }
1466}
1467
1468#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1469#[cfg_attr(
1470 feature = "doc-cfg",
1471 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1472)]
1473impl Drop for ThreadPool {
1474 fn drop(&mut self) {
1475 unsafe {
1476 zstd_sys::ZSTD_freeThreadPool(self.0.as_ptr());
1477 }
1478 }
1479}
1480
1481#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1482#[cfg_attr(
1483 feature = "doc-cfg",
1484 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1485)]
1486unsafe impl Send for ThreadPool {}
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 Sync for ThreadPool {}
1493
1494pub fn decompress_using_ddict(
1496 dctx: &mut DCtx<'_>,
1497 dst: &mut [u8],
1498 src: &[u8],
1499 ddict: &DDict<'_>,
1500) -> SafeResult {
1501 dctx.decompress_using_ddict(dst, src, ddict)
1502}
1503
1504pub type CStream<'a> = CCtx<'a>;
1508
1509pub fn create_cstream<'a>() -> CStream<'a> {
1513 CCtx::create()
1514}
1515
1516pub fn init_cstream(
1518 zcs: &mut CStream<'_>,
1519 compression_level: CompressionLevel,
1520) -> SafeResult {
1521 zcs.init(compression_level)
1522}
1523
1524#[derive(Debug)]
1525pub struct InBuffer<'a> {
1531 pub src: &'a [u8],
1532 pub pos: usize,
1533}
1534
1535pub unsafe trait WriteBuf {
1555 fn as_slice(&self) -> &[u8];
1557
1558 fn capacity(&self) -> usize;
1560
1561 fn as_mut_ptr(&mut self) -> *mut u8;
1563
1564 unsafe fn filled_until(&mut self, n: usize);
1569
1570 unsafe fn write_from<F>(&mut self, f: F) -> SafeResult
1581 where
1582 F: FnOnce(*mut c_void, usize) -> SafeResult,
1583 {
1584 let res = f(ptr_mut_void(self), self.capacity());
1585 if let Ok(n) = res {
1586 self.filled_until(n);
1587 }
1588 res
1589 }
1590}
1591
1592#[cfg(feature = "std")]
1593#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "std")))]
1594unsafe impl<T> WriteBuf for std::io::Cursor<T>
1595where
1596 T: WriteBuf,
1597{
1598 fn as_slice(&self) -> &[u8] {
1599 &self.get_ref().as_slice()[self.position() as usize..]
1600 }
1601
1602 fn capacity(&self) -> usize {
1603 self.get_ref()
1604 .capacity()
1605 .saturating_sub(self.position() as usize)
1606 }
1607
1608 fn as_mut_ptr(&mut self) -> *mut u8 {
1609 let start = self.position() as usize;
1610 assert!(start <= self.get_ref().capacity());
1611 unsafe { self.get_mut().as_mut_ptr().add(start) }
1613 }
1614
1615 unsafe fn filled_until(&mut self, n: usize) {
1616 if n == 0 {
1618 return;
1619 }
1620
1621 let position = self.position() as usize;
1625 let initialized = self.get_ref().as_slice().len();
1626 if let Some(uninitialized) = position.checked_sub(initialized) {
1627 unsafe {
1639 self.get_mut()
1640 .as_mut_ptr()
1641 .add(initialized)
1642 .write_bytes(0u8, uninitialized)
1643 };
1644 }
1645
1646 let start = self.position() as usize;
1647 assert!(start + n <= self.get_ref().capacity());
1648 self.get_mut().filled_until(start + n);
1649 }
1650}
1651
1652#[cfg(feature = "std")]
1653#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "std")))]
1654unsafe impl<'a> WriteBuf for &'a mut std::vec::Vec<u8> {
1655 fn as_slice(&self) -> &[u8] {
1656 std::vec::Vec::as_slice(self)
1657 }
1658
1659 fn capacity(&self) -> usize {
1660 std::vec::Vec::capacity(self)
1661 }
1662
1663 fn as_mut_ptr(&mut self) -> *mut u8 {
1664 std::vec::Vec::as_mut_ptr(self)
1665 }
1666
1667 unsafe fn filled_until(&mut self, n: usize) {
1668 std::vec::Vec::set_len(self, n)
1669 }
1670}
1671
1672#[cfg(feature = "std")]
1673#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "std")))]
1674unsafe impl WriteBuf for std::vec::Vec<u8> {
1675 fn as_slice(&self) -> &[u8] {
1676 &self[..]
1677 }
1678 fn capacity(&self) -> usize {
1679 self.capacity()
1680 }
1681 fn as_mut_ptr(&mut self) -> *mut u8 {
1682 self.as_mut_ptr()
1683 }
1684 unsafe fn filled_until(&mut self, n: usize) {
1685 self.set_len(n);
1686 }
1687}
1688
1689#[cfg(feature = "arrays")]
1690#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "arrays")))]
1691unsafe impl<const N: usize> WriteBuf for [u8; N] {
1692 fn as_slice(&self) -> &[u8] {
1693 self
1694 }
1695 fn capacity(&self) -> usize {
1696 self.len()
1697 }
1698
1699 fn as_mut_ptr(&mut self) -> *mut u8 {
1700 (&mut self[..]).as_mut_ptr()
1701 }
1702
1703 unsafe fn filled_until(&mut self, _n: usize) {
1704 }
1706}
1707
1708unsafe impl WriteBuf for [u8] {
1709 fn as_slice(&self) -> &[u8] {
1710 self
1711 }
1712 fn capacity(&self) -> usize {
1713 self.len()
1714 }
1715
1716 fn as_mut_ptr(&mut self) -> *mut u8 {
1717 self.as_mut_ptr()
1718 }
1719
1720 unsafe fn filled_until(&mut self, _n: usize) {
1721 }
1723}
1724
1725#[derive(Debug)]
1744pub struct OutBuffer<'a, C: WriteBuf + ?Sized> {
1756 dst: &'a mut C,
1757 pos: usize,
1758}
1759
1760fn ptr_mut<B>(ptr_void: &mut B) -> *mut B {
1762 ptr_void as *mut B
1763}
1764
1765struct OutBufferWrapper<'a, 'b, C: WriteBuf + ?Sized> {
1769 buf: zstd_sys::ZSTD_outBuffer,
1770 parent: &'a mut OutBuffer<'b, C>,
1771}
1772
1773impl<'a, 'b: 'a, C: WriteBuf + ?Sized> Deref for OutBufferWrapper<'a, 'b, C> {
1774 type Target = zstd_sys::ZSTD_outBuffer;
1775
1776 fn deref(&self) -> &Self::Target {
1777 &self.buf
1778 }
1779}
1780
1781impl<'a, 'b: 'a, C: WriteBuf + ?Sized> DerefMut
1782 for OutBufferWrapper<'a, 'b, C>
1783{
1784 fn deref_mut(&mut self) -> &mut Self::Target {
1785 &mut self.buf
1786 }
1787}
1788
1789impl<'a, C: WriteBuf + ?Sized> OutBuffer<'a, C> {
1790 pub fn around(dst: &'a mut C) -> Self {
1794 OutBuffer { dst, pos: 0 }
1795 }
1796
1797 pub fn around_pos(dst: &'a mut C, pos: usize) -> Self {
1803 if pos > dst.capacity() {
1804 panic!("Given position outside of the buffer bounds.");
1805 }
1806
1807 OutBuffer { dst, pos }
1808 }
1809
1810 pub fn pos(&self) -> usize {
1814 assert!(self.pos <= self.dst.capacity());
1815 self.pos
1816 }
1817
1818 pub fn capacity(&self) -> usize {
1820 self.dst.capacity()
1821 }
1822
1823 pub unsafe fn set_pos(&mut self, pos: usize) {
1833 if pos > self.dst.capacity() {
1834 panic!("Given position outside of the buffer bounds.");
1835 }
1836
1837 self.dst.filled_until(pos);
1838
1839 self.pos = pos;
1840 }
1841
1842 fn wrap<'b>(&'b mut self) -> OutBufferWrapper<'b, 'a, C> {
1843 OutBufferWrapper {
1844 buf: zstd_sys::ZSTD_outBuffer {
1845 dst: ptr_mut_void(self.dst),
1846 size: self.dst.capacity(),
1847 pos: self.pos,
1848 },
1849 parent: self,
1850 }
1851 }
1852
1853 pub fn as_slice<'b>(&'b self) -> &'a [u8]
1855 where
1856 'b: 'a,
1857 {
1858 let pos = self.pos;
1859 &self.dst.as_slice()[..pos]
1860 }
1861
1862 pub fn as_mut_ptr(&mut self) -> *mut u8 {
1864 self.dst.as_mut_ptr()
1865 }
1866}
1867
1868impl<'a, 'b, C: WriteBuf + ?Sized> Drop for OutBufferWrapper<'a, 'b, C> {
1869 fn drop(&mut self) {
1870 unsafe { self.parent.set_pos(self.buf.pos) };
1872 }
1873}
1874
1875struct InBufferWrapper<'a, 'b> {
1876 buf: zstd_sys::ZSTD_inBuffer,
1877 parent: &'a mut InBuffer<'b>,
1878}
1879
1880impl<'a, 'b: 'a> Deref for InBufferWrapper<'a, 'b> {
1881 type Target = zstd_sys::ZSTD_inBuffer;
1882
1883 fn deref(&self) -> &Self::Target {
1884 &self.buf
1885 }
1886}
1887
1888impl<'a, 'b: 'a> DerefMut for InBufferWrapper<'a, 'b> {
1889 fn deref_mut(&mut self) -> &mut Self::Target {
1890 &mut self.buf
1891 }
1892}
1893
1894impl<'a> InBuffer<'a> {
1895 pub fn around(src: &'a [u8]) -> Self {
1899 InBuffer { src, pos: 0 }
1900 }
1901
1902 pub fn pos(&self) -> usize {
1904 self.pos
1905 }
1906
1907 pub fn set_pos(&mut self, pos: usize) {
1913 if pos > self.src.len() {
1914 panic!("Given position outside of the buffer bounds.");
1915 }
1916 self.pos = pos;
1917 }
1918
1919 fn wrap<'b>(&'b mut self) -> InBufferWrapper<'b, 'a> {
1920 InBufferWrapper {
1921 buf: zstd_sys::ZSTD_inBuffer {
1922 src: ptr_void(self.src),
1923 size: self.src.len(),
1924 pos: self.pos,
1925 },
1926 parent: self,
1927 }
1928 }
1929}
1930
1931impl<'a, 'b> Drop for InBufferWrapper<'a, 'b> {
1932 fn drop(&mut self) {
1933 self.parent.set_pos(self.buf.pos);
1934 }
1935}
1936
1937pub type DStream<'a> = DCtx<'a>;
1941
1942pub fn find_frame_compressed_size(src: &[u8]) -> SafeResult {
1952 let code = unsafe {
1953 zstd_sys::ZSTD_findFrameCompressedSize(ptr_void(src), src.len())
1954 };
1955 parse_code(code)
1956}
1957
1958pub fn get_frame_content_size(
1968 src: &[u8],
1969) -> Result<Option<u64>, ContentSizeError> {
1970 parse_content_size(unsafe {
1971 zstd_sys::ZSTD_getFrameContentSize(ptr_void(src), src.len())
1972 })
1973}
1974
1975#[cfg(feature = "experimental")]
1979#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1980pub fn find_decompressed_size(
1981 src: &[u8],
1982) -> Result<Option<u64>, ContentSizeError> {
1983 parse_content_size(unsafe {
1984 zstd_sys::ZSTD_findDecompressedSize(ptr_void(src), src.len())
1985 })
1986}
1987
1988#[cfg(feature = "experimental")]
1990#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1991pub fn is_frame(buffer: &[u8]) -> bool {
1992 unsafe { zstd_sys::ZSTD_isFrame(ptr_void(buffer), buffer.len()) > 0 }
1993}
1994
1995pub fn get_dict_id_from_dict(dict: &[u8]) -> Option<NonZeroU32> {
1999 NonZeroU32::new(unsafe {
2000 zstd_sys::ZSTD_getDictID_fromDict(ptr_void(dict), dict.len()) as u32
2001 })
2002}
2003
2004pub fn get_dict_id_from_frame(src: &[u8]) -> Option<NonZeroU32> {
2013 NonZeroU32::new(unsafe {
2014 zstd_sys::ZSTD_getDictID_fromFrame(ptr_void(src), src.len()) as u32
2015 })
2016}
2017
2018pub enum ResetDirective {
2020 SessionOnly,
2028
2029 Parameters,
2035
2036 SessionAndParameters,
2040}
2041
2042impl ResetDirective {
2043 fn as_sys(self) -> zstd_sys::ZSTD_ResetDirective {
2044 match self {
2045 ResetDirective::SessionOnly => zstd_sys::ZSTD_ResetDirective::ZSTD_reset_session_only,
2046 ResetDirective::Parameters => zstd_sys::ZSTD_ResetDirective::ZSTD_reset_parameters,
2047 ResetDirective::SessionAndParameters => zstd_sys::ZSTD_ResetDirective::ZSTD_reset_session_and_parameters,
2048 }
2049 }
2050}
2051
2052#[cfg(feature = "experimental")]
2053#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2054#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2055#[repr(u32)]
2056pub enum FrameFormat {
2057 One = zstd_sys::ZSTD_format_e::ZSTD_f_zstd1 as u32,
2059
2060 Magicless = zstd_sys::ZSTD_format_e::ZSTD_f_zstd1_magicless as u32,
2062}
2063
2064#[cfg(feature = "experimental")]
2065#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2066#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2067#[repr(u32)]
2068pub enum DictAttachPref {
2069 DefaultAttach =
2070 zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictDefaultAttach as u32,
2071 ForceAttach = zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictForceAttach as u32,
2072 ForceCopy = zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictForceCopy as u32,
2073 ForceLoad = zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictForceLoad as u32,
2074}
2075
2076#[cfg(feature = "experimental")]
2077#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2078#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2079#[repr(u32)]
2080pub enum ParamSwitch {
2081 Auto = zstd_sys::ZSTD_paramSwitch_e::ZSTD_ps_auto as u32,
2082 Enable = zstd_sys::ZSTD_paramSwitch_e::ZSTD_ps_enable as u32,
2083 Disable = zstd_sys::ZSTD_paramSwitch_e::ZSTD_ps_disable as u32,
2084}
2085
2086#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2088#[non_exhaustive]
2089pub enum CParameter {
2090 #[cfg(feature = "experimental")]
2091 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2092 RSyncable(bool),
2093
2094 #[cfg(feature = "experimental")]
2095 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2096 Format(FrameFormat),
2097
2098 #[cfg(feature = "experimental")]
2099 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2100 ForceMaxWindow(bool),
2101
2102 #[cfg(feature = "experimental")]
2103 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2104 ForceAttachDict(DictAttachPref),
2105
2106 #[cfg(feature = "experimental")]
2107 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2108 LiteralCompressionMode(ParamSwitch),
2109
2110 #[cfg(feature = "experimental")]
2111 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2112 SrcSizeHint(u32),
2113
2114 #[cfg(feature = "experimental")]
2115 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2116 EnableDedicatedDictSearch(bool),
2117
2118 #[cfg(feature = "experimental")]
2119 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2120 StableInBuffer(bool),
2121
2122 #[cfg(feature = "experimental")]
2123 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2124 StableOutBuffer(bool),
2125
2126 #[cfg(feature = "experimental")]
2127 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2128 BlockDelimiters(bool),
2129
2130 #[cfg(feature = "experimental")]
2131 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2132 ValidateSequences(bool),
2133
2134 #[cfg(feature = "experimental")]
2135 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2136 UseBlockSplitter(ParamSwitch),
2137
2138 #[cfg(feature = "experimental")]
2139 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2140 UseRowMatchFinder(ParamSwitch),
2141
2142 #[cfg(feature = "experimental")]
2143 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2144 DeterministicRefPrefix(bool),
2145
2146 #[cfg(feature = "experimental")]
2147 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2148 PrefetchCDictTables(ParamSwitch),
2149
2150 #[cfg(feature = "experimental")]
2151 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2152 EnableSeqProducerFallback(bool),
2153
2154 #[cfg(feature = "experimental")]
2155 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2156 MaxBlockSize(u32),
2157
2158 #[cfg(feature = "experimental")]
2159 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2160 SearchForExternalRepcodes(ParamSwitch),
2161
2162 TargetCBlockSize(u32),
2169
2170 CompressionLevel(CompressionLevel),
2174
2175 WindowLog(u32),
2179
2180 HashLog(u32),
2181
2182 ChainLog(u32),
2183
2184 SearchLog(u32),
2185
2186 MinMatch(u32),
2187
2188 TargetLength(u32),
2189
2190 Strategy(Strategy),
2191
2192 EnableLongDistanceMatching(bool),
2193
2194 LdmHashLog(u32),
2195
2196 LdmMinMatch(u32),
2197
2198 LdmBucketSizeLog(u32),
2199
2200 LdmHashRateLog(u32),
2201
2202 ContentSizeFlag(bool),
2203
2204 ChecksumFlag(bool),
2205
2206 DictIdFlag(bool),
2207
2208 NbWorkers(u32),
2217
2218 JobSize(u32),
2226
2227 OverlapSizeLog(u32),
2239}
2240
2241#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2243#[non_exhaustive]
2244pub enum DParameter {
2245 WindowLogMax(u32),
2246
2247 #[cfg(feature = "experimental")]
2248 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2249 Format(FrameFormat),
2251
2252 #[cfg(feature = "experimental")]
2253 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2254 StableOutBuffer(bool),
2255
2256 #[cfg(feature = "experimental")]
2257 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2258 ForceIgnoreChecksum(bool),
2259
2260 #[cfg(feature = "experimental")]
2261 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2262 RefMultipleDDicts(bool),
2263}
2264
2265#[cfg(feature = "zdict_builder")]
2267#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "zdict_builder")))]
2268pub fn train_from_buffer<C: WriteBuf + ?Sized>(
2269 dict_buffer: &mut C,
2270 samples_buffer: &[u8],
2271 samples_sizes: &[usize],
2272) -> SafeResult {
2273 assert_eq!(samples_buffer.len(), samples_sizes.iter().sum());
2274
2275 unsafe {
2276 dict_buffer.write_from(|buffer, capacity| {
2277 parse_code(zstd_sys::ZDICT_trainFromBuffer(
2278 buffer,
2279 capacity,
2280 ptr_void(samples_buffer),
2281 samples_sizes.as_ptr(),
2282 samples_sizes.len() as u32,
2283 ))
2284 })
2285 }
2286}
2287
2288#[cfg(feature = "zdict_builder")]
2290#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "zdict_builder")))]
2291pub fn get_dict_id(dict_buffer: &[u8]) -> Option<NonZeroU32> {
2292 NonZeroU32::new(unsafe {
2293 zstd_sys::ZDICT_getDictID(ptr_void(dict_buffer), dict_buffer.len())
2294 })
2295}
2296
2297#[cfg(feature = "experimental")]
2299#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2300pub fn get_block_size(cctx: &CCtx) -> usize {
2301 unsafe { zstd_sys::ZSTD_getBlockSize(cctx.0.as_ptr()) }
2302}
2303
2304#[cfg(feature = "experimental")]
2306#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2307pub fn decompress_bound(data: &[u8]) -> Result<u64, ErrorCode> {
2308 let bound =
2309 unsafe { zstd_sys::ZSTD_decompressBound(ptr_void(data), data.len()) };
2310 if is_error(bound as usize) {
2311 Err(bound as usize)
2312 } else {
2313 Ok(bound)
2314 }
2315}
2316
2317#[cfg(feature = "experimental")]
2320#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2321pub fn sequence_bound(src_size: usize) -> usize {
2322 unsafe { zstd_sys::ZSTD_sequenceBound(src_size) }
2324}
2325
2326#[cfg(feature = "experimental")]
2332#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2333pub fn decompression_margin(
2334 compressed_data: &[u8],
2335) -> Result<usize, ErrorCode> {
2336 parse_code(unsafe {
2337 zstd_sys::ZSTD_decompressionMargin(
2338 ptr_void(compressed_data),
2339 compressed_data.len(),
2340 )
2341 })
2342}