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// ---------------------------------------------------------------------------
43// Buffer constants
44// ---------------------------------------------------------------------------
45
46/// Initial ring-buffer capacity (4 KiB).
47const INITIAL_BUF: usize = 4096;
48/// How many bytes to try to read per refill.
49const READ_CHUNK: usize = 4096;
50
51// ---------------------------------------------------------------------------
52// AbxStreamParser
53// ---------------------------------------------------------------------------
54
55/// Pull parser that reads from any `R: Read` source.
56///
57/// # Example
58/// ```rust,ignore
59/// use abx::AbxStreamParser;
60/// use std::io::BufReader;
61///
62/// let file = std::fs::File::open("backup.abx")?;
63/// let mut p = AbxStreamParser::new(BufReader::new(file))?;
64///
65/// while let Some(ev) = p.next_event()? {
66///     match ev {
67///         abx::Event::StartTag { name, attributes } => {
68///             println!("<{name}>");
69///             for a in &attributes {
70///                 println!("  {}={}", a.name, a.as_str());
71///             }
72///         }
73///         abx::Event::EndTag { name } => println!("</{name}>"),
74///         _ => {}
75///     }
76/// }
77/// ```
78#[derive(Debug)]
79pub struct AbxStreamParser<R: Read> {
80    reader: R,
81    /// Internal ring buffer.
82    buf: Vec<u8>,
83    /// Read cursor inside `buf`.
84    pos: usize,
85    /// Total valid bytes in `buf` (always >= pos).
86    len: usize,
87    /// `true` once the underlying reader returned 0 bytes.
88    eof: bool,
89    /// Interned string pool.
90    pool: Vec<crate::InternedStr>,
91}
92
93impl<R: Read> AbxStreamParser<R> {
94    // -----------------------------------------------------------------------
95    // Constructor
96    // -----------------------------------------------------------------------
97
98    /// Create a new parser from any reader.
99    ///
100    /// Reads and validates the 4-byte magic header immediately.  Returns an
101    /// error if the reader is too short or the header does not match.
102    pub fn new(reader: R) -> Result<Self> {
103        let mut p = AbxStreamParser {
104            reader,
105            buf: vec![0u8; INITIAL_BUF],
106            pos: 0,
107            len: 0,
108            eof: false,
109            pool: Vec::with_capacity(32),
110        };
111
112        // Read at least 4 bytes for the magic header.
113        p.ensure(4)?;
114
115        let magic: [u8; 4] = p.buf[p.pos..p.pos + 4].try_into().unwrap();
116        if magic != MAGIC {
117            return Err(AbxError::InvalidMagic {
118                expected: MAGIC,
119                actual: magic,
120            });
121        }
122        p.pos += 4;
123        Ok(p)
124    }
125
126    // -----------------------------------------------------------------------
127    // Buffer management
128    // -----------------------------------------------------------------------
129
130    /// Number of unconsumed bytes currently in the buffer.
131    #[inline]
132    fn available(&self) -> usize {
133        self.len - self.pos
134    }
135
136    /// Compact the buffer (slide unconsumed bytes to front) then read from the
137    /// underlying reader until we have at least `needed` bytes available, or
138    /// until EOF.
139    fn ensure(&mut self, needed: usize) -> Result<()> {
140        // Compact first so we always have room at the back.
141        if self.pos > 0 {
142            self.buf.copy_within(self.pos..self.len, 0);
143            self.len -= self.pos;
144            self.pos = 0;
145        }
146
147        while self.available() < needed && !self.eof {
148            // Grow if necessary.
149            let spare = self.buf.len() - self.len;
150            if spare < READ_CHUNK {
151                self.buf
152                    .resize(self.len + READ_CHUNK.max(needed - self.available()), 0);
153            }
154
155            let n = self.reader.read(&mut self.buf[self.len..])?;
156            if n == 0 {
157                self.eof = true;
158            } else {
159                self.len += n;
160            }
161        }
162
163        Ok(())
164    }
165
166    // -----------------------------------------------------------------------
167    // Primitive readers (nom-based, with auto-refill on Incomplete)
168    // -----------------------------------------------------------------------
169
170    /// Run a nom parser against the unconsumed tail of the buffer, refilling
171    /// if necessary.  Returns the parsed value and advances `pos`.
172    fn parse<F, T>(&mut self, mut f: F) -> Result<T>
173    where
174        F: FnMut(&[u8]) -> nom::IResult<&[u8], T>,
175    {
176        loop {
177            match f(&self.buf[self.pos..self.len]) {
178                Ok((rest, val)) => {
179                    self.pos = self.len - rest.len();
180                    return Ok(val);
181                }
182                Err(nom::Err::Incomplete(Needed::Size(n))) => {
183                    let need = self.available() + n.get();
184                    self.ensure(need)?;
185                    if self.eof && self.available() < n.get() {
186                        return Err(AbxError::UnexpectedEof("primitive"));
187                    }
188                }
189                Err(nom::Err::Incomplete(Needed::Unknown)) => {
190                    // Should not happen with our complete:: parsers, but handle gracefully.
191                    self.ensure(self.available() + 1)?;
192                    if self.eof {
193                        return Err(AbxError::UnexpectedEof("primitive"));
194                    }
195                }
196                Err(e) => return Err(AbxError::Nom(format!("{e:?}"))),
197            }
198        }
199    }
200
201    fn read_u8(&mut self) -> Result<u8> {
202        self.parse(|i| be_u8(i))
203    }
204    fn read_u16(&mut self) -> Result<u16> {
205        self.parse(|i| be_u16(i))
206    }
207    fn read_i32(&mut self) -> Result<i32> {
208        self.parse(|i| be_i32(i))
209    }
210    fn read_i64(&mut self) -> Result<i64> {
211        self.parse(|i| be_i64(i))
212    }
213    fn read_f32(&mut self) -> Result<f32> {
214        self.parse(|i| be_f32(i))
215    }
216    fn read_f64(&mut self) -> Result<f64> {
217        self.parse(|i| be_f64(i))
218    }
219
220    /// Read a `u16`-length-prefixed UTF-8 blob.
221    fn read_utf(&mut self) -> Result<String> {
222        let len = self.read_u16()? as usize;
223        // Make sure the whole string payload is buffered.
224        self.ensure(len)?;
225        if self.available() < len {
226            return Err(AbxError::UnexpectedEof("UTF string payload"));
227        }
228        let s = std::str::from_utf8(&self.buf[self.pos..self.pos + len])
229            .map_err(|_| AbxError::InvalidUtf8)?
230            .to_owned();
231        self.pos += len;
232        Ok(s)
233    }
234
235    /// Read a `u16`-length-prefixed raw byte blob.
236    fn read_bytes_blob(&mut self) -> Result<Vec<u8>> {
237        let len = self.read_u16()? as usize;
238        self.ensure(len)?;
239        if self.available() < len {
240            return Err(AbxError::UnexpectedEof("bytes payload"));
241        }
242        let v = self.buf[self.pos..self.pos + len].to_vec();
243        self.pos += len;
244        Ok(v)
245    }
246
247    /// Read an interned string. Every occurrence after the first is a
248    /// back-reference into `pool`, resolved with `InternedStr::clone` (a
249    /// refcount bump) rather than a fresh allocation and copy.
250    fn read_interned(&mut self) -> Result<crate::InternedStr> {
251        let idx = self.read_u16()?;
252        if idx == INTERNED_NEW {
253            let s: crate::InternedStr = self.read_utf()?.into();
254            self.pool.push(s.clone());
255            Ok(s)
256        } else {
257            self.pool
258                .get(idx as usize)
259                .cloned()
260                .ok_or(AbxError::BadInternedIndex(idx))
261        }
262    }
263
264    // -----------------------------------------------------------------------
265    // Attribute value
266    // -----------------------------------------------------------------------
267
268    fn read_attr_value(&mut self, type_nibble: u8) -> Result<AttributeValue> {
269        match type_nibble {
270            TYPE_NULL => Ok(AttributeValue::Null),
271            TYPE_STRING => Ok(AttributeValue::String(self.read_utf()?)),
272            TYPE_STRING_INTERNED => Ok(AttributeValue::String(self.read_interned()?.to_string())),
273            TYPE_BYTES_HEX => Ok(AttributeValue::BytesHex(self.read_bytes_blob()?)),
274            TYPE_BYTES_BASE64 => Ok(AttributeValue::BytesBase64(self.read_bytes_blob()?)),
275            TYPE_INT => Ok(AttributeValue::Int(self.read_i32()?)),
276            TYPE_INT_HEX => Ok(AttributeValue::IntHex(self.read_i32()? as u32)),
277            TYPE_LONG => Ok(AttributeValue::Long(self.read_i64()?)),
278            TYPE_LONG_HEX => Ok(AttributeValue::LongHex(self.read_i64()? as u64)),
279            TYPE_FLOAT => Ok(AttributeValue::Float(self.read_f32()?)),
280            TYPE_DOUBLE => Ok(AttributeValue::Double(self.read_f64()?)),
281            TYPE_BOOLEAN_TRUE => Ok(AttributeValue::Boolean(true)),
282            TYPE_BOOLEAN_FALSE => Ok(AttributeValue::Boolean(false)),
283            other => Err(AbxError::UnknownAttributeType(other)),
284        }
285    }
286
287    // -----------------------------------------------------------------------
288    // Peek helpers (non-consuming, with refill)
289    // -----------------------------------------------------------------------
290
291    /// Peek at the next byte without consuming it. Returns `None` on EOF.
292    fn peek_u8(&mut self) -> Result<Option<u8>> {
293        self.ensure(1)?;
294        Ok(self.buf.get(self.pos).copied())
295    }
296
297    // -----------------------------------------------------------------------
298    // Public event API
299    // -----------------------------------------------------------------------
300
301    /// Pull the next [`Event`].  Returns `None` at end of input.
302    pub fn next_event(&mut self) -> Result<Option<Event>> {
303        // Refill at least 1 byte.
304        self.ensure(1)?;
305        if self.available() == 0 {
306            return Ok(None);
307        }
308
309        let token = self.read_u8()?;
310        let cmd = token & 0x0F;
311        let type_nibble = token & 0xF0;
312
313        let event = match cmd {
314            CMD_START_DOCUMENT => Event::StartDocument,
315            CMD_END_DOCUMENT => return Ok(Some(Event::EndDocument)),
316
317            CMD_START_TAG => {
318                let name = self.read_interned()?;
319                let mut attributes = Vec::new();
320
321                // Eagerly consume following ATTRIBUTE tokens without peeking
322                // across I/O boundaries more than necessary.
323                loop {
324                    match self.peek_u8()? {
325                        Some(next) if (next & 0x0F) == CMD_ATTRIBUTE => {
326                            self.pos += 1; // consume peeked byte
327                            let attr_type = next & 0xF0;
328                            let attr_name = self.read_interned()?;
329                            let attr_value = self.read_attr_value(attr_type)?;
330                            attributes.push(Attribute {
331                                name: attr_name,
332                                value: attr_value,
333                            });
334                        }
335                        _ => break,
336                    }
337                }
338
339                Event::StartTag { name, attributes }
340            }
341
342            CMD_END_TAG => Event::EndTag {
343                name: self.read_interned()?,
344            },
345
346            CMD_TEXT => Event::Text(if type_nibble == TYPE_STRING {
347                self.read_utf()?
348            } else {
349                String::new()
350            }),
351            CMD_CDSECT => Event::CdataSection(if type_nibble == TYPE_STRING {
352                self.read_utf()?
353            } else {
354                String::new()
355            }),
356            CMD_ENTITY_REF => Event::EntityReference(if type_nibble == TYPE_STRING {
357                self.read_utf()?
358            } else {
359                String::new()
360            }),
361            CMD_IGNORABLE_WHITESPACE => Event::IgnorableWhitespace(if type_nibble == TYPE_STRING {
362                self.read_utf()?
363            } else {
364                String::new()
365            }),
366            CMD_PROCESSING_INSTRUCTION => {
367                Event::ProcessingInstruction(if type_nibble == TYPE_STRING {
368                    self.read_utf()?
369                } else {
370                    String::new()
371                })
372            }
373            CMD_COMMENT => Event::Comment(if type_nibble == TYPE_STRING {
374                self.read_utf()?
375            } else {
376                String::new()
377            }),
378            CMD_DOCDECL => Event::DocDecl(if type_nibble == TYPE_STRING {
379                self.read_utf()?
380            } else {
381                String::new()
382            }),
383
384            other => return Err(AbxError::UnknownCommand(other)),
385        };
386
387        Ok(Some(event))
388    }
389
390    // -----------------------------------------------------------------------
391    // Convenience API  (same surface as AbxParser)
392    // -----------------------------------------------------------------------
393
394    /// Drain all remaining events into a `Vec`.
395    pub fn collect_events(&mut self) -> Result<Vec<Event>> {
396        let mut out = Vec::new();
397        while let Some(ev) = self.next_event()? {
398            out.push(ev);
399        }
400        Ok(out)
401    }
402
403    /// Return the value of the first matching `attr` inside any `<element>` tag.
404    pub fn find_attribute(&mut self, element: &str, attr: &str) -> Option<AttributeValue> {
405        loop {
406            match self.next_event().ok()? {
407                Some(Event::StartTag { name, attributes }) if name == element => {
408                    if let Some(a) = attributes.into_iter().find(|a| a.name == attr) {
409                        return Some(a.value);
410                    }
411                }
412                Some(Event::EndDocument) | None => return None,
413                _ => {}
414            }
415        }
416    }
417
418    /// All values of `attr` found in `<element>` tags.
419    pub fn find_all_attributes(
420        &mut self,
421        element: &str,
422        attr: &str,
423    ) -> Result<Vec<AttributeValue>> {
424        let mut out = Vec::new();
425        while let Some(ev) = self.next_event()? {
426            if let Event::StartTag { name, attributes } = ev
427                && name == element
428            {
429                out.extend(
430                    attributes
431                        .into_iter()
432                        .filter(|a| a.name == attr)
433                        .map(|a| a.value),
434                );
435            }
436        }
437        Ok(out)
438    }
439
440    /// Attributes of the first `<element>` tag.
441    pub fn attributes_of(&mut self, element: &str) -> Option<Vec<Attribute>> {
442        loop {
443            match self.next_event().ok()? {
444                Some(Event::StartTag { name, attributes }) if name == element => {
445                    return Some(attributes);
446                }
447                Some(Event::EndDocument) | None => return 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
559// ---------------------------------------------------------------------------
560// Iterator impl  — lets you use `for ev in parser { … }`
561// ---------------------------------------------------------------------------
562
563impl<R: Read> Iterator for AbxStreamParser<R> {
564    type Item = Result<Event>;
565
566    fn next(&mut self) -> Option<Self::Item> {
567        match self.next_event() {
568            Ok(Some(ev)) => Some(Ok(ev)),
569            Ok(None) => None,
570            Err(e) => Some(Err(e)),
571        }
572    }
573}
574
575// ---------------------------------------------------------------------------
576// DeserializeIter — lazy struct-per-element streaming, from deserialize_iter
577// ---------------------------------------------------------------------------
578
579/// Lazily yields each remaining `<element>`, deserialized into `T`. See
580/// [`AbxStreamParser::deserialize_iter`].
581#[cfg(feature = "serialize")]
582pub struct DeserializeIter<'p, R: Read, T> {
583    parser: &'p mut AbxStreamParser<R>,
584    element: &'p str,
585    _marker: std::marker::PhantomData<T>,
586}
587
588#[cfg(feature = "serialize")]
589impl<'p, R: Read, T: serde::de::DeserializeOwned> Iterator for DeserializeIter<'p, R, T> {
590    type Item = Result<T>;
591
592    fn next(&mut self) -> Option<Self::Item> {
593        self.parser.deserialize_next(self.element).transpose()
594    }
595}