1use crate::alphabet::Alphabet;
2use crate::encoding::DecodeError;
3use std::io::{Read, Write};
4
5const CHUNK_SIZE: usize = 4096; pub struct StreamingEncoder<'a, W: Write> {
9 alphabet: &'a Alphabet,
10 writer: W,
11}
12
13impl<'a, W: Write> StreamingEncoder<'a, W> {
14 pub fn new(alphabet: &'a Alphabet, writer: W) -> Self {
15 StreamingEncoder { alphabet, writer }
16 }
17
18 pub fn encode<R: Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
20 match self.alphabet.mode() {
21 crate::config::EncodingMode::Chunked => {
22 self.encode_chunked(reader)
23 }
24 crate::config::EncodingMode::ByteRange => {
25 self.encode_byte_range(reader)
26 }
27 crate::config::EncodingMode::BaseConversion => {
28 let mut buffer = Vec::new();
30 reader.read_to_end(&mut buffer)?;
31 let encoded = crate::encoding::encode(&buffer, self.alphabet);
32 self.writer.write_all(encoded.as_bytes())?;
33 Ok(())
34 }
35 }
36 }
37
38 fn encode_chunked<R: Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
39 let base = self.alphabet.base();
40 let bits_per_char = (base as f64).log2() as usize;
41 let bytes_per_group = bits_per_char;
42
43 let aligned_chunk_size = (CHUNK_SIZE / bytes_per_group) * bytes_per_group;
45 let mut buffer = vec![0u8; aligned_chunk_size];
46
47 loop {
48 let bytes_read = reader.read(&mut buffer)?;
49 if bytes_read == 0 {
50 break;
51 }
52
53 let encoded = crate::chunked::encode_chunked(&buffer[..bytes_read], self.alphabet);
54 self.writer.write_all(encoded.as_bytes())?;
55 }
56
57 Ok(())
58 }
59
60 fn encode_byte_range<R: Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
61 let mut buffer = vec![0u8; CHUNK_SIZE];
62
63 loop {
64 let bytes_read = reader.read(&mut buffer)?;
65 if bytes_read == 0 {
66 break;
67 }
68
69 let encoded = crate::byte_range::encode_byte_range(&buffer[..bytes_read], self.alphabet);
70 self.writer.write_all(encoded.as_bytes())?;
71 }
72
73 Ok(())
74 }
75}
76
77pub struct StreamingDecoder<'a, W: Write> {
79 alphabet: &'a Alphabet,
80 writer: W,
81}
82
83impl<'a, W: Write> StreamingDecoder<'a, W> {
84 pub fn new(alphabet: &'a Alphabet, writer: W) -> Self {
85 StreamingDecoder { alphabet, writer }
86 }
87
88 pub fn decode<R: Read>(&mut self, reader: &mut R) -> Result<(), DecodeError> {
90 match self.alphabet.mode() {
91 crate::config::EncodingMode::Chunked => {
92 self.decode_chunked(reader)
93 }
94 crate::config::EncodingMode::ByteRange => {
95 self.decode_byte_range(reader)
96 }
97 crate::config::EncodingMode::BaseConversion => {
98 let mut buffer = String::new();
100 reader.read_to_string(&mut buffer)
101 .map_err(|_| DecodeError::InvalidCharacter('\0'))?;
102 let decoded = crate::encoding::decode(&buffer, self.alphabet)?;
103 self.writer.write_all(&decoded)
104 .map_err(|_| DecodeError::InvalidCharacter('\0'))?;
105 Ok(())
106 }
107 }
108 }
109
110 fn decode_chunked<R: Read>(&mut self, reader: &mut R) -> Result<(), DecodeError> {
111 let base = self.alphabet.base();
112 let bits_per_char = (base as f64).log2() as usize;
113 let chars_per_group = 8 / bits_per_char;
114
115 let mut text_buffer = String::new();
117 let mut char_buffer = vec![0u8; CHUNK_SIZE];
118
119 loop {
120 let bytes_read = reader.read(&mut char_buffer)
121 .map_err(|_| DecodeError::InvalidCharacter('\0'))?;
122 if bytes_read == 0 {
123 break;
124 }
125
126 let chunk_str = std::str::from_utf8(&char_buffer[..bytes_read])
127 .map_err(|_| DecodeError::InvalidCharacter('\0'))?;
128 text_buffer.push_str(chunk_str);
129
130 let chars: Vec<char> = text_buffer.chars().collect();
132 let complete_groups = (chars.len() / chars_per_group) * chars_per_group;
133
134 if complete_groups > 0 {
135 let to_decode: String = chars[..complete_groups].iter().collect();
136 let decoded = crate::chunked::decode_chunked(&to_decode, self.alphabet)?;
137 self.writer.write_all(&decoded)
138 .map_err(|_| DecodeError::InvalidCharacter('\0'))?;
139
140 text_buffer = chars[complete_groups..].iter().collect();
142 }
143 }
144
145 if !text_buffer.is_empty() {
147 let decoded = crate::chunked::decode_chunked(&text_buffer, self.alphabet)?;
148 self.writer.write_all(&decoded)
149 .map_err(|_| DecodeError::InvalidCharacter('\0'))?;
150 }
151
152 Ok(())
153 }
154
155 fn decode_byte_range<R: Read>(&mut self, reader: &mut R) -> Result<(), DecodeError> {
156 let mut char_buffer = vec![0u8; CHUNK_SIZE];
157
158 loop {
159 let bytes_read = reader.read(&mut char_buffer)
160 .map_err(|_| DecodeError::InvalidCharacter('\0'))?;
161 if bytes_read == 0 {
162 break;
163 }
164
165 let chunk_str = std::str::from_utf8(&char_buffer[..bytes_read])
166 .map_err(|_| DecodeError::InvalidCharacter('\0'))?;
167
168 let decoded = crate::byte_range::decode_byte_range(chunk_str, self.alphabet)?;
169 self.writer.write_all(&decoded)
170 .map_err(|_| DecodeError::InvalidCharacter('\0'))?;
171 }
172
173 Ok(())
174 }
175}
176
177#[cfg(test)]
178mod tests {
179 use super::*;
180 use crate::{AlphabetsConfig, Alphabet};
181 use std::io::Cursor;
182
183 fn get_alphabet(name: &str) -> Alphabet {
184 let config = AlphabetsConfig::load_default().unwrap();
185 let alphabet_config = config.get_alphabet(name).unwrap();
186
187 match alphabet_config.mode {
188 crate::config::EncodingMode::ByteRange => {
189 let start = alphabet_config.start_codepoint.unwrap();
190 Alphabet::new_with_mode_and_range(Vec::new(), alphabet_config.mode.clone(), None, Some(start)).unwrap()
191 }
192 _ => {
193 let chars: Vec<char> = alphabet_config.chars.chars().collect();
194 let padding = alphabet_config.padding.as_ref().and_then(|s| s.chars().next());
195 Alphabet::new_with_mode(chars, alphabet_config.mode.clone(), padding).unwrap()
196 }
197 }
198 }
199
200 #[test]
201 fn test_streaming_encode_decode_base64() {
202 let alphabet = get_alphabet("base64");
203 let data = b"Hello, World! This is a streaming test with multiple chunks of data.";
204
205 let mut encoded_output = Vec::new();
207 {
208 let mut encoder = StreamingEncoder::new(&alphabet, &mut encoded_output);
209 let mut reader = Cursor::new(data);
210 encoder.encode(&mut reader).unwrap();
211 }
212
213 let mut decoded_output = Vec::new();
215 {
216 let mut decoder = StreamingDecoder::new(&alphabet, &mut decoded_output);
217 let mut reader = Cursor::new(&encoded_output);
218 decoder.decode(&mut reader).unwrap();
219 }
220
221 assert_eq!(data, &decoded_output[..]);
222 }
223
224 #[test]
225 fn test_streaming_encode_decode_base100() {
226 let alphabet = get_alphabet("base100");
227 let data = b"Test data for byte range streaming";
228
229 let mut encoded_output = Vec::new();
231 {
232 let mut encoder = StreamingEncoder::new(&alphabet, &mut encoded_output);
233 let mut reader = Cursor::new(data);
234 encoder.encode(&mut reader).unwrap();
235 }
236
237 let mut decoded_output = Vec::new();
239 {
240 let mut decoder = StreamingDecoder::new(&alphabet, &mut decoded_output);
241 let mut reader = Cursor::new(&encoded_output);
242 decoder.decode(&mut reader).unwrap();
243 }
244
245 assert_eq!(data, &decoded_output[..]);
246 }
247
248 #[test]
249 fn test_streaming_large_data() {
250 let alphabet = get_alphabet("base64");
251 let data: Vec<u8> = (0..100000).map(|i| (i % 256) as u8).collect();
253
254 let mut encoded_output = Vec::new();
256 {
257 let mut encoder = StreamingEncoder::new(&alphabet, &mut encoded_output);
258 let mut reader = Cursor::new(&data);
259 encoder.encode(&mut reader).unwrap();
260 }
261
262 let mut decoded_output = Vec::new();
264 {
265 let mut decoder = StreamingDecoder::new(&alphabet, &mut decoded_output);
266 let mut reader = Cursor::new(&encoded_output);
267 decoder.decode(&mut reader).unwrap();
268 }
269
270 assert_eq!(data, decoded_output);
271 }
272}