Skip to main content

base64_ng/
stream.rs

1//! Streaming Base64 wrappers for `std::io`.
2//!
3//! Decoder adapters fail closed after malformed Base64 input. Use
4//! `is_failed()` for diagnostics; unchecked `into_inner()` remains
5//! available when the wrapped reader or writer must be explicitly
6//! recovered after a decode error.
7//!
8//! ```
9//! use std::io::{Read, Write};
10//! use base64_ng::{STANDARD, stream::{Decoder, DecoderReader, Encoder, EncoderReader}};
11//!
12//! let mut encoder = Encoder::new(Vec::new(), STANDARD);
13//! encoder.write_all(b"he").unwrap();
14//! encoder.write_all(b"llo").unwrap();
15//! let encoded = encoder.finish().unwrap();
16//! assert_eq!(encoded, b"aGVsbG8=");
17//!
18//! let mut reader = EncoderReader::new(&b"hello"[..], STANDARD);
19//! let mut encoded = String::new();
20//! reader.read_to_string(&mut encoded).unwrap();
21//! assert_eq!(encoded, "aGVsbG8=");
22//!
23//! let mut decoder = Decoder::new(Vec::new(), STANDARD);
24//! decoder.write_all(b"aGVs").unwrap();
25//! decoder.write_all(b"bG8=").unwrap();
26//! let decoded = decoder.finish().unwrap();
27//! assert_eq!(decoded, b"hello");
28//!
29//! let mut reader = DecoderReader::new(&b"aGVsbG8="[..], STANDARD);
30//! let mut decoded = Vec::new();
31//! reader.read_to_end(&mut decoded).unwrap();
32//! assert_eq!(decoded, b"hello");
33//! ```
34
35use super::{Alphabet, DecodeError, EncodeError, Engine};
36use std::io::{self, Read, Write};
37
38struct OutputQueue<const CAP: usize> {
39    buffer: [u8; CAP],
40    start: usize,
41    len: usize,
42}
43
44impl<const CAP: usize> OutputQueue<CAP> {
45    const fn new() -> Self {
46        Self {
47            buffer: [0; CAP],
48            start: 0,
49            len: 0,
50        }
51    }
52
53    const fn is_empty(&self) -> bool {
54        self.len == 0
55    }
56
57    const fn len(&self) -> usize {
58        self.len
59    }
60
61    const fn capacity(&self) -> usize {
62        self.len + self.available_capacity()
63    }
64
65    fn push_slice(&mut self, input: &[u8]) -> io::Result<()> {
66        if input.len() > self.available_capacity() {
67            return Err(io::Error::other(
68                "base64 stream output queue capacity exceeded",
69            ));
70        }
71
72        let mut read = 0;
73        while read < input.len() {
74            let write = (self.start + self.len) % CAP;
75            self.buffer[write] = input[read];
76            self.len += 1;
77            read += 1;
78        }
79
80        Ok(())
81    }
82
83    fn copy_front(&self, output: &mut [u8]) -> usize {
84        let count = core::cmp::min(self.len, output.len());
85        let first = core::cmp::min(count, CAP - self.start);
86        output[..first].copy_from_slice(&self.buffer[self.start..self.start + first]);
87
88        let second = count - first;
89        if second > 0 {
90            output[first..first + second].copy_from_slice(&self.buffer[..second]);
91        }
92
93        count
94    }
95
96    fn discard_front(&mut self, count: usize) {
97        let count = core::cmp::min(count, self.len);
98        let first = core::cmp::min(count, CAP - self.start);
99        crate::wipe_bytes(&mut self.buffer[self.start..self.start + first]);
100
101        let second = count - first;
102        if second > 0 {
103            crate::wipe_bytes(&mut self.buffer[..second]);
104        }
105
106        self.start = (self.start + count) % CAP;
107        self.len -= count;
108        if self.len == 0 {
109            self.start = 0;
110        }
111    }
112
113    fn pop_slice(&mut self, output: &mut [u8]) -> usize {
114        let count = self.copy_front(output);
115        self.discard_front(count);
116        count
117    }
118
119    fn clear_all(&mut self) {
120        crate::wipe_bytes(&mut self.buffer);
121        self.start = 0;
122        self.len = 0;
123    }
124
125    const fn available_capacity(&self) -> usize {
126        CAP - self.len
127    }
128}
129
130/// A streaming Base64 encoder for `std::io::Write`.
131///
132/// Like any [`Write`] implementation, [`Write::write`] may accept only
133/// part of the provided input. Accepted input may be held as encoded
134/// output until [`Write::flush`], [`Self::try_finish`], [`Self::finish`],
135/// or a later write drains the wrapped writer. Use [`Write::write_all`]
136/// when the whole input slice must be consumed.
137pub struct Encoder<W, A, const PAD: bool>
138where
139    A: Alphabet,
140{
141    inner: Option<W>,
142    engine: Engine<A, PAD>,
143    pending: [u8; 2],
144    pending_len: usize,
145    output: OutputQueue<1024>,
146    finalized: bool,
147}
148
149impl<W, A, const PAD: bool> Encoder<W, A, PAD>
150where
151    A: Alphabet,
152{
153    /// Creates a new streaming encoder.
154    #[must_use]
155    pub const fn new(inner: W, engine: Engine<A, PAD>) -> Self {
156        Self {
157            inner: Some(inner),
158            engine,
159            pending: [0; 2],
160            pending_len: 0,
161            output: OutputQueue::new(),
162            finalized: false,
163        }
164    }
165
166    /// Returns a shared reference to the wrapped writer.
167    #[must_use]
168    pub fn get_ref(&self) -> &W {
169        self.inner_ref()
170    }
171
172    /// Returns a mutable reference to the wrapped writer.
173    pub fn get_mut(&mut self) -> &mut W {
174        self.inner_mut()
175    }
176
177    /// Returns the Base64 engine used by this adapter.
178    #[must_use]
179    pub const fn engine(&self) -> Engine<A, PAD> {
180        self.engine
181    }
182
183    /// Returns whether this adapter uses padded Base64.
184    #[must_use]
185    pub const fn is_padded(&self) -> bool {
186        PAD
187    }
188
189    /// Returns the number of raw input bytes currently buffered until a
190    /// complete 3-byte Base64 encode quantum is available.
191    #[must_use]
192    pub const fn pending_len(&self) -> usize {
193        self.pending_len
194    }
195
196    /// Returns whether this encoder currently holds a partial input
197    /// quantum.
198    #[must_use]
199    pub const fn has_pending_input(&self) -> bool {
200        self.pending_len != 0
201    }
202
203    /// Returns how many additional input bytes are needed to complete the
204    /// currently buffered encode quantum.
205    ///
206    /// Returns `0` when no partial input quantum is buffered.
207    #[must_use]
208    pub const fn pending_input_needed_len(&self) -> usize {
209        if self.has_pending_input() {
210            3 - self.pending_len
211        } else {
212            0
213        }
214    }
215
216    /// Returns the number of encoded bytes buffered for the wrapped
217    /// writer after a previous write or flush could not fully drain them.
218    #[must_use]
219    pub const fn buffered_output_len(&self) -> usize {
220        self.output.len()
221    }
222
223    /// Returns the maximum number of encoded bytes this adapter can buffer
224    /// before returning bytes to the caller.
225    #[must_use]
226    pub const fn buffered_output_capacity(&self) -> usize {
227        self.output.capacity()
228    }
229
230    /// Returns how many more encoded bytes can be buffered before this
231    /// adapter must drain the wrapped writer.
232    #[must_use]
233    pub const fn buffered_output_remaining_capacity(&self) -> usize {
234        self.output.available_capacity()
235    }
236
237    /// Returns whether this encoder has encoded output waiting to be
238    /// written to the wrapped writer.
239    #[must_use]
240    pub const fn has_buffered_output(&self) -> bool {
241        !self.output.is_empty()
242    }
243
244    /// Returns whether this encoder has been finalized.
245    ///
246    /// Once this returns `true`, later writes return an error.
247    #[must_use]
248    pub const fn is_finalized(&self) -> bool {
249        self.finalized
250    }
251
252    /// Returns whether [`Self::try_into_inner`] can recover the wrapped
253    /// writer without discarding pending input.
254    #[must_use]
255    pub const fn can_into_inner(&self) -> bool {
256        !self.has_pending_input() && !self.has_buffered_output()
257    }
258
259    /// Consumes the encoder without flushing pending input.
260    ///
261    /// Prefer [`Self::finish`] when the encoded output must be complete.
262    #[must_use]
263    pub fn into_inner(mut self) -> W {
264        self.take_inner()
265    }
266
267    /// Consumes the encoder only when no partial input quantum is buffered.
268    ///
269    /// This does not flush or finalize the wrapped writer. It is a checked
270    /// alternative to [`Self::into_inner`] for callers that want to avoid
271    /// accidentally discarding pending input bytes.
272    #[allow(clippy::result_large_err)]
273    pub fn try_into_inner(mut self) -> Result<W, Self> {
274        if !self.can_into_inner() {
275            return Err(self);
276        }
277        Ok(self.take_inner())
278    }
279
280    fn inner_ref(&self) -> &W {
281        match &self.inner {
282            Some(inner) => inner,
283            None => unreachable!("stream encoder inner writer was already taken"),
284        }
285    }
286
287    fn inner_mut(&mut self) -> &mut W {
288        match &mut self.inner {
289            Some(inner) => inner,
290            None => unreachable!("stream encoder inner writer was already taken"),
291        }
292    }
293
294    fn take_inner(&mut self) -> W {
295        match self.inner.take() {
296            Some(inner) => inner,
297            None => unreachable!("stream encoder inner writer was already taken"),
298        }
299    }
300
301    fn clear_pending(&mut self) {
302        crate::wipe_bytes(&mut self.pending);
303        self.pending_len = 0;
304    }
305
306    fn clear_output(&mut self) {
307        self.output.clear_all();
308    }
309}
310
311impl<W, A, const PAD: bool> Drop for Encoder<W, A, PAD>
312where
313    A: Alphabet,
314{
315    fn drop(&mut self) {
316        self.clear_pending();
317        self.clear_output();
318    }
319}
320
321impl<W, A, const PAD: bool> core::fmt::Debug for Encoder<W, A, PAD>
322where
323    A: Alphabet,
324{
325    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
326        formatter
327            .debug_struct("Encoder")
328            .field("inner", &redacted_inner_state(self.inner.is_some()))
329            .field("engine", &self.engine)
330            .field("pending", &"<redacted>")
331            .field("pending_len", &self.pending_len)
332            .field("pending_input_needed_len", &self.pending_input_needed_len())
333            .field("buffered_output_len", &self.output.len())
334            .field("buffered_output_capacity", &self.output.capacity())
335            .field(
336                "buffered_output_remaining_capacity",
337                &self.output.available_capacity(),
338            )
339            .field("can_into_inner", &self.can_into_inner())
340            .field("finalized", &self.finalized)
341            .finish()
342    }
343}
344
345impl<W, A, const PAD: bool> Encoder<W, A, PAD>
346where
347    W: Write,
348    A: Alphabet,
349{
350    /// Writes any pending input and flushes the wrapped writer without
351    /// consuming this encoder.
352    ///
353    /// After this succeeds, [`Self::pending_len`] returns `0`, later
354    /// writes are rejected, and [`Self::finish`] can still be used to
355    /// recover the wrapped writer.
356    /// This is useful when a caller needs to finalize a framed payload
357    /// while keeping the stream adapter available for diagnostics or
358    /// explicit recovery.
359    pub fn try_finish(&mut self) -> io::Result<()> {
360        if !self.finalized {
361            self.queue_pending_final()?;
362            self.finalized = true;
363        }
364        self.flush()
365    }
366
367    /// Writes any pending input, flushes the wrapped writer, and returns it.
368    pub fn finish(mut self) -> io::Result<W> {
369        self.try_finish()?;
370        Ok(self.take_inner())
371    }
372
373    fn queue_pending_final(&mut self) -> io::Result<()> {
374        if self.pending_len == 0 {
375            return Ok(());
376        }
377
378        let mut pending = [0u8; 2];
379        pending[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
380        let pending_len = self.pending_len;
381        let mut encoded = [0u8; 4];
382        let result = self.queue_encoded_temp(&pending[..pending_len], &mut encoded);
383        crate::wipe_bytes(&mut pending);
384        result?;
385        self.clear_pending();
386        Ok(())
387    }
388
389    fn queue_encoded_temp(&mut self, input: &[u8], encoded: &mut [u8]) -> io::Result<()> {
390        let written = match self.engine.encode_slice(input, encoded) {
391            Ok(written) => written,
392            Err(err) => {
393                crate::wipe_bytes(encoded);
394                return Err(encode_error_to_io(err));
395            }
396        };
397
398        let result = self.output.push_slice(&encoded[..written]);
399        crate::wipe_bytes(encoded);
400        result
401    }
402
403    fn drain_output(&mut self) -> io::Result<()> {
404        let mut chunk = [0u8; 1024];
405        while !self.output.is_empty() {
406            let pending = self.output.copy_front(&mut chunk);
407            let result = self.inner_mut().write(&chunk[..pending]);
408            crate::wipe_bytes(&mut chunk[..pending]);
409            match result {
410                Ok(0) => {
411                    return Err(io::Error::new(
412                        io::ErrorKind::WriteZero,
413                        "base64 stream encoder could not drain buffered output",
414                    ));
415                }
416                Ok(written) => {
417                    if written > pending {
418                        return Err(io::Error::new(
419                            io::ErrorKind::InvalidData,
420                            "wrapped writer reported more bytes than provided",
421                        ));
422                    }
423                    self.output.discard_front(written);
424                }
425                Err(err) => return Err(err),
426            }
427        }
428
429        Ok(())
430    }
431}
432
433impl<W, A, const PAD: bool> Write for Encoder<W, A, PAD>
434where
435    W: Write,
436    A: Alphabet,
437{
438    fn write(&mut self, input: &[u8]) -> io::Result<usize> {
439        self.drain_output()?;
440        if self.finalized {
441            return Err(io::Error::new(
442                io::ErrorKind::InvalidInput,
443                "base64 stream encoder received input after finalization",
444            ));
445        }
446        if input.is_empty() {
447            return Ok(0);
448        }
449
450        let mut consumed = 0;
451        if self.pending_len > 0 {
452            let needed = 3 - self.pending_len;
453            if input.len() < needed {
454                self.pending[self.pending_len..self.pending_len + input.len()]
455                    .copy_from_slice(input);
456                self.pending_len += input.len();
457                return Ok(input.len());
458            }
459
460            let mut chunk = [0u8; 3];
461            chunk[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
462            chunk[self.pending_len..].copy_from_slice(&input[..needed]);
463
464            let mut encoded = [0u8; 4];
465            let result = self.queue_encoded_temp(&chunk, &mut encoded);
466            crate::wipe_bytes(&mut chunk);
467            result?;
468            self.clear_pending();
469            consumed += needed;
470        }
471
472        let remaining = &input[consumed..];
473        let full_len = remaining.len() / 3 * 3;
474        if full_len > 0 {
475            let max_by_queue = self.output.available_capacity() / 4 * 3;
476            let mut take = core::cmp::min(full_len, core::cmp::min(768, max_by_queue));
477            take -= take % 3;
478
479            if take == 0 {
480                return Ok(consumed);
481            }
482
483            let mut encoded = [0u8; 1024];
484            self.queue_encoded_temp(&remaining[..take], &mut encoded)?;
485            consumed += take;
486
487            if take < full_len {
488                return Ok(consumed);
489            }
490        }
491
492        let tail = &input[consumed..];
493        self.pending[..tail.len()].copy_from_slice(tail);
494        self.pending_len = tail.len();
495        consumed += tail.len();
496
497        Ok(consumed)
498    }
499
500    fn flush(&mut self) -> io::Result<()> {
501        self.drain_output()?;
502        self.inner_mut().flush()
503    }
504}
505
506fn encode_error_to_io(err: EncodeError) -> io::Error {
507    io::Error::new(io::ErrorKind::InvalidInput, err)
508}
509
510/// A streaming Base64 decoder for `std::io::Write`.
511///
512/// Like any [`Write`] implementation, [`Write::write`] may accept only
513/// part of the provided input. Accepted input may be held as decoded
514/// output until [`Write::flush`], [`Self::try_finish`], [`Self::finish`],
515/// or a later write drains the wrapped writer. Use [`Write::write_all`]
516/// when the whole input slice must be consumed.
517///
518/// # Security
519///
520/// This adapter uses the normal strict decoder, not the [`crate::ct`]
521/// module. It may branch or return early based on malformed input and it
522/// preserves strict error diagnostics. Do not use it for secret-bearing
523/// payloads when malformed-input timing matters; decode a complete frame
524/// with the matching `ct` engine instead.
525pub struct Decoder<W, A, const PAD: bool>
526where
527    A: Alphabet,
528{
529    inner: Option<W>,
530    engine: Engine<A, PAD>,
531    pending: [u8; 4],
532    pending_len: usize,
533    output: OutputQueue<1024>,
534    finished: bool,
535    failed: bool,
536    finalized: bool,
537}
538
539impl<W, A, const PAD: bool> Decoder<W, A, PAD>
540where
541    A: Alphabet,
542{
543    /// Creates a new streaming decoder.
544    ///
545    /// # Security
546    ///
547    /// Streaming decoders use the normal strict decode path. They are not
548    /// constant-time-oriented secret decoders.
549    #[must_use]
550    pub const fn new(inner: W, engine: Engine<A, PAD>) -> Self {
551        Self {
552            inner: Some(inner),
553            engine,
554            pending: [0; 4],
555            pending_len: 0,
556            output: OutputQueue::new(),
557            finished: false,
558            finalized: false,
559            failed: false,
560        }
561    }
562
563    /// Returns a shared reference to the wrapped writer.
564    #[must_use]
565    pub fn get_ref(&self) -> &W {
566        self.inner_ref()
567    }
568
569    /// Returns a mutable reference to the wrapped writer.
570    pub fn get_mut(&mut self) -> &mut W {
571        self.inner_mut()
572    }
573
574    /// Returns the Base64 engine used by this adapter.
575    #[must_use]
576    pub const fn engine(&self) -> Engine<A, PAD> {
577        self.engine
578    }
579
580    /// Returns whether this adapter uses padded Base64.
581    #[must_use]
582    pub const fn is_padded(&self) -> bool {
583        PAD
584    }
585
586    /// Returns the number of encoded input bytes currently buffered until
587    /// a complete 4-byte Base64 decode quantum is available.
588    #[must_use]
589    pub const fn pending_len(&self) -> usize {
590        self.pending_len
591    }
592
593    /// Returns whether this decoder currently holds a partial input
594    /// quantum.
595    #[must_use]
596    pub const fn has_pending_input(&self) -> bool {
597        self.pending_len != 0
598    }
599
600    /// Returns how many additional input bytes are needed to complete the
601    /// currently buffered decode quantum.
602    ///
603    /// Returns `0` when no partial input quantum is buffered.
604    #[must_use]
605    pub const fn pending_input_needed_len(&self) -> usize {
606        if self.has_pending_input() {
607            4 - self.pending_len
608        } else {
609            0
610        }
611    }
612
613    /// Returns the number of decoded bytes buffered for the wrapped writer
614    /// after a previous write or flush could not fully drain them.
615    #[must_use]
616    pub const fn buffered_output_len(&self) -> usize {
617        self.output.len()
618    }
619
620    /// Returns the maximum number of decoded bytes this adapter can buffer
621    /// before returning bytes to the caller.
622    #[must_use]
623    pub const fn buffered_output_capacity(&self) -> usize {
624        self.output.capacity()
625    }
626
627    /// Returns how many more decoded bytes can be buffered before this
628    /// adapter must drain the wrapped writer.
629    #[must_use]
630    pub const fn buffered_output_remaining_capacity(&self) -> usize {
631        self.output.available_capacity()
632    }
633
634    /// Returns whether this decoder has decoded output waiting to be
635    /// written to the wrapped writer.
636    #[must_use]
637    pub const fn has_buffered_output(&self) -> bool {
638        !self.output.is_empty()
639    }
640
641    /// Returns whether this decoder has processed a terminal padded block.
642    ///
643    /// Once this returns `true`, later calls to [`Write::write`] with
644    /// additional input return an error because strict Base64 does not
645    /// permit trailing payload bytes after padding.
646    #[must_use]
647    pub const fn has_terminal_padding(&self) -> bool {
648        self.finished
649    }
650
651    /// Returns whether this decoder has been finalized.
652    ///
653    /// Once this returns `true`, later non-empty writes return an error.
654    #[must_use]
655    pub const fn is_finalized(&self) -> bool {
656        self.finalized
657    }
658
659    /// Returns whether this decoder has rejected malformed Base64 input.
660    ///
661    /// Once this returns `true`, later writes, flushes, and finalization
662    /// attempts return an error. The unchecked [`Self::into_inner`] method
663    /// can still be used for explicit recovery of the wrapped writer.
664    #[must_use]
665    pub const fn is_failed(&self) -> bool {
666        self.failed
667    }
668
669    /// Returns whether [`Self::try_into_inner`] can recover the wrapped
670    /// writer without discarding pending encoded input.
671    #[must_use]
672    pub const fn can_into_inner(&self) -> bool {
673        !self.is_failed() && !self.has_pending_input() && !self.has_buffered_output()
674    }
675
676    /// Consumes the decoder without flushing pending input.
677    ///
678    /// Prefer [`Self::finish`] when the decoded output must be complete.
679    #[must_use]
680    pub fn into_inner(mut self) -> W {
681        self.take_inner()
682    }
683
684    /// Consumes the decoder only when no partial input quantum is buffered.
685    ///
686    /// This does not flush or finalize the wrapped writer. It is a checked
687    /// alternative to [`Self::into_inner`] for callers that want to avoid
688    /// accidentally discarding pending encoded input bytes.
689    #[allow(clippy::result_large_err)]
690    pub fn try_into_inner(mut self) -> Result<W, Self> {
691        if !self.can_into_inner() {
692            return Err(self);
693        }
694        Ok(self.take_inner())
695    }
696
697    fn inner_ref(&self) -> &W {
698        match &self.inner {
699            Some(inner) => inner,
700            None => unreachable!("stream decoder inner writer was already taken"),
701        }
702    }
703
704    fn inner_mut(&mut self) -> &mut W {
705        match &mut self.inner {
706            Some(inner) => inner,
707            None => unreachable!("stream decoder inner writer was already taken"),
708        }
709    }
710
711    fn take_inner(&mut self) -> W {
712        match self.inner.take() {
713            Some(inner) => inner,
714            None => unreachable!("stream decoder inner writer was already taken"),
715        }
716    }
717
718    fn clear_pending(&mut self) {
719        crate::wipe_bytes(&mut self.pending);
720        self.pending_len = 0;
721    }
722
723    fn clear_output(&mut self) {
724        self.output.clear_all();
725    }
726}
727
728impl<W, A, const PAD: bool> Drop for Decoder<W, A, PAD>
729where
730    A: Alphabet,
731{
732    fn drop(&mut self) {
733        self.clear_pending();
734        self.clear_output();
735    }
736}
737
738impl<W, A, const PAD: bool> core::fmt::Debug for Decoder<W, A, PAD>
739where
740    A: Alphabet,
741{
742    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
743        formatter
744            .debug_struct("Decoder")
745            .field("inner", &redacted_inner_state(self.inner.is_some()))
746            .field("engine", &self.engine)
747            .field("pending", &"<redacted>")
748            .field("pending_len", &self.pending_len)
749            .field("pending_input_needed_len", &self.pending_input_needed_len())
750            .field("buffered_output_len", &self.output.len())
751            .field("buffered_output_capacity", &self.output.capacity())
752            .field(
753                "buffered_output_remaining_capacity",
754                &self.output.available_capacity(),
755            )
756            .field("can_into_inner", &self.can_into_inner())
757            .field("terminal_padding", &self.finished)
758            .field("finalized", &self.finalized)
759            .field("failed", &self.failed)
760            .finish()
761    }
762}
763
764impl<W, A, const PAD: bool> Decoder<W, A, PAD>
765where
766    W: Write,
767    A: Alphabet,
768{
769    /// Validates any final pending input and flushes the wrapped writer
770    /// without consuming this decoder.
771    ///
772    /// After this succeeds, [`Self::pending_len`] returns `0`, later
773    /// writes are rejected, and [`Self::finish`] can still be used to
774    /// recover the wrapped writer.
775    /// If the final buffered input is malformed, an error is returned and
776    /// the caller still owns the decoder for diagnostics or explicit
777    /// recovery.
778    pub fn try_finish(&mut self) -> io::Result<()> {
779        if self.failed {
780            return Err(stream_decoder_failed_error());
781        }
782        if !self.finalized {
783            self.queue_pending_final()?;
784            self.finalized = true;
785        }
786        self.flush()
787    }
788
789    /// Validates final pending input, flushes the wrapped writer, and returns it.
790    pub fn finish(mut self) -> io::Result<W> {
791        self.try_finish()?;
792        Ok(self.take_inner())
793    }
794
795    fn queue_pending_final(&mut self) -> io::Result<()> {
796        if self.pending_len == 0 {
797            return Ok(());
798        }
799
800        let mut pending = [0u8; 4];
801        pending[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
802        let pending_len = self.pending_len;
803        let mut decoded = [0u8; 3];
804        let result = self.queue_decoded_temp(&pending[..pending_len], &mut decoded);
805        crate::wipe_bytes(&mut pending);
806        if let Err(err) = result {
807            self.clear_pending();
808            return Err(err);
809        }
810        self.clear_pending();
811        Ok(())
812    }
813
814    fn queue_full_quad(&mut self, mut input: [u8; 4]) -> io::Result<()> {
815        let mut decoded = [0u8; 3];
816        let result = self.queue_decoded_temp(&input, &mut decoded);
817        crate::wipe_bytes(&mut input);
818        let written = result?;
819        if written < 3 {
820            self.finished = true;
821        }
822        Ok(())
823    }
824
825    fn queue_decoded_temp(&mut self, input: &[u8], decoded: &mut [u8]) -> io::Result<usize> {
826        let written = match self.engine.decode_slice(input, decoded) {
827            Ok(written) => written,
828            Err(err) => {
829                crate::wipe_bytes(decoded);
830                self.failed = true;
831                return Err(decode_error_to_io(err));
832            }
833        };
834
835        let result = self.output.push_slice(&decoded[..written]);
836        crate::wipe_bytes(decoded);
837        result?;
838        Ok(written)
839    }
840
841    fn drain_output(&mut self) -> io::Result<()> {
842        let mut chunk = [0u8; 1024];
843        while !self.output.is_empty() {
844            let pending = self.output.copy_front(&mut chunk);
845            let result = self.inner_mut().write(&chunk[..pending]);
846            crate::wipe_bytes(&mut chunk[..pending]);
847            match result {
848                Ok(0) => {
849                    return Err(io::Error::new(
850                        io::ErrorKind::WriteZero,
851                        "base64 stream decoder could not drain buffered output",
852                    ));
853                }
854                Ok(written) => {
855                    if written > pending {
856                        return Err(io::Error::new(
857                            io::ErrorKind::InvalidData,
858                            "wrapped writer reported more bytes than provided",
859                        ));
860                    }
861                    self.output.discard_front(written);
862                }
863                Err(err) => return Err(err),
864            }
865        }
866
867        Ok(())
868    }
869}
870
871impl<W, A, const PAD: bool> Write for Decoder<W, A, PAD>
872where
873    W: Write,
874    A: Alphabet,
875{
876    fn write(&mut self, input: &[u8]) -> io::Result<usize> {
877        if self.failed {
878            return Err(stream_decoder_failed_error());
879        }
880        if input.is_empty() {
881            self.drain_output()?;
882            return Ok(0);
883        }
884        self.drain_output()?;
885        if self.finalized {
886            return Err(io::Error::new(
887                io::ErrorKind::InvalidInput,
888                "base64 stream decoder received input after finalization",
889            ));
890        }
891        if self.finished {
892            self.failed = true;
893            return Err(trailing_input_after_padding_error());
894        }
895
896        let mut consumed = 0;
897        if self.pending_len > 0 {
898            let needed = 4 - self.pending_len;
899            if input.len() < needed {
900                self.pending[self.pending_len..self.pending_len + input.len()]
901                    .copy_from_slice(input);
902                self.pending_len += input.len();
903                return Ok(input.len());
904            }
905
906            let mut quad = [0u8; 4];
907            quad[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
908            quad[self.pending_len..].copy_from_slice(&input[..needed]);
909            let result = self.queue_full_quad(quad);
910            crate::wipe_bytes(&mut quad);
911            if let Err(err) = result {
912                self.clear_pending();
913                return Err(err);
914            }
915            self.clear_pending();
916            consumed += needed;
917
918            if self.finished {
919                return Ok(consumed);
920            }
921        }
922
923        while input.len() - consumed >= 4 {
924            if self.output.available_capacity() < 3 {
925                return Ok(consumed);
926            }
927
928            let mut quad = [
929                input[consumed],
930                input[consumed + 1],
931                input[consumed + 2],
932                input[consumed + 3],
933            ];
934            let mut decoded = [0u8; 3];
935            let written = match self.engine.decode_slice(&quad, &mut decoded) {
936                Ok(written) => written,
937                Err(err) => {
938                    crate::wipe_bytes(&mut quad);
939                    crate::wipe_bytes(&mut decoded);
940                    self.failed = true;
941                    if consumed > 0 {
942                        return Ok(consumed);
943                    }
944
945                    return Err(decode_error_to_io(err));
946                }
947            };
948
949            let result = self.output.push_slice(&decoded[..written]);
950            crate::wipe_bytes(&mut quad);
951            crate::wipe_bytes(&mut decoded);
952            result?;
953            consumed += 4;
954
955            if written < 3 {
956                self.finished = true;
957                return Ok(consumed);
958            }
959        }
960
961        let tail = &input[consumed..];
962        self.pending[..tail.len()].copy_from_slice(tail);
963        self.pending_len = tail.len();
964        consumed += tail.len();
965
966        Ok(consumed)
967    }
968
969    fn flush(&mut self) -> io::Result<()> {
970        if self.failed {
971            return Err(stream_decoder_failed_error());
972        }
973        self.drain_output()?;
974        self.inner_mut().flush()
975    }
976}
977
978fn decode_error_to_io(err: DecodeError) -> io::Error {
979    io::Error::new(io::ErrorKind::InvalidInput, err)
980}
981
982fn trailing_input_after_padding_error() -> io::Error {
983    io::Error::new(
984        io::ErrorKind::InvalidInput,
985        "base64 decoder received trailing input after padding",
986    )
987}
988
989fn stream_decoder_failed_error() -> io::Error {
990    io::Error::new(
991        io::ErrorKind::InvalidInput,
992        "base64 stream decoder is failed after malformed input",
993    )
994}
995
996fn stream_encoder_failed_error() -> io::Error {
997    io::Error::new(
998        io::ErrorKind::InvalidInput,
999        "base64 stream encoder is failed after internal error",
1000    )
1001}
1002
1003/// A streaming Base64 decoder for `std::io::Read`.
1004///
1005/// For padded engines, this reader stops at the terminal padded Base64
1006/// block and leaves later bytes unread in the wrapped reader. This preserves
1007/// boundaries for callers that decode one Base64 payload from a larger
1008/// stream.
1009///
1010/// # Security
1011///
1012/// This adapter uses the normal strict decoder, not the [`crate::ct`]
1013/// module. It may branch or return early based on malformed input and it
1014/// preserves strict error diagnostics. Do not use it for secret-bearing
1015/// payloads when malformed-input timing matters; decode a complete frame
1016/// with the matching `ct` engine instead.
1017pub struct DecoderReader<R, A, const PAD: bool>
1018where
1019    A: Alphabet,
1020{
1021    inner: Option<R>,
1022    engine: Engine<A, PAD>,
1023    pending: [u8; 4],
1024    pending_len: usize,
1025    output: OutputQueue<3>,
1026    finished: bool,
1027    terminal_seen: bool,
1028    failed: bool,
1029}
1030
1031impl<R, A, const PAD: bool> DecoderReader<R, A, PAD>
1032where
1033    A: Alphabet,
1034{
1035    /// Creates a new streaming decoder reader.
1036    ///
1037    /// # Security
1038    ///
1039    /// Streaming decoder readers use the normal strict decode path. They
1040    /// are not constant-time-oriented secret decoders.
1041    #[must_use]
1042    pub fn new(inner: R, engine: Engine<A, PAD>) -> Self {
1043        Self {
1044            inner: Some(inner),
1045            engine,
1046            pending: [0; 4],
1047            pending_len: 0,
1048            output: OutputQueue::new(),
1049            finished: false,
1050            terminal_seen: false,
1051            failed: false,
1052        }
1053    }
1054
1055    /// Returns a shared reference to the wrapped reader.
1056    #[must_use]
1057    pub fn get_ref(&self) -> &R {
1058        self.inner_ref()
1059    }
1060
1061    /// Returns a mutable reference to the wrapped reader.
1062    pub fn get_mut(&mut self) -> &mut R {
1063        self.inner_mut()
1064    }
1065
1066    /// Returns the Base64 engine used by this adapter.
1067    #[must_use]
1068    pub const fn engine(&self) -> Engine<A, PAD> {
1069        self.engine
1070    }
1071
1072    /// Returns whether this adapter uses padded Base64.
1073    #[must_use]
1074    pub const fn is_padded(&self) -> bool {
1075        PAD
1076    }
1077
1078    /// Returns the number of encoded input bytes currently buffered until
1079    /// a complete 4-byte Base64 decode quantum is available.
1080    #[must_use]
1081    pub const fn pending_len(&self) -> usize {
1082        self.pending_len
1083    }
1084
1085    /// Returns whether this decoder reader currently holds a partial input
1086    /// quantum.
1087    #[must_use]
1088    pub const fn has_pending_input(&self) -> bool {
1089        self.pending_len != 0
1090    }
1091
1092    /// Returns how many additional encoded input bytes are needed to
1093    /// complete the currently buffered decode quantum.
1094    ///
1095    /// Returns `0` when no partial input quantum is buffered.
1096    #[must_use]
1097    pub const fn pending_input_needed_len(&self) -> usize {
1098        if self.has_pending_input() {
1099            4 - self.pending_len
1100        } else {
1101            0
1102        }
1103    }
1104
1105    /// Returns the number of decoded bytes currently buffered and ready to
1106    /// be read before this adapter polls the wrapped reader again.
1107    #[must_use]
1108    pub const fn buffered_output_len(&self) -> usize {
1109        self.output.len()
1110    }
1111
1112    /// Returns the maximum number of decoded bytes this adapter can buffer
1113    /// before returning bytes to the caller.
1114    #[must_use]
1115    pub const fn buffered_output_capacity(&self) -> usize {
1116        self.output.capacity()
1117    }
1118
1119    /// Returns how many more decoded bytes can be buffered before this
1120    /// adapter must return bytes to the caller.
1121    #[must_use]
1122    pub const fn buffered_output_remaining_capacity(&self) -> usize {
1123        self.output.available_capacity()
1124    }
1125
1126    /// Returns whether this decoder reader currently has decoded output
1127    /// waiting in its internal queue.
1128    #[must_use]
1129    pub const fn has_buffered_output(&self) -> bool {
1130        !self.output.is_empty()
1131    }
1132
1133    /// Returns whether this decoder reader has seen terminal padding.
1134    ///
1135    /// For padded engines, this becomes `true` after the terminal padded
1136    /// block is decoded. The wrapped reader is then left positioned after
1137    /// that Base64 block so adjacent framed bytes can be read by the
1138    /// caller.
1139    #[must_use]
1140    pub const fn has_terminal_padding(&self) -> bool {
1141        self.terminal_seen
1142    }
1143
1144    /// Returns whether this decoder reader has reached EOF or terminal
1145    /// padding in the wrapped reader.
1146    ///
1147    /// This may become `true` before [`Self::is_finished`] when decoded
1148    /// output is still buffered for the caller.
1149    #[must_use]
1150    pub const fn has_finished_input(&self) -> bool {
1151        self.finished
1152    }
1153
1154    /// Returns whether this reader has reached EOF or terminal padding
1155    /// and has no decoded output buffered for the caller.
1156    #[must_use]
1157    pub const fn is_finished(&self) -> bool {
1158        self.finished && self.output.is_empty()
1159    }
1160
1161    /// Returns whether this decoder reader has rejected malformed Base64
1162    /// input.
1163    ///
1164    /// Once this returns `true`, later reads return an error. The unchecked
1165    /// [`Self::into_inner`] method can still be used for explicit recovery
1166    /// of the wrapped reader.
1167    #[must_use]
1168    pub const fn is_failed(&self) -> bool {
1169        self.failed
1170    }
1171
1172    /// Returns whether [`Self::try_into_inner`] can recover the wrapped
1173    /// reader without discarding buffered decoded output.
1174    #[must_use]
1175    pub const fn can_into_inner(&self) -> bool {
1176        !self.is_failed() && self.is_finished()
1177    }
1178
1179    /// Consumes the decoder reader and returns the wrapped reader.
1180    #[must_use]
1181    pub fn into_inner(mut self) -> R {
1182        self.take_inner()
1183    }
1184
1185    /// Consumes the decoder reader only after the Base64 payload is fully
1186    /// drained.
1187    ///
1188    /// For padded streams, terminal padding may leave adjacent framed bytes
1189    /// unread in the wrapped reader. This method succeeds only after all
1190    /// decoded output buffered by this adapter has been read, so recovering
1191    /// the wrapped reader does not silently discard decoded bytes.
1192    #[allow(clippy::result_large_err)]
1193    pub fn try_into_inner(mut self) -> Result<R, Self> {
1194        if !self.can_into_inner() {
1195            return Err(self);
1196        }
1197        Ok(self.take_inner())
1198    }
1199
1200    fn inner_ref(&self) -> &R {
1201        match &self.inner {
1202            Some(inner) => inner,
1203            None => unreachable!("stream decoder reader inner reader was already taken"),
1204        }
1205    }
1206
1207    fn inner_mut(&mut self) -> &mut R {
1208        match &mut self.inner {
1209            Some(inner) => inner,
1210            None => unreachable!("stream decoder reader inner reader was already taken"),
1211        }
1212    }
1213
1214    fn take_inner(&mut self) -> R {
1215        match self.inner.take() {
1216            Some(inner) => inner,
1217            None => unreachable!("stream decoder reader inner reader was already taken"),
1218        }
1219    }
1220
1221    fn clear_pending(&mut self) {
1222        crate::wipe_bytes(&mut self.pending);
1223        self.pending_len = 0;
1224    }
1225}
1226
1227impl<R, A, const PAD: bool> Drop for DecoderReader<R, A, PAD>
1228where
1229    A: Alphabet,
1230{
1231    fn drop(&mut self) {
1232        self.clear_pending();
1233        self.output.clear_all();
1234    }
1235}
1236
1237impl<R, A, const PAD: bool> core::fmt::Debug for DecoderReader<R, A, PAD>
1238where
1239    A: Alphabet,
1240{
1241    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1242        formatter
1243            .debug_struct("DecoderReader")
1244            .field("inner", &redacted_inner_state(self.inner.is_some()))
1245            .field("engine", &self.engine)
1246            .field("pending", &"<redacted>")
1247            .field("pending_len", &self.pending_len)
1248            .field("pending_input_needed_len", &self.pending_input_needed_len())
1249            .field("buffered_output_len", &self.output.len())
1250            .field("buffered_output_capacity", &self.output.capacity())
1251            .field(
1252                "buffered_output_remaining_capacity",
1253                &self.output.available_capacity(),
1254            )
1255            .field("can_into_inner", &self.can_into_inner())
1256            .field("finished", &self.finished)
1257            .field("terminal_padding", &self.terminal_seen)
1258            .field("failed", &self.failed)
1259            .finish()
1260    }
1261}
1262
1263impl<R, A, const PAD: bool> Read for DecoderReader<R, A, PAD>
1264where
1265    R: Read,
1266    A: Alphabet,
1267{
1268    fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
1269        if output.is_empty() {
1270            return Ok(0);
1271        }
1272        if self.failed {
1273            return Err(stream_decoder_failed_error());
1274        }
1275
1276        while self.output.is_empty() && !self.finished {
1277            self.fill_output()?;
1278        }
1279
1280        Ok(self.output.pop_slice(output))
1281    }
1282}
1283
1284impl<R, A, const PAD: bool> DecoderReader<R, A, PAD>
1285where
1286    R: Read,
1287    A: Alphabet,
1288{
1289    fn fill_output(&mut self) -> io::Result<()> {
1290        if self.failed {
1291            return Err(stream_decoder_failed_error());
1292        }
1293        if self.terminal_seen {
1294            self.finished = true;
1295            return Ok(());
1296        }
1297
1298        let mut input = [0u8; 4];
1299        let available = 4 - self.pending_len;
1300        let read = match self.inner_mut().read(&mut input[..available]) {
1301            Ok(read) => read,
1302            Err(err) => {
1303                crate::wipe_bytes(&mut input);
1304                return Err(err);
1305            }
1306        };
1307        if read == 0 {
1308            crate::wipe_bytes(&mut input);
1309            self.finished = true;
1310            self.push_final_pending()?;
1311            return Ok(());
1312        }
1313
1314        self.pending[self.pending_len..self.pending_len + read].copy_from_slice(&input[..read]);
1315        crate::wipe_bytes(&mut input);
1316        self.pending_len += read;
1317        if self.pending_len < 4 {
1318            return Ok(());
1319        }
1320
1321        let mut quad = self.pending;
1322        self.clear_pending();
1323        let result = self.push_decoded(&quad);
1324        crate::wipe_bytes(&mut quad);
1325        result?;
1326        if self.terminal_seen {
1327            self.finished = true;
1328        }
1329        Ok(())
1330    }
1331
1332    fn push_final_pending(&mut self) -> io::Result<()> {
1333        if self.pending_len == 0 {
1334            return Ok(());
1335        }
1336
1337        let mut pending = [0u8; 4];
1338        pending[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
1339        let pending_len = self.pending_len;
1340        self.clear_pending();
1341        let result = self.push_decoded(&pending[..pending_len]);
1342        crate::wipe_bytes(&mut pending);
1343        result
1344    }
1345
1346    fn push_decoded(&mut self, input: &[u8]) -> io::Result<()> {
1347        let mut decoded = [0u8; 3];
1348        let written = match self.engine.decode_slice(input, &mut decoded) {
1349            Ok(written) => written,
1350            Err(err) => {
1351                crate::wipe_bytes(&mut decoded);
1352                self.failed = true;
1353                return Err(decode_error_to_io(err));
1354            }
1355        };
1356        let result = self.output.push_slice(&decoded[..written]);
1357        crate::wipe_bytes(&mut decoded);
1358        result?;
1359        if input.len() == 4 && written < 3 {
1360            self.terminal_seen = true;
1361        }
1362        Ok(())
1363    }
1364}
1365
1366/// A streaming Base64 encoder for `std::io::Read`.
1367pub struct EncoderReader<R, A, const PAD: bool>
1368where
1369    A: Alphabet,
1370{
1371    inner: Option<R>,
1372    engine: Engine<A, PAD>,
1373    pending: [u8; 2],
1374    pending_len: usize,
1375    output: OutputQueue<1024>,
1376    finished: bool,
1377    failed: bool,
1378}
1379
1380impl<R, A, const PAD: bool> EncoderReader<R, A, PAD>
1381where
1382    A: Alphabet,
1383{
1384    /// Creates a new streaming encoder reader.
1385    #[must_use]
1386    pub fn new(inner: R, engine: Engine<A, PAD>) -> Self {
1387        Self {
1388            inner: Some(inner),
1389            engine,
1390            pending: [0; 2],
1391            pending_len: 0,
1392            output: OutputQueue::new(),
1393            finished: false,
1394            failed: false,
1395        }
1396    }
1397
1398    /// Returns a shared reference to the wrapped reader.
1399    #[must_use]
1400    pub fn get_ref(&self) -> &R {
1401        self.inner_ref()
1402    }
1403
1404    /// Returns a mutable reference to the wrapped reader.
1405    pub fn get_mut(&mut self) -> &mut R {
1406        self.inner_mut()
1407    }
1408
1409    /// Returns the Base64 engine used by this adapter.
1410    #[must_use]
1411    pub const fn engine(&self) -> Engine<A, PAD> {
1412        self.engine
1413    }
1414
1415    /// Returns whether this adapter uses padded Base64.
1416    #[must_use]
1417    pub const fn is_padded(&self) -> bool {
1418        PAD
1419    }
1420
1421    /// Returns the number of raw input bytes currently buffered until a
1422    /// complete 3-byte Base64 encode quantum is available.
1423    #[must_use]
1424    pub const fn pending_len(&self) -> usize {
1425        self.pending_len
1426    }
1427
1428    /// Returns whether this encoder reader currently holds a partial input
1429    /// quantum.
1430    #[must_use]
1431    pub const fn has_pending_input(&self) -> bool {
1432        self.pending_len != 0
1433    }
1434
1435    /// Returns how many additional raw input bytes are needed to complete
1436    /// the currently buffered encode quantum.
1437    ///
1438    /// Returns `0` when no partial input quantum is buffered.
1439    #[must_use]
1440    pub const fn pending_input_needed_len(&self) -> usize {
1441        if self.has_pending_input() {
1442            3 - self.pending_len
1443        } else {
1444            0
1445        }
1446    }
1447
1448    /// Returns the number of encoded bytes currently buffered and ready to
1449    /// be read before this adapter polls the wrapped reader again.
1450    #[must_use]
1451    pub const fn buffered_output_len(&self) -> usize {
1452        self.output.len()
1453    }
1454
1455    /// Returns the maximum number of encoded bytes this adapter can buffer
1456    /// before returning bytes to the caller.
1457    #[must_use]
1458    pub const fn buffered_output_capacity(&self) -> usize {
1459        self.output.capacity()
1460    }
1461
1462    /// Returns how many more encoded bytes can be buffered before this
1463    /// adapter must return bytes to the caller.
1464    #[must_use]
1465    pub const fn buffered_output_remaining_capacity(&self) -> usize {
1466        self.output.available_capacity()
1467    }
1468
1469    /// Returns whether this encoder reader currently has encoded output
1470    /// waiting in its internal queue.
1471    #[must_use]
1472    pub const fn has_buffered_output(&self) -> bool {
1473        !self.output.is_empty()
1474    }
1475
1476    /// Returns whether this encoder reader has reached EOF in the wrapped
1477    /// reader.
1478    ///
1479    /// This may become `true` before [`Self::is_finished`] when encoded
1480    /// output is still buffered for the caller.
1481    #[must_use]
1482    pub const fn has_finished_input(&self) -> bool {
1483        self.finished
1484    }
1485
1486    /// Returns whether this reader has reached EOF and has no encoded
1487    /// output buffered for the caller.
1488    #[must_use]
1489    pub const fn is_finished(&self) -> bool {
1490        self.finished && self.output.is_empty()
1491    }
1492
1493    /// Returns whether this adapter has failed closed after an internal
1494    /// stream error.
1495    #[must_use]
1496    pub const fn is_failed(&self) -> bool {
1497        self.failed
1498    }
1499
1500    /// Returns whether [`Self::try_into_inner`] can recover the wrapped
1501    /// reader without discarding pending input or buffered encoded output.
1502    #[must_use]
1503    pub const fn can_into_inner(&self) -> bool {
1504        self.is_finished() && !self.failed
1505    }
1506
1507    /// Consumes the encoder reader and returns the wrapped reader.
1508    #[must_use]
1509    pub fn into_inner(mut self) -> R {
1510        self.take_inner()
1511    }
1512
1513    /// Consumes the encoder reader only after the encoded stream is fully
1514    /// drained.
1515    ///
1516    /// This is a checked alternative to [`Self::into_inner`] for callers
1517    /// that want to avoid accidentally discarding pending input or encoded
1518    /// output buffered inside the adapter.
1519    #[allow(clippy::result_large_err)]
1520    pub fn try_into_inner(mut self) -> Result<R, Self> {
1521        if !self.can_into_inner() {
1522            return Err(self);
1523        }
1524        Ok(self.take_inner())
1525    }
1526
1527    fn inner_ref(&self) -> &R {
1528        match &self.inner {
1529            Some(inner) => inner,
1530            None => unreachable!("stream encoder reader inner reader was already taken"),
1531        }
1532    }
1533
1534    fn inner_mut(&mut self) -> &mut R {
1535        match &mut self.inner {
1536            Some(inner) => inner,
1537            None => unreachable!("stream encoder reader inner reader was already taken"),
1538        }
1539    }
1540
1541    fn take_inner(&mut self) -> R {
1542        match self.inner.take() {
1543            Some(inner) => inner,
1544            None => unreachable!("stream encoder reader inner reader was already taken"),
1545        }
1546    }
1547
1548    fn clear_pending(&mut self) {
1549        crate::wipe_bytes(&mut self.pending);
1550        self.pending_len = 0;
1551    }
1552}
1553
1554impl<R, A, const PAD: bool> Drop for EncoderReader<R, A, PAD>
1555where
1556    A: Alphabet,
1557{
1558    fn drop(&mut self) {
1559        self.clear_pending();
1560        self.output.clear_all();
1561    }
1562}
1563
1564impl<R, A, const PAD: bool> core::fmt::Debug for EncoderReader<R, A, PAD>
1565where
1566    A: Alphabet,
1567{
1568    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1569        formatter
1570            .debug_struct("EncoderReader")
1571            .field("inner", &redacted_inner_state(self.inner.is_some()))
1572            .field("engine", &self.engine)
1573            .field("pending", &"<redacted>")
1574            .field("pending_len", &self.pending_len)
1575            .field("pending_input_needed_len", &self.pending_input_needed_len())
1576            .field("buffered_output_len", &self.output.len())
1577            .field("buffered_output_capacity", &self.output.capacity())
1578            .field(
1579                "buffered_output_remaining_capacity",
1580                &self.output.available_capacity(),
1581            )
1582            .field("can_into_inner", &self.can_into_inner())
1583            .field("finished", &self.finished)
1584            .field("failed", &self.failed)
1585            .finish()
1586    }
1587}
1588
1589impl<R, A, const PAD: bool> Read for EncoderReader<R, A, PAD>
1590where
1591    R: Read,
1592    A: Alphabet,
1593{
1594    fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
1595        if self.failed {
1596            return Err(stream_encoder_failed_error());
1597        }
1598
1599        if output.is_empty() {
1600            return Ok(0);
1601        }
1602
1603        while self.output.is_empty() && !self.finished {
1604            self.fill_output()?;
1605        }
1606
1607        Ok(self.output.pop_slice(output))
1608    }
1609}
1610
1611impl<R, A, const PAD: bool> EncoderReader<R, A, PAD>
1612where
1613    R: Read,
1614    A: Alphabet,
1615{
1616    fn fill_output(&mut self) -> io::Result<()> {
1617        let mut input = [0u8; 768];
1618        let read = match self.inner_mut().read(&mut input) {
1619            Ok(read) => read,
1620            Err(err) => {
1621                crate::wipe_bytes(&mut input);
1622                return Err(err);
1623            }
1624        };
1625        if read == 0 {
1626            crate::wipe_bytes(&mut input);
1627            self.finished = true;
1628            if let Err(err) = self.push_final_pending() {
1629                self.failed = true;
1630                return Err(err);
1631            }
1632            return Ok(());
1633        }
1634
1635        let mut consumed = 0;
1636        if self.pending_len > 0 {
1637            let needed = 3 - self.pending_len;
1638            if read < needed {
1639                self.pending[self.pending_len..self.pending_len + read]
1640                    .copy_from_slice(&input[..read]);
1641                self.pending_len += read;
1642                crate::wipe_bytes(&mut input);
1643                return Ok(());
1644            }
1645
1646            let mut chunk = [0u8; 3];
1647            chunk[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
1648            chunk[self.pending_len..].copy_from_slice(&input[..needed]);
1649            let result = self.push_encoded(&chunk);
1650            crate::wipe_bytes(&mut chunk);
1651            if let Err(err) = result {
1652                crate::wipe_bytes(&mut input);
1653                self.failed = true;
1654                return Err(err);
1655            }
1656            self.clear_pending();
1657            consumed += needed;
1658        }
1659
1660        let remaining = &input[consumed..read];
1661        let full_len = remaining.len() / 3 * 3;
1662        let tail_len = remaining.len() - full_len;
1663        let mut tail = [0u8; 2];
1664        tail[..tail_len].copy_from_slice(&remaining[full_len..]);
1665        let result = if full_len > 0 {
1666            self.push_encoded(&remaining[..full_len])
1667        } else {
1668            Ok(())
1669        };
1670        crate::wipe_bytes(&mut input);
1671        if let Err(err) = result {
1672            crate::wipe_bytes(&mut tail);
1673            self.failed = true;
1674            return Err(err);
1675        }
1676        self.pending[..tail_len].copy_from_slice(&tail[..tail_len]);
1677        crate::wipe_bytes(&mut tail);
1678        self.pending_len = tail_len;
1679        Ok(())
1680    }
1681
1682    fn push_final_pending(&mut self) -> io::Result<()> {
1683        if self.pending_len == 0 {
1684            return Ok(());
1685        }
1686
1687        let mut pending = [0u8; 2];
1688        pending[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
1689        let pending_len = self.pending_len;
1690        self.clear_pending();
1691        let result = self.push_encoded(&pending[..pending_len]);
1692        crate::wipe_bytes(&mut pending);
1693        result
1694    }
1695
1696    fn push_encoded(&mut self, input: &[u8]) -> io::Result<()> {
1697        let mut encoded = [0u8; 1024];
1698        let written = match self.engine.encode_slice(input, &mut encoded) {
1699            Ok(written) => written,
1700            Err(err) => {
1701                crate::wipe_bytes(&mut encoded);
1702                return Err(encode_error_to_io(err));
1703            }
1704        };
1705        let result = self.output.push_slice(&encoded[..written]);
1706        crate::wipe_bytes(&mut encoded);
1707        result
1708    }
1709}
1710
1711const fn redacted_inner_state(present: bool) -> &'static str {
1712    if present { "<present>" } else { "<taken>" }
1713}