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
223pub struct CCtx<'a>(NonNull<zstd_sys::ZSTD_CCtx>, PhantomData<&'a ()>);
228
229impl Default for CCtx<'_> {
230 fn default() -> Self {
231 CCtx::create()
232 }
233}
234
235impl<'a> CCtx<'a> {
236 pub fn try_create() -> Option<Self> {
240 Some(CCtx(
242 NonNull::new(unsafe { zstd_sys::ZSTD_createCCtx() })?,
243 PhantomData,
244 ))
245 }
246
247 pub fn create() -> Self {
253 Self::try_create()
254 .expect("zstd returned null pointer when creating new context")
255 }
256
257 pub fn compress<C: WriteBuf + ?Sized>(
259 &mut self,
260 dst: &mut C,
261 src: &[u8],
262 compression_level: CompressionLevel,
263 ) -> SafeResult {
264 unsafe {
266 dst.write_from(|buffer, capacity| {
267 parse_code(zstd_sys::ZSTD_compressCCtx(
268 self.0.as_ptr(),
269 buffer,
270 capacity,
271 ptr_void(src),
272 src.len(),
273 compression_level,
274 ))
275 })
276 }
277 }
278
279 pub fn compress2<C: WriteBuf + ?Sized>(
281 &mut self,
282 dst: &mut C,
283 src: &[u8],
284 ) -> SafeResult {
285 unsafe {
287 dst.write_from(|buffer, capacity| {
288 parse_code(zstd_sys::ZSTD_compress2(
289 self.0.as_ptr(),
290 buffer,
291 capacity,
292 ptr_void(src),
293 src.len(),
294 ))
295 })
296 }
297 }
298
299 pub fn compress_using_dict<C: WriteBuf + ?Sized>(
301 &mut self,
302 dst: &mut C,
303 src: &[u8],
304 dict: &[u8],
305 compression_level: CompressionLevel,
306 ) -> SafeResult {
307 unsafe {
309 dst.write_from(|buffer, capacity| {
310 parse_code(zstd_sys::ZSTD_compress_usingDict(
311 self.0.as_ptr(),
312 buffer,
313 capacity,
314 ptr_void(src),
315 src.len(),
316 ptr_void(dict),
317 dict.len(),
318 compression_level,
319 ))
320 })
321 }
322 }
323
324 pub fn compress_using_cdict<C: WriteBuf + ?Sized>(
326 &mut self,
327 dst: &mut C,
328 src: &[u8],
329 cdict: &CDict<'_>,
330 ) -> SafeResult {
331 unsafe {
333 dst.write_from(|buffer, capacity| {
334 parse_code(zstd_sys::ZSTD_compress_usingCDict(
335 self.0.as_ptr(),
336 buffer,
337 capacity,
338 ptr_void(src),
339 src.len(),
340 cdict.0.as_ptr(),
341 ))
342 })
343 }
344 }
345
346 pub fn init(&mut self, compression_level: CompressionLevel) -> SafeResult {
352 let code = unsafe {
354 zstd_sys::ZSTD_initCStream(self.0.as_ptr(), compression_level)
355 };
356 parse_code(code)
357 }
358
359 #[cfg(feature = "experimental")]
361 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
362 #[deprecated]
363 pub fn init_src_size(
364 &mut self,
365 compression_level: CompressionLevel,
366 pledged_src_size: u64,
367 ) -> SafeResult {
368 let code = unsafe {
370 zstd_sys::ZSTD_initCStream_srcSize(
371 self.0.as_ptr(),
372 compression_level as c_int,
373 pledged_src_size as c_ulonglong,
374 )
375 };
376 parse_code(code)
377 }
378
379 #[cfg(feature = "experimental")]
381 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
382 #[deprecated]
383 pub fn init_using_dict(
384 &mut self,
385 dict: &[u8],
386 compression_level: CompressionLevel,
387 ) -> SafeResult {
388 let code = unsafe {
390 zstd_sys::ZSTD_initCStream_usingDict(
391 self.0.as_ptr(),
392 ptr_void(dict),
393 dict.len(),
394 compression_level,
395 )
396 };
397 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_using_cdict<'b>(&mut self, cdict: &CDict<'b>) -> SafeResult
405 where
406 'b: 'a, {
408 let code = unsafe {
410 zstd_sys::ZSTD_initCStream_usingCDict(
411 self.0.as_ptr(),
412 cdict.0.as_ptr(),
413 )
414 };
415 parse_code(code)
416 }
417
418 pub fn load_dictionary(&mut self, dict: &[u8]) -> SafeResult {
428 parse_code(unsafe {
430 zstd_sys::ZSTD_CCtx_loadDictionary(
431 self.0.as_ptr(),
432 ptr_void(dict),
433 dict.len(),
434 )
435 })
436 }
437
438 pub fn ref_cdict<'b>(&mut self, cdict: &CDict<'b>) -> SafeResult
442 where
443 'b: 'a,
444 {
445 parse_code(unsafe {
447 zstd_sys::ZSTD_CCtx_refCDict(self.0.as_ptr(), cdict.0.as_ptr())
448 })
449 }
450
451 pub fn disable_dictionary(&mut self) -> SafeResult {
455 parse_code(unsafe {
457 zstd_sys::ZSTD_CCtx_loadDictionary(
458 self.0.as_ptr(),
459 core::ptr::null(),
460 0,
461 )
462 })
463 }
464
465 pub fn ref_prefix<'b>(&mut self, prefix: &'b [u8]) -> SafeResult
471 where
472 'b: 'a,
473 {
474 parse_code(unsafe {
476 zstd_sys::ZSTD_CCtx_refPrefix(
477 self.0.as_ptr(),
478 ptr_void(prefix),
479 prefix.len(),
480 )
481 })
482 }
483
484 pub fn compress_stream<C: WriteBuf + ?Sized>(
496 &mut self,
497 output: &mut OutBuffer<'_, C>,
498 input: &mut InBuffer<'_>,
499 ) -> SafeResult {
500 let mut output = output.wrap();
501 let mut input = input.wrap();
502 let code = unsafe {
504 zstd_sys::ZSTD_compressStream(
505 self.0.as_ptr(),
506 ptr_mut(&mut output),
507 ptr_mut(&mut input),
508 )
509 };
510 parse_code(code)
511 }
512
513 pub fn compress_stream2<C: WriteBuf + ?Sized>(
529 &mut self,
530 output: &mut OutBuffer<'_, C>,
531 input: &mut InBuffer<'_>,
532 end_op: zstd_sys::ZSTD_EndDirective,
533 ) -> SafeResult {
534 let mut output = output.wrap();
535 let mut input = input.wrap();
536 parse_code(unsafe {
538 zstd_sys::ZSTD_compressStream2(
539 self.0.as_ptr(),
540 ptr_mut(&mut output),
541 ptr_mut(&mut input),
542 end_op,
543 )
544 })
545 }
546
547 pub fn flush_stream<C: WriteBuf + ?Sized>(
553 &mut self,
554 output: &mut OutBuffer<'_, C>,
555 ) -> SafeResult {
556 let mut output = output.wrap();
557 let code = unsafe {
559 zstd_sys::ZSTD_flushStream(self.0.as_ptr(), ptr_mut(&mut output))
560 };
561 parse_code(code)
562 }
563
564 pub fn end_stream<C: WriteBuf + ?Sized>(
570 &mut self,
571 output: &mut OutBuffer<'_, C>,
572 ) -> SafeResult {
573 let mut output = output.wrap();
574 let code = unsafe {
576 zstd_sys::ZSTD_endStream(self.0.as_ptr(), ptr_mut(&mut output))
577 };
578 parse_code(code)
579 }
580
581 pub fn sizeof(&self) -> usize {
585 unsafe { zstd_sys::ZSTD_sizeof_CCtx(self.0.as_ptr()) }
587 }
588
589 pub fn reset(&mut self, reset: ResetDirective) -> SafeResult {
595 parse_code(unsafe {
597 zstd_sys::ZSTD_CCtx_reset(self.0.as_ptr(), reset.as_sys())
598 })
599 }
600
601 pub fn set_parameter(&mut self, param: CParameter) -> SafeResult {
605 #[cfg(feature = "experimental")]
608 use zstd_sys::ZSTD_cParameter::{
609 ZSTD_c_experimentalParam1 as ZSTD_c_rsyncable,
610 ZSTD_c_experimentalParam10 as ZSTD_c_stableOutBuffer,
611 ZSTD_c_experimentalParam11 as ZSTD_c_blockDelimiters,
612 ZSTD_c_experimentalParam12 as ZSTD_c_validateSequences,
613 ZSTD_c_experimentalParam13 as ZSTD_c_useBlockSplitter,
614 ZSTD_c_experimentalParam14 as ZSTD_c_useRowMatchFinder,
615 ZSTD_c_experimentalParam15 as ZSTD_c_deterministicRefPrefix,
616 ZSTD_c_experimentalParam16 as ZSTD_c_prefetchCDictTables,
617 ZSTD_c_experimentalParam17 as ZSTD_c_enableSeqProducerFallback,
618 ZSTD_c_experimentalParam18 as ZSTD_c_maxBlockSize,
619 ZSTD_c_experimentalParam19 as ZSTD_c_searchForExternalRepcodes,
620 ZSTD_c_experimentalParam2 as ZSTD_c_format,
621 ZSTD_c_experimentalParam3 as ZSTD_c_forceMaxWindow,
622 ZSTD_c_experimentalParam4 as ZSTD_c_forceAttachDict,
623 ZSTD_c_experimentalParam5 as ZSTD_c_literalCompressionMode,
624 ZSTD_c_experimentalParam7 as ZSTD_c_srcSizeHint,
625 ZSTD_c_experimentalParam8 as ZSTD_c_enableDedicatedDictSearch,
626 ZSTD_c_experimentalParam9 as ZSTD_c_stableInBuffer,
627 };
628
629 use zstd_sys::ZSTD_cParameter::*;
630 use CParameter::*;
631
632 let (param, value) = match param {
633 #[cfg(feature = "experimental")]
634 RSyncable(rsyncable) => (ZSTD_c_rsyncable, rsyncable as c_int),
635 #[cfg(feature = "experimental")]
636 Format(format) => (ZSTD_c_format, format as c_int),
637 #[cfg(feature = "experimental")]
638 ForceMaxWindow(force) => (ZSTD_c_forceMaxWindow, force as c_int),
639 #[cfg(feature = "experimental")]
640 ForceAttachDict(force) => (ZSTD_c_forceAttachDict, force as c_int),
641 #[cfg(feature = "experimental")]
642 LiteralCompressionMode(mode) => {
643 (ZSTD_c_literalCompressionMode, mode as c_int)
644 }
645 #[cfg(feature = "experimental")]
646 SrcSizeHint(value) => (ZSTD_c_srcSizeHint, value as c_int),
647 #[cfg(feature = "experimental")]
648 EnableDedicatedDictSearch(enable) => {
649 (ZSTD_c_enableDedicatedDictSearch, enable as c_int)
650 }
651 #[cfg(feature = "experimental")]
652 StableInBuffer(stable) => (ZSTD_c_stableInBuffer, stable as c_int),
653 #[cfg(feature = "experimental")]
654 StableOutBuffer(stable) => {
655 (ZSTD_c_stableOutBuffer, stable as c_int)
656 }
657 #[cfg(feature = "experimental")]
658 BlockDelimiters(value) => (ZSTD_c_blockDelimiters, value as c_int),
659 #[cfg(feature = "experimental")]
660 ValidateSequences(validate) => {
661 (ZSTD_c_validateSequences, validate as c_int)
662 }
663 #[cfg(feature = "experimental")]
664 UseBlockSplitter(split) => {
665 (ZSTD_c_useBlockSplitter, split as c_int)
666 }
667 #[cfg(feature = "experimental")]
668 UseRowMatchFinder(mode) => {
669 (ZSTD_c_useRowMatchFinder, mode as c_int)
670 }
671 #[cfg(feature = "experimental")]
672 DeterministicRefPrefix(deterministic) => {
673 (ZSTD_c_deterministicRefPrefix, deterministic as c_int)
674 }
675 #[cfg(feature = "experimental")]
676 PrefetchCDictTables(prefetch) => {
677 (ZSTD_c_prefetchCDictTables, prefetch as c_int)
678 }
679 #[cfg(feature = "experimental")]
680 EnableSeqProducerFallback(enable) => {
681 (ZSTD_c_enableSeqProducerFallback, enable as c_int)
682 }
683 #[cfg(feature = "experimental")]
684 MaxBlockSize(value) => (ZSTD_c_maxBlockSize, value as c_int),
685 #[cfg(feature = "experimental")]
686 SearchForExternalRepcodes(value) => {
687 (ZSTD_c_searchForExternalRepcodes, value as c_int)
688 }
689 TargetCBlockSize(value) => {
690 (ZSTD_c_targetCBlockSize, value as c_int)
691 }
692 CompressionLevel(level) => (ZSTD_c_compressionLevel, level),
693 WindowLog(value) => (ZSTD_c_windowLog, value as c_int),
694 HashLog(value) => (ZSTD_c_hashLog, value as c_int),
695 ChainLog(value) => (ZSTD_c_chainLog, value as c_int),
696 SearchLog(value) => (ZSTD_c_searchLog, value as c_int),
697 MinMatch(value) => (ZSTD_c_minMatch, value as c_int),
698 TargetLength(value) => (ZSTD_c_targetLength, value as c_int),
699 Strategy(strategy) => (ZSTD_c_strategy, strategy as c_int),
700 EnableLongDistanceMatching(flag) => {
701 (ZSTD_c_enableLongDistanceMatching, flag as c_int)
702 }
703 LdmHashLog(value) => (ZSTD_c_ldmHashLog, value as c_int),
704 LdmMinMatch(value) => (ZSTD_c_ldmMinMatch, value as c_int),
705 LdmBucketSizeLog(value) => {
706 (ZSTD_c_ldmBucketSizeLog, value as c_int)
707 }
708 LdmHashRateLog(value) => (ZSTD_c_ldmHashRateLog, value as c_int),
709 ContentSizeFlag(flag) => (ZSTD_c_contentSizeFlag, flag as c_int),
710 ChecksumFlag(flag) => (ZSTD_c_checksumFlag, flag as c_int),
711 DictIdFlag(flag) => (ZSTD_c_dictIDFlag, flag as c_int),
712
713 NbWorkers(value) => (ZSTD_c_nbWorkers, value as c_int),
714
715 JobSize(value) => (ZSTD_c_jobSize, value as c_int),
716
717 OverlapSizeLog(value) => (ZSTD_c_overlapLog, value as c_int),
718 };
719
720 parse_code(unsafe {
722 zstd_sys::ZSTD_CCtx_setParameter(self.0.as_ptr(), param, value)
723 })
724 }
725
726 pub fn set_pledged_src_size(
735 &mut self,
736 pledged_src_size: Option<u64>,
737 ) -> SafeResult {
738 parse_code(unsafe {
740 zstd_sys::ZSTD_CCtx_setPledgedSrcSize(
741 self.0.as_ptr(),
742 pledged_src_size.unwrap_or(CONTENTSIZE_UNKNOWN) as c_ulonglong,
743 )
744 })
745 }
746
747 #[cfg(feature = "experimental")]
752 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
753 pub fn try_clone(
754 &self,
755 pledged_src_size: Option<u64>,
756 ) -> Result<Self, ErrorCode> {
757 let context = NonNull::new(unsafe { zstd_sys::ZSTD_createCCtx() })
759 .ok_or(0usize)?;
760
761 parse_code(unsafe {
763 zstd_sys::ZSTD_copyCCtx(
764 context.as_ptr(),
765 self.0.as_ptr(),
766 pledged_src_size.unwrap_or(CONTENTSIZE_UNKNOWN),
767 )
768 })?;
769
770 Ok(CCtx(context, self.1))
771 }
772
773 #[cfg(feature = "experimental")]
775 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
776 pub fn get_block_size(&self) -> usize {
777 unsafe { zstd_sys::ZSTD_getBlockSize(self.0.as_ptr()) }
779 }
780
781 #[cfg(feature = "experimental")]
789 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
790 pub unsafe fn compress_block<C: WriteBuf + ?Sized>(
791 &mut self,
792 dst: &mut C,
793 src: &[u8],
794 ) -> SafeResult {
795 unsafe {
797 dst.write_from(|buffer, capacity| {
798 parse_code(zstd_sys::ZSTD_compressBlock(
799 self.0.as_ptr(),
800 buffer,
801 capacity,
802 ptr_void(src),
803 src.len(),
804 ))
805 })
806 }
807 }
808
809 pub fn in_size() -> usize {
813 unsafe { zstd_sys::ZSTD_CStreamInSize() }
815 }
816
817 pub fn out_size() -> usize {
821 unsafe { zstd_sys::ZSTD_CStreamOutSize() }
823 }
824
825 #[cfg(all(feature = "experimental", feature = "zstdmt"))]
829 #[cfg_attr(
830 feature = "doc-cfg",
831 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
832 )]
833 pub fn ref_thread_pool<'b>(&mut self, pool: &'b ThreadPool) -> SafeResult
834 where
835 'b: 'a,
836 {
837 parse_code(unsafe {
838 zstd_sys::ZSTD_CCtx_refThreadPool(self.0.as_ptr(), pool.0.as_ptr())
839 })
840 }
841
842 #[cfg(all(feature = "experimental", feature = "zstdmt"))]
844 #[cfg_attr(
845 feature = "doc-cfg",
846 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
847 )]
848 pub fn disable_thread_pool(&mut self) -> SafeResult {
849 parse_code(unsafe {
850 zstd_sys::ZSTD_CCtx_refThreadPool(
851 self.0.as_ptr(),
852 core::ptr::null_mut(),
853 )
854 })
855 }
856
857 #[cfg(feature = "experimental")]
858 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
859 pub fn get_frame_progression(&self) -> FrameProgression {
860 unsafe { zstd_sys::ZSTD_getFrameProgression(self.0.as_ptr()) }
862 }
863}
864
865impl<'a> Drop for CCtx<'a> {
866 fn drop(&mut self) {
867 unsafe {
869 zstd_sys::ZSTD_freeCCtx(self.0.as_ptr());
870 }
871 }
872}
873
874unsafe impl Send for CCtx<'_> {}
875unsafe impl Sync for CCtx<'_> {}
877
878unsafe fn c_char_to_str(text: *const c_char) -> &'static str {
879 core::ffi::CStr::from_ptr(text)
880 .to_str()
881 .expect("bad error message from zstd")
882}
883
884pub fn get_error_name(code: usize) -> &'static str {
886 unsafe {
887 let name = zstd_sys::ZSTD_getErrorName(code);
889 c_char_to_str(name)
890 }
891}
892
893pub struct DCtx<'a>(NonNull<zstd_sys::ZSTD_DCtx>, PhantomData<&'a ()>);
901
902impl Default for DCtx<'_> {
903 fn default() -> Self {
904 DCtx::create()
905 }
906}
907
908impl<'a> DCtx<'a> {
909 pub fn try_create() -> Option<Self> {
913 Some(DCtx(
914 NonNull::new(unsafe { zstd_sys::ZSTD_createDCtx() })?,
915 PhantomData,
916 ))
917 }
918
919 pub fn create() -> Self {
925 Self::try_create()
926 .expect("zstd returned null pointer when creating new context")
927 }
928
929 pub fn decompress<C: WriteBuf + ?Sized>(
936 &mut self,
937 dst: &mut C,
938 src: &[u8],
939 ) -> SafeResult {
940 unsafe {
941 dst.write_from(|buffer, capacity| {
942 parse_code(zstd_sys::ZSTD_decompressDCtx(
943 self.0.as_ptr(),
944 buffer,
945 capacity,
946 ptr_void(src),
947 src.len(),
948 ))
949 })
950 }
951 }
952
953 pub fn decompress_using_dict<C: WriteBuf + ?Sized>(
962 &mut self,
963 dst: &mut C,
964 src: &[u8],
965 dict: &[u8],
966 ) -> SafeResult {
967 unsafe {
968 dst.write_from(|buffer, capacity| {
969 parse_code(zstd_sys::ZSTD_decompress_usingDict(
970 self.0.as_ptr(),
971 buffer,
972 capacity,
973 ptr_void(src),
974 src.len(),
975 ptr_void(dict),
976 dict.len(),
977 ))
978 })
979 }
980 }
981
982 pub fn decompress_using_ddict<C: WriteBuf + ?Sized>(
988 &mut self,
989 dst: &mut C,
990 src: &[u8],
991 ddict: &DDict<'_>,
992 ) -> SafeResult {
993 unsafe {
994 dst.write_from(|buffer, capacity| {
995 parse_code(zstd_sys::ZSTD_decompress_usingDDict(
996 self.0.as_ptr(),
997 buffer,
998 capacity,
999 ptr_void(src),
1000 src.len(),
1001 ddict.0.as_ptr(),
1002 ))
1003 })
1004 }
1005 }
1006
1007 pub fn init(&mut self) -> SafeResult {
1015 let code = unsafe { zstd_sys::ZSTD_initDStream(self.0.as_ptr()) };
1016 parse_code(code)
1017 }
1018
1019 #[cfg(feature = "experimental")]
1021 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1022 #[deprecated]
1023 pub fn init_using_dict(&mut self, dict: &[u8]) -> SafeResult {
1024 let code = unsafe {
1025 zstd_sys::ZSTD_initDStream_usingDict(
1026 self.0.as_ptr(),
1027 ptr_void(dict),
1028 dict.len(),
1029 )
1030 };
1031 parse_code(code)
1032 }
1033
1034 #[cfg(feature = "experimental")]
1036 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1037 #[deprecated]
1038 pub fn init_using_ddict<'b>(&mut self, ddict: &DDict<'b>) -> SafeResult
1039 where
1040 'b: 'a,
1041 {
1042 let code = unsafe {
1043 zstd_sys::ZSTD_initDStream_usingDDict(
1044 self.0.as_ptr(),
1045 ddict.0.as_ptr(),
1046 )
1047 };
1048 parse_code(code)
1049 }
1050
1051 pub fn reset(&mut self, reset: ResetDirective) -> SafeResult {
1057 parse_code(unsafe {
1058 zstd_sys::ZSTD_DCtx_reset(self.0.as_ptr(), reset.as_sys())
1059 })
1060 }
1061
1062 pub fn load_dictionary(&mut self, dict: &[u8]) -> SafeResult {
1074 parse_code(unsafe {
1075 zstd_sys::ZSTD_DCtx_loadDictionary(
1076 self.0.as_ptr(),
1077 ptr_void(dict),
1078 dict.len(),
1079 )
1080 })
1081 }
1082
1083 pub fn disable_dictionary(&mut self) -> SafeResult {
1087 parse_code(unsafe {
1088 zstd_sys::ZSTD_DCtx_loadDictionary(
1089 self.0.as_ptr(),
1090 core::ptr::null(),
1091 0,
1092 )
1093 })
1094 }
1095
1096 pub fn ref_ddict<'b>(&mut self, ddict: &DDict<'b>) -> SafeResult
1104 where
1105 'b: 'a,
1106 {
1107 parse_code(unsafe {
1108 zstd_sys::ZSTD_DCtx_refDDict(self.0.as_ptr(), ddict.0.as_ptr())
1109 })
1110 }
1111
1112 pub fn ref_prefix<'b>(&mut self, prefix: &'b [u8]) -> SafeResult
1120 where
1121 'b: 'a,
1122 {
1123 parse_code(unsafe {
1124 zstd_sys::ZSTD_DCtx_refPrefix(
1125 self.0.as_ptr(),
1126 ptr_void(prefix),
1127 prefix.len(),
1128 )
1129 })
1130 }
1131
1132 pub fn set_parameter(&mut self, param: DParameter) -> SafeResult {
1134 #[cfg(feature = "experimental")]
1135 use zstd_sys::ZSTD_dParameter::{
1136 ZSTD_d_experimentalParam1 as ZSTD_d_format,
1137 ZSTD_d_experimentalParam2 as ZSTD_d_stableOutBuffer,
1138 ZSTD_d_experimentalParam3 as ZSTD_d_forceIgnoreChecksum,
1139 ZSTD_d_experimentalParam4 as ZSTD_d_refMultipleDDicts,
1140 };
1141
1142 use zstd_sys::ZSTD_dParameter::*;
1143 use DParameter::*;
1144
1145 let (param, value) = match param {
1146 #[cfg(feature = "experimental")]
1147 Format(format) => (ZSTD_d_format, format as c_int),
1148 #[cfg(feature = "experimental")]
1149 StableOutBuffer(stable) => {
1150 (ZSTD_d_stableOutBuffer, stable as c_int)
1151 }
1152 #[cfg(feature = "experimental")]
1153 ForceIgnoreChecksum(force) => {
1154 (ZSTD_d_forceIgnoreChecksum, force as c_int)
1155 }
1156 #[cfg(feature = "experimental")]
1157 RefMultipleDDicts(value) => {
1158 (ZSTD_d_refMultipleDDicts, value as c_int)
1159 }
1160
1161 WindowLogMax(value) => (ZSTD_d_windowLogMax, value as c_int),
1162 };
1163
1164 parse_code(unsafe {
1165 zstd_sys::ZSTD_DCtx_setParameter(self.0.as_ptr(), param, value)
1166 })
1167 }
1168
1169 pub fn decompress_stream<C: WriteBuf + ?Sized>(
1181 &mut self,
1182 output: &mut OutBuffer<'_, C>,
1183 input: &mut InBuffer<'_>,
1184 ) -> SafeResult {
1185 let mut output = output.wrap();
1186 let mut input = input.wrap();
1187 let code = unsafe {
1188 zstd_sys::ZSTD_decompressStream(
1189 self.0.as_ptr(),
1190 ptr_mut(&mut output),
1191 ptr_mut(&mut input),
1192 )
1193 };
1194 parse_code(code)
1195 }
1196
1197 pub fn in_size() -> usize {
1201 unsafe { zstd_sys::ZSTD_DStreamInSize() }
1202 }
1203
1204 pub fn out_size() -> usize {
1208 unsafe { zstd_sys::ZSTD_DStreamOutSize() }
1209 }
1210
1211 pub fn sizeof(&self) -> usize {
1213 unsafe { zstd_sys::ZSTD_sizeof_DCtx(self.0.as_ptr()) }
1214 }
1215
1216 #[cfg(feature = "experimental")]
1224 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1225 pub unsafe fn decompress_block<C: WriteBuf + ?Sized>(
1226 &mut self,
1227 dst: &mut C,
1228 src: &[u8],
1229 ) -> SafeResult {
1230 unsafe {
1231 dst.write_from(|buffer, capacity| {
1232 parse_code(zstd_sys::ZSTD_decompressBlock(
1233 self.0.as_ptr(),
1234 buffer,
1235 capacity,
1236 ptr_void(src),
1237 src.len(),
1238 ))
1239 })
1240 }
1241 }
1242
1243 #[cfg(feature = "experimental")]
1251 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1252 pub unsafe fn insert_block(&mut self, block: &[u8]) -> usize {
1253 unsafe {
1254 zstd_sys::ZSTD_insertBlock(
1255 self.0.as_ptr(),
1256 ptr_void(block),
1257 block.len(),
1258 )
1259 }
1260 }
1261
1262 #[cfg(feature = "experimental")]
1267 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1268 pub fn try_clone(&self) -> Result<Self, ErrorCode> {
1269 let context = NonNull::new(unsafe { zstd_sys::ZSTD_createDCtx() })
1270 .ok_or(0usize)?;
1271
1272 unsafe { zstd_sys::ZSTD_copyDCtx(context.as_ptr(), self.0.as_ptr()) };
1273
1274 Ok(DCtx(context, self.1))
1275 }
1276}
1277
1278impl Drop for DCtx<'_> {
1279 fn drop(&mut self) {
1280 unsafe {
1281 zstd_sys::ZSTD_freeDCtx(self.0.as_ptr());
1282 }
1283 }
1284}
1285
1286unsafe impl Send for DCtx<'_> {}
1287unsafe impl Sync for DCtx<'_> {}
1289
1290pub struct CDict<'a>(NonNull<zstd_sys::ZSTD_CDict>, PhantomData<&'a ()>);
1292
1293impl CDict<'static> {
1294 pub fn create(
1304 dict_buffer: &[u8],
1305 compression_level: CompressionLevel,
1306 ) -> Self {
1307 Self::try_create(dict_buffer, compression_level)
1308 .expect("zstd returned null pointer when creating dict")
1309 }
1310
1311 pub fn try_create(
1317 dict_buffer: &[u8],
1318 compression_level: CompressionLevel,
1319 ) -> Option<Self> {
1320 Some(CDict(
1321 NonNull::new(unsafe {
1322 zstd_sys::ZSTD_createCDict(
1323 ptr_void(dict_buffer),
1324 dict_buffer.len(),
1325 compression_level,
1326 )
1327 })?,
1328 PhantomData,
1329 ))
1330 }
1331}
1332
1333impl<'a> CDict<'a> {
1334 #[cfg(feature = "experimental")]
1335 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1336 pub fn create_by_reference(
1337 dict_buffer: &'a [u8],
1338 compression_level: CompressionLevel,
1339 ) -> Self {
1340 CDict(
1341 NonNull::new(unsafe {
1342 zstd_sys::ZSTD_createCDict_byReference(
1343 ptr_void(dict_buffer),
1344 dict_buffer.len(),
1345 compression_level,
1346 )
1347 })
1348 .expect("zstd returned null pointer"),
1349 PhantomData,
1350 )
1351 }
1352
1353 pub fn sizeof(&self) -> usize {
1357 unsafe { zstd_sys::ZSTD_sizeof_CDict(self.0.as_ptr()) }
1358 }
1359
1360 pub fn get_dict_id(&self) -> Option<NonZeroU32> {
1364 NonZeroU32::new(unsafe {
1365 zstd_sys::ZSTD_getDictID_fromCDict(self.0.as_ptr()) as u32
1366 })
1367 }
1368}
1369
1370pub fn create_cdict(
1372 dict_buffer: &[u8],
1373 compression_level: CompressionLevel,
1374) -> CDict<'static> {
1375 CDict::create(dict_buffer, compression_level)
1376}
1377
1378impl<'a> Drop for CDict<'a> {
1379 fn drop(&mut self) {
1380 unsafe {
1381 zstd_sys::ZSTD_freeCDict(self.0.as_ptr());
1382 }
1383 }
1384}
1385
1386unsafe impl<'a> Send for CDict<'a> {}
1387unsafe impl<'a> Sync for CDict<'a> {}
1388
1389pub fn compress_using_cdict(
1391 cctx: &mut CCtx<'_>,
1392 dst: &mut [u8],
1393 src: &[u8],
1394 cdict: &CDict<'_>,
1395) -> SafeResult {
1396 cctx.compress_using_cdict(dst, src, cdict)
1397}
1398
1399pub struct DDict<'a>(NonNull<zstd_sys::ZSTD_DDict>, PhantomData<&'a ()>);
1401
1402impl DDict<'static> {
1403 pub fn create(dict_buffer: &[u8]) -> Self {
1404 Self::try_create(dict_buffer)
1405 .expect("zstd returned null pointer when creating dict")
1406 }
1407
1408 pub fn try_create(dict_buffer: &[u8]) -> Option<Self> {
1409 Some(DDict(
1410 NonNull::new(unsafe {
1411 zstd_sys::ZSTD_createDDict(
1412 ptr_void(dict_buffer),
1413 dict_buffer.len(),
1414 )
1415 })?,
1416 PhantomData,
1417 ))
1418 }
1419}
1420
1421impl<'a> DDict<'a> {
1422 pub fn sizeof(&self) -> usize {
1423 unsafe { zstd_sys::ZSTD_sizeof_DDict(self.0.as_ptr()) }
1424 }
1425
1426 #[cfg(feature = "experimental")]
1430 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
1431 pub fn create_by_reference(dict_buffer: &'a [u8]) -> Self {
1432 DDict(
1433 NonNull::new(unsafe {
1434 zstd_sys::ZSTD_createDDict_byReference(
1435 ptr_void(dict_buffer),
1436 dict_buffer.len(),
1437 )
1438 })
1439 .expect("zstd returned null pointer"),
1440 PhantomData,
1441 )
1442 }
1443
1444 pub fn get_dict_id(&self) -> Option<NonZeroU32> {
1448 NonZeroU32::new(unsafe {
1449 zstd_sys::ZSTD_getDictID_fromDDict(self.0.as_ptr()) as u32
1450 })
1451 }
1452}
1453
1454pub fn create_ddict(dict_buffer: &[u8]) -> DDict<'static> {
1458 DDict::create(dict_buffer)
1459}
1460
1461impl<'a> Drop for DDict<'a> {
1462 fn drop(&mut self) {
1463 unsafe {
1464 zstd_sys::ZSTD_freeDDict(self.0.as_ptr());
1465 }
1466 }
1467}
1468
1469unsafe impl<'a> Send for DDict<'a> {}
1470unsafe impl<'a> Sync for DDict<'a> {}
1471
1472#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1474#[cfg_attr(
1475 feature = "doc-cfg",
1476 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1477)]
1478pub struct ThreadPool(NonNull<zstd_sys::ZSTD_threadPool>);
1479
1480#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1481#[cfg_attr(
1482 feature = "doc-cfg",
1483 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1484)]
1485impl ThreadPool {
1486 pub fn new(num_threads: usize) -> Self {
1492 Self::try_new(num_threads)
1493 .expect("zstd returned null pointer when creating thread pool")
1494 }
1495
1496 pub fn try_new(num_threads: usize) -> Option<Self> {
1498 Some(Self(NonNull::new(unsafe {
1499 zstd_sys::ZSTD_createThreadPool(num_threads)
1500 })?))
1501 }
1502}
1503
1504#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1505#[cfg_attr(
1506 feature = "doc-cfg",
1507 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1508)]
1509impl Drop for ThreadPool {
1510 fn drop(&mut self) {
1511 unsafe {
1512 zstd_sys::ZSTD_freeThreadPool(self.0.as_ptr());
1513 }
1514 }
1515}
1516
1517#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1518#[cfg_attr(
1519 feature = "doc-cfg",
1520 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1521)]
1522unsafe impl Send for ThreadPool {}
1523#[cfg(all(feature = "experimental", feature = "zstdmt"))]
1524#[cfg_attr(
1525 feature = "doc-cfg",
1526 doc(cfg(all(feature = "experimental", feature = "zstdmt")))
1527)]
1528unsafe impl Sync for ThreadPool {}
1529
1530pub fn decompress_using_ddict(
1532 dctx: &mut DCtx<'_>,
1533 dst: &mut [u8],
1534 src: &[u8],
1535 ddict: &DDict<'_>,
1536) -> SafeResult {
1537 dctx.decompress_using_ddict(dst, src, ddict)
1538}
1539
1540pub type CStream<'a> = CCtx<'a>;
1544
1545pub fn create_cstream<'a>() -> CStream<'a> {
1549 CCtx::create()
1550}
1551
1552pub fn init_cstream(
1554 zcs: &mut CStream<'_>,
1555 compression_level: CompressionLevel,
1556) -> SafeResult {
1557 zcs.init(compression_level)
1558}
1559
1560#[derive(Debug)]
1561pub struct InBuffer<'a> {
1567 pub src: &'a [u8],
1568 pub pos: usize,
1569}
1570
1571pub unsafe trait WriteBuf {
1591 fn as_slice(&self) -> &[u8];
1593
1594 fn capacity(&self) -> usize;
1596
1597 fn as_mut_ptr(&mut self) -> *mut u8;
1599
1600 unsafe fn filled_until(&mut self, n: usize);
1605
1606 unsafe fn write_from<F>(&mut self, f: F) -> SafeResult
1617 where
1618 F: FnOnce(*mut c_void, usize) -> SafeResult,
1619 {
1620 let res = f(ptr_mut_void(self), self.capacity());
1621 if let Ok(n) = res {
1622 self.filled_until(n);
1623 }
1624 res
1625 }
1626}
1627
1628#[cfg(feature = "std")]
1629#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "std")))]
1630unsafe impl<T> WriteBuf for std::io::Cursor<T>
1631where
1632 T: WriteBuf,
1633{
1634 fn as_slice(&self) -> &[u8] {
1635 &self.get_ref().as_slice()[self.position() as usize..]
1636 }
1637
1638 fn capacity(&self) -> usize {
1639 self.get_ref()
1640 .capacity()
1641 .saturating_sub(self.position() as usize)
1642 }
1643
1644 fn as_mut_ptr(&mut self) -> *mut u8 {
1645 let start = self.position() as usize;
1646 assert!(start <= self.get_ref().capacity());
1647 unsafe { self.get_mut().as_mut_ptr().add(start) }
1649 }
1650
1651 unsafe fn filled_until(&mut self, n: usize) {
1652 if n == 0 {
1654 return;
1655 }
1656
1657 let position = self.position() as usize;
1661 let initialized = self.get_ref().as_slice().len();
1662 if let Some(uninitialized) = position.checked_sub(initialized) {
1663 unsafe {
1675 self.get_mut()
1676 .as_mut_ptr()
1677 .add(initialized)
1678 .write_bytes(0u8, uninitialized)
1679 };
1680 }
1681
1682 let start = self.position() as usize;
1683 assert!(start + n <= self.get_ref().capacity());
1684 self.get_mut().filled_until(start + n);
1685 }
1686}
1687
1688#[cfg(feature = "std")]
1689#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "std")))]
1690unsafe impl<'a> WriteBuf for &'a mut std::vec::Vec<u8> {
1691 fn as_slice(&self) -> &[u8] {
1692 std::vec::Vec::as_slice(self)
1693 }
1694
1695 fn capacity(&self) -> usize {
1696 std::vec::Vec::capacity(self)
1697 }
1698
1699 fn as_mut_ptr(&mut self) -> *mut u8 {
1700 std::vec::Vec::as_mut_ptr(self)
1701 }
1702
1703 unsafe fn filled_until(&mut self, n: usize) {
1704 std::vec::Vec::set_len(self, n)
1705 }
1706}
1707
1708#[cfg(feature = "std")]
1709#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "std")))]
1710unsafe impl WriteBuf for std::vec::Vec<u8> {
1711 fn as_slice(&self) -> &[u8] {
1712 &self[..]
1713 }
1714 fn capacity(&self) -> usize {
1715 self.capacity()
1716 }
1717 fn as_mut_ptr(&mut self) -> *mut u8 {
1718 self.as_mut_ptr()
1719 }
1720 unsafe fn filled_until(&mut self, n: usize) {
1721 self.set_len(n);
1722 }
1723}
1724
1725#[cfg(feature = "arrays")]
1726#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "arrays")))]
1727unsafe impl<const N: usize> WriteBuf for [u8; N] {
1728 fn as_slice(&self) -> &[u8] {
1729 self
1730 }
1731 fn capacity(&self) -> usize {
1732 self.len()
1733 }
1734
1735 fn as_mut_ptr(&mut self) -> *mut u8 {
1736 (&mut self[..]).as_mut_ptr()
1737 }
1738
1739 unsafe fn filled_until(&mut self, _n: usize) {
1740 }
1742}
1743
1744unsafe impl WriteBuf for [u8] {
1745 fn as_slice(&self) -> &[u8] {
1746 self
1747 }
1748 fn capacity(&self) -> usize {
1749 self.len()
1750 }
1751
1752 fn as_mut_ptr(&mut self) -> *mut u8 {
1753 self.as_mut_ptr()
1754 }
1755
1756 unsafe fn filled_until(&mut self, _n: usize) {
1757 }
1759}
1760
1761#[derive(Debug)]
1780pub struct OutBuffer<'a, C: WriteBuf + ?Sized> {
1792 dst: &'a mut C,
1793 pos: usize,
1794}
1795
1796fn ptr_mut<B>(ptr_void: &mut B) -> *mut B {
1798 ptr_void as *mut B
1799}
1800
1801struct OutBufferWrapper<'a, 'b, C: WriteBuf + ?Sized> {
1805 buf: zstd_sys::ZSTD_outBuffer,
1806 parent: &'a mut OutBuffer<'b, C>,
1807}
1808
1809impl<'a, 'b: 'a, C: WriteBuf + ?Sized> Deref for OutBufferWrapper<'a, 'b, C> {
1810 type Target = zstd_sys::ZSTD_outBuffer;
1811
1812 fn deref(&self) -> &Self::Target {
1813 &self.buf
1814 }
1815}
1816
1817impl<'a, 'b: 'a, C: WriteBuf + ?Sized> DerefMut
1818 for OutBufferWrapper<'a, 'b, C>
1819{
1820 fn deref_mut(&mut self) -> &mut Self::Target {
1821 &mut self.buf
1822 }
1823}
1824
1825impl<'a, C: WriteBuf + ?Sized> OutBuffer<'a, C> {
1826 pub fn around(dst: &'a mut C) -> Self {
1830 OutBuffer { dst, pos: 0 }
1831 }
1832
1833 pub fn around_pos(dst: &'a mut C, pos: usize) -> Self {
1839 if pos > dst.capacity() {
1840 panic!("Given position outside of the buffer bounds.");
1841 }
1842
1843 OutBuffer { dst, pos }
1844 }
1845
1846 pub fn pos(&self) -> usize {
1850 assert!(self.pos <= self.dst.capacity());
1851 self.pos
1852 }
1853
1854 pub fn capacity(&self) -> usize {
1856 self.dst.capacity()
1857 }
1858
1859 pub unsafe fn set_pos(&mut self, pos: usize) {
1869 if pos > self.dst.capacity() {
1870 panic!("Given position outside of the buffer bounds.");
1871 }
1872
1873 self.dst.filled_until(pos);
1874
1875 self.pos = pos;
1876 }
1877
1878 fn wrap<'b>(&'b mut self) -> OutBufferWrapper<'b, 'a, C> {
1879 OutBufferWrapper {
1880 buf: zstd_sys::ZSTD_outBuffer {
1881 dst: ptr_mut_void(self.dst),
1882 size: self.dst.capacity(),
1883 pos: self.pos,
1884 },
1885 parent: self,
1886 }
1887 }
1888
1889 pub fn as_slice<'b>(&'b self) -> &'a [u8]
1891 where
1892 'b: 'a,
1893 {
1894 let pos = self.pos;
1895 &self.dst.as_slice()[..pos]
1896 }
1897
1898 pub fn as_mut_ptr(&mut self) -> *mut u8 {
1900 self.dst.as_mut_ptr()
1901 }
1902}
1903
1904impl<'a, 'b, C: WriteBuf + ?Sized> Drop for OutBufferWrapper<'a, 'b, C> {
1905 fn drop(&mut self) {
1906 unsafe { self.parent.set_pos(self.buf.pos) };
1908 }
1909}
1910
1911struct InBufferWrapper<'a, 'b> {
1912 buf: zstd_sys::ZSTD_inBuffer,
1913 parent: &'a mut InBuffer<'b>,
1914}
1915
1916impl<'a, 'b: 'a> Deref for InBufferWrapper<'a, 'b> {
1917 type Target = zstd_sys::ZSTD_inBuffer;
1918
1919 fn deref(&self) -> &Self::Target {
1920 &self.buf
1921 }
1922}
1923
1924impl<'a, 'b: 'a> DerefMut for InBufferWrapper<'a, 'b> {
1925 fn deref_mut(&mut self) -> &mut Self::Target {
1926 &mut self.buf
1927 }
1928}
1929
1930impl<'a> InBuffer<'a> {
1931 pub fn around(src: &'a [u8]) -> Self {
1935 InBuffer { src, pos: 0 }
1936 }
1937
1938 pub fn pos(&self) -> usize {
1940 self.pos
1941 }
1942
1943 pub fn set_pos(&mut self, pos: usize) {
1949 if pos > self.src.len() {
1950 panic!("Given position outside of the buffer bounds.");
1951 }
1952 self.pos = pos;
1953 }
1954
1955 fn wrap<'b>(&'b mut self) -> InBufferWrapper<'b, 'a> {
1956 InBufferWrapper {
1957 buf: zstd_sys::ZSTD_inBuffer {
1958 src: ptr_void(self.src),
1959 size: self.src.len(),
1960 pos: self.pos,
1961 },
1962 parent: self,
1963 }
1964 }
1965}
1966
1967impl<'a, 'b> Drop for InBufferWrapper<'a, 'b> {
1968 fn drop(&mut self) {
1969 self.parent.set_pos(self.buf.pos);
1970 }
1971}
1972
1973pub type DStream<'a> = DCtx<'a>;
1977
1978pub fn find_frame_compressed_size(src: &[u8]) -> SafeResult {
1988 let code = unsafe {
1989 zstd_sys::ZSTD_findFrameCompressedSize(ptr_void(src), src.len())
1990 };
1991 parse_code(code)
1992}
1993
1994pub fn get_frame_content_size(
2004 src: &[u8],
2005) -> Result<Option<u64>, ContentSizeError> {
2006 parse_content_size(unsafe {
2007 zstd_sys::ZSTD_getFrameContentSize(ptr_void(src), src.len())
2008 })
2009}
2010
2011#[cfg(feature = "experimental")]
2015#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2016pub fn find_decompressed_size(
2017 src: &[u8],
2018) -> Result<Option<u64>, ContentSizeError> {
2019 parse_content_size(unsafe {
2020 zstd_sys::ZSTD_findDecompressedSize(ptr_void(src), src.len())
2021 })
2022}
2023
2024#[cfg(feature = "experimental")]
2026#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2027pub fn is_frame(buffer: &[u8]) -> bool {
2028 unsafe { zstd_sys::ZSTD_isFrame(ptr_void(buffer), buffer.len()) > 0 }
2029}
2030
2031pub fn get_dict_id_from_dict(dict: &[u8]) -> Option<NonZeroU32> {
2035 NonZeroU32::new(unsafe {
2036 zstd_sys::ZSTD_getDictID_fromDict(ptr_void(dict), dict.len()) as u32
2037 })
2038}
2039
2040pub fn get_dict_id_from_frame(src: &[u8]) -> Option<NonZeroU32> {
2049 NonZeroU32::new(unsafe {
2050 zstd_sys::ZSTD_getDictID_fromFrame(ptr_void(src), src.len()) as u32
2051 })
2052}
2053
2054pub enum ResetDirective {
2056 SessionOnly,
2064
2065 Parameters,
2071
2072 SessionAndParameters,
2076}
2077
2078impl ResetDirective {
2079 fn as_sys(self) -> zstd_sys::ZSTD_ResetDirective {
2080 match self {
2081 ResetDirective::SessionOnly => zstd_sys::ZSTD_ResetDirective::ZSTD_reset_session_only,
2082 ResetDirective::Parameters => zstd_sys::ZSTD_ResetDirective::ZSTD_reset_parameters,
2083 ResetDirective::SessionAndParameters => zstd_sys::ZSTD_ResetDirective::ZSTD_reset_session_and_parameters,
2084 }
2085 }
2086}
2087
2088#[cfg(feature = "experimental")]
2089#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2090#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2091#[repr(u32)]
2092pub enum FrameFormat {
2093 One = zstd_sys::ZSTD_format_e::ZSTD_f_zstd1 as u32,
2095
2096 Magicless = zstd_sys::ZSTD_format_e::ZSTD_f_zstd1_magicless as u32,
2098}
2099
2100#[cfg(feature = "experimental")]
2101#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2102#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2103#[repr(u32)]
2104pub enum DictAttachPref {
2105 DefaultAttach =
2106 zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictDefaultAttach as u32,
2107 ForceAttach = zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictForceAttach as u32,
2108 ForceCopy = zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictForceCopy as u32,
2109 ForceLoad = zstd_sys::ZSTD_dictAttachPref_e::ZSTD_dictForceLoad as u32,
2110}
2111
2112#[cfg(feature = "experimental")]
2113#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2114#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2115#[repr(u32)]
2116pub enum ParamSwitch {
2117 Auto = zstd_sys::ZSTD_ParamSwitch_e::ZSTD_ps_auto as u32,
2118 Enable = zstd_sys::ZSTD_ParamSwitch_e::ZSTD_ps_enable as u32,
2119 Disable = zstd_sys::ZSTD_ParamSwitch_e::ZSTD_ps_disable as u32,
2120}
2121
2122#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2124#[non_exhaustive]
2125pub enum CParameter {
2126 #[cfg(feature = "experimental")]
2127 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2128 RSyncable(bool),
2129
2130 #[cfg(feature = "experimental")]
2131 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2132 Format(FrameFormat),
2133
2134 #[cfg(feature = "experimental")]
2135 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2136 ForceMaxWindow(bool),
2137
2138 #[cfg(feature = "experimental")]
2139 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2140 ForceAttachDict(DictAttachPref),
2141
2142 #[cfg(feature = "experimental")]
2143 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2144 LiteralCompressionMode(ParamSwitch),
2145
2146 #[cfg(feature = "experimental")]
2147 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2148 SrcSizeHint(u32),
2149
2150 #[cfg(feature = "experimental")]
2151 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2152 EnableDedicatedDictSearch(bool),
2153
2154 #[cfg(feature = "experimental")]
2155 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2156 StableInBuffer(bool),
2157
2158 #[cfg(feature = "experimental")]
2159 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2160 StableOutBuffer(bool),
2161
2162 #[cfg(feature = "experimental")]
2163 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2164 BlockDelimiters(bool),
2165
2166 #[cfg(feature = "experimental")]
2167 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2168 ValidateSequences(bool),
2169
2170 #[cfg(feature = "experimental")]
2171 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2172 UseBlockSplitter(ParamSwitch),
2173
2174 #[cfg(feature = "experimental")]
2175 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2176 UseRowMatchFinder(ParamSwitch),
2177
2178 #[cfg(feature = "experimental")]
2179 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2180 DeterministicRefPrefix(bool),
2181
2182 #[cfg(feature = "experimental")]
2183 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2184 PrefetchCDictTables(ParamSwitch),
2185
2186 #[cfg(feature = "experimental")]
2187 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2188 EnableSeqProducerFallback(bool),
2189
2190 #[cfg(feature = "experimental")]
2191 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2192 MaxBlockSize(u32),
2193
2194 #[cfg(feature = "experimental")]
2195 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2196 SearchForExternalRepcodes(ParamSwitch),
2197
2198 TargetCBlockSize(u32),
2205
2206 CompressionLevel(CompressionLevel),
2210
2211 WindowLog(u32),
2215
2216 HashLog(u32),
2217
2218 ChainLog(u32),
2219
2220 SearchLog(u32),
2221
2222 MinMatch(u32),
2223
2224 TargetLength(u32),
2225
2226 Strategy(Strategy),
2227
2228 EnableLongDistanceMatching(bool),
2229
2230 LdmHashLog(u32),
2231
2232 LdmMinMatch(u32),
2233
2234 LdmBucketSizeLog(u32),
2235
2236 LdmHashRateLog(u32),
2237
2238 ContentSizeFlag(bool),
2239
2240 ChecksumFlag(bool),
2241
2242 DictIdFlag(bool),
2243
2244 NbWorkers(u32),
2253
2254 JobSize(u32),
2262
2263 OverlapSizeLog(u32),
2275}
2276
2277#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2279#[non_exhaustive]
2280pub enum DParameter {
2281 WindowLogMax(u32),
2282
2283 #[cfg(feature = "experimental")]
2284 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2285 Format(FrameFormat),
2287
2288 #[cfg(feature = "experimental")]
2289 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2290 StableOutBuffer(bool),
2291
2292 #[cfg(feature = "experimental")]
2293 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2294 ForceIgnoreChecksum(bool),
2295
2296 #[cfg(feature = "experimental")]
2297 #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2298 RefMultipleDDicts(bool),
2299}
2300
2301#[cfg(feature = "zdict_builder")]
2303#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "zdict_builder")))]
2304pub fn train_from_buffer<C: WriteBuf + ?Sized>(
2305 dict_buffer: &mut C,
2306 samples_buffer: &[u8],
2307 samples_sizes: &[usize],
2308) -> SafeResult {
2309 assert_eq!(samples_buffer.len(), samples_sizes.iter().sum());
2310
2311 unsafe {
2312 dict_buffer.write_from(|buffer, capacity| {
2313 parse_code(zstd_sys::ZDICT_trainFromBuffer(
2314 buffer,
2315 capacity,
2316 ptr_void(samples_buffer),
2317 samples_sizes.as_ptr(),
2318 samples_sizes.len() as u32,
2319 ))
2320 })
2321 }
2322}
2323
2324#[cfg(feature = "zdict_builder")]
2326#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "zdict_builder")))]
2327pub fn get_dict_id(dict_buffer: &[u8]) -> Option<NonZeroU32> {
2328 NonZeroU32::new(unsafe {
2329 zstd_sys::ZDICT_getDictID(ptr_void(dict_buffer), dict_buffer.len())
2330 })
2331}
2332
2333#[cfg(feature = "experimental")]
2335#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2336pub fn get_block_size(cctx: &CCtx) -> usize {
2337 unsafe { zstd_sys::ZSTD_getBlockSize(cctx.0.as_ptr()) }
2338}
2339
2340#[cfg(feature = "experimental")]
2342#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2343pub fn decompress_bound(data: &[u8]) -> Result<u64, ErrorCode> {
2344 let bound =
2345 unsafe { zstd_sys::ZSTD_decompressBound(ptr_void(data), data.len()) };
2346 if is_error(bound as usize) {
2347 Err(bound as usize)
2348 } else {
2349 Ok(bound)
2350 }
2351}
2352
2353#[cfg(feature = "experimental")]
2356#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2357pub fn sequence_bound(src_size: usize) -> usize {
2358 unsafe { zstd_sys::ZSTD_sequenceBound(src_size) }
2360}
2361
2362#[cfg(feature = "experimental")]
2368#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "experimental")))]
2369pub fn decompression_margin(
2370 compressed_data: &[u8],
2371) -> Result<usize, ErrorCode> {
2372 parse_code(unsafe {
2373 zstd_sys::ZSTD_decompressionMargin(
2374 ptr_void(compressed_data),
2375 compressed_data.len(),
2376 )
2377 })
2378}