Skip to main content

bgpkit_parser/parser/iters/
mod.rs

1/*!
2Iterator implementations for bgpkit-parser.
3
4This module contains different iterator implementations for parsing BGP data:
5- `default`: Standard iterators that skip errors (RecordIterator, ElemIterator)
6- `fallible`: Fallible iterators that return Results (FallibleRecordIterator, FallibleElemIterator)
7- `update`: Iterators for BGP UPDATE messages (UpdateIterator, FallibleUpdateIterator)
8
9It also contains the trait implementations that enable BgpkitParser to be used with
10Rust's iterator syntax.
11*/
12
13pub mod default;
14pub mod fallible;
15mod raw;
16mod update;
17
18// Re-export all iterator types for convenience
19pub use default::{ElemIterator, RecordIterator};
20pub use fallible::{FallibleElemIterator, FallibleRecordIterator};
21pub use raw::RawRecordIterator;
22pub use update::{
23    Bgp4MpUpdate, FallibleUpdateIterator, MrtUpdate, TableDumpV2Entry, UpdateIterator,
24};
25
26use crate::models::BgpElem;
27use crate::models::{MrtMessage, MrtRecord, TableDumpV2Message};
28use crate::parser::BgpkitParser;
29use crate::Elementor;
30use crate::RawMrtRecord;
31use std::io::Read;
32
33/// Use [ElemIterator] as the default iterator to return [BgpElem]s instead of [MrtRecord]s.
34impl<R: Read> IntoIterator for BgpkitParser<R> {
35    type Item = BgpElem;
36    type IntoIter = ElemIterator<R>;
37
38    fn into_iter(self) -> Self::IntoIter {
39        ElemIterator::new(self)
40    }
41}
42
43impl<R> BgpkitParser<R> {
44    pub fn into_record_iter(self) -> RecordIterator<R> {
45        RecordIterator::new(self)
46    }
47
48    pub fn into_elem_iter(self) -> ElemIterator<R> {
49        ElemIterator::new(self)
50    }
51
52    pub fn into_raw_record_iter(self) -> RawRecordIterator<R> {
53        RawRecordIterator::new(self)
54    }
55
56    /// Creates an iterator over BGP announcements from MRT data.
57    ///
58    /// This iterator yields `MrtUpdate` items from both UPDATES files (BGP4MP messages)
59    /// and RIB dump files (TableDump/TableDumpV2 messages). It's a middle ground
60    /// between `into_record_iter()` and `into_elem_iter()`:
61    ///
62    /// - More focused than `into_record_iter()` as it only returns BGP announcements
63    /// - More efficient than `into_elem_iter()` as it doesn't duplicate attributes per prefix
64    ///
65    /// The iterator returns an `MrtUpdate` enum with variants:
66    /// - `Bgp4MpUpdate`: BGP UPDATE messages from UPDATES files
67    /// - `TableDumpV2Entry`: RIB entries from TableDumpV2 RIB dumps
68    /// - `TableDumpMessage`: Legacy TableDump v1 messages
69    ///
70    /// # Example
71    /// ```no_run
72    /// use bgpkit_parser::{BgpkitParser, MrtUpdate};
73    ///
74    /// let parser = BgpkitParser::new("updates.mrt").unwrap();
75    /// for update in parser.into_update_iter() {
76    ///     match update {
77    ///         MrtUpdate::Bgp4MpUpdate(u) => {
78    ///             println!("Peer {} announced {} prefixes",
79    ///                 u.peer_ip,
80    ///                 u.message.announced_prefixes.len()
81    ///             );
82    ///         }
83    ///         MrtUpdate::TableDumpV2Entry(e) => {
84    ///             println!("RIB entry for {} with {} peers",
85    ///                 e.prefix,
86    ///                 e.rib_entries.len()
87    ///             );
88    ///         }
89    ///         MrtUpdate::TableDumpMessage(m) => {
90    ///             println!("Legacy table dump for {}", m.prefix);
91    ///         }
92    ///     }
93    /// }
94    /// ```
95    pub fn into_update_iter(self) -> UpdateIterator<R> {
96        UpdateIterator::new(self)
97    }
98
99    /// Creates a fallible iterator over MRT records that returns parsing errors.
100    ///
101    /// # Example
102    /// ```no_run
103    /// use bgpkit_parser::BgpkitParser;
104    ///
105    /// let parser = BgpkitParser::new("updates.mrt").unwrap();
106    /// for result in parser.into_fallible_record_iter() {
107    ///     match result {
108    ///         Ok(record) => {
109    ///             // Process the record
110    ///         }
111    ///         Err(e) => {
112    ///             // Handle the error
113    ///             eprintln!("Error parsing record: {}", e);
114    ///         }
115    ///     }
116    /// }
117    /// ```
118    pub fn into_fallible_record_iter(self) -> FallibleRecordIterator<R> {
119        FallibleRecordIterator::new(self)
120    }
121
122    /// Creates a fallible iterator over BGP elements that returns parsing errors.
123    ///
124    /// # Example
125    /// ```no_run
126    /// use bgpkit_parser::BgpkitParser;
127    ///
128    /// let parser = BgpkitParser::new("updates.mrt").unwrap();
129    /// for result in parser.into_fallible_elem_iter() {
130    ///     match result {
131    ///         Ok(elem) => {
132    ///             // Process the element
133    ///         }
134    ///         Err(e) => {
135    ///             // Handle the error
136    ///             eprintln!("Error parsing element: {}", e);
137    ///         }
138    ///     }
139    /// }
140    /// ```
141    pub fn into_fallible_elem_iter(self) -> FallibleElemIterator<R> {
142        FallibleElemIterator::new(self)
143    }
144
145    /// Creates a fallible iterator over BGP announcements that returns parsing errors.
146    ///
147    /// Unlike the default `into_update_iter()`, this iterator returns
148    /// `Result<MrtUpdate, ParserErrorWithBytes>` allowing users to handle parsing
149    /// errors explicitly instead of having them logged and skipped.
150    ///
151    /// # Example
152    /// ```no_run
153    /// use bgpkit_parser::{BgpkitParser, MrtUpdate};
154    ///
155    /// let parser = BgpkitParser::new("updates.mrt").unwrap();
156    /// for result in parser.into_fallible_update_iter() {
157    ///     match result {
158    ///         Ok(MrtUpdate::Bgp4MpUpdate(update)) => {
159    ///             println!("Peer {} announced {} prefixes",
160    ///                 update.peer_ip,
161    ///                 update.message.announced_prefixes.len()
162    ///             );
163    ///         }
164    ///         Ok(_) => { /* handle other variants */ }
165    ///         Err(e) => {
166    ///             eprintln!("Error parsing: {}", e);
167    ///         }
168    ///     }
169    /// }
170    /// ```
171    pub fn into_fallible_update_iter(self) -> FallibleUpdateIterator<R> {
172        FallibleUpdateIterator::new(self)
173    }
174
175    /// Creates an Elementor pre-initialized with PeerIndexTable and an iterator over raw records.
176    ///
177    /// This is useful for parallel processing where the Elementor needs to be shared across threads.
178    /// The Elementor is created with the PeerIndexTable from the first record if present,
179    /// otherwise a new Elementor is created.
180    ///
181    /// # Example
182    /// See the `parallel_records_to_elem` example for full usage.
183    /// ```ignore
184    /// use bgpkit_parser::BgpkitParser;
185    ///
186    /// let parser = BgpkitParser::new_cached(url, "/tmp")?;
187    /// let (elementor, records) = parser.into_elementor_and_raw_record_iter();
188    /// ```
189    ///
190    pub fn into_elementor_and_raw_record_iter(
191        self,
192    ) -> (Elementor, impl Iterator<Item = RawMrtRecord>)
193    where
194        R: Read,
195    {
196        let mut raw_iter = RawRecordIterator::new(self).peekable();
197        let elementor = match raw_iter.peek().cloned().and_then(|r| r.parse().ok()) {
198            Some(MrtRecord {
199                message: MrtMessage::TableDumpV2Message(TableDumpV2Message::PeerIndexTable(pit)),
200                ..
201            }) => {
202                raw_iter.next();
203                Elementor::with_peer_table(pit)
204            }
205            _ => Elementor::new(),
206        };
207        (elementor, raw_iter)
208    }
209
210    /// Creates an Elementor pre-initialized with PeerIndexTable and an iterator over parsed records.
211    ///
212    /// This is useful for parallel processing where the Elementor needs to be shared across threads.
213    /// The Elementor is created with the PeerIndexTable from the first record if present,
214    /// otherwise a new Elementor is created.
215    ///
216    /// # Example
217    /// See the `parallel_records_to_elem` example for full usage.
218    pub fn into_elementor_and_record_iter(self) -> (Elementor, impl Iterator<Item = MrtRecord>)
219    where
220        R: Read,
221    {
222        let mut record_iter = RecordIterator::new(self).peekable();
223        let elementor = match record_iter.peek().cloned() {
224            Some(MrtRecord {
225                message: MrtMessage::TableDumpV2Message(TableDumpV2Message::PeerIndexTable(pit)),
226                ..
227            }) => {
228                record_iter.next();
229                Elementor::with_peer_table(pit)
230            }
231            _ => Elementor::new(),
232        };
233        (elementor, record_iter)
234    }
235}