base64_stream/
from_base64_writer.rs1use std::{
2 fmt,
3 io::{self, ErrorKind, Write},
4};
5
6use base64::{
7 DecodeSliceError, Engine,
8 engine::{GeneralPurpose, general_purpose::STANDARD},
9};
10
11#[inline]
12fn decode_error_to_io_error(error: DecodeSliceError) -> io::Error {
13 io::Error::new(ErrorKind::InvalidData, error)
14}
15
16pub struct FromBase64Writer<W: Write, const N: usize = 4096> {
18 inner: W,
19 buf: [u8; 4],
20 buf_length: usize,
21 temp: [u8; N],
22 engine: &'static GeneralPurpose,
23}
24
25impl<W: Write, const N: usize> fmt::Debug for FromBase64Writer<W, N> {
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 f.debug_struct("FromBase64Writer")
28 .field("buf", &&self.buf[..self.buf_length])
29 .field("buf_length", &self.buf_length)
30 .finish_non_exhaustive()
31 }
32}
33
34impl<W: Write> FromBase64Writer<W> {
35 #[inline]
36 pub fn new(writer: W) -> FromBase64Writer<W> {
37 Self::new2(writer)
38 }
39}
40
41impl<W: Write, const N: usize> FromBase64Writer<W, N> {
42 #[inline]
43 pub fn new2(writer: W) -> FromBase64Writer<W, N> {
44 const { assert!(N >= 4, "buffer size N must be at least 4") };
45 FromBase64Writer {
46 inner: writer,
47 buf: [0; 4],
48 buf_length: 0,
49 temp: [0u8; N],
50 engine: &STANDARD,
51 }
52 }
53}
54
55impl<W: Write, const N: usize> FromBase64Writer<W, N> {
56 fn drain_block(&mut self) -> Result<(), io::Error> {
57 debug_assert!(self.buf_length > 0);
58
59 let decode_length = self
60 .engine
61 .decode_slice(&self.buf[..self.buf_length], &mut self.temp)
62 .map_err(decode_error_to_io_error)?;
63
64 self.inner.write_all(&self.temp[..decode_length])?;
65
66 self.buf_length = 0;
67
68 Ok(())
69 }
70
71 #[inline]
73 pub fn finish(mut self) -> Result<W, io::Error> {
74 if self.buf_length > 0 {
75 self.drain_block()?;
76 }
77
78 self.inner.flush()?;
79
80 Ok(self.inner)
81 }
82
83 #[inline]
87 pub fn into_inner(self) -> W {
88 self.inner
89 }
90}
91
92impl<W: Write, const N: usize> Write for FromBase64Writer<W, N> {
93 fn write(&mut self, mut buf: &[u8]) -> Result<usize, io::Error> {
94 let original_buf_length = buf.len();
95
96 if self.buf_length == 0 {
97 while buf.len() >= 4 {
98 let max_available_buf_length = (buf.len() & !0b11).min((N / 3) << 2); let decode_length = self
101 .engine
102 .decode_slice(&buf[..max_available_buf_length], &mut self.temp)
103 .map_err(decode_error_to_io_error)?;
104
105 buf = &buf[max_available_buf_length..];
106
107 self.inner.write_all(&self.temp[..decode_length])?;
108 }
109
110 let buf_length = buf.len();
111
112 if buf_length > 0 {
113 self.buf[..buf_length].copy_from_slice(&buf[..buf_length]);
114
115 self.buf_length = buf_length;
116 }
117 } else {
118 debug_assert!(self.buf_length < 4);
119
120 let r = 4 - self.buf_length;
121
122 let buf_length = buf.len();
123
124 let drain_length = r.min(buf_length);
125
126 self.buf[self.buf_length..self.buf_length + drain_length]
127 .copy_from_slice(&buf[..drain_length]);
128
129 buf = &buf[drain_length..];
130
131 self.buf_length += drain_length;
132
133 if self.buf_length == 4 {
134 self.drain_block()?;
135
136 if buf_length > r {
137 self.write_all(buf)?;
138 }
139 }
140 }
141
142 Ok(original_buf_length)
143 }
144
145 #[inline]
146 fn flush(&mut self) -> Result<(), io::Error> {
147 self.inner.flush()
148 }
149}
150
151impl<W: Write> From<W> for FromBase64Writer<W> {
152 #[inline]
153 fn from(reader: W) -> Self {
154 FromBase64Writer::new(reader)
155 }
156}