dbc_rs/nodes/builder/
build.rs

1use super::NodesBuilder;
2use crate::{Error, MAX_NAME_SIZE, MAX_NODES, Nodes, Result};
3
4impl NodesBuilder {
5    /// Convert std strings to compat strings and validate
6    fn to_compat_nodes(
7        &self,
8    ) -> Result<crate::compat::Vec<crate::compat::String<{ MAX_NAME_SIZE }>, { MAX_NODES }>> {
9        use crate::compat::{String, Vec};
10        let mut result: Vec<String<{ MAX_NAME_SIZE }>, { MAX_NODES }> = Vec::new();
11        for node_str in &self.nodes {
12            let compat_str = String::try_from(node_str.as_str())
13                .map_err(|_| Error::Validation(Error::MAX_NAME_SIZE_EXCEEDED))?;
14            result.push(compat_str).map_err(|_| Error::Validation(Error::NODES_TOO_MANY))?;
15        }
16        Nodes::validate(&result)?;
17        Ok(result)
18    }
19
20    /// Validates the current builder state without building.
21    ///
22    /// This is useful for checking if the configuration is valid before building.
23    /// Returns a new builder with validated nodes, or an error if validation fails.
24    ///
25    /// # Returns
26    ///
27    /// Returns `Ok(Self)` if validation succeeds, or `Err(Error::Validation)` if:
28    /// - Too many nodes are specified (exceeds 256 nodes  limit by default)
29    /// - Duplicate node names are found (case-sensitive)
30    /// - Node name exceeds maximum length (32 characters by default)
31    ///
32    /// # Examples
33    ///
34    /// ```rust,no_run
35    /// use dbc_rs::NodesBuilder;
36    ///
37    /// // Valid configuration
38    /// let builder = NodesBuilder::new()
39    ///     .add_node("ECM")
40    ///     .add_node("TCM");
41    /// assert!(builder.validate().is_ok());
42    ///
43    /// // Invalid: duplicate nodes
44    /// let builder2 = NodesBuilder::new()
45    ///     .add_node("ECM")
46    ///     .add_node("ECM"); // Duplicate
47    /// assert!(builder2.validate().is_err());
48    /// # Ok::<(), dbc_rs::Error>(())
49    /// ```
50    #[must_use = "validation result should be checked"]
51    pub fn validate(self) -> Result<Self> {
52        self.to_compat_nodes()?;
53        Ok(self)
54    }
55
56    /// Builds the `Nodes` from the builder configuration.
57    ///
58    /// This validates the nodes and constructs a `Nodes` instance.
59    ///
60    /// # Returns
61    ///
62    /// Returns `Ok(Nodes)` if successful, or `Err(Error::Validation)` if:
63    /// - Too many nodes are specified (exceeds 256 nodes limit by default)
64    /// - Duplicate node names are found (case-sensitive)
65    /// - Node name exceeds maximum length (32 characters)
66    ///
67    /// # Examples
68    ///
69    /// ```rust,no_run
70    /// use dbc_rs::NodesBuilder;
71    ///
72    /// // Build with nodes
73    /// let nodes = NodesBuilder::new()
74    ///     .add_node("ECM")
75    ///     .add_node("TCM")
76    ///     .build()?;
77    /// assert_eq!(nodes.len(), 2);
78    ///
79    /// // Build empty
80    /// let empty = NodesBuilder::new().build()?;
81    /// assert!(empty.is_empty());
82    /// # Ok::<(), dbc_rs::Error>(())
83    /// ```
84    ///
85    /// # Errors
86    ///
87    /// ```rust,no_run
88    /// use dbc_rs::NodesBuilder;
89    ///
90    /// // Duplicate nodes
91    /// let result = NodesBuilder::new()
92    ///     .add_node("ECM")
93    ///     .add_node("ECM") // Duplicate
94    ///     .build();
95    /// assert!(result.is_err());
96    /// # Ok::<(), dbc_rs::Error>(())
97    /// ```
98    pub fn build(self) -> Result<Nodes> {
99        let compat_nodes = self.to_compat_nodes()?;
100        Ok(Nodes::new(compat_nodes))
101    }
102}
103
104#[cfg(test)]
105mod tests {
106    #![allow(clippy::float_cmp)]
107    use super::*;
108    use crate::Error;
109
110    #[test]
111    fn test_nodes_builder_empty() {
112        let nodes = NodesBuilder::new().build().unwrap();
113        assert!(nodes.is_empty());
114        assert_eq!(nodes.len(), 0);
115    }
116
117    #[test]
118    fn test_nodes_builder_duplicate() {
119        let result = NodesBuilder::new().add_node("ECM").add_node("TCM").add_node("ECM").build();
120        assert!(result.is_err());
121        match result.unwrap_err() {
122            Error::Validation(msg) => assert!(msg.contains(Error::NODES_DUPLICATE_NAME)),
123            _ => panic!("Expected Validation error"),
124        }
125    }
126
127    #[test]
128    fn test_nodes_builder_too_many() {
129        let mut builder = NodesBuilder::new();
130        for i in 0..MAX_NODES {
131            let node_str = format!("Node{i}");
132            builder = builder.add_node(node_str);
133        }
134        let node = "NodeLast".to_string();
135        let result = builder.add_node(node).build();
136        assert!(result.is_err());
137        match result.unwrap_err() {
138            Error::Validation(msg) => {
139                assert!(msg.contains(Error::NODES_TOO_MANY));
140            }
141            _ => panic!("Expected Validation error"),
142        }
143    }
144
145    #[test]
146    fn test_nodes_builder_validate() {
147        let builder = NodesBuilder::new().add_node("TCM").add_node("BCM");
148        let validated = builder.validate().unwrap();
149        let nodes = validated.build().unwrap();
150        assert_eq!(nodes.len(), 2);
151    }
152
153    #[test]
154    fn test_nodes_builder_validate_duplicate() {
155        let result = NodesBuilder::new().add_node("ECM").add_node("TCM").add_node("ECM").build();
156        assert!(result.is_err());
157        match result.unwrap_err() {
158            Error::Validation(msg) => assert!(msg.contains(Error::NODES_DUPLICATE_NAME)),
159            _ => panic!("Expected Validation error"),
160        }
161    }
162
163    #[test]
164    fn test_nodes_builder_validate_too_many() {
165        let mut builder = NodesBuilder::new();
166        for i in 0..MAX_NODES {
167            let node_str = format!("Node{i}");
168            builder = builder.add_node(node_str);
169        }
170
171        let result = builder.validate();
172        assert!(result.is_ok());
173
174        // Try to adding one past the limit
175        builder = result.unwrap();
176        let result = builder.add_node("NodeLast").build();
177        assert!(result.is_err());
178        match result.unwrap_err() {
179            Error::Validation(msg) => assert!(msg.contains(Error::NODES_TOO_MANY)),
180            _ => panic!("Expected Validation error"),
181        }
182    }
183}