Skip to main content

base64_ng/stream/
encoder_reader.rs

1use super::{OutputQueue, encode_error_to_io, redacted_inner_state, stream_encoder_failed_error};
2use crate::{Alphabet, Engine};
3use std::io::{self, Read};
4
5/// A streaming Base64 encoder for `std::io::Read`.
6pub struct EncoderReader<R, A, const PAD: bool>
7where
8    A: Alphabet,
9{
10    inner: Option<R>,
11    engine: Engine<A, PAD>,
12    pending: [u8; 2],
13    pending_len: usize,
14    output: OutputQueue<1024>,
15    finished: bool,
16    failed: bool,
17}
18
19impl<R, A, const PAD: bool> EncoderReader<R, A, PAD>
20where
21    A: Alphabet,
22{
23    /// Creates a new streaming encoder reader.
24    #[must_use]
25    pub fn new(inner: R, engine: Engine<A, PAD>) -> Self {
26        Self {
27            inner: Some(inner),
28            engine,
29            pending: [0; 2],
30            pending_len: 0,
31            output: OutputQueue::new(),
32            finished: false,
33            failed: false,
34        }
35    }
36
37    /// Returns a shared reference to the wrapped reader.
38    #[must_use]
39    pub fn get_ref(&self) -> &R {
40        self.inner_ref()
41    }
42
43    /// Returns a mutable reference to the wrapped reader.
44    pub fn get_mut(&mut self) -> &mut R {
45        self.inner_mut()
46    }
47
48    /// Returns the Base64 engine used by this adapter.
49    #[must_use]
50    pub const fn engine(&self) -> Engine<A, PAD> {
51        self.engine
52    }
53
54    /// Returns whether this adapter uses padded Base64.
55    #[must_use]
56    pub const fn is_padded(&self) -> bool {
57        PAD
58    }
59
60    /// Returns the number of raw input bytes currently buffered until a
61    /// complete 3-byte Base64 encode quantum is available.
62    #[must_use]
63    pub const fn pending_len(&self) -> usize {
64        self.pending_len
65    }
66
67    /// Returns whether this encoder reader currently holds a partial input
68    /// quantum.
69    #[must_use]
70    pub const fn has_pending_input(&self) -> bool {
71        self.pending_len != 0
72    }
73
74    /// Returns how many additional raw input bytes are needed to complete
75    /// the currently buffered encode quantum.
76    ///
77    /// Returns `0` when no partial input quantum is buffered.
78    #[must_use]
79    pub const fn pending_input_needed_len(&self) -> usize {
80        if self.has_pending_input() {
81            3 - self.pending_len
82        } else {
83            0
84        }
85    }
86
87    /// Returns the number of encoded bytes currently buffered and ready to
88    /// be read before this adapter polls the wrapped reader again.
89    #[must_use]
90    pub const fn buffered_output_len(&self) -> usize {
91        self.output.len()
92    }
93
94    /// Returns the maximum number of encoded bytes this adapter can buffer
95    /// before returning bytes to the caller.
96    #[must_use]
97    pub const fn buffered_output_capacity(&self) -> usize {
98        self.output.capacity()
99    }
100
101    /// Returns how many more encoded bytes can be buffered before this
102    /// adapter must return bytes to the caller.
103    #[must_use]
104    pub const fn buffered_output_remaining_capacity(&self) -> usize {
105        self.output.available_capacity()
106    }
107
108    /// Returns whether this encoder reader currently has encoded output
109    /// waiting in its internal queue.
110    #[must_use]
111    pub const fn has_buffered_output(&self) -> bool {
112        !self.output.is_empty()
113    }
114
115    /// Returns whether this encoder reader has reached EOF in the wrapped
116    /// reader.
117    ///
118    /// This may become `true` before [`Self::is_finished`] when encoded
119    /// output is still buffered for the caller.
120    #[must_use]
121    pub const fn has_finished_input(&self) -> bool {
122        self.finished
123    }
124
125    /// Returns whether this reader has reached EOF and has no encoded
126    /// output buffered for the caller.
127    #[must_use]
128    pub const fn is_finished(&self) -> bool {
129        self.finished && self.output.is_empty()
130    }
131
132    /// Returns whether this adapter has failed closed after an internal
133    /// stream error.
134    #[must_use]
135    pub const fn is_failed(&self) -> bool {
136        self.failed
137    }
138
139    /// Returns whether [`Self::try_into_inner`] can recover the wrapped
140    /// reader without discarding pending input or buffered encoded output.
141    #[must_use]
142    pub const fn can_into_inner(&self) -> bool {
143        self.is_finished() && !self.failed
144    }
145
146    /// Consumes the encoder reader and returns the wrapped reader.
147    #[must_use]
148    pub fn into_inner(mut self) -> R {
149        self.take_inner()
150    }
151
152    /// Consumes the encoder reader only after the encoded stream is fully
153    /// drained.
154    ///
155    /// This is a checked alternative to [`Self::into_inner`] for callers
156    /// that want to avoid accidentally discarding pending input or encoded
157    /// output buffered inside the adapter.
158    #[allow(clippy::result_large_err)]
159    pub fn try_into_inner(mut self) -> Result<R, Self> {
160        if !self.can_into_inner() {
161            return Err(self);
162        }
163        Ok(self.take_inner())
164    }
165
166    fn inner_ref(&self) -> &R {
167        match &self.inner {
168            Some(inner) => inner,
169            None => unreachable!("stream encoder reader inner reader was already taken"),
170        }
171    }
172
173    fn inner_mut(&mut self) -> &mut R {
174        match &mut self.inner {
175            Some(inner) => inner,
176            None => unreachable!("stream encoder reader inner reader was already taken"),
177        }
178    }
179
180    fn take_inner(&mut self) -> R {
181        match self.inner.take() {
182            Some(inner) => inner,
183            None => unreachable!("stream encoder reader inner reader was already taken"),
184        }
185    }
186
187    fn clear_pending(&mut self) {
188        crate::wipe_bytes(&mut self.pending);
189        self.pending_len = 0;
190    }
191}
192
193impl<R, A, const PAD: bool> Drop for EncoderReader<R, A, PAD>
194where
195    A: Alphabet,
196{
197    fn drop(&mut self) {
198        self.clear_pending();
199        self.output.clear_all();
200    }
201}
202
203impl<R, A, const PAD: bool> core::fmt::Debug for EncoderReader<R, A, PAD>
204where
205    A: Alphabet,
206{
207    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
208        formatter
209            .debug_struct("EncoderReader")
210            .field("inner", &redacted_inner_state(self.inner.is_some()))
211            .field("engine", &self.engine)
212            .field("pending", &"<redacted>")
213            .field("pending_len", &self.pending_len)
214            .field("pending_input_needed_len", &self.pending_input_needed_len())
215            .field("buffered_output_len", &self.output.len())
216            .field("buffered_output_capacity", &self.output.capacity())
217            .field(
218                "buffered_output_remaining_capacity",
219                &self.output.available_capacity(),
220            )
221            .field("can_into_inner", &self.can_into_inner())
222            .field("finished", &self.finished)
223            .field("failed", &self.failed)
224            .finish()
225    }
226}
227
228impl<R, A, const PAD: bool> Read for EncoderReader<R, A, PAD>
229where
230    R: Read,
231    A: Alphabet,
232{
233    fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
234        if self.failed {
235            return Err(stream_encoder_failed_error());
236        }
237
238        if output.is_empty() {
239            return Ok(0);
240        }
241
242        while self.output.is_empty() && !self.finished {
243            self.fill_output()?;
244        }
245
246        Ok(self.output.pop_slice(output))
247    }
248}
249
250impl<R, A, const PAD: bool> EncoderReader<R, A, PAD>
251where
252    R: Read,
253    A: Alphabet,
254{
255    fn fill_output(&mut self) -> io::Result<()> {
256        let mut input = [0u8; 768];
257        let read = match self.inner_mut().read(&mut input) {
258            Ok(read) => read,
259            Err(err) => {
260                crate::wipe_bytes(&mut input);
261                return Err(err);
262            }
263        };
264        if read == 0 {
265            crate::wipe_bytes(&mut input);
266            self.finished = true;
267            if let Err(err) = self.push_final_pending() {
268                self.failed = true;
269                return Err(err);
270            }
271            return Ok(());
272        }
273
274        let mut consumed = 0;
275        if self.pending_len > 0 {
276            let needed = 3 - self.pending_len;
277            if read < needed {
278                self.pending[self.pending_len..self.pending_len + read]
279                    .copy_from_slice(&input[..read]);
280                self.pending_len += read;
281                crate::wipe_bytes(&mut input);
282                return Ok(());
283            }
284
285            let mut chunk = [0u8; 3];
286            chunk[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
287            chunk[self.pending_len..].copy_from_slice(&input[..needed]);
288            let result = self.push_encoded(&chunk);
289            crate::wipe_bytes(&mut chunk);
290            if let Err(err) = result {
291                crate::wipe_bytes(&mut input);
292                self.failed = true;
293                return Err(err);
294            }
295            self.clear_pending();
296            consumed += needed;
297        }
298
299        let remaining = &input[consumed..read];
300        let full_len = remaining.len() / 3 * 3;
301        let tail_len = remaining.len() - full_len;
302        let mut tail = [0u8; 2];
303        tail[..tail_len].copy_from_slice(&remaining[full_len..]);
304        let result = if full_len > 0 {
305            self.push_encoded(&remaining[..full_len])
306        } else {
307            Ok(())
308        };
309        crate::wipe_bytes(&mut input);
310        if let Err(err) = result {
311            crate::wipe_bytes(&mut tail);
312            self.failed = true;
313            return Err(err);
314        }
315        self.pending[..tail_len].copy_from_slice(&tail[..tail_len]);
316        crate::wipe_bytes(&mut tail);
317        self.pending_len = tail_len;
318        Ok(())
319    }
320
321    fn push_final_pending(&mut self) -> io::Result<()> {
322        if self.pending_len == 0 {
323            return Ok(());
324        }
325
326        let mut pending = [0u8; 2];
327        pending[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
328        let pending_len = self.pending_len;
329        self.clear_pending();
330        let result = self.push_encoded(&pending[..pending_len]);
331        crate::wipe_bytes(&mut pending);
332        result
333    }
334
335    fn push_encoded(&mut self, input: &[u8]) -> io::Result<()> {
336        let mut encoded = [0u8; 1024];
337        let written = match self.engine.encode_slice(input, &mut encoded) {
338            Ok(written) => written,
339            Err(err) => {
340                crate::wipe_bytes(&mut encoded);
341                return Err(encode_error_to_io(err));
342            }
343        };
344        let result = self.output.push_slice(&encoded[..written]);
345        crate::wipe_bytes(&mut encoded);
346        result
347    }
348}