dbc_rs/nodes/
impls.rs

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