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}