base_d/
streaming.rs

1use crate::alphabet::Alphabet;
2use crate::encoding::DecodeError;
3use std::io::{Read, Write};
4
5const CHUNK_SIZE: usize = 4096; // 4KB chunks
6
7/// Streaming encoder that processes data in chunks
8pub 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    /// Encode data from a reader in chunks
19    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                // Mathematical mode requires entire input - read all and encode
29                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        // Adjust chunk size to align with encoding groups
44        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
77/// Streaming decoder that processes data in chunks
78pub 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    /// Decode data from a reader in chunks
89    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                // Mathematical mode requires entire input
99                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        // Read text in chunks
116        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            // Process complete character groups
131            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                // Keep remaining chars for next iteration
141                text_buffer = chars[complete_groups..].iter().collect();
142            }
143        }
144        
145        // Process any remaining characters
146        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        // Encode
206        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        // Decode
214        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        // Encode
230        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        // Decode
238        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        // Create 100KB of data
252        let data: Vec<u8> = (0..100000).map(|i| (i % 256) as u8).collect();
253        
254        // Encode
255        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        // Decode
263        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}