Skip to main content

dbc_rs/nodes/
impls.rs

1use super::{InnerNodes, Node, Nodes};
2
3impl Nodes {
4    /// Node set from parsed names.
5    pub(crate) fn new(nodes: InnerNodes) -> Self {
6        // Validation should have been done prior (by builder)
7        Self { nodes }
8    }
9
10    /// Returns an iterator over the node names.
11    ///
12    /// # Examples
13    ///
14    /// ```rust,no_run
15    /// use dbc_rs::Dbc;
16    ///
17    /// let dbc = Dbc::parse(r#"VERSION "1.0"
18    ///
19    /// BU_: ECM TCM BCM
20    /// "#)?;
21    ///
22    /// // Iterate over nodes
23    /// let mut iter = dbc.nodes().iter();
24    /// assert_eq!(iter.next(), Some("ECM"));
25    /// assert_eq!(iter.next(), Some("TCM"));
26    /// assert_eq!(iter.next(), Some("BCM"));
27    /// assert_eq!(iter.next(), None);
28    ///
29    /// // Or use in a loop
30    /// for node in dbc.nodes().iter() {
31    ///     println!("Node: {}", node);
32    /// }
33    /// # Ok::<(), dbc_rs::Error>(())
34    /// ```
35    #[inline]
36    #[must_use = "iterator is lazy and does nothing unless consumed"]
37    pub fn iter(&self) -> impl Iterator<Item = &str> + '_ {
38        self.nodes.iter().map(|node| node.name())
39    }
40
41    /// Returns an iterator over the node structs.
42    ///
43    /// This provides access to both the node name and its comment.
44    ///
45    /// # Examples
46    ///
47    /// ```rust,no_run
48    /// use dbc_rs::Dbc;
49    ///
50    /// let dbc = Dbc::parse(r#"VERSION "1.0"
51    ///
52    /// BU_: ECM TCM
53    ///
54    /// BO_ 256 Engine : 8 ECM
55    ///
56    /// CM_ BU_ ECM "Engine Control Module";
57    /// "#)?;
58    ///
59    /// for node in dbc.nodes().iter_nodes() {
60    ///     println!("Node: {}", node.name());
61    ///     if let Some(comment) = node.comment() {
62    ///         println!("  Comment: {}", comment);
63    ///     }
64    /// }
65    /// # Ok::<(), dbc_rs::Error>(())
66    /// ```
67    #[inline]
68    #[must_use = "iterator is lazy and does nothing unless consumed"]
69    pub fn iter_nodes(&self) -> impl Iterator<Item = &Node> + '_ {
70        self.nodes.iter()
71    }
72
73    /// Checks if a node name is in the list.
74    ///
75    /// The check is case-sensitive.
76    ///
77    /// # Arguments
78    ///
79    /// * `node` - The node name to check
80    ///
81    /// # Examples
82    ///
83    /// ```rust,no_run
84    /// use dbc_rs::Dbc;
85    ///
86    /// let dbc = Dbc::parse(r#"VERSION "1.0"
87    ///
88    /// BU_: ECM TCM
89    /// "#)?;
90    ///
91    /// assert!(dbc.nodes().contains("ECM"));
92    /// assert!(dbc.nodes().contains("TCM"));
93    /// assert!(!dbc.nodes().contains("BCM"));
94    /// assert!(!dbc.nodes().contains("ecm")); // Case-sensitive
95    /// # Ok::<(), dbc_rs::Error>(())
96    /// ```
97    #[inline]
98    #[must_use = "return value should be used"]
99    pub fn contains(&self, node: &str) -> bool {
100        self.iter().any(|n| n == node)
101    }
102
103    /// Returns the number of nodes in the collection.
104    ///
105    /// # Examples
106    ///
107    /// ```rust,no_run
108    /// use dbc_rs::Dbc;
109    ///
110    /// let dbc = Dbc::parse(r#"VERSION "1.0"
111    ///
112    /// BU_: ECM TCM BCM
113    /// "#)?;
114    ///
115    /// assert_eq!(dbc.nodes().len(), 3);
116    /// # Ok::<(), dbc_rs::Error>(())
117    /// ```
118    #[inline]
119    #[must_use = "return value should be used"]
120    pub fn len(&self) -> usize {
121        self.nodes.len()
122    }
123
124    /// Returns `true` if there are no nodes in the collection.
125    ///
126    /// # Examples
127    ///
128    /// ```rust,no_run
129    /// use dbc_rs::Dbc;
130    ///
131    /// // Empty node list
132    /// let dbc = Dbc::parse(r#"VERSION "1.0"
133    ///
134    /// BU_:
135    /// "#)?;
136    /// assert!(dbc.nodes().is_empty());
137    ///
138    /// // With nodes
139    /// let dbc2 = Dbc::parse(r#"VERSION "1.0"
140    ///
141    /// BU_: ECM
142    /// "#)?;
143    /// assert!(!dbc2.nodes().is_empty());
144    /// # Ok::<(), dbc_rs::Error>(())
145    /// ```
146    #[inline]
147    #[must_use = "return value should be used"]
148    pub fn is_empty(&self) -> bool {
149        self.nodes.is_empty()
150    }
151
152    /// Gets a node name by index.
153    ///
154    /// Returns `None` if the index is out of bounds.
155    ///
156    /// # Arguments
157    ///
158    /// * `index` - The zero-based index of the node
159    ///
160    /// # Examples
161    ///
162    /// ```rust,no_run
163    /// use dbc_rs::Dbc;
164    ///
165    /// let dbc = Dbc::parse(r#"VERSION "1.0"
166    ///
167    /// BU_: ECM TCM BCM
168    /// "#)?;
169    ///
170    /// assert_eq!(dbc.nodes().at(0), Some("ECM"));
171    /// assert_eq!(dbc.nodes().at(1), Some("TCM"));
172    /// assert_eq!(dbc.nodes().at(2), Some("BCM"));
173    /// assert_eq!(dbc.nodes().at(3), None); // Out of bounds
174    /// # Ok::<(), dbc_rs::Error>(())
175    /// ```
176    #[inline]
177    #[must_use = "return value should be used"]
178    pub fn at(&self, index: usize) -> Option<&str> {
179        self.nodes.get(index).map(|node| node.name())
180    }
181
182    /// Gets a node by index.
183    ///
184    /// Returns `None` if the index is out of bounds.
185    ///
186    /// # Arguments
187    ///
188    /// * `index` - The zero-based index of the node
189    ///
190    /// # Examples
191    ///
192    /// ```rust,no_run
193    /// use dbc_rs::Dbc;
194    ///
195    /// let dbc = Dbc::parse(r#"VERSION "1.0"
196    ///
197    /// BU_: ECM TCM BCM
198    /// "#)?;
199    ///
200    /// let node = dbc.nodes().get(0).unwrap();
201    /// assert_eq!(node.name(), "ECM");
202    /// # Ok::<(), dbc_rs::Error>(())
203    /// ```
204    #[inline]
205    #[must_use = "return value should be used"]
206    pub fn get(&self, index: usize) -> Option<&Node> {
207        self.nodes.get(index)
208    }
209
210    /// Returns the comment for a specific node, if present.
211    ///
212    /// # Examples
213    ///
214    /// ```rust,no_run
215    /// use dbc_rs::Dbc;
216    ///
217    /// let dbc = Dbc::parse(r#"VERSION "1.0"
218    ///
219    /// BU_: ECM TCM
220    ///
221    /// BO_ 256 Engine : 8 ECM
222    ///
223    /// CM_ BU_ ECM "Engine Control Module";
224    /// "#)?;
225    ///
226    /// assert_eq!(dbc.nodes().node_comment("ECM"), Some("Engine Control Module"));
227    /// assert_eq!(dbc.nodes().node_comment("TCM"), None);
228    /// # Ok::<(), dbc_rs::Error>(())
229    /// ```
230    #[inline]
231    #[must_use = "return value should be used"]
232    pub fn node_comment(&self, node_name: &str) -> Option<&str> {
233        self.nodes
234            .iter()
235            .find(|node| node.name() == node_name)
236            .and_then(|node| node.comment())
237    }
238
239    /// Sets the comment for a node by name.
240    ///
241    /// Returns `true` if the node was found and the comment was set,
242    /// `false` if the node was not found.
243    pub(crate) fn set_node_comment(
244        &mut self,
245        node_name: &str,
246        comment: crate::compat::Comment,
247    ) -> bool {
248        if let Some(node) = self.nodes.iter_mut().find(|n| n.name() == node_name) {
249            node.set_comment(comment);
250            true
251        } else {
252            false
253        }
254    }
255}