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::lang::SIGNAL_RECEIVERS_TOO_MANY));
267            }
268            Ok(Receivers::new_nodes(&node_refs))
269        }
270    }
271}
272
273#[cfg(test)]
274mod tests {
275    use super::*;
276    #[cfg(any(feature = "alloc", feature = "kernel"))]
277    use crate::error::Error;
278    #[cfg(any(feature = "alloc", feature = "kernel"))]
279    use alloc::format;
280
281    #[test]
282    fn test_receivers_builder_broadcast() {
283        let receivers = ReceiversBuilder::new().broadcast().build().unwrap();
284        assert_eq!(receivers, Receivers::Broadcast);
285    }
286
287    #[test]
288    fn test_receivers_builder_none() {
289        let receivers = ReceiversBuilder::new().none().build().unwrap();
290        assert_eq!(receivers, Receivers::None);
291    }
292
293    #[test]
294    fn test_receivers_builder_empty() {
295        let receivers = ReceiversBuilder::new().build().unwrap();
296        assert_eq!(receivers, Receivers::None);
297    }
298
299    #[test]
300    fn test_receivers_builder_single_node() {
301        let receivers = ReceiversBuilder::new().add_node("TCM").build().unwrap();
302        match receivers {
303            Receivers::Nodes(_, count) => assert_eq!(count, 1),
304            _ => panic!("Expected Nodes variant"),
305        }
306    }
307
308    #[test]
309    fn test_receivers_builder_multiple_nodes() {
310        let receivers = ReceiversBuilder::new()
311            .add_node("TCM")
312            .add_node("BCM")
313            .add_node("ECM")
314            .build()
315            .unwrap();
316        match receivers {
317            Receivers::Nodes(_, count) => assert_eq!(count, 3),
318            _ => panic!("Expected Nodes variant"),
319        }
320    }
321
322    #[test]
323    fn test_receivers_builder_too_many() {
324        #[cfg(any(feature = "alloc", feature = "kernel"))]
325        use alloc::format;
326        let mut builder = ReceiversBuilder::new();
327        for i in 0..65 {
328            builder = builder.add_node(format!("Node{i}"));
329        }
330        let result = builder.build();
331        assert!(result.is_err());
332        match result.unwrap_err() {
333            Error::Signal(_) => {}
334            _ => panic!("Expected Signal error"),
335        }
336    }
337
338    #[test]
339    fn test_receivers_builder_add_nodes() {
340        let receivers = ReceiversBuilder::new().add_nodes(["ECM", "TCM", "BCM"]).build().unwrap();
341        match receivers {
342            Receivers::Nodes(_, count) => assert_eq!(count, 3),
343            _ => panic!("Expected Nodes variant"),
344        }
345        assert!(receivers.contains("ECM"));
346        assert!(receivers.contains("TCM"));
347        assert!(receivers.contains("BCM"));
348    }
349
350    #[test]
351    fn test_receivers_builder_add_nodes_iterator() {
352        let node_vec = ["Node1", "Node2", "Node3"];
353        let receivers = ReceiversBuilder::new().add_nodes(node_vec.iter()).build().unwrap();
354        match receivers {
355            Receivers::Nodes(_, count) => assert_eq!(count, 3),
356            _ => panic!("Expected Nodes variant"),
357        }
358    }
359
360    #[test]
361    fn test_receivers_builder_clear() {
362        let receivers = ReceiversBuilder::new()
363            .add_node("ECM")
364            .add_node("TCM")
365            .clear()
366            .add_node("BCM")
367            .build()
368            .unwrap();
369        match receivers {
370            Receivers::Nodes(_, count) => {
371                assert_eq!(count, 1);
372                assert!(receivers.contains("BCM"));
373                assert!(!receivers.contains("ECM"));
374            }
375            _ => panic!("Expected Nodes variant"),
376        }
377    }
378
379    #[test]
380    fn test_receivers_builder_broadcast_clears_nodes() {
381        let receivers = ReceiversBuilder::new()
382            .add_node("ECM")
383            .add_node("TCM")
384            .broadcast()
385            .build()
386            .unwrap();
387        assert_eq!(receivers, Receivers::Broadcast);
388        assert_eq!(receivers.len(), 0);
389    }
390
391    #[test]
392    fn test_receivers_builder_none_clears_nodes() {
393        let receivers =
394            ReceiversBuilder::new().add_node("ECM").add_node("TCM").none().build().unwrap();
395        assert_eq!(receivers, Receivers::None);
396        assert_eq!(receivers.len(), 0);
397    }
398
399    #[test]
400    fn test_receivers_builder_add_node_clears_broadcast() {
401        let receivers = ReceiversBuilder::new().broadcast().add_node("ECM").build().unwrap();
402        match receivers {
403            Receivers::Nodes(_, count) => assert_eq!(count, 1),
404            _ => panic!("Expected Nodes variant"),
405        }
406    }
407
408    #[test]
409    fn test_receivers_builder_add_node_clears_none() {
410        let receivers = ReceiversBuilder::new().none().add_node("ECM").build().unwrap();
411        match receivers {
412            Receivers::Nodes(_, count) => assert_eq!(count, 1),
413            _ => panic!("Expected Nodes variant"),
414        }
415    }
416
417    #[test]
418    fn test_receivers_builder_at_limit() {
419        #[cfg(any(feature = "alloc", feature = "kernel"))]
420        use alloc::format;
421        let mut builder = ReceiversBuilder::new();
422        for i in 0..64 {
423            builder = builder.add_node(format!("Node{i}"));
424        }
425        let receivers = builder.build().unwrap();
426        match receivers {
427            Receivers::Nodes(_, count) => assert_eq!(count, 64),
428            _ => panic!("Expected Nodes variant"),
429        }
430    }
431}