Skip to main content

base64_ng_bytes/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2#![deny(unsafe_code)]
3#![deny(missing_docs)]
4#![deny(clippy::all)]
5#![deny(clippy::pedantic)]
6
7//! Optional `bytes` integration for `base64-ng`.
8
9extern crate alloc;
10
11use alloc::vec::Vec;
12use base64_ng::{Alphabet, DecodeError, EncodeError, Engine};
13use bytes::{Buf, BufMut, Bytes};
14
15/// Encoding error for bounded `bytes` integration helpers.
16#[derive(Clone, Copy, Debug, Eq, PartialEq)]
17pub enum BytesEncodeError {
18    /// The input buffer reports more remaining bytes than the caller permits.
19    InputTooLarge {
20        /// Remaining input bytes reported by [`Buf::remaining`].
21        input_len: usize,
22        /// Caller-provided maximum input bytes.
23        max_input_len: usize,
24    },
25    /// Base64 encoding failed after the input-size check passed.
26    Encode(EncodeError),
27}
28
29impl core::fmt::Display for BytesEncodeError {
30    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
31        match self {
32            Self::InputTooLarge {
33                input_len,
34                max_input_len,
35            } => write!(
36                formatter,
37                "bytes input length {input_len} exceeds limit {max_input_len}"
38            ),
39            Self::Encode(error) => core::fmt::Display::fmt(error, formatter),
40        }
41    }
42}
43
44#[cfg(feature = "std")]
45impl std::error::Error for BytesEncodeError {
46    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
47        match self {
48            Self::InputTooLarge { .. } => None,
49            Self::Encode(error) => Some(error),
50        }
51    }
52}
53
54impl From<EncodeError> for BytesEncodeError {
55    fn from(error: EncodeError) -> Self {
56        Self::Encode(error)
57    }
58}
59
60/// Decoding error for bounded `bytes` integration helpers.
61#[derive(Clone, Copy, Debug, Eq, PartialEq)]
62pub enum BytesDecodeError {
63    /// The input buffer reports more remaining bytes than the caller permits.
64    InputTooLarge {
65        /// Remaining input bytes reported by [`Buf::remaining`].
66        input_len: usize,
67        /// Caller-provided maximum input bytes.
68        max_input_len: usize,
69    },
70    /// Base64 decoding failed after the input-size check passed.
71    Decode(DecodeError),
72}
73
74impl core::fmt::Display for BytesDecodeError {
75    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
76        match self {
77            Self::InputTooLarge {
78                input_len,
79                max_input_len,
80            } => write!(
81                formatter,
82                "bytes input length {input_len} exceeds limit {max_input_len}"
83            ),
84            Self::Decode(error) => core::fmt::Display::fmt(error, formatter),
85        }
86    }
87}
88
89#[cfg(feature = "std")]
90impl std::error::Error for BytesDecodeError {
91    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
92        match self {
93            Self::InputTooLarge { .. } => None,
94            Self::Decode(error) => Some(error),
95        }
96    }
97}
98
99impl From<DecodeError> for BytesDecodeError {
100    fn from(error: DecodeError) -> Self {
101        Self::Decode(error)
102    }
103}
104
105/// Extension helpers for [`base64_ng::Engine`] and `bytes` buffers.
106pub trait EngineBytesExt<A, const PAD: bool>
107where
108    A: Alphabet,
109{
110    /// Encodes bytes into a [`Bytes`] value.
111    ///
112    /// # Errors
113    ///
114    /// Returns [`EncodeError`] if the encoded length overflows.
115    fn encode_bytes(&self, input: impl AsRef<[u8]>) -> Result<Bytes, EncodeError>;
116
117    /// Decodes Base64 bytes into a [`Bytes`] value.
118    ///
119    /// # Errors
120    ///
121    /// Returns [`DecodeError`] if decoding fails.
122    fn decode_bytes(&self, input: impl AsRef<[u8]>) -> Result<Bytes, DecodeError>;
123
124    /// Encodes all remaining bytes from `input` into a [`Bytes`] value.
125    ///
126    /// The input buffer is advanced to completion only after its current
127    /// chunks have been copied into a temporary contiguous buffer.
128    ///
129    /// # Errors
130    ///
131    /// Returns [`EncodeError`] if the encoded length overflows.
132    fn encode_buf<B>(&self, input: B) -> Result<Bytes, EncodeError>
133    where
134        B: Buf;
135
136    /// Encodes at most `max_input_len` remaining bytes from `input` into a
137    /// [`Bytes`] value.
138    ///
139    /// Use this variant for peer-controlled or metadata-declared frame sizes.
140    /// The input buffer is not collected if [`Buf::remaining`] exceeds
141    /// `max_input_len`.
142    ///
143    /// # Errors
144    ///
145    /// Returns [`BytesEncodeError::InputTooLarge`] if `input.remaining()`
146    /// exceeds `max_input_len`, or [`BytesEncodeError::Encode`] if Base64
147    /// encoding fails.
148    fn encode_buf_limited<B>(
149        &self,
150        input: B,
151        max_input_len: usize,
152    ) -> Result<Bytes, BytesEncodeError>
153    where
154        B: Buf;
155
156    /// Decodes all remaining bytes from `input` into a [`Bytes`] value.
157    ///
158    /// # Errors
159    ///
160    /// Returns [`DecodeError`] if decoding fails.
161    fn decode_buf<B>(&self, input: B) -> Result<Bytes, DecodeError>
162    where
163        B: Buf;
164
165    /// Decodes at most `max_input_len` remaining Base64 bytes from `input`
166    /// into a [`Bytes`] value.
167    ///
168    /// Use this variant for peer-controlled or metadata-declared frame sizes.
169    /// The input buffer is not collected if [`Buf::remaining`] exceeds
170    /// `max_input_len`.
171    ///
172    /// # Errors
173    ///
174    /// Returns [`BytesDecodeError::InputTooLarge`] if `input.remaining()`
175    /// exceeds `max_input_len`, or [`BytesDecodeError::Decode`] if Base64
176    /// decoding fails.
177    fn decode_buf_limited<B>(
178        &self,
179        input: B,
180        max_input_len: usize,
181    ) -> Result<Bytes, BytesDecodeError>
182    where
183        B: Buf;
184
185    /// Encodes all remaining bytes from `input` into `output`.
186    ///
187    /// # Errors
188    ///
189    /// Returns [`EncodeError::OutputTooSmall`] if `output` does not have enough
190    /// remaining mutable capacity.
191    fn encode_buf_to_mut<B, M>(&self, input: B, output: &mut M) -> Result<usize, EncodeError>
192    where
193        B: Buf,
194        M: BufMut;
195
196    /// Encodes at most `max_input_len` remaining bytes from `input` into
197    /// `output`.
198    ///
199    /// # Errors
200    ///
201    /// Returns [`BytesEncodeError::InputTooLarge`] if `input.remaining()`
202    /// exceeds `max_input_len`, [`BytesEncodeError::Encode`] with
203    /// [`EncodeError::OutputTooSmall`] if `output` is too small, or another
204    /// wrapped [`EncodeError`] if Base64 encoding fails.
205    fn encode_buf_to_mut_limited<B, M>(
206        &self,
207        input: B,
208        output: &mut M,
209        max_input_len: usize,
210    ) -> Result<usize, BytesEncodeError>
211    where
212        B: Buf,
213        M: BufMut;
214
215    /// Decodes all remaining Base64 bytes from `input` into `output`.
216    ///
217    /// # Errors
218    ///
219    /// Returns [`DecodeError::OutputTooSmall`] if `output` does not have enough
220    /// remaining mutable capacity, or another [`DecodeError`] if decoding
221    /// fails.
222    fn decode_buf_to_mut<B, M>(&self, input: B, output: &mut M) -> Result<usize, DecodeError>
223    where
224        B: Buf,
225        M: BufMut;
226
227    /// Decodes at most `max_input_len` remaining Base64 bytes from `input`
228    /// into `output`.
229    ///
230    /// # Errors
231    ///
232    /// Returns [`BytesDecodeError::InputTooLarge`] if `input.remaining()`
233    /// exceeds `max_input_len`, [`BytesDecodeError::Decode`] with
234    /// [`DecodeError::OutputTooSmall`] if `output` is too small, or another
235    /// wrapped [`DecodeError`] if Base64 decoding fails.
236    fn decode_buf_to_mut_limited<B, M>(
237        &self,
238        input: B,
239        output: &mut M,
240        max_input_len: usize,
241    ) -> Result<usize, BytesDecodeError>
242    where
243        B: Buf,
244        M: BufMut;
245}
246
247impl<A, const PAD: bool> EngineBytesExt<A, PAD> for Engine<A, PAD>
248where
249    A: Alphabet,
250{
251    fn encode_bytes(&self, input: impl AsRef<[u8]>) -> Result<Bytes, EncodeError> {
252        self.encode_vec(input.as_ref()).map(Bytes::from)
253    }
254
255    fn decode_bytes(&self, input: impl AsRef<[u8]>) -> Result<Bytes, DecodeError> {
256        self.decode_vec(input.as_ref()).map(Bytes::from)
257    }
258
259    fn encode_buf<B>(&self, input: B) -> Result<Bytes, EncodeError>
260    where
261        B: Buf,
262    {
263        self.encode_bytes(collect_buf(input))
264    }
265
266    fn encode_buf_limited<B>(
267        &self,
268        input: B,
269        max_input_len: usize,
270    ) -> Result<Bytes, BytesEncodeError>
271    where
272        B: Buf,
273    {
274        let input =
275            collect_buf_limited(input, max_input_len).map_err(|(input_len, max_input_len)| {
276                BytesEncodeError::InputTooLarge {
277                    input_len,
278                    max_input_len,
279                }
280            })?;
281        self.encode_bytes(input).map_err(BytesEncodeError::Encode)
282    }
283
284    fn decode_buf<B>(&self, input: B) -> Result<Bytes, DecodeError>
285    where
286        B: Buf,
287    {
288        self.decode_bytes(collect_buf(input))
289    }
290
291    fn decode_buf_limited<B>(
292        &self,
293        input: B,
294        max_input_len: usize,
295    ) -> Result<Bytes, BytesDecodeError>
296    where
297        B: Buf,
298    {
299        let input =
300            collect_buf_limited(input, max_input_len).map_err(|(input_len, max_input_len)| {
301                BytesDecodeError::InputTooLarge {
302                    input_len,
303                    max_input_len,
304                }
305            })?;
306        self.decode_bytes(input).map_err(BytesDecodeError::Decode)
307    }
308
309    fn encode_buf_to_mut<B, M>(&self, input: B, output: &mut M) -> Result<usize, EncodeError>
310    where
311        B: Buf,
312        M: BufMut,
313    {
314        let encoded = self.encode_buf(input)?;
315        let len = encoded.len();
316        if output.remaining_mut() < len {
317            return Err(EncodeError::OutputTooSmall {
318                required: len,
319                available: output.remaining_mut(),
320            });
321        }
322        output.put_slice(&encoded);
323        Ok(len)
324    }
325
326    fn encode_buf_to_mut_limited<B, M>(
327        &self,
328        input: B,
329        output: &mut M,
330        max_input_len: usize,
331    ) -> Result<usize, BytesEncodeError>
332    where
333        B: Buf,
334        M: BufMut,
335    {
336        let encoded = self.encode_buf_limited(input, max_input_len)?;
337        let len = encoded.len();
338        if output.remaining_mut() < len {
339            return Err(BytesEncodeError::Encode(EncodeError::OutputTooSmall {
340                required: len,
341                available: output.remaining_mut(),
342            }));
343        }
344        output.put_slice(&encoded);
345        Ok(len)
346    }
347
348    fn decode_buf_to_mut<B, M>(&self, input: B, output: &mut M) -> Result<usize, DecodeError>
349    where
350        B: Buf,
351        M: BufMut,
352    {
353        let decoded = self.decode_buf(input)?;
354        let len = decoded.len();
355        if output.remaining_mut() < len {
356            return Err(DecodeError::OutputTooSmall {
357                required: len,
358                available: output.remaining_mut(),
359            });
360        }
361        output.put_slice(&decoded);
362        Ok(len)
363    }
364
365    fn decode_buf_to_mut_limited<B, M>(
366        &self,
367        input: B,
368        output: &mut M,
369        max_input_len: usize,
370    ) -> Result<usize, BytesDecodeError>
371    where
372        B: Buf,
373        M: BufMut,
374    {
375        let decoded = self.decode_buf_limited(input, max_input_len)?;
376        let len = decoded.len();
377        if output.remaining_mut() < len {
378            return Err(BytesDecodeError::Decode(DecodeError::OutputTooSmall {
379                required: len,
380                available: output.remaining_mut(),
381            }));
382        }
383        output.put_slice(&decoded);
384        Ok(len)
385    }
386}
387
388fn collect_buf<B>(mut input: B) -> Vec<u8>
389where
390    B: Buf,
391{
392    let mut output = Vec::with_capacity(input.remaining());
393    while input.has_remaining() {
394        let chunk = input.chunk();
395        output.extend_from_slice(chunk);
396        let len = chunk.len();
397        input.advance(len);
398    }
399    output
400}
401
402fn collect_buf_limited<B>(input: B, max_input_len: usize) -> Result<Vec<u8>, (usize, usize)>
403where
404    B: Buf,
405{
406    let input_len = input.remaining();
407    if input_len > max_input_len {
408        return Err((input_len, max_input_len));
409    }
410
411    Ok(collect_buf(input))
412}