base64_stream/
to_base64_reader.rs1use std::{
2 fmt,
3 io::{self, ErrorKind, Read},
4};
5
6use base64::{
7 Engine,
8 engine::{GeneralPurpose, general_purpose::STANDARD},
9};
10
11pub struct ToBase64Reader<R: Read, const N: usize = 4096> {
13 inner: R,
14 buf: [u8; N],
15 buf_length: usize,
16 buf_offset: usize,
17 temp: [u8; 3],
18 temp_length: usize,
19 engine: &'static GeneralPurpose,
20}
21
22impl<R: Read, const N: usize> fmt::Debug for ToBase64Reader<R, N> {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 f.debug_struct("ToBase64Reader")
25 .field("buf_length", &self.buf_length)
26 .field("buf_offset", &self.buf_offset)
27 .field("temp", &&self.temp[..self.temp_length])
28 .field("temp_length", &self.temp_length)
29 .finish_non_exhaustive()
30 }
31}
32
33impl<R: Read> ToBase64Reader<R> {
34 #[inline]
35 pub fn new(reader: R) -> ToBase64Reader<R> {
36 Self::new2(reader)
37 }
38}
39
40impl<R: Read, const N: usize> ToBase64Reader<R, N> {
41 #[inline]
42 pub fn new2(reader: R) -> ToBase64Reader<R, N> {
43 const { assert!(N >= 4, "buffer size N must be at least 4") };
44 ToBase64Reader {
45 inner: reader,
46 buf: [0u8; N],
47 buf_length: 0,
48 buf_offset: 0,
49 temp: [0; 3],
50 temp_length: 0,
51 engine: &STANDARD,
52 }
53 }
54}
55
56impl<R: Read, const N: usize> ToBase64Reader<R, N> {
57 fn buf_left_shift(&mut self, distance: usize) {
58 debug_assert!(self.buf_length >= distance);
59
60 self.buf_offset += distance;
61 self.buf_length -= distance;
62
63 if self.buf_offset >= N - 4 {
64 self.buf.copy_within(self.buf_offset..self.buf_offset + self.buf_length, 0);
65
66 self.buf_offset = 0;
67 }
68 }
69
70 #[inline]
71 fn drain_temp<'a>(&mut self, buf: &'a mut [u8]) -> &'a mut [u8] {
72 debug_assert!(self.temp_length > 0);
73 debug_assert!(!buf.is_empty());
74
75 let drain_length = buf.len().min(self.temp_length);
76
77 buf[..drain_length].copy_from_slice(&self.temp[..drain_length]);
78
79 self.temp_length -= drain_length;
80 self.temp.copy_within(drain_length..drain_length + self.temp_length, 0);
81
82 &mut buf[drain_length..]
83 }
84
85 #[inline]
86 fn drain_block<'a>(&mut self, mut buf: &'a mut [u8]) -> &'a mut [u8] {
87 debug_assert!(self.buf_length > 0);
88 debug_assert!(self.temp_length == 0);
89 debug_assert!(!buf.is_empty());
90
91 let drain_length = self.buf_length.min(3);
92
93 let mut b = [0; 4];
94
95 let encode_length = self
96 .engine
97 .encode_slice(&self.buf[self.buf_offset..(self.buf_offset + drain_length)], &mut b)
98 .unwrap();
99
100 self.buf_left_shift(drain_length);
101
102 let buf_length = buf.len();
103
104 if buf_length >= encode_length {
105 buf[..encode_length].copy_from_slice(&b[..encode_length]);
106
107 buf = &mut buf[encode_length..];
108 } else {
109 buf[..buf_length].copy_from_slice(&b[..buf_length]);
110
111 buf = &mut buf[buf_length..];
112
113 self.temp_length = encode_length - buf_length;
114 self.temp[..self.temp_length].copy_from_slice(&b[buf_length..encode_length]);
115 }
116
117 buf
118 }
119
120 fn drain<'a>(&mut self, mut buf: &'a mut [u8]) -> &'a mut [u8] {
121 if buf.is_empty() {
122 return buf;
123 }
124
125 if self.temp_length > 0 {
126 buf = self.drain_temp(buf);
127 }
128
129 debug_assert!(self.buf_length >= 3);
130
131 let buf_length = buf.len();
132
133 if buf_length >= 4 {
134 debug_assert!(self.temp_length == 0);
135
136 let actual_max_read_size = (buf_length >> 2) * 3; let max_available_self_buf_length = self.buf_length - (self.buf_length % 3);
138
139 let drain_length = max_available_self_buf_length.min(actual_max_read_size);
140
141 let encode_length = self
142 .engine
143 .encode_slice(&self.buf[self.buf_offset..(self.buf_offset + drain_length)], buf)
144 .unwrap();
145
146 buf = &mut buf[encode_length..];
147
148 self.buf_left_shift(drain_length);
149 }
150
151 if !buf.is_empty() && self.buf_length >= 3 { self.drain_block(buf) } else { buf }
152 }
153
154 #[inline]
155 fn drain_end<'a>(&mut self, mut buf: &'a mut [u8]) -> &'a mut [u8] {
156 if buf.is_empty() {
157 return buf;
158 }
159
160 if self.temp_length > 0 {
161 buf = self.drain_temp(buf);
162 }
163
164 if !buf.is_empty() && self.buf_length > 0 { self.drain_block(buf) } else { buf }
165 }
166
167 #[inline]
169 pub fn into_inner(self) -> R {
170 self.inner
171 }
172}
173
174impl<R: Read, const N: usize> Read for ToBase64Reader<R, N> {
175 fn read(&mut self, mut buf: &mut [u8]) -> Result<usize, io::Error> {
176 let original_buf_length = buf.len();
177
178 while self.buf_length < 3 {
179 match self.inner.read(&mut self.buf[(self.buf_offset + self.buf_length)..]) {
180 Ok(0) => {
181 buf = self.drain_end(buf);
182
183 return Ok(original_buf_length - buf.len());
184 },
185 Ok(c) => self.buf_length += c,
186 Err(ref e) if e.kind() == ErrorKind::Interrupted => {},
187 Err(e) => return Err(e),
188 }
189 }
190
191 buf = self.drain(buf);
192
193 Ok(original_buf_length - buf.len())
194 }
195}
196
197impl<R: Read> From<R> for ToBase64Reader<R> {
198 #[inline]
199 fn from(reader: R) -> Self {
200 ToBase64Reader::new(reader)
201 }
202}