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).map_err(DecoderWorkspaceError::Capacity)?;
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 Capacity(crate::workspace::CapacityError),
108 InvalidWindowSize,
109 InsufficientStorage { required: usize, provided: usize },
110 SizeOverflow,
111 DictionaryTooLarge { maximum: usize, provided: usize },
112 Decode(FrameDecoderError),
113}
114
115impl fmt::Display for DecoderWorkspaceError {
116 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
117 match self {
118 Self::Capacity(error) => write!(formatter, "decoder storage admission failed: {error:?}"),
119 Self::InvalidWindowSize => formatter.write_str("maximum window size must be non-zero"),
120 Self::InsufficientStorage { required, provided } => write!(
121 formatter,
122 "decoder workspace needs {required} bytes but only {provided} were provided"
123 ),
124 Self::SizeOverflow => formatter.write_str("decoder workspace size overflowed"),
125 Self::DictionaryTooLarge { maximum, provided } => write!(
126 formatter,
127 "dictionary has {provided} bytes but this workspace permits at most {maximum}"
128 ),
129 Self::Decode(error) => error.fmt(formatter),
130 }
131 }
132}
133
134#[cfg(feature = "std")]
135impl std::error::Error for DecoderWorkspaceError {
136 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
137 match self {
138 Self::Decode(error) => Some(error),
139 Self::Capacity(_)
140 | Self::InvalidWindowSize
141 | Self::InsufficientStorage { .. }
142 | Self::SizeOverflow
143 | Self::DictionaryTooLarge { .. } => None,
144 }
145 }
146}
147
148pub struct StaticDecoderWorkspace<'storage> {
150 decoder: FrameDecoder,
151 max_window_size: usize,
152 max_dictionary_size: usize,
153 workspace_bytes: usize,
154 marker: PhantomData<&'storage mut [MaybeUninit<u8>]>,
155}
156
157impl<'storage> StaticDecoderWorkspace<'storage> {
158 pub fn required_size(
159 max_window_size: usize,
160 max_dictionary_size: usize,
161 ) -> Result<usize, DecoderWorkspaceError> {
162 if max_window_size == 0 {
163 return Err(DecoderWorkspaceError::InvalidWindowSize);
164 }
165 DecoderScratch::workspace_size(max_window_size, max_dictionary_size)
166 .map_err(map_arena_error)
167 }
168
169 pub fn new(
170 storage: &'storage mut [u8],
171 max_window_size: usize,
172 max_dictionary_size: usize,
173 ) -> Result<Self, DecoderWorkspaceError> {
174 Self::new_uninit(
175 initialized_bytes_as_uninit(storage),
176 max_window_size,
177 max_dictionary_size,
178 )
179 }
180
181 pub fn new_uninit(
183 storage: &'storage mut [MaybeUninit<u8>],
184 max_window_size: usize,
185 max_dictionary_size: usize,
186 ) -> Result<Self, DecoderWorkspaceError> {
187 let required = Self::required_size(max_window_size, max_dictionary_size)?;
188 if storage.len() < required {
189 return Err(DecoderWorkspaceError::InsufficientStorage {
190 required,
191 provided: storage.len(),
192 });
193 }
194 let mut arena = Arena::new(storage);
195 let scratch = DecoderScratch::new_in(&mut arena, max_window_size, max_dictionary_size)
196 .map_err(map_arena_error)?;
197 let mut decoder = FrameDecoder::new();
198 decoder.install_prepared_scratch(scratch);
199 Ok(Self {
200 decoder,
201 max_window_size,
202 max_dictionary_size,
203 workspace_bytes: storage.len(),
204 marker: PhantomData,
205 })
206 }
207
208 pub fn decode_into(
209 &mut self,
210 input: &[u8],
211 output: &mut [u8],
212 ) -> Result<usize, DecoderWorkspaceError> {
213 self.decoder
214 .decode_all_with_window_limit(input, output, self.max_window_size as u64)
215 .map_err(DecoderWorkspaceError::Decode)
216 }
217
218 pub fn decode_into_with_dictionary(
220 &mut self,
221 input: &[u8],
222 dictionary: &[u8],
223 output: &mut [u8],
224 ) -> Result<usize, DecoderWorkspaceError> {
225 ensure_dictionary_size(dictionary.len(), self.max_dictionary_size)?;
226 self.decoder
227 .decode_all_with_window_limit_and_dictionary(
228 input,
229 output,
230 self.max_window_size as u64,
231 Some(PreparedDictionaryBytes::Formatted(dictionary)),
232 )
233 .map_err(DecoderWorkspaceError::Decode)
234 }
235
236 pub fn decode_into_with_raw_dictionary(
238 &mut self,
239 input: &[u8],
240 dictionary: &[u8],
241 output: &mut [u8],
242 ) -> Result<usize, DecoderWorkspaceError> {
243 ensure_dictionary_size(dictionary.len(), self.max_dictionary_size)?;
244 self.decoder
245 .decode_all_with_window_limit_and_dictionary(
246 input,
247 output,
248 self.max_window_size as u64,
249 Some(PreparedDictionaryBytes::Raw(dictionary)),
250 )
251 .map_err(DecoderWorkspaceError::Decode)
252 }
253
254 pub const fn max_window_size(&self) -> usize {
255 self.max_window_size
256 }
257
258 pub const fn max_dictionary_size(&self) -> usize {
259 self.max_dictionary_size
260 }
261
262 pub const fn workspace_bytes(&self) -> usize {
263 self.workspace_bytes
264 }
265}
266
267fn initialized_bytes_as_uninit(storage: &mut [u8]) -> &mut [MaybeUninit<u8>] {
268 unsafe { core::slice::from_raw_parts_mut(storage.as_mut_ptr().cast(), storage.len()) }
271}
272
273fn ensure_dictionary_size(provided: usize, maximum: usize) -> Result<(), DecoderWorkspaceError> {
274 if provided > maximum {
275 Err(DecoderWorkspaceError::DictionaryTooLarge { maximum, provided })
276 } else {
277 Ok(())
278 }
279}
280
281fn map_arena_error(error: ArenaError) -> DecoderWorkspaceError {
282 match error {
283 ArenaError::Capacity(error) => DecoderWorkspaceError::Capacity(error),
284 ArenaError::InsufficientStorage { required, provided } => {
285 DecoderWorkspaceError::InsufficientStorage { required, provided }
286 }
287 ArenaError::CapacityExceeded { capacity } => DecoderWorkspaceError::InsufficientStorage {
288 required: capacity.saturating_add(1),
289 provided: capacity,
290 },
291 ArenaError::SizeOverflow => DecoderWorkspaceError::SizeOverflow,
292 }
293}