dbc_rs/nodes/
mod.rs

1mod impls;
2mod parse;
3#[cfg(feature = "std")]
4mod std;
5mod validate;
6
7#[cfg(feature = "std")]
8mod builder;
9
10use crate::{
11    MAX_NODES,
12    compat::{Comment, Name, Vec},
13};
14#[cfg(feature = "std")]
15pub use builder::NodesBuilder;
16
17/// Represents a single node (ECU) with its name and optional comment.
18#[derive(Debug, Default, PartialEq, Eq, Hash, Clone)]
19pub struct Node {
20    name: Name,
21    comment: Option<Comment>,
22}
23
24impl Node {
25    /// Creates a new node with the given name and no comment.
26    #[inline]
27    pub(crate) fn new(name: Name) -> Self {
28        Self {
29            name,
30            comment: None,
31        }
32    }
33
34    /// Creates a new node with the given name and comment.
35    #[inline]
36    #[cfg(feature = "std")]
37    pub(crate) fn with_comment(name: Name, comment: Option<Comment>) -> Self {
38        Self { name, comment }
39    }
40
41    /// Returns the node name.
42    #[inline]
43    #[must_use = "return value should be used"]
44    pub fn name(&self) -> &str {
45        self.name.as_str()
46    }
47
48    /// Returns the node comment, if any.
49    #[inline]
50    #[must_use = "return value should be used"]
51    pub fn comment(&self) -> Option<&str> {
52        self.comment.as_ref().map(|c| c.as_str())
53    }
54
55    /// Sets the comment for this node.
56    #[inline]
57    pub(crate) fn set_comment(&mut self, comment: Comment) {
58        self.comment = Some(comment);
59    }
60}
61
62type InnerNodes = Vec<Node, { MAX_NODES }>;
63
64/// Represents a collection of node (ECU) names from a DBC file.
65///
66/// The `BU_` statement in a DBC file lists all nodes (ECUs) on the CAN bus.
67/// This struct stores the node names as borrowed references.
68///
69/// # Examples
70///
71/// ```rust,no_run
72/// use dbc_rs::Dbc;
73///
74/// let dbc = Dbc::parse(r#"VERSION "1.0"
75///
76/// BU_: ECM TCM BCM
77///
78/// BO_ 256 Engine : 8 ECM
79///  SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
80/// "#)?;
81///
82/// // Access nodes
83/// assert_eq!(dbc.nodes().len(), 3);
84/// assert!(dbc.nodes().contains("ECM"));
85/// assert!(dbc.nodes().contains("TCM"));
86///
87/// // Iterate over nodes
88/// for node in dbc.nodes().iter() {
89///     println!("Node: {}", node);
90/// }
91/// # Ok::<(), dbc_rs::Error>(())
92/// ```
93///
94/// # Empty Nodes
95///
96/// A DBC file may have an empty node list (`BU_:` with no nodes):
97///
98/// ```rust,no_run
99/// use dbc_rs::Dbc;
100///
101/// let dbc = Dbc::parse(r#"VERSION "1.0"
102///
103/// BU_:
104///
105/// BO_ 256 Engine : 8 ECM
106/// "#)?;
107///
108/// assert!(dbc.nodes().is_empty());
109/// # Ok::<(), dbc_rs::Error>(())
110/// ```
111///
112/// # DBC Format
113///
114/// In DBC files, nodes are specified on the `BU_` line:
115/// - Format: `BU_: Node1 Node2 Node3 ...`
116/// - Node names are space-separated
117/// - Maximum of 256 nodes (DoS protection)
118/// - All node names must be unique (case-sensitive)
119/// - Empty node list is valid (`BU_:`)
120/// - Maximum 32 characters per node name by default
121#[derive(Debug, Default, PartialEq, Eq, Hash, Clone)]
122pub struct Nodes {
123    nodes: InnerNodes,
124}