1use crate::map_error_code;
23#[cfg(feature = "experimental")]
4use std::convert::TryInto;
5use std::io;
6use zstd_safe;
78/// Allows to decompress independently multiple blocks of data.
9///
10/// This reduces memory usage compared to calling `decompress` multiple times.
11#[derive(Default)]
12pub struct Decompressor<'a> {
13 context: zstd_safe::DCtx<'a>,
14}
1516impl Decompressor<'static> {
17/// Creates a new zstd decompressor.
18pub fn new() -> io::Result<Self> {
19Self::with_dictionary(&[])
20 }
2122/// Creates a new zstd decompressor, using the given dictionary.
23pub fn with_dictionary(dictionary: &[u8]) -> io::Result<Self> {
24let mut decompressor = Self::default();
2526 decompressor.set_dictionary(dictionary)?;
2728Ok(decompressor)
29 }
30}
3132impl<'a> Decompressor<'a> {
33/// Creates a new decompressor using an existing `DecoderDictionary`.
34 ///
35 /// Note that using a dictionary means that compression will need to use
36 /// the same dictionary.
37pub fn with_prepared_dictionary<'b>(
38 dictionary: &'a crate::dict::DecoderDictionary<'b>,
39 ) -> io::Result<Self>
40where
41'b: 'a,
42 {
43let mut decompressor = Self::default();
4445 decompressor.set_prepared_dictionary(dictionary)?;
4647Ok(decompressor)
48 }
4950/// Changes the dictionary used by this decompressor.
51 ///
52 /// Will affect future compression jobs.
53 ///
54 /// Note that using a dictionary means that compression will need to use
55 /// the same dictionary.
56pub fn set_dictionary(&mut self, dictionary: &[u8]) -> io::Result<()> {
57self.context
58 .load_dictionary(dictionary)
59 .map_err(map_error_code)?;
6061Ok(())
62 }
6364/// Changes the dictionary used by this decompressor.
65 ///
66 /// Note that using a dictionary means that compression will need to use
67 /// the same dictionary.
68pub fn set_prepared_dictionary<'b>(
69&mut self,
70 dictionary: &'a crate::dict::DecoderDictionary<'b>,
71 ) -> io::Result<()>
72where
73'b: 'a,
74 {
75self.context
76 .ref_ddict(dictionary.as_ddict())
77 .map_err(map_error_code)?;
7879Ok(())
80 }
8182/// Deompress a single block of data to the given destination buffer.
83 ///
84 /// Returns the number of bytes written, or an error if something happened
85 /// (for instance if the destination buffer was too small).
86pub fn decompress_to_buffer<C: zstd_safe::WriteBuf + ?Sized>(
87&mut self,
88 source: &[u8],
89 destination: &mut C,
90 ) -> io::Result<usize> {
91self.context
92 .decompress(destination, source)
93 .map_err(map_error_code)
94 }
9596/// Decompress a block of data, and return the result in a `Vec<u8>`.
97 ///
98 /// The decompressed data should be less than `capacity` bytes,
99 /// or an error will be returned.
100pub fn decompress(
101&mut self,
102 data: &[u8],
103 capacity: usize,
104 ) -> io::Result<Vec<u8>> {
105let capacity =
106Self::upper_bound(data).unwrap_or(capacity).min(capacity);
107let mut buffer = Vec::with_capacity(capacity);
108self.decompress_to_buffer(data, &mut buffer)?;
109Ok(buffer)
110 }
111112/// Sets a decompression parameter for this decompressor.
113pub fn set_parameter(
114&mut self,
115 parameter: zstd_safe::DParameter,
116 ) -> io::Result<()> {
117self.context
118 .set_parameter(parameter)
119 .map_err(map_error_code)?;
120Ok(())
121 }
122123crate::decoder_parameters!();
124125/// Get an upper bound on the decompressed size of data, if available
126 ///
127 /// This can be used to pre-allocate enough capacity for `decompress_to_buffer`
128 /// and is used by `decompress` to ensure that it does not over-allocate if
129 /// you supply a large `capacity`.
130 ///
131 /// Will return `None` if the upper bound cannot be determined or is larger than `usize::MAX`
132 ///
133 /// Note that unless the `experimental` feature is enabled, this will always return `None`.
134pub fn upper_bound(_data: &[u8]) -> Option<usize> {
135#[cfg(feature = "experimental")]
136{
137let bound = zstd_safe::decompress_bound(_data).ok()?;
138 bound.try_into().ok()
139 }
140#[cfg(not(feature = "experimental"))]
141{
142None
143}
144 }
145}
146147fn _assert_traits() {
148fn _assert_send<T: Send>(_: T) {}
149150 _assert_send(Decompressor::new());
151}