1use std::collections::VecDeque;
6use std::io::Read;
7
8use crate::blocks::SbfBlock;
9use crate::error::{SbfError, SbfResult};
10use crate::header::{SbfHeader, MIN_BLOCK_LENGTH, SBF_SYNC};
11
12const DEFAULT_BUFFER_CAPACITY: usize = 65536;
14
15const MAX_BUFFER_SIZE: usize = 131072;
17
18enum Fill {
20 Filled,
22 Eof,
24 WouldBlock,
26}
27
28pub struct SbfReader<R: Read> {
49 inner: R,
50 buffer: VecDeque<u8>,
51 validate_crc: bool,
53 stats: ReaderStats,
55}
56
57#[derive(Debug, Clone, Default)]
59pub struct ReaderStats {
60 pub bytes_read: u64,
62 pub blocks_parsed: u64,
64 pub crc_errors: u64,
66 pub parse_errors: u64,
68 pub bytes_skipped: u64,
70}
71
72impl<R: Read> SbfReader<R> {
73 pub fn new(reader: R) -> Self {
75 Self {
76 inner: reader,
77 buffer: VecDeque::with_capacity(DEFAULT_BUFFER_CAPACITY),
78 validate_crc: true,
79 stats: ReaderStats::default(),
80 }
81 }
82
83 pub fn with_capacity(reader: R, capacity: usize) -> Self {
85 Self {
86 inner: reader,
87 buffer: VecDeque::with_capacity(capacity),
88 validate_crc: true,
89 stats: ReaderStats::default(),
90 }
91 }
92
93 pub fn validate_crc(mut self, validate: bool) -> Self {
95 self.validate_crc = validate;
96 self
97 }
98
99 pub fn stats(&self) -> &ReaderStats {
101 &self.stats
102 }
103
104 pub fn reset_stats(&mut self) {
106 self.stats = ReaderStats::default();
107 }
108
109 pub fn read_block(&mut self) -> SbfResult<Option<SbfBlock>> {
122 loop {
123 if let Some(sync_pos) = self.find_sync() {
125 if sync_pos > 0 {
127 self.stats.bytes_skipped += sync_pos as u64;
128 self.buffer.drain(0..sync_pos);
129 }
130
131 match self.try_parse_block() {
133 Ok(Some((block, consumed))) => {
134 self.buffer.drain(0..consumed);
136 self.stats.blocks_parsed += 1;
137 return Ok(Some(block));
138 }
139 Ok(None) => {
140 match self.fill_buffer()? {
142 Fill::Filled => {}
143 Fill::WouldBlock => return Err(SbfError::WouldBlock),
144 Fill::Eof => {
145 if !self.buffer.is_empty() {
146 return Err(SbfError::IncompleteBlock {
148 needed: 8,
149 have: self.buffer.len(),
150 });
151 }
152 return Ok(None);
153 }
154 }
155 }
156 Err(SbfError::InvalidSync) => {
157 self.buffer.remove(0);
159 self.stats.bytes_skipped += 1;
160 }
161 Err(SbfError::CrcMismatch { .. }) => {
162 self.buffer.remove(0);
164 self.stats.crc_errors += 1;
165 self.stats.bytes_skipped += 1;
166 }
167 Err(_) => {
168 self.buffer.remove(0);
170 self.stats.parse_errors += 1;
171 self.stats.bytes_skipped += 1;
172 }
174 }
175 } else {
176 let len = self.buffer.len();
181 if len > 1 {
182 self.stats.bytes_skipped += (len - 1) as u64;
183 self.buffer.drain(0..len - 1);
184 }
185 match self.fill_buffer()? {
186 Fill::Filled => {}
187 Fill::WouldBlock => return Err(SbfError::WouldBlock),
188 Fill::Eof => return Ok(None),
189 }
190 }
191
192 self.trim_buffer();
194 }
195 }
196
197 fn find_sync(&self) -> Option<usize> {
199 if self.buffer.len() < 2 {
200 return None;
201 }
202
203 (0..(self.buffer.len() - 1))
204 .find(|&i| self.buffer[i] == SBF_SYNC[0] && self.buffer[i + 1] == SBF_SYNC[1])
205 }
206
207 fn try_parse_block(&mut self) -> SbfResult<Option<(SbfBlock, usize)>> {
209 if self.buffer.len() < 8 {
210 return Ok(None);
211 }
212
213 let peek_len = u16::from_le_bytes([self.buffer[6], self.buffer[7]]) as usize;
216 if peek_len >= MIN_BLOCK_LENGTH as usize && self.buffer.len() < peek_len {
217 return Ok(None); }
219
220 let front_len = self.buffer.as_slices().0.len();
225 let contiguous_front = peek_len >= MIN_BLOCK_LENGTH as usize && front_len >= peek_len;
226 if !contiguous_front {
227 self.buffer.make_contiguous();
228 }
229 let buffer = self.buffer.as_slices().0;
230
231 let header = SbfHeader::parse(&buffer[2..])?;
233 let total_len = header.length as usize;
234
235 if buffer.len() < total_len {
236 return Ok(None);
237 }
238
239 if self.validate_crc {
242 header.validate_crc(&buffer[..total_len])?;
243 }
244
245 let (block, consumed) = SbfBlock::parse(&buffer[..total_len])?;
247
248 Ok(Some((block, consumed)))
249 }
250
251 fn fill_buffer(&mut self) -> SbfResult<Fill> {
256 let mut temp = [0u8; 4096];
257 match self.inner.read(&mut temp) {
258 Ok(0) => Ok(Fill::Eof),
259 Ok(n) => {
260 self.buffer.extend(&temp[..n]);
261 self.stats.bytes_read += n as u64;
262 Ok(Fill::Filled)
263 }
264 Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => Ok(Fill::WouldBlock),
265 Err(e) if e.kind() == std::io::ErrorKind::Interrupted => self.fill_buffer(),
266 Err(e) => Err(SbfError::Io(e)),
267 }
268 }
269
270 fn trim_buffer(&mut self) {
272 if self.buffer.capacity() > MAX_BUFFER_SIZE && self.buffer.len() < MAX_BUFFER_SIZE / 2 {
273 self.buffer.shrink_to_fit();
274 }
275 }
276}
277
278impl<R: Read> Iterator for SbfReader<R> {
280 type Item = SbfResult<SbfBlock>;
281
282 fn next(&mut self) -> Option<Self::Item> {
283 match self.read_block() {
284 Ok(Some(block)) => Some(Ok(block)),
285 Ok(None) => None,
286 Err(e) => Some(Err(e)),
287 }
288 }
289}
290
291pub trait SbfReadExt: Read + Sized {
293 fn sbf_blocks(self) -> SbfReader<Self> {
295 SbfReader::new(self)
296 }
297}
298
299impl<R: Read> SbfReadExt for R {}
300
301#[cfg(test)]
302mod tests {
303 use super::*;
304 use std::io::Cursor;
305
306 #[test]
307 fn test_reader_empty() {
308 let data: &[u8] = &[];
309 let mut reader = SbfReader::new(Cursor::new(data));
310
311 assert!(reader.read_block().unwrap().is_none());
312 }
313
314 #[test]
315 fn test_reader_no_sync() {
316 let data = [0x00, 0x00, 0x00, 0x00];
317 let mut reader = SbfReader::new(Cursor::new(&data[..]));
318
319 assert!(reader.read_block().unwrap().is_none());
320 }
321
322 #[test]
323 fn test_reader_stats() {
324 let data: &[u8] = &[0x00, 0x00];
325 let mut reader = SbfReader::new(Cursor::new(data));
326
327 let _ = reader.read_block();
328
329 assert_eq!(reader.stats().bytes_read, 2);
330 }
331
332 #[test]
333 fn test_sbf_read_ext() {
334 let data: &[u8] = &[];
335 let reader = Cursor::new(data).sbf_blocks();
336
337 assert!(reader.validate_crc);
338 }
339
340 #[test]
341 fn crc_mismatch_reports_computed_actual() {
342 let mut block = vec![0u8; 16];
345 block[0] = SBF_SYNC[0];
346 block[1] = SBF_SYNC[1];
347 block[4..6].copy_from_slice(&5922u16.to_le_bytes()); block[6..8].copy_from_slice(&16u16.to_le_bytes()); let stored = crate::crc::crc16_ccitt(&block[4..16]);
350 block[2..4].copy_from_slice(&stored.to_le_bytes());
351 block[12] ^= 0xFF; let computed = crate::crc::crc16_ccitt(&block[4..16]);
353 assert_ne!(stored, computed);
354
355 let mut reader = SbfReader::new(Cursor::new(block.clone()));
356 while reader.buffer.len() < block.len() {
357 match reader.fill_buffer().unwrap() {
358 Fill::Filled => {}
359 _ => break,
360 }
361 }
362
363 match reader.try_parse_block() {
364 Err(SbfError::CrcMismatch { expected, actual }) => {
365 assert_eq!(expected, stored);
366 assert_eq!(actual, computed);
367 assert_ne!(actual, 0);
368 }
369 other => panic!("expected CrcMismatch, got {other:?}"),
370 }
371 }
372}