dbc_rs/receivers/
receivers_builder.rs

1use super::Receivers;
2#[cfg(any(feature = "alloc", feature = "kernel"))]
3use crate::compat::{Box, String, Vec, str_to_string};
4use crate::{Error, Result};
5
6/// Builder for creating `Receivers` programmatically.
7///
8/// This builder allows you to construct receiver configurations for signals
9/// when building DBC files programmatically.
10///
11/// # Examples
12///
13/// ```rust,no_run
14/// use dbc_rs::{ReceiversBuilder, SignalBuilder, ByteOrder};
15///
16/// // Broadcast receiver
17/// let broadcast = ReceiversBuilder::new().broadcast().build()?;
18///
19/// // Specific nodes
20/// let specific = ReceiversBuilder::new()
21///     .add_node("TCM")
22///     .add_node("BCM")
23///     .build()?;
24///
25/// // No receivers
26/// let none = ReceiversBuilder::new().none().build()?;
27///
28/// // Use with signal builder
29/// let signal = SignalBuilder::new()
30///     .name("RPM")
31///     .start_bit(0)
32///     .length(16)
33///     .byte_order(ByteOrder::BigEndian)
34///     .unsigned(true)
35///     .factor(0.25)
36///     .offset(0.0)
37///     .min(0.0)
38///     .max(8000.0)
39///     .receivers(specific)
40///     .build()?;
41/// # Ok::<(), dbc_rs::Error>(())
42/// ```
43///
44/// # Feature Requirements
45///
46/// This builder requires the `alloc` feature to be enabled.
47#[derive(Debug, Default)]
48pub struct ReceiversBuilder {
49    is_broadcast: bool,
50    is_none: bool,
51    nodes: Vec<String>,
52}
53
54impl ReceiversBuilder {
55    /// Creates a new `ReceiversBuilder` with default settings (no receivers).
56    ///
57    /// # Examples
58    ///
59    /// ```rust,no_run
60    /// use dbc_rs::ReceiversBuilder;
61    ///
62    /// let builder = ReceiversBuilder::new();
63    /// let receivers = builder.build()?;
64    /// assert_eq!(receivers.len(), 0);
65    /// # Ok::<(), dbc_rs::Error>(())
66    /// ```
67    pub fn new() -> Self {
68        Self::default()
69    }
70
71    /// Sets the receiver to broadcast (`*` in DBC format).
72    ///
73    /// This clears any previously set nodes and sets the receiver to broadcast mode.
74    ///
75    /// # Examples
76    ///
77    /// ```rust,no_run
78    /// use dbc_rs::ReceiversBuilder;
79    ///
80    /// let receivers = ReceiversBuilder::new()
81    ///     .add_node("TCM")  // This will be cleared
82    ///     .broadcast()
83    ///     .build()?;
84    /// assert_eq!(receivers, dbc_rs::Receivers::Broadcast);
85    /// # Ok::<(), dbc_rs::Error>(())
86    /// ```
87    #[must_use]
88    pub fn broadcast(mut self) -> Self {
89        self.is_broadcast = true;
90        self.is_none = false;
91        self.nodes.clear();
92        self
93    }
94
95    /// Sets the receiver to none (no explicit receivers).
96    ///
97    /// This clears any previously set nodes and sets the receiver to none mode.
98    ///
99    /// # Examples
100    ///
101    /// ```rust,no_run
102    /// use dbc_rs::ReceiversBuilder;
103    ///
104    /// let receivers = ReceiversBuilder::new()
105    ///     .add_node("TCM")  // This will be cleared
106    ///     .none()
107    ///     .build()?;
108    /// assert_eq!(receivers, dbc_rs::Receivers::None);
109    /// # Ok::<(), dbc_rs::Error>(())
110    /// ```
111    #[must_use]
112    pub fn none(mut self) -> Self {
113        self.is_none = true;
114        self.is_broadcast = false;
115        self.nodes.clear();
116        self
117    }
118
119    /// Adds a single receiver node.
120    ///
121    /// This automatically clears broadcast and none modes, switching to specific nodes mode.
122    ///
123    /// # Arguments
124    ///
125    /// * `node` - The node name (anything that implements `AsRef<str>`)
126    ///
127    /// # Examples
128    ///
129    /// ```rust,no_run
130    /// use dbc_rs::ReceiversBuilder;
131    ///
132    /// let receivers = ReceiversBuilder::new()
133    ///     .add_node("TCM")
134    ///     .add_node("BCM")
135    ///     .build()?;
136    /// assert_eq!(receivers.len(), 2);
137    /// assert!(receivers.contains("TCM"));
138    /// # Ok::<(), dbc_rs::Error>(())
139    /// ```
140    #[must_use]
141    pub fn add_node(mut self, node: impl AsRef<str>) -> Self {
142        self.is_broadcast = false;
143        self.is_none = false;
144        self.nodes.push(str_to_string(node));
145        self
146    }
147
148    /// Adds multiple receiver nodes from an iterator.
149    ///
150    /// This automatically clears broadcast and none modes, switching to specific nodes mode.
151    ///
152    /// # Arguments
153    ///
154    /// * `nodes` - An iterator of node names (each item must implement `AsRef<str>`)
155    ///
156    /// # Examples
157    ///
158    /// ```rust,no_run
159    /// use dbc_rs::ReceiversBuilder;
160    ///
161    /// // From a slice
162    /// let receivers = ReceiversBuilder::new()
163    ///     .add_nodes(&["TCM", "BCM", "ECM"])
164    ///     .build()?;
165    /// assert_eq!(receivers.len(), 3);
166    ///
167    /// // From a vector
168    /// let node_vec = vec!["Node1", "Node2"];
169    /// let receivers2 = ReceiversBuilder::new()
170    ///     .add_nodes(node_vec.iter())
171    ///     .build()?;
172    /// assert_eq!(receivers2.len(), 2);
173    /// # Ok::<(), dbc_rs::Error>(())
174    /// ```
175    #[must_use]
176    pub fn add_nodes<I, S>(mut self, nodes: I) -> Self
177    where
178        I: IntoIterator<Item = S>,
179        S: AsRef<str>,
180    {
181        self.is_broadcast = false;
182        self.is_none = false;
183        self.nodes.extend(nodes.into_iter().map(str_to_string));
184        self
185    }
186
187    /// Clears all receiver nodes and resets to default state (none).
188    ///
189    /// # Examples
190    ///
191    /// ```rust,no_run
192    /// use dbc_rs::ReceiversBuilder;
193    ///
194    /// let receivers = ReceiversBuilder::new()
195    ///     .add_node("TCM")
196    ///     .add_node("BCM")
197    ///     .clear()
198    ///     .add_node("ECM")
199    ///     .build()?;
200    /// assert_eq!(receivers.len(), 1);
201    /// assert!(receivers.contains("ECM"));
202    /// assert!(!receivers.contains("TCM"));
203    /// # Ok::<(), dbc_rs::Error>(())
204    /// ```
205    #[must_use]
206    pub fn clear(mut self) -> Self {
207        self.nodes.clear();
208        self.is_broadcast = false;
209        self.is_none = false;
210        self
211    }
212
213    /// Builds the `Receivers` from the builder configuration.
214    ///
215    /// # Returns
216    ///
217    /// Returns `Ok(Receivers)` if successful, or `Err(Error::Signal)` if:
218    /// - More than 64 receiver nodes are specified (exceeds maximum limit)
219    ///
220    /// # Examples
221    ///
222    /// ```rust,no_run
223    /// use dbc_rs::ReceiversBuilder;
224    ///
225    /// // Broadcast
226    /// let broadcast = ReceiversBuilder::new().broadcast().build()?;
227    ///
228    /// // Specific nodes
229    /// let nodes = ReceiversBuilder::new()
230    ///     .add_node("TCM")
231    ///     .add_node("BCM")
232    ///     .build()?;
233    ///
234    /// // None (default)
235    /// let none = ReceiversBuilder::new().build()?;
236    /// # Ok::<(), dbc_rs::Error>(())
237    /// ```
238    ///
239    /// # Errors
240    ///
241    /// ```rust,no_run
242    /// use dbc_rs::ReceiversBuilder;
243    ///
244    /// // Too many nodes (limit is 64)
245    /// let mut builder = ReceiversBuilder::new();
246    /// for i in 0..65 {
247    ///     builder = builder.add_node(format!("Node{i}"));
248    /// }
249    /// assert!(builder.build().is_err());
250    /// ```
251    pub fn build(self) -> Result<Receivers<'static>> {
252        if self.is_broadcast {
253            Ok(Receivers::new_broadcast())
254        } else if self.is_none || self.nodes.is_empty() {
255            Ok(Receivers::new_none())
256        } else {
257            // Convert owned Strings to static references by leaking Box<str>
258            let mut node_refs: Vec<&'static str> = Vec::new();
259            for s in self.nodes {
260                let boxed: Box<str> = s.into_boxed_str();
261                node_refs.push(Box::leak(boxed));
262            }
263            // Validate before construction
264            const MAX_RECEIVER_NODES: usize = 64;
265            if node_refs.len() > MAX_RECEIVER_NODES {
266                return Err(Error::Signal(crate::error::str_to_error_string(
267                    crate::error::messages::SIGNAL_RECEIVERS_TOO_MANY,
268                )));
269            }
270            Ok(Receivers::new_nodes(&node_refs))
271        }
272    }
273}
274
275#[cfg(test)]
276mod tests {
277    use super::*;
278    #[cfg(any(feature = "alloc", feature = "kernel"))]
279    use crate::error::Error;
280    #[cfg(any(feature = "alloc", feature = "kernel"))]
281    use alloc::format;
282
283    #[test]
284    fn test_receivers_builder_broadcast() {
285        let receivers = ReceiversBuilder::new().broadcast().build().unwrap();
286        assert_eq!(receivers, Receivers::Broadcast);
287    }
288
289    #[test]
290    fn test_receivers_builder_none() {
291        let receivers = ReceiversBuilder::new().none().build().unwrap();
292        assert_eq!(receivers, Receivers::None);
293    }
294
295    #[test]
296    fn test_receivers_builder_empty() {
297        let receivers = ReceiversBuilder::new().build().unwrap();
298        assert_eq!(receivers, Receivers::None);
299    }
300
301    #[test]
302    fn test_receivers_builder_single_node() {
303        let receivers = ReceiversBuilder::new().add_node("TCM").build().unwrap();
304        match receivers {
305            Receivers::Nodes(_, count) => assert_eq!(count, 1),
306            _ => panic!("Expected Nodes variant"),
307        }
308    }
309
310    #[test]
311    fn test_receivers_builder_multiple_nodes() {
312        let receivers = ReceiversBuilder::new()
313            .add_node("TCM")
314            .add_node("BCM")
315            .add_node("ECM")
316            .build()
317            .unwrap();
318        match receivers {
319            Receivers::Nodes(_, count) => assert_eq!(count, 3),
320            _ => panic!("Expected Nodes variant"),
321        }
322    }
323
324    #[test]
325    fn test_receivers_builder_too_many() {
326        #[cfg(any(feature = "alloc", feature = "kernel"))]
327        use alloc::format;
328        let mut builder = ReceiversBuilder::new();
329        for i in 0..65 {
330            builder = builder.add_node(format!("Node{i}"));
331        }
332        let result = builder.build();
333        assert!(result.is_err());
334        match result.unwrap_err() {
335            Error::Signal(_) => {}
336            _ => panic!("Expected Signal error"),
337        }
338    }
339
340    #[test]
341    fn test_receivers_builder_add_nodes() {
342        let receivers = ReceiversBuilder::new().add_nodes(["ECM", "TCM", "BCM"]).build().unwrap();
343        match receivers {
344            Receivers::Nodes(_, count) => assert_eq!(count, 3),
345            _ => panic!("Expected Nodes variant"),
346        }
347        assert!(receivers.contains("ECM"));
348        assert!(receivers.contains("TCM"));
349        assert!(receivers.contains("BCM"));
350    }
351
352    #[test]
353    fn test_receivers_builder_add_nodes_iterator() {
354        let node_vec = ["Node1", "Node2", "Node3"];
355        let receivers = ReceiversBuilder::new().add_nodes(node_vec.iter()).build().unwrap();
356        match receivers {
357            Receivers::Nodes(_, count) => assert_eq!(count, 3),
358            _ => panic!("Expected Nodes variant"),
359        }
360    }
361
362    #[test]
363    fn test_receivers_builder_clear() {
364        let receivers = ReceiversBuilder::new()
365            .add_node("ECM")
366            .add_node("TCM")
367            .clear()
368            .add_node("BCM")
369            .build()
370            .unwrap();
371        match receivers {
372            Receivers::Nodes(_, count) => {
373                assert_eq!(count, 1);
374                assert!(receivers.contains("BCM"));
375                assert!(!receivers.contains("ECM"));
376            }
377            _ => panic!("Expected Nodes variant"),
378        }
379    }
380
381    #[test]
382    fn test_receivers_builder_broadcast_clears_nodes() {
383        let receivers = ReceiversBuilder::new()
384            .add_node("ECM")
385            .add_node("TCM")
386            .broadcast()
387            .build()
388            .unwrap();
389        assert_eq!(receivers, Receivers::Broadcast);
390        assert_eq!(receivers.len(), 0);
391    }
392
393    #[test]
394    fn test_receivers_builder_none_clears_nodes() {
395        let receivers =
396            ReceiversBuilder::new().add_node("ECM").add_node("TCM").none().build().unwrap();
397        assert_eq!(receivers, Receivers::None);
398        assert_eq!(receivers.len(), 0);
399    }
400
401    #[test]
402    fn test_receivers_builder_add_node_clears_broadcast() {
403        let receivers = ReceiversBuilder::new().broadcast().add_node("ECM").build().unwrap();
404        match receivers {
405            Receivers::Nodes(_, count) => assert_eq!(count, 1),
406            _ => panic!("Expected Nodes variant"),
407        }
408    }
409
410    #[test]
411    fn test_receivers_builder_add_node_clears_none() {
412        let receivers = ReceiversBuilder::new().none().add_node("ECM").build().unwrap();
413        match receivers {
414            Receivers::Nodes(_, count) => assert_eq!(count, 1),
415            _ => panic!("Expected Nodes variant"),
416        }
417    }
418
419    #[test]
420    fn test_receivers_builder_at_limit() {
421        #[cfg(any(feature = "alloc", feature = "kernel"))]
422        use alloc::format;
423        let mut builder = ReceiversBuilder::new();
424        for i in 0..64 {
425            builder = builder.add_node(format!("Node{i}"));
426        }
427        let receivers = builder.build().unwrap();
428        match receivers {
429            Receivers::Nodes(_, count) => assert_eq!(count, 64),
430            _ => panic!("Expected Nodes variant"),
431        }
432    }
433}