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/// Extension helpers for [`base64_ng::Engine`] and `bytes` buffers.
16pub trait EngineBytesExt<A, const PAD: bool>
17where
18    A: Alphabet,
19{
20    /// Encodes bytes into a [`Bytes`] value.
21    ///
22    /// # Errors
23    ///
24    /// Returns [`EncodeError`] if the encoded length overflows.
25    fn encode_bytes(&self, input: impl AsRef<[u8]>) -> Result<Bytes, EncodeError>;
26
27    /// Decodes Base64 bytes into a [`Bytes`] value.
28    ///
29    /// # Errors
30    ///
31    /// Returns [`DecodeError`] if decoding fails.
32    fn decode_bytes(&self, input: impl AsRef<[u8]>) -> Result<Bytes, DecodeError>;
33
34    /// Encodes all remaining bytes from `input` into a [`Bytes`] value.
35    ///
36    /// The input buffer is advanced to completion only after its current
37    /// chunks have been copied into a temporary contiguous buffer.
38    ///
39    /// # Errors
40    ///
41    /// Returns [`EncodeError`] if the encoded length overflows.
42    fn encode_buf<B>(&self, input: B) -> Result<Bytes, EncodeError>
43    where
44        B: Buf;
45
46    /// Decodes all remaining bytes from `input` into a [`Bytes`] value.
47    ///
48    /// # Errors
49    ///
50    /// Returns [`DecodeError`] if decoding fails.
51    fn decode_buf<B>(&self, input: B) -> Result<Bytes, DecodeError>
52    where
53        B: Buf;
54
55    /// Encodes all remaining bytes from `input` into `output`.
56    ///
57    /// # Errors
58    ///
59    /// Returns [`EncodeError::OutputTooSmall`] if `output` does not have enough
60    /// remaining mutable capacity.
61    fn encode_buf_to_mut<B, M>(&self, input: B, output: &mut M) -> Result<usize, EncodeError>
62    where
63        B: Buf,
64        M: BufMut;
65
66    /// Decodes all remaining Base64 bytes from `input` into `output`.
67    ///
68    /// # Errors
69    ///
70    /// Returns [`DecodeError::OutputTooSmall`] if `output` does not have enough
71    /// remaining mutable capacity, or another [`DecodeError`] if decoding
72    /// fails.
73    fn decode_buf_to_mut<B, M>(&self, input: B, output: &mut M) -> Result<usize, DecodeError>
74    where
75        B: Buf,
76        M: BufMut;
77}
78
79impl<A, const PAD: bool> EngineBytesExt<A, PAD> for Engine<A, PAD>
80where
81    A: Alphabet,
82{
83    fn encode_bytes(&self, input: impl AsRef<[u8]>) -> Result<Bytes, EncodeError> {
84        self.encode_vec(input.as_ref()).map(Bytes::from)
85    }
86
87    fn decode_bytes(&self, input: impl AsRef<[u8]>) -> Result<Bytes, DecodeError> {
88        self.decode_vec(input.as_ref()).map(Bytes::from)
89    }
90
91    fn encode_buf<B>(&self, input: B) -> Result<Bytes, EncodeError>
92    where
93        B: Buf,
94    {
95        self.encode_bytes(collect_buf(input))
96    }
97
98    fn decode_buf<B>(&self, input: B) -> Result<Bytes, DecodeError>
99    where
100        B: Buf,
101    {
102        self.decode_bytes(collect_buf(input))
103    }
104
105    fn encode_buf_to_mut<B, M>(&self, input: B, output: &mut M) -> Result<usize, EncodeError>
106    where
107        B: Buf,
108        M: BufMut,
109    {
110        let encoded = self.encode_buf(input)?;
111        let len = encoded.len();
112        if output.remaining_mut() < len {
113            return Err(EncodeError::OutputTooSmall {
114                required: len,
115                available: output.remaining_mut(),
116            });
117        }
118        output.put_slice(&encoded);
119        Ok(len)
120    }
121
122    fn decode_buf_to_mut<B, M>(&self, input: B, output: &mut M) -> Result<usize, DecodeError>
123    where
124        B: Buf,
125        M: BufMut,
126    {
127        let decoded = self.decode_buf(input)?;
128        let len = decoded.len();
129        if output.remaining_mut() < len {
130            return Err(DecodeError::OutputTooSmall {
131                required: len,
132                available: output.remaining_mut(),
133            });
134        }
135        output.put_slice(&decoded);
136        Ok(len)
137    }
138}
139
140fn collect_buf<B>(mut input: B) -> Vec<u8>
141where
142    B: Buf,
143{
144    let mut output = Vec::with_capacity(input.remaining());
145    while input.has_remaining() {
146        let chunk = input.chunk();
147        output.extend_from_slice(chunk);
148        let len = chunk.len();
149        input.advance(len);
150    }
151    output
152}