Skip to main content

bgpkit_parser/parser/iters/
default.rs

1/*!
2Default iterator implementations that skip errors and return successfully parsed items.
3*/
4use crate::models::*;
5use crate::parser::iters::{handle_record_parse_error, record_matches_filters};
6use crate::parser::mrt::mrt_elem::PendingElems;
7use crate::parser::BgpkitParser;
8use crate::{Elementor, Filterable};
9use std::io::Read;
10
11#[cfg(test)]
12mod tests;
13
14/*********
15MrtRecord Iterator
16**********/
17
18pub struct RecordIterator<R> {
19    pub parser: BgpkitParser<R>,
20    pub count: u64,
21    elementor: Elementor,
22}
23
24impl<R> RecordIterator<R> {
25    pub(crate) fn new(parser: BgpkitParser<R>) -> Self {
26        RecordIterator {
27            parser,
28            count: 0,
29            elementor: Elementor::new(),
30        }
31    }
32}
33
34impl<R: Read> Iterator for RecordIterator<R> {
35    type Item = MrtRecord;
36
37    fn next(&mut self) -> Option<MrtRecord> {
38        // Text-dump parsers have no MRT-record representation; short-circuit
39        // instead of spinning forever on Unsupported errors from next_record().
40        if self.parser.text_dump_iter.is_some() {
41            return None;
42        }
43        self.count += 1;
44        loop {
45            return match self.parser.next_record() {
46                Ok(v) => {
47                    if record_matches_filters(&v, &self.parser.filters, &mut self.elementor) {
48                        Some(v)
49                    } else {
50                        continue;
51                    }
52                }
53                Err(e) => {
54                    if handle_record_parse_error(&mut self.parser, e.error, e.bytes) {
55                        continue;
56                    }
57                    None
58                }
59            };
60        }
61    }
62}
63
64/*********
65BgpElem Iterator
66**********/
67
68pub struct ElemIterator<R> {
69    pending: PendingElems,
70    record_iter: RecordIterator<R>,
71    elementor: Elementor,
72    count: u64,
73}
74
75impl<R> ElemIterator<R> {
76    pub(crate) fn new(parser: BgpkitParser<R>) -> Self {
77        ElemIterator {
78            record_iter: RecordIterator::new(parser),
79            count: 0,
80            pending: PendingElems::Empty,
81            elementor: Elementor::new(),
82        }
83    }
84}
85
86impl<R: Read> Iterator for ElemIterator<R> {
87    type Item = BgpElem;
88
89    fn next(&mut self) -> Option<BgpElem> {
90        self.count += 1;
91
92        // Fast path: drain streaming text-dump elems directly, with filter support.
93        if let Some(iter) = &mut self.record_iter.parser.text_dump_iter {
94            for elem in iter.by_ref() {
95                if elem.match_filters(&self.record_iter.parser.filters) {
96                    return Some(elem);
97                }
98            }
99            return None;
100        }
101
102        loop {
103            // drain the current record's elems before reading the next record
104            while let Some(elem) = self.pending.next_elem(self.elementor.peer_table.as_ref()) {
105                if elem.match_filters(&self.record_iter.parser.filters) {
106                    return Some(elem);
107                }
108            }
109            // records without elems leave nothing pending, and the loop moves on to the next
110            let record = self.record_iter.next()?;
111            self.pending = self.elementor.ingest(record);
112        }
113    }
114}