Skip to main content

abx/decode/
stream.rs

1//! [`AbxStreamParser`] — pull parser over any `Read` source.
2//!
3//! Unlike [`crate::AbxParser`] which requires the whole document in memory,
4//! `AbxStreamParser` reads from any `std::io::Read` implementor (files, TCP
5//! sockets, `stdin`, in-memory `Cursor<Vec<u8>>`, …) using a small internal
6//! ring buffer.
7//!
8//! The public surface is intentionally identical to `AbxParser` so the two
9//! types are interchangeable; just swap the constructor.
10//!
11//! # Internal design
12//!
13//! We keep a `Vec<u8>` ring buffer (`buf`) and a `pos` cursor.  When a nom
14//! parser reports `Incomplete` we refill from the reader, slide unconsumed
15//! bytes to the front, and retry.  This gives us:
16//!
17//! - **bounded memory** — the buffer only grows when a single atom (e.g. a
18//!   very long string) exceeds the current capacity.
19//! - **zero extra copies** — nom operates directly on `&buf[pos..]`.
20//! - **identical event types** — `Event`, `Attribute`, `AttributeValue` are
21//!   all shared with the slice parser.
22
23use std::io::Read;
24
25use nom::{
26    Needed,
27    number::streaming::{be_f32, be_f64, be_i32, be_i64, be_u8, be_u16},
28};
29
30use crate::{
31    AbxError, Attribute, AttributeValue, CMD_ATTRIBUTE, CMD_CDSECT, CMD_COMMENT, CMD_DOCDECL,
32    CMD_END_DOCUMENT, CMD_END_TAG, CMD_ENTITY_REF, CMD_IGNORABLE_WHITESPACE,
33    CMD_PROCESSING_INSTRUCTION, CMD_START_DOCUMENT, CMD_START_TAG, CMD_TEXT, Event, MAGIC, Result,
34    TYPE_BOOLEAN_FALSE, TYPE_BOOLEAN_TRUE, TYPE_BYTES_BASE64, TYPE_BYTES_HEX, TYPE_DOUBLE,
35    TYPE_FLOAT, TYPE_INT, TYPE_INT_HEX, TYPE_LONG, TYPE_LONG_HEX, TYPE_NULL, TYPE_STRING,
36    TYPE_STRING_INTERNED, render_event,
37};
38
39use crate::INTERNED_NEW;
40use std::collections::HashMap;
41
42/// Initial ring-buffer capacity (4 KiB).
43const INITIAL_BUF: usize = 4096;
44/// How many bytes to try to read per refill.
45const READ_CHUNK: usize = 4096;
46
47/// Pull parser that reads from any `R: Read` source.
48///
49/// # Example
50/// ```rust,ignore
51/// use abx::AbxStreamParser;
52/// use std::io::BufReader;
53///
54/// let file = std::fs::File::open("backup.abx")?;
55/// let mut p = AbxStreamParser::new(BufReader::new(file))?;
56///
57/// while let Some(ev) = p.next_event()? {
58///     match ev {
59///         abx::Event::StartTag { name, attributes } => {
60///             println!("<{name}>");
61///             for a in &attributes {
62///                 println!("  {}={}", a.name, a.as_str());
63///             }
64///         }
65///         abx::Event::EndTag { name } => println!("</{name}>"),
66///         _ => {}
67///     }
68/// }
69/// ```
70#[derive(Debug)]
71pub struct AbxStreamParser<R: Read> {
72    reader: R,
73    /// Internal ring buffer.
74    buf: Vec<u8>,
75    /// Read cursor inside `buf`.
76    pos: usize,
77    /// Total valid bytes in `buf` (always >= pos).
78    len: usize,
79    /// `true` once the underlying reader returned 0 bytes.
80    eof: bool,
81    /// Interned string pool.
82    pool: Vec<crate::InternedStr>,
83}
84
85impl<R: Read> AbxStreamParser<R> {
86    // -----------------------------------------------------------------------
87    // Constructor
88    // -----------------------------------------------------------------------
89
90    /// Create a new parser from any reader.
91    ///
92    /// Reads and validates the 4-byte magic header immediately.  Returns an
93    /// error if the reader is too short or the header does not match.
94    pub fn new(reader: R) -> Result<Self> {
95        let mut p = AbxStreamParser {
96            reader,
97            buf: vec![0u8; INITIAL_BUF],
98            pos: 0,
99            len: 0,
100            eof: false,
101            pool: Vec::with_capacity(32),
102        };
103
104        // Read at least 4 bytes for the magic header.
105        p.ensure(4)?;
106
107        let magic: [u8; 4] = p.buf[p.pos..p.pos + 4].try_into().unwrap();
108        if magic != MAGIC {
109            return Err(AbxError::InvalidMagic {
110                expected: MAGIC,
111                actual: magic,
112            });
113        }
114        p.pos += 4;
115        Ok(p)
116    }
117
118    // -----------------------------------------------------------------------
119    // Buffer management
120    // -----------------------------------------------------------------------
121
122    /// Number of unconsumed bytes currently in the buffer.
123    #[inline]
124    fn available(&self) -> usize {
125        self.len - self.pos
126    }
127
128    /// Compact the buffer (slide unconsumed bytes to front) then read from the
129    /// underlying reader until we have at least `needed` bytes available, or
130    /// until EOF.
131    fn ensure(&mut self, needed: usize) -> Result<()> {
132        // Compact first so we always have room at the back.
133        if self.pos > 0 {
134            self.buf.copy_within(self.pos..self.len, 0);
135            self.len -= self.pos;
136            self.pos = 0;
137        }
138
139        while self.available() < needed && !self.eof {
140            // Grow if necessary.
141            let spare = self.buf.len() - self.len;
142            if spare < READ_CHUNK {
143                self.buf
144                    .resize(self.len + READ_CHUNK.max(needed - self.available()), 0);
145            }
146
147            let n = self.reader.read(&mut self.buf[self.len..])?;
148            if n == 0 {
149                self.eof = true;
150            } else {
151                self.len += n;
152            }
153        }
154
155        Ok(())
156    }
157
158    // -----------------------------------------------------------------------
159    // Primitive readers (nom-based, with auto-refill on Incomplete)
160    // -----------------------------------------------------------------------
161
162    /// Run a nom parser against the unconsumed tail of the buffer, refilling
163    /// if necessary.  Returns the parsed value and advances `pos`.
164    fn parse<F, T>(&mut self, mut f: F) -> Result<T>
165    where
166        F: FnMut(&[u8]) -> nom::IResult<&[u8], T>,
167    {
168        loop {
169            match f(&self.buf[self.pos..self.len]) {
170                Ok((rest, val)) => {
171                    self.pos = self.len - rest.len();
172                    return Ok(val);
173                }
174                Err(nom::Err::Incomplete(Needed::Size(n))) => {
175                    let need = self.available() + n.get();
176                    self.ensure(need)?;
177                    if self.eof && self.available() < n.get() {
178                        return Err(AbxError::UnexpectedEof("primitive"));
179                    }
180                }
181                Err(nom::Err::Incomplete(Needed::Unknown)) => {
182                    // Should not happen with our complete:: parsers, but handle gracefully.
183                    self.ensure(self.available() + 1)?;
184                    if self.eof {
185                        return Err(AbxError::UnexpectedEof("primitive"));
186                    }
187                }
188                Err(e) => return Err(AbxError::Nom(format!("{e:?}"))),
189            }
190        }
191    }
192
193    fn read_u8(&mut self) -> Result<u8> {
194        self.parse(|i| be_u8(i))
195    }
196    fn read_u16(&mut self) -> Result<u16> {
197        self.parse(|i| be_u16(i))
198    }
199    fn read_i32(&mut self) -> Result<i32> {
200        self.parse(|i| be_i32(i))
201    }
202    fn read_i64(&mut self) -> Result<i64> {
203        self.parse(|i| be_i64(i))
204    }
205    fn read_f32(&mut self) -> Result<f32> {
206        self.parse(|i| be_f32(i))
207    }
208    fn read_f64(&mut self) -> Result<f64> {
209        self.parse(|i| be_f64(i))
210    }
211
212    /// Read a `u16`-length-prefixed UTF-8 blob.
213    fn read_utf(&mut self) -> Result<String> {
214        let len = self.read_u16()? as usize;
215        // Make sure the whole string payload is buffered.
216        self.ensure(len)?;
217        if self.available() < len {
218            return Err(AbxError::UnexpectedEof("UTF string payload"));
219        }
220        let s = std::str::from_utf8(&self.buf[self.pos..self.pos + len])
221            .map_err(|_| AbxError::InvalidUtf8)?
222            .to_owned();
223        self.pos += len;
224        Ok(s)
225    }
226
227    /// Read a `u16`-length-prefixed raw byte blob.
228    fn read_bytes_blob(&mut self) -> Result<Vec<u8>> {
229        let len = self.read_u16()? as usize;
230        self.ensure(len)?;
231        if self.available() < len {
232            return Err(AbxError::UnexpectedEof("bytes payload"));
233        }
234        let v = self.buf[self.pos..self.pos + len].to_vec();
235        self.pos += len;
236        Ok(v)
237    }
238
239    /// Read an interned string. Every occurrence after the first is a
240    /// back-reference into `pool`, resolved with `InternedStr::clone` (a
241    /// refcount bump) rather than a fresh allocation and copy.
242    fn read_interned(&mut self) -> Result<crate::InternedStr> {
243        let idx = self.read_u16()?;
244        if idx == INTERNED_NEW {
245            let s: crate::InternedStr = self.read_utf()?.into();
246            self.pool.push(s.clone());
247            Ok(s)
248        } else {
249            self.pool
250                .get(idx as usize)
251                .cloned()
252                .ok_or(AbxError::BadInternedIndex(idx))
253        }
254    }
255
256    // -----------------------------------------------------------------------
257    // Attribute value
258    // -----------------------------------------------------------------------
259
260    fn read_attr_value(&mut self, type_nibble: u8) -> Result<AttributeValue> {
261        match type_nibble {
262            TYPE_NULL => Ok(AttributeValue::Null),
263            TYPE_STRING => Ok(AttributeValue::String(self.read_utf()?)),
264            TYPE_STRING_INTERNED => Ok(AttributeValue::String(self.read_interned()?.to_string())),
265            TYPE_BYTES_HEX => Ok(AttributeValue::BytesHex(self.read_bytes_blob()?)),
266            TYPE_BYTES_BASE64 => Ok(AttributeValue::BytesBase64(self.read_bytes_blob()?)),
267            TYPE_INT => Ok(AttributeValue::Int(self.read_i32()?)),
268            TYPE_INT_HEX => Ok(AttributeValue::IntHex(self.read_i32()? as u32)),
269            TYPE_LONG => Ok(AttributeValue::Long(self.read_i64()?)),
270            TYPE_LONG_HEX => Ok(AttributeValue::LongHex(self.read_i64()? as u64)),
271            TYPE_FLOAT => Ok(AttributeValue::Float(self.read_f32()?)),
272            TYPE_DOUBLE => Ok(AttributeValue::Double(self.read_f64()?)),
273            TYPE_BOOLEAN_TRUE => Ok(AttributeValue::Boolean(true)),
274            TYPE_BOOLEAN_FALSE => Ok(AttributeValue::Boolean(false)),
275            other => Err(AbxError::UnknownAttributeType(other)),
276        }
277    }
278
279    // -----------------------------------------------------------------------
280    // Peek helpers (non-consuming, with refill)
281    // -----------------------------------------------------------------------
282
283    /// Peek at the next byte without consuming it. Returns `None` on EOF.
284    fn peek_u8(&mut self) -> Result<Option<u8>> {
285        self.ensure(1)?;
286        Ok(self.buf.get(self.pos).copied())
287    }
288
289    // -----------------------------------------------------------------------
290    // Public event API
291    // -----------------------------------------------------------------------
292
293    /// Pull the next [`Event`].  Returns `None` at end of input.
294    pub fn next_event(&mut self) -> Result<Option<Event>> {
295        // Refill at least 1 byte.
296        self.ensure(1)?;
297        if self.available() == 0 {
298            return Ok(None);
299        }
300
301        let token = self.read_u8()?;
302        let cmd = token & 0x0F;
303        let type_nibble = token & 0xF0;
304
305        let event = match cmd {
306            CMD_START_DOCUMENT => Event::StartDocument,
307            CMD_END_DOCUMENT => return Ok(Some(Event::EndDocument)),
308
309            CMD_START_TAG => {
310                let name = self.read_interned()?;
311                let mut attributes = Vec::new();
312
313                // Eagerly consume following ATTRIBUTE tokens without peeking
314                // across I/O boundaries more than necessary.
315                loop {
316                    match self.peek_u8()? {
317                        Some(next) if (next & 0x0F) == CMD_ATTRIBUTE => {
318                            self.pos += 1; // consume peeked byte
319                            let attr_type = next & 0xF0;
320                            let attr_name = self.read_interned()?;
321                            let attr_value = self.read_attr_value(attr_type)?;
322                            attributes.push(Attribute {
323                                name: attr_name,
324                                value: attr_value,
325                            });
326                        }
327                        _ => break,
328                    }
329                }
330
331                Event::StartTag { name, attributes }
332            }
333
334            CMD_END_TAG => Event::EndTag {
335                name: self.read_interned()?,
336            },
337
338            CMD_TEXT => Event::Text(if type_nibble == TYPE_STRING {
339                self.read_utf()?
340            } else {
341                String::new()
342            }),
343            CMD_CDSECT => Event::CdataSection(if type_nibble == TYPE_STRING {
344                self.read_utf()?
345            } else {
346                String::new()
347            }),
348            CMD_ENTITY_REF => Event::EntityReference(if type_nibble == TYPE_STRING {
349                self.read_utf()?
350            } else {
351                String::new()
352            }),
353            CMD_IGNORABLE_WHITESPACE => Event::IgnorableWhitespace(if type_nibble == TYPE_STRING {
354                self.read_utf()?
355            } else {
356                String::new()
357            }),
358            CMD_PROCESSING_INSTRUCTION => {
359                Event::ProcessingInstruction(if type_nibble == TYPE_STRING {
360                    self.read_utf()?
361                } else {
362                    String::new()
363                })
364            }
365            CMD_COMMENT => Event::Comment(if type_nibble == TYPE_STRING {
366                self.read_utf()?
367            } else {
368                String::new()
369            }),
370            CMD_DOCDECL => Event::DocDecl(if type_nibble == TYPE_STRING {
371                self.read_utf()?
372            } else {
373                String::new()
374            }),
375
376            other => return Err(AbxError::UnknownCommand(other)),
377        };
378
379        Ok(Some(event))
380    }
381
382    // -----------------------------------------------------------------------
383    // Convenience API  (same surface as AbxParser)
384    // -----------------------------------------------------------------------
385
386    /// Drain all remaining events into a `Vec`.
387    pub fn collect_events(&mut self) -> Result<Vec<Event>> {
388        let mut out = Vec::new();
389        while let Some(ev) = self.next_event()? {
390            out.push(ev);
391        }
392        Ok(out)
393    }
394
395    /// Return the value of the first matching `attr` inside any `<element>` tag.
396    pub fn find_attribute(&mut self, element: &str, attr: &str) -> Option<AttributeValue> {
397        loop {
398            match self.next_event().ok()? {
399                Some(Event::StartTag { name, attributes }) if name == element => {
400                    if let Some(a) = attributes.into_iter().find(|a| a.name == attr) {
401                        return Some(a.value);
402                    }
403                }
404                Some(Event::EndDocument) | None => return None,
405                _ => {}
406            }
407        }
408    }
409
410    /// All values of `attr` found in `<element>` tags.
411    pub fn find_all_attributes(
412        &mut self,
413        element: &str,
414        attr: &str,
415    ) -> Result<Vec<AttributeValue>> {
416        let mut out = Vec::new();
417        while let Some(ev) = self.next_event()? {
418            if let Event::StartTag { name, attributes } = ev
419                && name == element
420            {
421                out.extend(
422                    attributes
423                        .into_iter()
424                        .filter(|a| a.name == attr)
425                        .map(|a| a.value),
426                );
427            }
428        }
429        Ok(out)
430    }
431
432    /// Attributes of the first `<element>` tag.
433    pub fn attributes_of(&mut self, element: &str) -> Option<Vec<Attribute>> {
434        loop {
435            match self.next_event().ok()? {
436                Some(Event::StartTag { name, attributes }) if name == element => {
437                    return Some(attributes);
438                }
439                Some(Event::EndDocument) | None => return None,
440                _ => {}
441            }
442        }
443    }
444
445    /// Attributes of every `<element>` tag.
446    pub fn all_attributes_of(&mut self, element: &str) -> Result<Vec<Vec<Attribute>>> {
447        let mut out = Vec::new();
448        while let Some(ev) = self.next_event()? {
449            if let Event::StartTag { name, attributes } = ev
450                && name == element
451            {
452                out.push(attributes);
453            }
454        }
455        Ok(out)
456    }
457
458    /// Find the next `<element>`, deserialize its attributes (and direct
459    /// text content, via a `#[serde(rename = "$text")]` field) into `T`,
460    /// then skip past its matching end tag. `Ok(None)` at end of document.
461    #[cfg(feature = "serialize")]
462    pub fn deserialize_next<T: serde::de::DeserializeOwned>(
463        &mut self,
464        element: &str,
465    ) -> Result<Option<T>> {
466        crate::de::find_and_consume_element(self, element)
467    }
468
469    /// Deserialize every remaining `<element>` into a `Vec<T>`.
470    #[cfg(feature = "serialize")]
471    pub fn deserialize_all<T: serde::de::DeserializeOwned>(
472        &mut self,
473        element: &str,
474    ) -> Result<Vec<T>> {
475        let mut out = Vec::new();
476        while let Some(item) = self.deserialize_next(element)? {
477            out.push(item);
478        }
479        Ok(out)
480    }
481
482    /// Lazily deserialize every remaining `<element>` as a `T`, one at a
483    /// time, without buffering the whole document or the whole result set —
484    /// the streaming counterpart to [`deserialize_all`](Self::deserialize_all).
485    #[cfg(feature = "serialize")]
486    pub fn deserialize_iter<'p, T: serde::de::DeserializeOwned>(
487        &'p mut self,
488        element: &'p str,
489    ) -> DeserializeIter<'p, R, T> {
490        DeserializeIter {
491            parser: self,
492            element,
493            _marker: std::marker::PhantomData,
494        }
495    }
496
497    /// Render the rest of the document as an XML string.
498    pub fn to_xml(&mut self) -> Result<String> {
499        let mut buf = String::from(r#"<?xml version="1.0" encoding="UTF-8"?>"#);
500        while let Some(ev) = self.next_event()? {
501            if matches!(ev, Event::EndDocument) {
502                break;
503            }
504            render_event(&ev, &mut buf);
505        }
506        Ok(buf)
507    }
508
509    /// Write the rest of the document as XML into any `std::io::Write` sink.
510    ///
511    /// More memory-efficient than [`to_xml`](AbxStreamParser::to_xml) for very
512    /// large files because it does not accumulate the whole result in a `String`.
513    pub fn write_xml(&mut self, writer: &mut impl std::io::Write) -> Result<()> {
514        writer.write_all(b"<?xml version=\"1.0\" encoding=\"UTF-8\"?>")?;
515        // One scratch buffer reused (cleared, not reallocated) across every
516        // event, instead of a fresh allocation per event.
517        let mut tmp = String::new();
518        while let Some(ev) = self.next_event()? {
519            if matches!(ev, Event::EndDocument) {
520                break;
521            }
522            tmp.clear();
523            render_event(&ev, &mut tmp);
524            writer.write_all(tmp.as_bytes())?;
525        }
526        Ok(())
527    }
528
529    /// Collect the whole document into a `HashMap<element → Vec<HashMap<attr → value_str>>>`.
530    pub fn into_map(mut self) -> Result<HashMap<String, Vec<HashMap<String, String>>>> {
531        let mut map: HashMap<String, Vec<HashMap<String, String>>> = HashMap::new();
532        while let Some(ev) = self.next_event()? {
533            if let Event::StartTag { name, attributes } = ev {
534                let entry = map.entry(name.into()).or_default();
535                let mut attrs = HashMap::new();
536                for attr in attributes {
537                    attrs.insert(attr.name.into(), attr.value.as_str().into_owned());
538                }
539                entry.push(attrs);
540            }
541        }
542        Ok(map)
543    }
544
545    /// Unwrap the underlying reader, discarding any buffered data.
546    pub fn into_inner(self) -> R {
547        self.reader
548    }
549}
550
551impl<R: Read> Iterator for AbxStreamParser<R> {
552    type Item = Result<Event>;
553
554    fn next(&mut self) -> Option<Self::Item> {
555        match self.next_event() {
556            Ok(Some(ev)) => Some(Ok(ev)),
557            Ok(None) => None,
558            Err(e) => Some(Err(e)),
559        }
560    }
561}
562
563/// Lazily yields each remaining `<element>`, deserialized into `T`. See
564/// [`AbxStreamParser::deserialize_iter`].
565#[cfg(feature = "serialize")]
566pub struct DeserializeIter<'p, R: Read, T> {
567    parser: &'p mut AbxStreamParser<R>,
568    element: &'p str,
569    _marker: std::marker::PhantomData<T>,
570}
571
572#[cfg(feature = "serialize")]
573impl<'p, R: Read, T: serde::de::DeserializeOwned> Iterator for DeserializeIter<'p, R, T> {
574    type Item = Result<T>;
575
576    fn next(&mut self) -> Option<Self::Item> {
577        self.parser.deserialize_next(self.element).transpose()
578    }
579}