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}