Skip to main content

marc_rs/raw/
reader.rs

1use crate::encoding::Encoding;
2use crate::error::MarcError;
3use crate::raw::{RawRecord, RawRecordView};
4
5/// Simple in-memory binary reader over concatenated ISO2709 records.
6///
7/// Yields `RawRecordView` so that an optional encoding override can be applied
8/// when decoding field data (e.g. for display).
9pub struct BinaryReader<'a> {
10    data: &'a [u8],
11    pos: usize,
12    encoding_override: Option<Encoding>,
13}
14
15impl<'a> BinaryReader<'a> {
16    pub fn new(data: &'a [u8]) -> Self {
17        Self {
18            data,
19            pos: 0,
20            encoding_override: None,
21        }
22    }
23
24    pub fn with_encoding(data: &'a [u8], encoding_override: Option<Encoding>) -> Self {
25        Self { data, pos: 0, encoding_override }
26    }
27}
28
29impl<'a> Iterator for BinaryReader<'a> {
30    type Item = Result<RawRecordView<'a>, MarcError>;
31
32    fn next(&mut self) -> Option<Self::Item> {
33        if self.pos >= self.data.len() {
34            return None;
35        }
36        if self.data.len() - self.pos < 24 {
37            return Some(Err(MarcError::InvalidRecord("trailing bytes shorter than leader")));
38        }
39        let leader = &self.data[self.pos..self.pos + 24];
40        let len = match std::str::from_utf8(&leader[0..5]).ok().and_then(|s| s.trim().parse::<usize>().ok()) {
41            Some(l) if l >= 24 && self.pos + l <= self.data.len() => l,
42            _ => return Some(Err(MarcError::InvalidRecord("invalid record length in leader"))),
43        };
44        let start = self.pos;
45        let end = self.pos + len;
46        self.pos = end;
47        let raw = RawRecord(&self.data[start..end]);
48        Some(Ok(RawRecordView::new(raw, self.encoding_override)))
49    }
50}