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        // Bail out before touching the buffer at all when nothing needs to
133        // be read: this is called on every event (and every string/blob
134        // read), so compacting unconditionally here turned every one of
135        // those calls into an O(available()) memmove even when no refill
136        // was going to happen.
137        if self.available() >= needed || self.eof {
138            return Ok(());
139        }
140
141        // Compact first so we always have room at the back.
142        if self.pos > 0 {
143            self.buf.copy_within(self.pos..self.len, 0);
144            self.len -= self.pos;
145            self.pos = 0;
146        }
147
148        while self.available() < needed && !self.eof {
149            // Grow if necessary.
150            let spare = self.buf.len() - self.len;
151            if spare < READ_CHUNK {
152                self.buf
153                    .resize(self.len + READ_CHUNK.max(needed - self.available()), 0);
154            }
155
156            let n = self.reader.read(&mut self.buf[self.len..])?;
157            if n == 0 {
158                self.eof = true;
159            } else {
160                self.len += n;
161            }
162        }
163
164        Ok(())
165    }
166
167    // -----------------------------------------------------------------------
168    // Primitive readers (nom-based, with auto-refill on Incomplete)
169    // -----------------------------------------------------------------------
170
171    /// Run a nom parser against the unconsumed tail of the buffer, refilling
172    /// if necessary.  Returns the parsed value and advances `pos`.
173    fn parse<F, T>(&mut self, mut f: F) -> Result<T>
174    where
175        F: FnMut(&[u8]) -> nom::IResult<&[u8], T>,
176    {
177        loop {
178            match f(&self.buf[self.pos..self.len]) {
179                Ok((rest, val)) => {
180                    self.pos = self.len - rest.len();
181                    return Ok(val);
182                }
183                Err(nom::Err::Incomplete(Needed::Size(n))) => {
184                    let need = self.available() + n.get();
185                    self.ensure(need)?;
186                    if self.eof && self.available() < n.get() {
187                        return Err(AbxError::UnexpectedEof("primitive"));
188                    }
189                }
190                Err(nom::Err::Incomplete(Needed::Unknown)) => {
191                    // Should not happen with our complete:: parsers, but handle gracefully.
192                    self.ensure(self.available() + 1)?;
193                    if self.eof {
194                        return Err(AbxError::UnexpectedEof("primitive"));
195                    }
196                }
197                Err(e) => return Err(AbxError::Nom(format!("{e:?}"))),
198            }
199        }
200    }
201
202    fn read_u8(&mut self) -> Result<u8> {
203        self.parse(|i| be_u8(i))
204    }
205    fn read_u16(&mut self) -> Result<u16> {
206        self.parse(|i| be_u16(i))
207    }
208    fn read_i32(&mut self) -> Result<i32> {
209        self.parse(|i| be_i32(i))
210    }
211    fn read_i64(&mut self) -> Result<i64> {
212        self.parse(|i| be_i64(i))
213    }
214    fn read_f32(&mut self) -> Result<f32> {
215        self.parse(|i| be_f32(i))
216    }
217    fn read_f64(&mut self) -> Result<f64> {
218        self.parse(|i| be_f64(i))
219    }
220
221    /// Read a `u16`-length-prefixed UTF-8 blob.
222    fn read_utf(&mut self) -> Result<String> {
223        let len = self.read_u16()? as usize;
224        // Make sure the whole string payload is buffered.
225        self.ensure(len)?;
226        if self.available() < len {
227            return Err(AbxError::UnexpectedEof("UTF string payload"));
228        }
229        let s = std::str::from_utf8(&self.buf[self.pos..self.pos + len])
230            .map_err(|_| AbxError::InvalidUtf8)?
231            .to_owned();
232        self.pos += len;
233        Ok(s)
234    }
235
236    /// Read a `u16`-length-prefixed raw byte blob.
237    fn read_bytes_blob(&mut self) -> Result<Vec<u8>> {
238        let len = self.read_u16()? as usize;
239        self.ensure(len)?;
240        if self.available() < len {
241            return Err(AbxError::UnexpectedEof("bytes payload"));
242        }
243        let v = self.buf[self.pos..self.pos + len].to_vec();
244        self.pos += len;
245        Ok(v)
246    }
247
248    /// Read an interned string. Every occurrence after the first is a
249    /// back-reference into `pool`, resolved with `InternedStr::clone` (a
250    /// refcount bump) rather than a fresh allocation and copy.
251    fn read_interned(&mut self) -> Result<crate::InternedStr> {
252        let idx = self.read_u16()?;
253        if idx == INTERNED_NEW {
254            let s: crate::InternedStr = self.read_utf()?.into();
255            self.pool.push(s.clone());
256            Ok(s)
257        } else {
258            self.pool
259                .get(idx as usize)
260                .cloned()
261                .ok_or(AbxError::BadInternedIndex(idx))
262        }
263    }
264
265    // -----------------------------------------------------------------------
266    // Attribute value
267    // -----------------------------------------------------------------------
268
269    fn read_attr_value(&mut self, type_nibble: u8) -> Result<AttributeValue> {
270        match type_nibble {
271            TYPE_NULL => Ok(AttributeValue::Null),
272            TYPE_STRING => Ok(AttributeValue::String(self.read_utf()?)),
273            TYPE_STRING_INTERNED => Ok(AttributeValue::String(String::from(self.read_interned()?))),
274            TYPE_BYTES_HEX => Ok(AttributeValue::BytesHex(self.read_bytes_blob()?)),
275            TYPE_BYTES_BASE64 => Ok(AttributeValue::BytesBase64(self.read_bytes_blob()?)),
276            TYPE_INT => Ok(AttributeValue::Int(self.read_i32()?)),
277            TYPE_INT_HEX => Ok(AttributeValue::IntHex(self.read_i32()? as u32)),
278            TYPE_LONG => Ok(AttributeValue::Long(self.read_i64()?)),
279            TYPE_LONG_HEX => Ok(AttributeValue::LongHex(self.read_i64()? as u64)),
280            TYPE_FLOAT => Ok(AttributeValue::Float(self.read_f32()?)),
281            TYPE_DOUBLE => Ok(AttributeValue::Double(self.read_f64()?)),
282            TYPE_BOOLEAN_TRUE => Ok(AttributeValue::Boolean(true)),
283            TYPE_BOOLEAN_FALSE => Ok(AttributeValue::Boolean(false)),
284            other => Err(AbxError::UnknownAttributeType(other)),
285        }
286    }
287
288    // -----------------------------------------------------------------------
289    // Peek helpers (non-consuming, with refill)
290    // -----------------------------------------------------------------------
291
292    /// Peek at the next byte without consuming it. Returns `None` on EOF.
293    fn peek_u8(&mut self) -> Result<Option<u8>> {
294        self.ensure(1)?;
295        Ok(self.buf.get(self.pos).copied())
296    }
297
298    // -----------------------------------------------------------------------
299    // Public event API
300    // -----------------------------------------------------------------------
301
302    /// Pull the next [`Event`].  Returns `None` at end of input.
303    pub fn next_event(&mut self) -> Result<Option<Event>> {
304        // Refill at least 1 byte.
305        self.ensure(1)?;
306        if self.available() == 0 {
307            return Ok(None);
308        }
309
310        let token = self.read_u8()?;
311        let cmd = token & 0x0F;
312        let type_nibble = token & 0xF0;
313
314        let event = match cmd {
315            CMD_START_DOCUMENT => Event::StartDocument,
316            CMD_END_DOCUMENT => return Ok(Some(Event::EndDocument)),
317
318            CMD_START_TAG => {
319                let name = self.read_interned()?;
320                let mut attributes = Vec::with_capacity(4);
321
322                // Eagerly consume following ATTRIBUTE tokens without peeking
323                // across I/O boundaries more than necessary.
324                loop {
325                    match self.peek_u8()? {
326                        Some(next) if (next & 0x0F) == CMD_ATTRIBUTE => {
327                            self.pos += 1; // consume peeked byte
328                            let attr_type = next & 0xF0;
329                            let attr_name = self.read_interned()?;
330                            let attr_value = self.read_attr_value(attr_type)?;
331                            attributes.push(Attribute {
332                                name: attr_name,
333                                value: attr_value,
334                            });
335                        }
336                        _ => break,
337                    }
338                }
339
340                Event::StartTag { name, attributes }
341            }
342
343            CMD_END_TAG => Event::EndTag {
344                name: self.read_interned()?,
345            },
346
347            CMD_TEXT => Event::Text(if type_nibble == TYPE_STRING {
348                self.read_utf()?
349            } else {
350                String::new()
351            }),
352            CMD_CDSECT => Event::CdataSection(if type_nibble == TYPE_STRING {
353                self.read_utf()?
354            } else {
355                String::new()
356            }),
357            CMD_ENTITY_REF => Event::EntityReference(if type_nibble == TYPE_STRING {
358                self.read_utf()?
359            } else {
360                String::new()
361            }),
362            CMD_IGNORABLE_WHITESPACE => Event::IgnorableWhitespace(if type_nibble == TYPE_STRING {
363                self.read_utf()?
364            } else {
365                String::new()
366            }),
367            CMD_PROCESSING_INSTRUCTION => {
368                Event::ProcessingInstruction(if type_nibble == TYPE_STRING {
369                    self.read_utf()?
370                } else {
371                    String::new()
372                })
373            }
374            CMD_COMMENT => Event::Comment(if type_nibble == TYPE_STRING {
375                self.read_utf()?
376            } else {
377                String::new()
378            }),
379            CMD_DOCDECL => Event::DocDecl(if type_nibble == TYPE_STRING {
380                self.read_utf()?
381            } else {
382                String::new()
383            }),
384
385            other => return Err(AbxError::UnknownCommand(other)),
386        };
387
388        Ok(Some(event))
389    }
390
391    // -----------------------------------------------------------------------
392    // Convenience API  (same surface as AbxParser)
393    // -----------------------------------------------------------------------
394
395    /// Drain all remaining events into a `Vec`.
396    pub fn collect_events(&mut self) -> Result<Vec<Event>> {
397        let mut out = Vec::new();
398        while let Some(ev) = self.next_event()? {
399            out.push(ev);
400        }
401        Ok(out)
402    }
403
404    /// Return the value of the first matching `attr` inside any `<element>`
405    /// tag. `Ok(None)` means the element/attribute wasn't found before the
406    /// document ended; `Err` means a parse failure interrupted the search.
407    /// Callers that don't care about that distinction can collapse both
408    /// into `None` with `.ok().flatten()`.
409    pub fn find_attribute(&mut self, element: &str, attr: &str) -> Result<Option<AttributeValue>> {
410        loop {
411            match self.next_event()? {
412                Some(Event::StartTag { name, attributes }) if name == element => {
413                    if let Some(a) = attributes.into_iter().find(|a| a.name == attr) {
414                        return Ok(Some(a.value));
415                    }
416                }
417                Some(Event::EndDocument) | None => return Ok(None),
418                _ => {}
419            }
420        }
421    }
422
423    /// All values of `attr` found in `<element>` tags.
424    pub fn find_all_attributes(
425        &mut self,
426        element: &str,
427        attr: &str,
428    ) -> Result<Vec<AttributeValue>> {
429        let mut out = Vec::new();
430        while let Some(ev) = self.next_event()? {
431            if let Event::StartTag { name, attributes } = ev
432                && name == element
433            {
434                out.extend(
435                    attributes
436                        .into_iter()
437                        .filter(|a| a.name == attr)
438                        .map(|a| a.value),
439                );
440            }
441        }
442        Ok(out)
443    }
444
445    /// Attributes of the first `<element>` tag. `Ok(None)` means no
446    /// matching tag was found before the document ended; `Err` means a
447    /// parse failure interrupted the search — see
448    /// [`find_attribute`](Self::find_attribute) for how to collapse both
449    /// into a plain `None`.
450    pub fn attributes_of(&mut self, element: &str) -> Result<Option<Vec<Attribute>>> {
451        loop {
452            match self.next_event()? {
453                Some(Event::StartTag { name, attributes }) if name == element => {
454                    return Ok(Some(attributes));
455                }
456                Some(Event::EndDocument) | None => return Ok(None),
457                _ => {}
458            }
459        }
460    }
461
462    /// Attributes of every `<element>` tag.
463    pub fn all_attributes_of(&mut self, element: &str) -> Result<Vec<Vec<Attribute>>> {
464        let mut out = Vec::new();
465        while let Some(ev) = self.next_event()? {
466            if let Event::StartTag { name, attributes } = ev
467                && name == element
468            {
469                out.push(attributes);
470            }
471        }
472        Ok(out)
473    }
474
475    /// Find the next `<element>`, deserialize its attributes (and direct
476    /// text content, via a `#[serde(rename = "$text")]` field) into `T`,
477    /// then skip past its matching end tag. `Ok(None)` at end of document.
478    #[cfg(feature = "serialize")]
479    pub fn deserialize_next<T: serde::de::DeserializeOwned>(
480        &mut self,
481        element: &str,
482    ) -> Result<Option<T>> {
483        crate::de::find_and_consume_element(self, element)
484    }
485
486    /// Deserialize every remaining `<element>` into a `Vec<T>`.
487    #[cfg(feature = "serialize")]
488    pub fn deserialize_all<T: serde::de::DeserializeOwned>(
489        &mut self,
490        element: &str,
491    ) -> Result<Vec<T>> {
492        let mut out = Vec::new();
493        while let Some(item) = self.deserialize_next(element)? {
494            out.push(item);
495        }
496        Ok(out)
497    }
498
499    /// Lazily deserialize every remaining `<element>` as a `T`, one at a
500    /// time, without buffering the whole document or the whole result set —
501    /// the streaming counterpart to [`deserialize_all`](Self::deserialize_all).
502    #[cfg(feature = "serialize")]
503    pub fn deserialize_iter<'p, T: serde::de::DeserializeOwned>(
504        &'p mut self,
505        element: &'p str,
506    ) -> DeserializeIter<'p, R, T> {
507        DeserializeIter {
508            parser: self,
509            element,
510            _marker: std::marker::PhantomData,
511        }
512    }
513
514    /// Render the rest of the document as an XML string.
515    pub fn to_xml(&mut self) -> Result<String> {
516        let mut buf = String::from(r#"<?xml version="1.0" encoding="UTF-8"?>"#);
517        while let Some(ev) = self.next_event()? {
518            if matches!(ev, Event::EndDocument) {
519                break;
520            }
521            render_event(&ev, &mut buf);
522        }
523        Ok(buf)
524    }
525
526    /// Write the rest of the document as XML into any `std::io::Write` sink.
527    ///
528    /// More memory-efficient than [`to_xml`](AbxStreamParser::to_xml) for very
529    /// large files because it does not accumulate the whole result in a `String`.
530    pub fn write_xml(&mut self, writer: &mut impl std::io::Write) -> Result<()> {
531        writer.write_all(b"<?xml version=\"1.0\" encoding=\"UTF-8\"?>")?;
532        // One scratch buffer reused (cleared, not reallocated) across every
533        // event, instead of a fresh allocation per event.
534        let mut tmp = String::new();
535        while let Some(ev) = self.next_event()? {
536            if matches!(ev, Event::EndDocument) {
537                break;
538            }
539            tmp.clear();
540            render_event(&ev, &mut tmp);
541            writer.write_all(tmp.as_bytes())?;
542        }
543        Ok(())
544    }
545
546    /// Collect the whole document into a `HashMap<element → Vec<HashMap<attr → value_str>>>`.
547    pub fn into_map(mut self) -> Result<HashMap<String, Vec<HashMap<String, String>>>> {
548        let mut map: HashMap<String, Vec<HashMap<String, String>>> = HashMap::new();
549        while let Some(ev) = self.next_event()? {
550            if let Event::StartTag { name, attributes } = ev {
551                let entry = map.entry(name.into()).or_default();
552                let mut attrs = HashMap::new();
553                for attr in attributes {
554                    attrs.insert(attr.name.into(), attr.value.as_str().into_owned());
555                }
556                entry.push(attrs);
557            }
558        }
559        Ok(map)
560    }
561
562    /// Unwrap the underlying reader, discarding any buffered data.
563    pub fn into_inner(self) -> R {
564        self.reader
565    }
566}
567
568impl<R: Read> Iterator for AbxStreamParser<R> {
569    type Item = Result<Event>;
570
571    fn next(&mut self) -> Option<Self::Item> {
572        match self.next_event() {
573            Ok(Some(ev)) => Some(Ok(ev)),
574            Ok(None) => None,
575            Err(e) => Some(Err(e)),
576        }
577    }
578}
579
580/// Lazily yields each remaining `<element>`, deserialized into `T`. See
581/// [`AbxStreamParser::deserialize_iter`].
582#[cfg(feature = "serialize")]
583pub struct DeserializeIter<'p, R: Read, T> {
584    parser: &'p mut AbxStreamParser<R>,
585    element: &'p str,
586    _marker: std::marker::PhantomData<T>,
587}
588
589#[cfg(feature = "serialize")]
590impl<'p, R: Read, T: serde::de::DeserializeOwned> Iterator for DeserializeIter<'p, R, T> {
591    type Item = Result<T>;
592
593    fn next(&mut self) -> Option<Self::Item> {
594        self.parser.deserialize_next(self.element).transpose()
595    }
596}