1use crate::{
2 Parser,
3 error::{ParseError, ParseResult, messages},
4};
5
6struct NodesIter<'a, 'b> {
8 nodes: &'b [Option<&'a str>],
9 count: usize,
10 pos: usize,
11}
12
13impl<'a, 'b> Iterator for NodesIter<'a, 'b> {
14 type Item = &'a str;
15
16 #[inline]
17 fn next(&mut self) -> Option<Self::Item> {
18 while self.pos < self.count {
19 let result = self.nodes[self.pos];
20 self.pos += 1;
21 if let Some(node) = result {
22 return Some(node);
23 }
24 }
25 None
26 }
27}
28
29#[derive(Debug, PartialEq, Eq, Hash)]
30pub struct Nodes<'a> {
31 nodes: [Option<&'a str>; crate::MAX_NODES],
32 count: usize,
33}
34
35impl<'a> Default for Nodes<'a> {
36 fn default() -> Self {
37 Self {
38 nodes: [const { None }; crate::MAX_NODES],
39 count: 0,
40 }
41 }
42}
43
44impl<'a> Nodes<'a> {
45 pub(crate) fn validate_nodes(nodes: &[&str]) -> ParseResult<()> {
47 use crate::error::lang;
48 if nodes.len() > crate::MAX_NODES {
50 return Err(ParseError::Version(messages::NODES_TOO_MANY));
51 }
52
53 for (i, node1) in nodes.iter().enumerate() {
55 for node2 in nodes.iter().skip(i + 1) {
56 if *node1 == *node2 {
57 return Err(ParseError::Version(lang::NODES_DUPLICATE_NAME));
58 }
59 }
60 }
61 Ok(())
62 }
63
64 #[allow(dead_code)] pub(crate) fn new(nodes: &[&'a str]) -> Self {
66 let mut node_array: [Option<&'a str>; crate::MAX_NODES] =
68 [const { None }; crate::MAX_NODES];
69 let count = nodes.len().min(crate::MAX_NODES);
70 for (i, node) in nodes.iter().take(crate::MAX_NODES).enumerate() {
71 node_array[i] = Some(*node);
72 }
73 Self {
74 nodes: node_array,
75 count,
76 }
77 }
78
79 #[must_use = "parse result should be checked"]
80 pub(crate) fn parse<'b: 'a>(parser: &mut Parser<'b>) -> ParseResult<Self> {
81 if parser.expect(crate::BU_.as_bytes()).is_ok() {
85 parser
87 .expect(b":")
88 .map_err(|_| ParseError::Expected("Expected colon after BU_"))?;
89 } else {
90 if parser.expect(b":").is_err() {
94 parser.skip_newlines_and_spaces();
96 parser
97 .expect(b":")
98 .map_err(|_| ParseError::Expected("Expected colon after BU_"))?;
99 }
100 }
101
102 parser.skip_newlines_and_spaces();
104
105 let mut node_names: [Option<&'b str>; crate::MAX_NODES] =
107 [const { None }; crate::MAX_NODES];
108 let mut count = 0;
109
110 loop {
111 let _ = parser.skip_whitespace();
113
114 match parser.parse_identifier() {
117 Ok(node) => {
118 if count >= crate::MAX_NODES {
119 return Err(ParseError::Version(messages::NODES_TOO_MANY));
120 }
121 node_names[count] = Some(node);
122 count += 1;
123 }
124 Err(_) => {
125 break;
127 }
128 }
129 }
130
131 if count == 0 {
132 return Ok(Nodes {
133 nodes: [const { None }; crate::MAX_NODES],
134 count: 0,
135 });
136 }
137
138 let mut node_refs: [&'b str; crate::MAX_NODES] = [""; crate::MAX_NODES];
141 for i in 0..count {
142 if let Some(node) = node_names[i] {
143 node_refs[i] = node;
144 }
145 }
146
147 Self::validate_nodes(&node_refs[..count])?;
149 let mut node_array: [Option<&'a str>; crate::MAX_NODES] =
151 [const { None }; crate::MAX_NODES];
152 for (i, node) in node_refs.iter().take(count).enumerate() {
153 node_array[i] = Some(*node);
154 }
155 Ok(Self {
156 nodes: node_array,
157 count,
158 })
159 }
160
161 #[inline]
175 #[must_use = "iterator is lazy and does nothing unless consumed"]
176 pub fn iter(&self) -> impl Iterator<Item = &'a str> + '_ {
177 NodesIter {
178 nodes: &self.nodes,
179 count: self.count,
180 pos: 0,
181 }
182 }
183
184 #[inline]
197 #[must_use]
198 pub fn contains(&self, node: &str) -> bool {
199 self.iter().any(|n| n == node)
200 }
201
202 #[inline]
214 #[must_use]
215 pub fn len(&self) -> usize {
216 self.count
217 }
218
219 pub fn is_empty(&self) -> bool {
231 self.count == 0
232 }
233
234 #[inline]
248 #[must_use]
249 pub fn at(&self, index: usize) -> Option<&'a str> {
250 if index >= self.count {
251 return None;
252 }
253 self.nodes[index]
254 }
255
256 #[cfg(feature = "alloc")]
257 #[must_use]
258 pub fn to_dbc_string(&self) -> String {
259 let mut result = String::from(crate::BU_);
260 result.push(':');
261 let nodes_str = alloc::format!("{}", self);
262 if !nodes_str.is_empty() {
263 result.push(' ');
264 result.push_str(&nodes_str);
265 }
266 result
267 }
268}
269
270#[cfg(feature = "alloc")]
271impl<'a> core::fmt::Display for Nodes<'a> {
272 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
273 if self.count == 0 {
274 return Ok(());
275 }
276 for (i, node) in self.iter().enumerate() {
277 if i > 0 {
278 write!(f, " ")?;
279 }
280 write!(f, "{}", node)?;
281 }
282 Ok(())
283 }
284}
285
286#[cfg(test)]
287mod tests {
288 #![allow(clippy::float_cmp)]
289 use super::*;
290 use crate::{
291 Parser,
292 error::{ParseError, lang},
293 };
294
295 #[test]
296 fn test_nodes_from_valid_line() {
297 let line = b"BU_: ECM TCM BCM ABS";
298 let mut parser = Parser::new(line).unwrap();
299 let nodes = Nodes::parse(&mut parser).unwrap();
300 let node_vec: alloc::vec::Vec<&str> = nodes.iter().collect();
301 assert_eq!(node_vec, &["ECM", "TCM", "BCM", "ABS"]);
302 }
303
304 #[test]
305 fn test_nodes_from_single_node() {
306 let line = b"BU_: ONLYONE";
307 let mut parser = Parser::new(line).unwrap();
308 let nodes = Nodes::parse(&mut parser).unwrap();
309 let node_vec: alloc::vec::Vec<&str> = nodes.iter().collect();
310 assert_eq!(node_vec, &["ONLYONE"]);
311 }
312
313 #[test]
314 fn test_nodes_from_with_extra_spaces() {
315 let line = b"BU_: Node1 Node2 ";
316 let mut parser = Parser::new(line).unwrap();
317 let nodes = Nodes::parse(&mut parser).unwrap();
318 let node_vec: alloc::vec::Vec<&str> = nodes.iter().collect();
319 assert_eq!(node_vec, &["Node1", "Node2"]);
320 }
321
322 #[test]
323 fn test_nodes_from_empty_list() {
324 let line = b"BU_:";
325 let mut parser = Parser::new(line).unwrap();
326 let nodes = Nodes::parse(&mut parser).unwrap();
327 assert!(nodes.is_empty());
328 }
329
330 #[test]
331 #[cfg(feature = "alloc")]
332 fn test_nodes_new() {
333 use crate::nodes::NodesBuilder;
334 let nodes = NodesBuilder::new()
335 .add_node("ECM")
336 .add_node("TCM")
337 .add_node("BCM")
338 .build()
339 .unwrap();
340 assert!(nodes.contains("ECM"));
341 assert!(nodes.contains("TCM"));
342 assert!(nodes.contains("BCM"));
343 assert!(!nodes.contains("ABS"));
344 assert_eq!(nodes.iter().count(), 3);
345 }
346
347 #[test]
348 #[cfg(feature = "alloc")]
349 fn test_nodes_new_from_vec() {
350 use crate::nodes::NodesBuilder;
351 let nodes = NodesBuilder::new()
352 .add_node("Node1")
353 .add_node("Node2")
354 .add_node("Node3")
355 .build()
356 .unwrap();
357 assert!(nodes.contains("Node1"));
358 assert_eq!(nodes.iter().count(), 3);
359 }
360
361 #[test]
362 #[cfg(feature = "alloc")]
363 fn test_nodes_new_from_slice() {
364 use crate::nodes::NodesBuilder;
365 let nodes = NodesBuilder::new().add_node("A").add_node("B").add_node("C").build().unwrap();
366 assert!(nodes.contains("A"));
367 assert_eq!(nodes.iter().count(), 3);
368 }
369
370 #[test]
371 #[cfg(feature = "alloc")]
372 fn test_nodes_new_duplicate() {
373 use crate::nodes::NodesBuilder;
374 let result = NodesBuilder::new().add_node("ECM").add_node("TCM").add_node("ECM").build();
375 assert!(result.is_err());
376 use crate::Error;
377 match result.unwrap_err() {
378 Error::Nodes(msg) => {
379 assert!(msg.contains(lang::NODES_DUPLICATE_NAME))
380 }
381 _ => panic!("Expected Error::Nodes with NODES_DUPLICATE_NAME"),
382 }
383 }
384
385 #[test]
386 #[cfg(feature = "alloc")]
387 fn test_nodes_to_string_single() {
388 use crate::nodes::NodesBuilder;
389 let nodes = NodesBuilder::new().add_node("ECM").build().unwrap();
390 assert_eq!(alloc::format!("{}", nodes), "ECM");
391 }
392
393 #[test]
394 #[cfg(feature = "alloc")]
395 fn test_nodes_to_string_multiple() {
396 use crate::nodes::NodesBuilder;
397 let nodes = NodesBuilder::new()
398 .add_node("ECM")
399 .add_node("TCM")
400 .add_node("BCM")
401 .build()
402 .unwrap();
403 assert_eq!(alloc::format!("{}", nodes), "ECM TCM BCM");
404 }
405
406 #[test]
407 #[cfg(feature = "alloc")]
408 fn test_nodes_to_dbc_string() {
409 use crate::nodes::NodesBuilder;
410 let nodes_single = NodesBuilder::new().add_node("ECM").build().unwrap();
411 assert_eq!(nodes_single.to_dbc_string(), "BU_: ECM");
412
413 let nodes_multiple = NodesBuilder::new()
414 .add_node("ECM")
415 .add_node("TCM")
416 .add_node("BCM")
417 .build()
418 .unwrap();
419 assert_eq!(nodes_multiple.to_dbc_string(), "BU_: ECM TCM BCM");
420 }
421
422 #[test]
423 fn test_nodes_parse_duplicate() {
424 let line = b"BU_: ECM TCM ECM";
425 let mut parser = Parser::new(line).unwrap();
426 let result = Nodes::parse(&mut parser);
427 assert!(result.is_err());
428 match result.unwrap_err() {
429 ParseError::Version(msg) => assert!(msg == lang::NODES_DUPLICATE_NAME),
430 _ => panic!("Expected ParseError::Version"),
431 }
432 }
433
434 #[test]
435 #[cfg(feature = "alloc")]
436 fn test_nodes_too_many() {
437 use crate::nodes::NodesBuilder;
438 let mut builder = NodesBuilder::new();
440 for i in 0..257 {
441 builder = builder.add_node(format!("Node{i}"));
442 }
443 let result = builder.build();
444 assert!(result.is_err());
445 use crate::Error;
446 match result.unwrap_err() {
447 Error::Nodes(msg) => {
448 assert!(msg.contains(lang::NODES_TOO_MANY));
449 }
450 _ => panic!("Expected Error::Nodes"),
451 }
452 }
453
454 #[test]
455 #[cfg(feature = "alloc")]
456 fn test_nodes_at_limit() {
457 use crate::nodes::NodesBuilder;
458 let mut builder = NodesBuilder::new();
460 for i in 0..256 {
461 builder = builder.add_node(format!("Node{i}"));
462 }
463 let result = builder.build();
464 assert!(result.is_ok());
465 assert_eq!(result.unwrap().len(), 256);
466 }
467}