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