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>`
396    /// tag. `Ok(None)` means the element/attribute wasn't found before the
397    /// document ended; `Err` means a parse failure interrupted the search.
398    /// Callers that don't care about that distinction can collapse both
399    /// into `None` with `.ok().flatten()`.
400    pub fn find_attribute(&mut self, element: &str, attr: &str) -> Result<Option<AttributeValue>> {
401        loop {
402            match self.next_event()? {
403                Some(Event::StartTag { name, attributes }) if name == element => {
404                    if let Some(a) = attributes.into_iter().find(|a| a.name == attr) {
405                        return Ok(Some(a.value));
406                    }
407                }
408                Some(Event::EndDocument) | None => return Ok(None),
409                _ => {}
410            }
411        }
412    }
413
414    /// All values of `attr` found in `<element>` tags.
415    pub fn find_all_attributes(
416        &mut self,
417        element: &str,
418        attr: &str,
419    ) -> Result<Vec<AttributeValue>> {
420        let mut out = Vec::new();
421        while let Some(ev) = self.next_event()? {
422            if let Event::StartTag { name, attributes } = ev
423                && name == element
424            {
425                out.extend(
426                    attributes
427                        .into_iter()
428                        .filter(|a| a.name == attr)
429                        .map(|a| a.value),
430                );
431            }
432        }
433        Ok(out)
434    }
435
436    /// Attributes of the first `<element>` tag. `Ok(None)` means no
437    /// matching tag was found before the document ended; `Err` means a
438    /// parse failure interrupted the search — see
439    /// [`find_attribute`](Self::find_attribute) for how to collapse both
440    /// into a plain `None`.
441    pub fn attributes_of(&mut self, element: &str) -> Result<Option<Vec<Attribute>>> {
442        loop {
443            match self.next_event()? {
444                Some(Event::StartTag { name, attributes }) if name == element => {
445                    return Ok(Some(attributes));
446                }
447                Some(Event::EndDocument) | None => return Ok(None),
448                _ => {}
449            }
450        }
451    }
452
453    /// Attributes of every `<element>` tag.
454    pub fn all_attributes_of(&mut self, element: &str) -> Result<Vec<Vec<Attribute>>> {
455        let mut out = Vec::new();
456        while let Some(ev) = self.next_event()? {
457            if let Event::StartTag { name, attributes } = ev
458                && name == element
459            {
460                out.push(attributes);
461            }
462        }
463        Ok(out)
464    }
465
466    /// Find the next `<element>`, deserialize its attributes (and direct
467    /// text content, via a `#[serde(rename = "$text")]` field) into `T`,
468    /// then skip past its matching end tag. `Ok(None)` at end of document.
469    #[cfg(feature = "serialize")]
470    pub fn deserialize_next<T: serde::de::DeserializeOwned>(
471        &mut self,
472        element: &str,
473    ) -> Result<Option<T>> {
474        crate::de::find_and_consume_element(self, element)
475    }
476
477    /// Deserialize every remaining `<element>` into a `Vec<T>`.
478    #[cfg(feature = "serialize")]
479    pub fn deserialize_all<T: serde::de::DeserializeOwned>(
480        &mut self,
481        element: &str,
482    ) -> Result<Vec<T>> {
483        let mut out = Vec::new();
484        while let Some(item) = self.deserialize_next(element)? {
485            out.push(item);
486        }
487        Ok(out)
488    }
489
490    /// Lazily deserialize every remaining `<element>` as a `T`, one at a
491    /// time, without buffering the whole document or the whole result set —
492    /// the streaming counterpart to [`deserialize_all`](Self::deserialize_all).
493    #[cfg(feature = "serialize")]
494    pub fn deserialize_iter<'p, T: serde::de::DeserializeOwned>(
495        &'p mut self,
496        element: &'p str,
497    ) -> DeserializeIter<'p, R, T> {
498        DeserializeIter {
499            parser: self,
500            element,
501            _marker: std::marker::PhantomData,
502        }
503    }
504
505    /// Render the rest of the document as an XML string.
506    pub fn to_xml(&mut self) -> Result<String> {
507        let mut buf = String::from(r#"<?xml version="1.0" encoding="UTF-8"?>"#);
508        while let Some(ev) = self.next_event()? {
509            if matches!(ev, Event::EndDocument) {
510                break;
511            }
512            render_event(&ev, &mut buf);
513        }
514        Ok(buf)
515    }
516
517    /// Write the rest of the document as XML into any `std::io::Write` sink.
518    ///
519    /// More memory-efficient than [`to_xml`](AbxStreamParser::to_xml) for very
520    /// large files because it does not accumulate the whole result in a `String`.
521    pub fn write_xml(&mut self, writer: &mut impl std::io::Write) -> Result<()> {
522        writer.write_all(b"<?xml version=\"1.0\" encoding=\"UTF-8\"?>")?;
523        // One scratch buffer reused (cleared, not reallocated) across every
524        // event, instead of a fresh allocation per event.
525        let mut tmp = String::new();
526        while let Some(ev) = self.next_event()? {
527            if matches!(ev, Event::EndDocument) {
528                break;
529            }
530            tmp.clear();
531            render_event(&ev, &mut tmp);
532            writer.write_all(tmp.as_bytes())?;
533        }
534        Ok(())
535    }
536
537    /// Collect the whole document into a `HashMap<element → Vec<HashMap<attr → value_str>>>`.
538    pub fn into_map(mut self) -> Result<HashMap<String, Vec<HashMap<String, String>>>> {
539        let mut map: HashMap<String, Vec<HashMap<String, String>>> = HashMap::new();
540        while let Some(ev) = self.next_event()? {
541            if let Event::StartTag { name, attributes } = ev {
542                let entry = map.entry(name.into()).or_default();
543                let mut attrs = HashMap::new();
544                for attr in attributes {
545                    attrs.insert(attr.name.into(), attr.value.as_str().into_owned());
546                }
547                entry.push(attrs);
548            }
549        }
550        Ok(map)
551    }
552
553    /// Unwrap the underlying reader, discarding any buffered data.
554    pub fn into_inner(self) -> R {
555        self.reader
556    }
557}
558
559impl<R: Read> Iterator for AbxStreamParser<R> {
560    type Item = Result<Event>;
561
562    fn next(&mut self) -> Option<Self::Item> {
563        match self.next_event() {
564            Ok(Some(ev)) => Some(Ok(ev)),
565            Ok(None) => None,
566            Err(e) => Some(Err(e)),
567        }
568    }
569}
570
571/// Lazily yields each remaining `<element>`, deserialized into `T`. See
572/// [`AbxStreamParser::deserialize_iter`].
573#[cfg(feature = "serialize")]
574pub struct DeserializeIter<'p, R: Read, T> {
575    parser: &'p mut AbxStreamParser<R>,
576    element: &'p str,
577    _marker: std::marker::PhantomData<T>,
578}
579
580#[cfg(feature = "serialize")]
581impl<'p, R: Read, T: serde::de::DeserializeOwned> Iterator for DeserializeIter<'p, R, T> {
582    type Item = Result<T>;
583
584    fn next(&mut self) -> Option<Self::Item> {
585        self.parser.deserialize_next(self.element).transpose()
586    }
587}