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}