1use core::{fmt, marker::PhantomData, mem::MaybeUninit};
4
5use super::{errors::FrameDecoderError, frame_decoder::PreparedDictionaryBytes, FrameDecoder};
6use crate::{
7 decoding::scratch::DecoderScratch,
8 workspace::{Arena, ArenaError},
9};
10
11pub struct DecoderWorkspace {
18 decoder: FrameDecoder,
19 max_window_size: usize,
20 max_dictionary_size: usize,
21}
22
23impl DecoderWorkspace {
24 pub fn new(
26 max_window_size: usize,
27 max_dictionary_size: usize,
28 ) -> Result<Self, DecoderWorkspaceError> {
29 if max_window_size == 0 {
30 return Err(DecoderWorkspaceError::InvalidWindowSize);
31 }
32 let mut decoder = FrameDecoder::new();
33 decoder.prepare_workspace(max_window_size, max_dictionary_size);
34 Ok(Self {
35 decoder,
36 max_window_size,
37 max_dictionary_size,
38 })
39 }
40
41 pub const fn max_window_size(&self) -> usize {
42 self.max_window_size
43 }
44
45 pub const fn max_dictionary_size(&self) -> usize {
46 self.max_dictionary_size
47 }
48
49 pub fn decode_into(
51 &mut self,
52 input: &[u8],
53 output: &mut [u8],
54 ) -> Result<usize, DecoderWorkspaceError> {
55 self.decoder
56 .decode_all_with_window_limit(input, output, self.max_window_size as u64)
57 .map_err(DecoderWorkspaceError::Decode)
58 }
59
60 pub fn decode_into_with_dictionary(
63 &mut self,
64 input: &[u8],
65 dictionary: &[u8],
66 output: &mut [u8],
67 ) -> Result<usize, DecoderWorkspaceError> {
68 ensure_dictionary_size(dictionary.len(), self.max_dictionary_size)?;
69 self.decoder
70 .decode_all_with_window_limit_and_dictionary(
71 input,
72 output,
73 self.max_window_size as u64,
74 Some(PreparedDictionaryBytes::Formatted(dictionary)),
75 )
76 .map_err(DecoderWorkspaceError::Decode)
77 }
78
79 pub fn decoder_mut(&mut self) -> &mut FrameDecoder {
82 &mut self.decoder
83 }
84
85 pub fn decode_into_with_raw_dictionary(
87 &mut self,
88 input: &[u8],
89 dictionary: &[u8],
90 output: &mut [u8],
91 ) -> Result<usize, DecoderWorkspaceError> {
92 ensure_dictionary_size(dictionary.len(), self.max_dictionary_size)?;
93 self.decoder
94 .decode_all_with_window_limit_and_dictionary(
95 input,
96 output,
97 self.max_window_size as u64,
98 Some(PreparedDictionaryBytes::Raw(dictionary)),
99 )
100 .map_err(DecoderWorkspaceError::Decode)
101 }
102}
103
104#[derive(Debug)]
106pub enum DecoderWorkspaceError {
107 InvalidWindowSize,
108 InsufficientStorage { required: usize, provided: usize },
109 SizeOverflow,
110 DictionaryTooLarge { maximum: usize, provided: usize },
111 Decode(FrameDecoderError),
112}
113
114impl fmt::Display for DecoderWorkspaceError {
115 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
116 match self {
117 Self::InvalidWindowSize => formatter.write_str("maximum window size must be non-zero"),
118 Self::InsufficientStorage { required, provided } => write!(
119 formatter,
120 "decoder workspace needs {required} bytes but only {provided} were provided"
121 ),
122 Self::SizeOverflow => formatter.write_str("decoder workspace size overflowed"),
123 Self::DictionaryTooLarge { maximum, provided } => write!(
124 formatter,
125 "dictionary has {provided} bytes but this workspace permits at most {maximum}"
126 ),
127 Self::Decode(error) => error.fmt(formatter),
128 }
129 }
130}
131
132#[cfg(feature = "std")]
133impl std::error::Error for DecoderWorkspaceError {
134 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
135 match self {
136 Self::Decode(error) => Some(error),
137 Self::InvalidWindowSize
138 | Self::InsufficientStorage { .. }
139 | Self::SizeOverflow
140 | Self::DictionaryTooLarge { .. } => None,
141 }
142 }
143}
144
145pub struct StaticDecoderWorkspace<'storage> {
147 decoder: FrameDecoder,
148 max_window_size: usize,
149 max_dictionary_size: usize,
150 workspace_bytes: usize,
151 marker: PhantomData<&'storage mut [MaybeUninit<u8>]>,
152}
153
154impl<'storage> StaticDecoderWorkspace<'storage> {
155 pub fn required_size(
156 max_window_size: usize,
157 max_dictionary_size: usize,
158 ) -> Result<usize, DecoderWorkspaceError> {
159 if max_window_size == 0 {
160 return Err(DecoderWorkspaceError::InvalidWindowSize);
161 }
162 DecoderScratch::workspace_size(max_window_size, max_dictionary_size)
163 .map_err(map_arena_error)
164 }
165
166 pub fn new(
167 storage: &'storage mut [u8],
168 max_window_size: usize,
169 max_dictionary_size: usize,
170 ) -> Result<Self, DecoderWorkspaceError> {
171 Self::new_uninit(
172 initialized_bytes_as_uninit(storage),
173 max_window_size,
174 max_dictionary_size,
175 )
176 }
177
178 pub fn new_uninit(
180 storage: &'storage mut [MaybeUninit<u8>],
181 max_window_size: usize,
182 max_dictionary_size: usize,
183 ) -> Result<Self, DecoderWorkspaceError> {
184 let required = Self::required_size(max_window_size, max_dictionary_size)?;
185 if storage.len() < required {
186 return Err(DecoderWorkspaceError::InsufficientStorage {
187 required,
188 provided: storage.len(),
189 });
190 }
191 let mut arena = Arena::new(storage);
192 let scratch = DecoderScratch::new_in(&mut arena, max_window_size, max_dictionary_size)
193 .map_err(map_arena_error)?;
194 let mut decoder = FrameDecoder::new();
195 decoder.install_prepared_scratch(scratch);
196 Ok(Self {
197 decoder,
198 max_window_size,
199 max_dictionary_size,
200 workspace_bytes: storage.len(),
201 marker: PhantomData,
202 })
203 }
204
205 pub fn decode_into(
206 &mut self,
207 input: &[u8],
208 output: &mut [u8],
209 ) -> Result<usize, DecoderWorkspaceError> {
210 self.decoder
211 .decode_all_with_window_limit(input, output, self.max_window_size as u64)
212 .map_err(DecoderWorkspaceError::Decode)
213 }
214
215 pub fn decode_into_with_dictionary(
217 &mut self,
218 input: &[u8],
219 dictionary: &[u8],
220 output: &mut [u8],
221 ) -> Result<usize, DecoderWorkspaceError> {
222 ensure_dictionary_size(dictionary.len(), self.max_dictionary_size)?;
223 self.decoder
224 .decode_all_with_window_limit_and_dictionary(
225 input,
226 output,
227 self.max_window_size as u64,
228 Some(PreparedDictionaryBytes::Formatted(dictionary)),
229 )
230 .map_err(DecoderWorkspaceError::Decode)
231 }
232
233 pub fn decode_into_with_raw_dictionary(
235 &mut self,
236 input: &[u8],
237 dictionary: &[u8],
238 output: &mut [u8],
239 ) -> Result<usize, DecoderWorkspaceError> {
240 ensure_dictionary_size(dictionary.len(), self.max_dictionary_size)?;
241 self.decoder
242 .decode_all_with_window_limit_and_dictionary(
243 input,
244 output,
245 self.max_window_size as u64,
246 Some(PreparedDictionaryBytes::Raw(dictionary)),
247 )
248 .map_err(DecoderWorkspaceError::Decode)
249 }
250
251 pub const fn max_window_size(&self) -> usize {
252 self.max_window_size
253 }
254
255 pub const fn max_dictionary_size(&self) -> usize {
256 self.max_dictionary_size
257 }
258
259 pub const fn workspace_bytes(&self) -> usize {
260 self.workspace_bytes
261 }
262}
263
264fn initialized_bytes_as_uninit(storage: &mut [u8]) -> &mut [MaybeUninit<u8>] {
265 unsafe { core::slice::from_raw_parts_mut(storage.as_mut_ptr().cast(), storage.len()) }
268}
269
270fn ensure_dictionary_size(provided: usize, maximum: usize) -> Result<(), DecoderWorkspaceError> {
271 if provided > maximum {
272 Err(DecoderWorkspaceError::DictionaryTooLarge { maximum, provided })
273 } else {
274 Ok(())
275 }
276}
277
278fn map_arena_error(error: ArenaError) -> DecoderWorkspaceError {
279 match error {
280 ArenaError::InsufficientStorage { required, provided } => {
281 DecoderWorkspaceError::InsufficientStorage { required, provided }
282 }
283 ArenaError::CapacityExceeded { capacity } => DecoderWorkspaceError::InsufficientStorage {
284 required: capacity.saturating_add(1),
285 provided: capacity,
286 },
287 ArenaError::SizeOverflow => DecoderWorkspaceError::SizeOverflow,
288 }
289}