dbc_rs/receivers/builder/mod.rs
1use super::Receivers;
2use crate::{Error, MAX_NAME_SIZE, MAX_NODES, Result};
3use std::{collections::HashSet, string::String};
4
5/// Builder for creating `Receivers` programmatically.
6///
7/// This builder allows you to construct receiver configurations for signals
8/// when building DBC files programmatically.
9///
10/// # Examples
11///
12/// ```rust,no_run
13/// use dbc_rs::{ReceiversBuilder, SignalBuilder, ByteOrder};
14///
15/// // Broadcast receiver
16/// let broadcast = ReceiversBuilder::new().broadcast().build()?;
17///
18/// // Specific nodes
19/// let specific = ReceiversBuilder::new()
20/// .add_node("TCM")
21/// .add_node("BCM")
22/// .build()?;
23///
24/// // No receivers
25/// let none = ReceiversBuilder::new().none().build()?;
26///
27/// // Use with signal builder
28/// let signal = SignalBuilder::new()
29/// .name("RPM")
30/// .start_bit(0)
31/// .length(16)
32/// .byte_order(ByteOrder::BigEndian)
33/// .unsigned(true)
34/// .factor(0.25)
35/// .offset(0.0)
36/// .min(0.0)
37/// .max(8000.0)
38/// .receivers(ReceiversBuilder::new().add_node("TCM").add_node("BCM"))
39/// .build()?;
40/// # Ok::<(), dbc_rs::Error>(())
41/// ```
42///
43/// # Feature Requirements
44///
45/// This builder requires the `std` feature to be enabled.
46#[derive(Debug, Clone)]
47pub struct ReceiversBuilder {
48 is_broadcast: bool,
49 nodes: Vec<String>,
50}
51
52impl ReceiversBuilder {
53 /// Creates a new `ReceiversBuilder` with default settings (no receivers).
54 ///
55 /// # Examples
56 ///
57 /// ```rust,no_run
58 /// use dbc_rs::ReceiversBuilder;
59 ///
60 /// let builder = ReceiversBuilder::new();
61 /// let receivers = builder.build()?;
62 /// assert_eq!(receivers.len(), 0);
63 /// # Ok::<(), dbc_rs::Error>(())
64 /// ```
65 pub fn new() -> Self {
66 Self {
67 is_broadcast: false,
68 nodes: Vec::new(),
69 }
70 }
71
72 /// Sets the receiver to broadcast (`*` in DBC format).
73 ///
74 /// This clears any previously set nodes and sets the receiver to broadcast mode.
75 ///
76 /// # Examples
77 ///
78 /// ```rust,no_run
79 /// use dbc_rs::ReceiversBuilder;
80 ///
81 /// let receivers = ReceiversBuilder::new()
82 /// .add_node("TCM") // This will be cleared
83 /// .broadcast()
84 /// .build()?;
85 /// assert_eq!(receivers, dbc_rs::Receivers::Broadcast);
86 /// # Ok::<(), dbc_rs::Error>(())
87 /// ```
88 #[must_use = "builder method returns modified builder"]
89 pub fn broadcast(mut self) -> Self {
90 self.is_broadcast = true;
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 = "builder method returns modified builder"]
112 pub fn none(mut self) -> Self {
113 self.is_broadcast = false;
114 self.nodes.clear();
115 self
116 }
117
118 /// Adds a single receiver node.
119 ///
120 /// This automatically clears broadcast and none modes, switching to specific nodes mode.
121 ///
122 /// # Arguments
123 ///
124 /// * `node` - The node name (anything that implements `AsRef<str>`)
125 ///
126 /// # Examples
127 ///
128 /// ```rust,no_run
129 /// use dbc_rs::ReceiversBuilder;
130 ///
131 /// let receivers = ReceiversBuilder::new()
132 /// .add_node("TCM")
133 /// .add_node("BCM")
134 /// .build()?;
135 /// assert_eq!(receivers.len(), 2);
136 /// assert!(receivers.contains("TCM"));
137 /// # Ok::<(), dbc_rs::Error>(())
138 /// ```
139 pub fn add_node(mut self, node: impl AsRef<str>) -> Self {
140 let node = node.as_ref().to_string();
141 self.is_broadcast = false;
142 self.nodes.push(node);
143
144 self
145 }
146
147 /// Adds multiple receiver nodes from an iterator.
148 ///
149 /// This automatically clears broadcast and none modes, switching to specific nodes mode.
150 ///
151 /// # Arguments
152 ///
153 /// * `nodes` - An iterator of node names (each item must implement `AsRef<str>`)
154 ///
155 /// # Examples
156 ///
157 /// ```rust,no_run
158 /// use dbc_rs::ReceiversBuilder;
159 ///
160 /// // From a slice
161 /// let receivers = ReceiversBuilder::new()
162 /// .add_nodes(&["TCM", "BCM", "ECM"])
163 /// .build()?;
164 /// assert_eq!(receivers.len(), 3);
165 ///
166 /// // From a vector
167 /// let node_vec = vec!["Node1", "Node2"];
168 /// let receivers2 = ReceiversBuilder::new()
169 /// .add_nodes(node_vec.iter())
170 /// .build()?;
171 /// assert_eq!(receivers2.len(), 2);
172 /// # Ok::<(), dbc_rs::Error>(())
173 /// ```
174 pub fn add_nodes<I, S>(mut self, nodes: I) -> Self
175 where
176 I: IntoIterator<Item = S>,
177 S: AsRef<str>,
178 {
179 for node in nodes {
180 self = self.add_node(node);
181 }
182
183 self
184 }
185
186 /// Clears all receiver nodes and resets to default state (none).
187 ///
188 /// # Examples
189 ///
190 /// ```rust,no_run
191 /// use dbc_rs::ReceiversBuilder;
192 ///
193 /// let receivers = ReceiversBuilder::new()
194 /// .add_node("TCM")
195 /// .add_node("BCM")
196 /// .clear()
197 /// .add_node("ECM")
198 /// .build()?;
199 /// assert_eq!(receivers.len(), 1);
200 /// assert!(receivers.contains("ECM"));
201 /// assert!(!receivers.contains("TCM"));
202 /// # Ok::<(), dbc_rs::Error>(())
203 /// ```
204 #[must_use = "builder method returns modified builder"]
205 pub fn clear(mut self) -> Self {
206 self.nodes.clear();
207 self.is_broadcast = false;
208 self
209 }
210}
211
212impl ReceiversBuilder {
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> {
252 if self.is_broadcast {
253 Ok(Receivers::new_broadcast())
254 } else if self.nodes.is_empty() {
255 Ok(Receivers::new_none())
256 } else {
257 // Make sure the number of nodes is not greater than the maximum allowed
258 // Receivers can have at most MAX_NODES - 1 nodes
259 if let Some(err) = crate::error::check_max_limit(
260 self.nodes.len(),
261 MAX_NODES - 1,
262 Error::Signal(Error::SIGNAL_RECEIVERS_TOO_MANY),
263 ) {
264 return Err(err);
265 }
266
267 // Make sure the nodes are not duplicated
268 let mut seen = HashSet::new();
269 if !self.nodes.iter().all(|item| seen.insert(item)) {
270 return Err(Error::Signal(Error::RECEIVERS_DUPLICATE_NAME));
271 }
272
273 // Make sure the node names are not too long and convert to compat::String
274 use crate::compat::{String, Vec};
275 let mut compat_nodes: Vec<String<{ MAX_NAME_SIZE }>, { MAX_NODES }> = Vec::new();
276 for node in &self.nodes {
277 if let Some(err) = crate::error::check_max_limit(
278 node.len(),
279 MAX_NAME_SIZE,
280 Error::Signal(Error::MAX_NAME_SIZE_EXCEEDED),
281 ) {
282 return Err(err);
283 }
284 let compat_str = String::try_from(node.as_str())
285 .map_err(|_| Error::Signal(Error::MAX_NAME_SIZE_EXCEEDED))?;
286 compat_nodes
287 .push(compat_str)
288 .map_err(|_| Error::Signal(Error::SIGNAL_RECEIVERS_TOO_MANY))?;
289 }
290
291 Ok(Receivers::new_nodes(compat_nodes.as_slice()))
292 }
293 }
294}
295
296impl Default for ReceiversBuilder {
297 fn default() -> Self {
298 Self::new()
299 }
300}
301
302#[cfg(test)]
303mod tests {
304 use super::*;
305 use crate::error::Error;
306
307 #[test]
308 fn test_receivers_builder_broadcast() {
309 let receivers = ReceiversBuilder::new().broadcast().build().unwrap();
310 assert_eq!(receivers, Receivers::Broadcast);
311 }
312
313 #[test]
314 fn test_receivers_builder_none() {
315 let receivers = ReceiversBuilder::new().none().build().unwrap();
316 assert_eq!(receivers, Receivers::None);
317 }
318
319 #[test]
320 fn test_receivers_builder_empty() {
321 let receivers = ReceiversBuilder::new().build().unwrap();
322 assert_eq!(receivers, Receivers::None);
323 }
324
325 #[test]
326 fn test_receivers_builder_single_node() {
327 let receivers = ReceiversBuilder::new().add_node("TCM").build().unwrap();
328 match &receivers {
329 Receivers::Nodes(nodes) => assert_eq!(nodes.len(), 1),
330 _ => panic!("Expected Nodes variant"),
331 }
332 }
333
334 #[test]
335 fn test_receivers_builder_multiple_nodes() {
336 let receivers = ReceiversBuilder::new()
337 .add_node("TCM")
338 .add_node("BCM")
339 .add_node("ECM")
340 .build()
341 .unwrap();
342 match &receivers {
343 Receivers::Nodes(nodes) => assert_eq!(nodes.len(), 3),
344 _ => panic!("Expected Nodes variant"),
345 }
346 }
347
348 #[test]
349 fn test_receivers_builder_too_many() {
350 let mut builder = ReceiversBuilder::new();
351 for i in 0..MAX_NODES {
352 builder = builder.add_node(format!("Node{i}"));
353 }
354 let result = builder.add_node(format!("Node{}", MAX_NODES)).build();
355 assert!(result.is_err());
356 match result.unwrap_err() {
357 Error::Signal(msg) => {
358 assert_eq!(msg, Error::SIGNAL_RECEIVERS_TOO_MANY);
359 }
360 _ => panic!("Expected Signal error"),
361 }
362 }
363
364 #[test]
365 fn test_receivers_builder_add_nodes() {
366 let receivers = ReceiversBuilder::new().add_nodes(["ECM", "TCM", "BCM"]).build().unwrap();
367 match &receivers {
368 Receivers::Nodes(nodes) => assert_eq!(nodes.len(), 3),
369 _ => panic!("Expected Nodes variant"),
370 }
371 assert!(receivers.contains("ECM"));
372 assert!(receivers.contains("TCM"));
373 assert!(receivers.contains("BCM"));
374 }
375
376 #[test]
377 fn test_receivers_builder_add_nodes_iterator() {
378 let node_vec = ["Node1", "Node2", "Node3"];
379 let receivers = ReceiversBuilder::new().add_nodes(node_vec.iter()).build().unwrap();
380 match &receivers {
381 Receivers::Nodes(nodes) => assert_eq!(nodes.len(), 3),
382 _ => panic!("Expected Nodes variant"),
383 }
384 }
385
386 #[test]
387 fn test_receivers_builder_clear() {
388 let receivers = ReceiversBuilder::new()
389 .add_node("ECM")
390 .add_node("TCM")
391 .clear()
392 .add_node("BCM")
393 .build()
394 .unwrap();
395 match &receivers {
396 Receivers::Nodes(nodes) => {
397 assert_eq!(nodes.len(), 1);
398 assert!(receivers.contains("BCM"));
399 assert!(!receivers.contains("ECM"));
400 }
401 _ => panic!("Expected Nodes variant"),
402 }
403 }
404
405 #[test]
406 fn test_receivers_builder_broadcast_clears_nodes() {
407 let receivers = ReceiversBuilder::new()
408 .add_node("ECM")
409 .add_node("TCM")
410 .broadcast()
411 .build()
412 .unwrap();
413 assert_eq!(receivers, Receivers::Broadcast);
414 assert_eq!(receivers.len(), 0);
415 }
416
417 #[test]
418 fn test_receivers_builder_none_clears_nodes() {
419 let receivers =
420 ReceiversBuilder::new().add_node("ECM").add_node("TCM").none().build().unwrap();
421 assert_eq!(receivers, Receivers::None);
422 assert_eq!(receivers.len(), 0);
423 }
424
425 #[test]
426 fn test_receivers_builder_add_node_clears_broadcast() {
427 let receivers = ReceiversBuilder::new().broadcast().add_node("ECM").build().unwrap();
428 match &receivers {
429 Receivers::Nodes(nodes) => assert_eq!(nodes.len(), 1),
430 _ => panic!("Expected Nodes variant"),
431 }
432 }
433
434 #[test]
435 fn test_receivers_builder_add_node_clears_none() {
436 let receivers = ReceiversBuilder::new().none().add_node("ECM").build().unwrap();
437 match &receivers {
438 Receivers::Nodes(nodes) => assert_eq!(nodes.len(), 1),
439 _ => panic!("Expected Nodes variant"),
440 }
441 }
442
443 #[test]
444 fn test_receivers_builder_at_limit() {
445 let mut builder = ReceiversBuilder::new();
446 // Fill up to MAX_NODES - 1 (the limit)
447 for i in 0..(MAX_NODES - 1) {
448 let node_str = format!("Node{i}");
449 builder = builder.add_node(node_str);
450 }
451 let receivers = builder.build().unwrap();
452 match &receivers {
453 Receivers::Nodes(nodes) => assert_eq!(nodes.len(), MAX_NODES - 1),
454 _ => panic!("Expected Nodes variant"),
455 }
456 }
457}