dbc_rs/receivers/receivers.rs
1use crate::{
2 Error, MAX_NAME_SIZE, MAX_RECEIVER_NODES, Parser, Result,
3 compat::{String, Vec},
4 error::lang,
5};
6
7/// Represents the receiver nodes for a signal in a DBC file.
8///
9/// A signal can have three types of receivers:
10/// - **Broadcast** (`*`): The signal is broadcast to all nodes on the bus
11/// - **Specific nodes**: A list of specific node names that receive this signal
12/// - **None**: No explicit receivers specified (signal may be unused or receiver is implicit)
13///
14/// # Examples
15///
16/// ```rust,no_run
17/// use dbc_rs::Dbc;
18///
19/// let dbc = Dbc::parse(r#"VERSION "1.0"
20///
21/// BU_: ECM TCM BCM
22///
23/// BO_ 256 Engine : 8 ECM
24/// SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
25/// SG_ Temp : 16|8@0- (1,-40) [-40|215] "°C" TCM BCM
26/// "#)?;
27///
28/// let message = dbc.messages().at(0).unwrap();
29///
30/// // Broadcast receiver
31/// let rpm_signal = message.signals().find("RPM").unwrap();
32/// assert_eq!(rpm_signal.receivers().len(), 0); // Broadcast has no specific nodes
33///
34/// // Specific nodes
35/// let temp_signal = message.signals().find("Temp").unwrap();
36/// assert_eq!(temp_signal.receivers().len(), 2);
37/// assert!(temp_signal.receivers().contains("TCM"));
38/// # Ok::<(), dbc_rs::Error>(())
39/// ```
40///
41/// # DBC Format
42///
43/// In DBC files, receivers are specified after the signal definition:
44/// - `*` indicates broadcast
45/// - Space-separated node names indicate specific receivers
46/// - No receivers means `None`
47#[derive(Debug, Clone, PartialEq, Eq, Hash)]
48#[allow(clippy::large_enum_variant)]
49pub enum Receivers {
50 /// Broadcast receiver - signal is sent to all nodes on the bus.
51 Broadcast,
52 /// Specific receiver nodes - vector of node names.
53 Nodes(Vec<String<{ MAX_NAME_SIZE }>, { MAX_RECEIVER_NODES }>),
54 /// No explicit receivers specified.
55 None,
56}
57
58impl Receivers {
59 pub(crate) fn new_broadcast() -> Self {
60 Receivers::Broadcast
61 }
62
63 pub(crate) fn new_none() -> Self {
64 Receivers::None
65 }
66
67 #[cfg(feature = "std")]
68 pub(crate) fn new_nodes(nodes: &[String<{ MAX_NAME_SIZE }>]) -> Self {
69 // Validation should have been done prior (by builder or parse)
70 let vec_nodes: Vec<String<{ MAX_NAME_SIZE }>, { MAX_RECEIVER_NODES }> =
71 nodes.iter().take(MAX_RECEIVER_NODES).cloned().collect();
72 Receivers::Nodes(vec_nodes)
73 }
74
75 pub(crate) fn parse(parser: &mut Parser) -> Result<Self> {
76 // Skip any leading spaces (but not newlines - newlines indicate end of line)
77 // If we get UnexpectedEof, we're at EOF, so return None
78 match parser.skip_whitespace() {
79 Ok(_) => {}
80 Err(Error::UnexpectedEof) => return Ok(Self::new_none()),
81 Err(_) => {} // Other errors (like Expected) mean there's no whitespace, continue
82 }
83
84 // Check if next character is '*' (broadcast marker)
85 if parser.expect(b"*").is_ok() {
86 return Ok(Self::new_broadcast());
87 }
88
89 // Check if we're at a newline (end of signal line)
90 if parser.expect(b"\n").is_ok() || parser.expect(b"\r").is_ok() {
91 return Ok(Self::new_none());
92 }
93
94 // Parse space-separated identifiers into Vec
95 let mut nodes: Vec<String<{ MAX_NAME_SIZE }>, { MAX_RECEIVER_NODES }> = Vec::new();
96
97 loop {
98 // Skip spaces (but not newlines)
99 // If we get UnexpectedEof, we're at EOF, so break
100 match parser.skip_whitespace() {
101 Ok(_) => {}
102 Err(Error::UnexpectedEof) => break,
103 Err(_) => {} // Other errors mean there's no whitespace, continue
104 }
105
106 // Check if we're at a newline (end of signal line)
107 if parser.expect(b"\n").is_ok() || parser.expect(b"\r").is_ok() {
108 break;
109 }
110
111 // Try to parse an identifier
112 // parse_identifier() stops at newlines without consuming them
113 let pos_before = parser.pos();
114 match parser.parse_identifier() {
115 Ok(node) => {
116 if let Some(err) = crate::check_max_limit(
117 nodes.len(),
118 MAX_RECEIVER_NODES - 1,
119 Error::Receivers(lang::SIGNAL_RECEIVERS_TOO_MANY),
120 ) {
121 return Err(err);
122 }
123 let node = crate::validate_name(node)?;
124 nodes
125 .push(node)
126 .map_err(|_| Error::Receivers(lang::SIGNAL_RECEIVERS_TOO_MANY))?;
127 }
128 Err(Error::UnexpectedEof) => break,
129 Err(_) => {
130 // Failed to parse - if position didn't change, we're at newline or invalid char
131 if parser.pos() == pos_before {
132 break;
133 }
134 // Position changed but parsing failed - invalid character, also break
135 break;
136 }
137 }
138 }
139
140 if nodes.is_empty() {
141 Ok(Self::new_none())
142 } else {
143 Ok(Receivers::Nodes(nodes))
144 }
145 }
146
147 /// Returns an iterator over the receiver node names.
148 ///
149 /// For `Receivers::Broadcast` and `Receivers::None`, the iterator will be empty.
150 /// For `Receivers::Nodes`, it iterates over the specific node names.
151 ///
152 /// # Examples
153 ///
154 /// ```rust,no_run
155 /// use dbc_rs::Dbc;
156 ///
157 /// let dbc = Dbc::parse(r#"VERSION "1.0"
158 ///
159 /// BU_: ECM TCM BCM
160 ///
161 /// BO_ 256 Engine : 8 ECM
162 /// SG_ Temp : 0|8@1+ (1,0) [0|255] "°C" TCM BCM
163 /// "#)?;
164 ///
165 /// let message = dbc.messages().at(0).unwrap();
166 /// let signal = message.signals().at(0).unwrap();
167 ///
168 /// // Iterate over receiver nodes
169 /// let mut iter = signal.receivers().iter();
170 /// assert_eq!(iter.next().map(|s| s.to_string()), Some("TCM".to_string()));
171 /// assert_eq!(iter.next().map(|s| s.to_string()), Some("BCM".to_string()));
172 /// assert_eq!(iter.next(), None);
173 /// # Ok::<(), dbc_rs::Error>(())
174 /// ```
175 ///
176 /// # Broadcast and None
177 ///
178 /// ```rust,no_run
179 /// use dbc_rs::Dbc;
180 ///
181 /// let dbc = Dbc::parse(r#"VERSION "1.0"
182 ///
183 /// BU_: ECM
184 ///
185 /// BO_ 256 Engine : 8 ECM
186 /// SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
187 /// "#)?;
188 ///
189 /// let message = dbc.messages().at(0).unwrap();
190 /// let signal = message.signals().at(0).unwrap();
191 ///
192 /// // Broadcast receivers return empty iterator
193 /// assert_eq!(signal.receivers().iter().count(), 0);
194 /// # Ok::<(), dbc_rs::Error>(())
195 /// ```
196 #[inline]
197 #[must_use = "iterator is lazy and does nothing unless consumed"]
198 pub fn iter(&self) -> impl Iterator<Item = String<{ MAX_NAME_SIZE }>> {
199 match self {
200 Receivers::Nodes(nodes) => ReceiversIter {
201 nodes: Some(nodes.clone()),
202 pos: 0,
203 },
204 _ => ReceiversIter {
205 nodes: None,
206 pos: 0,
207 },
208 }
209 }
210
211 /// Returns the number of receiver nodes.
212 ///
213 /// - For `Receivers::Nodes`: Returns the count of specific receiver nodes
214 /// - For `Receivers::Broadcast` and `Receivers::None`: Returns `0`
215 ///
216 /// # Examples
217 ///
218 /// ```rust,no_run
219 /// use dbc_rs::Dbc;
220 ///
221 /// let dbc = Dbc::parse(r#"VERSION "1.0"
222 ///
223 /// BU_: ECM TCM BCM
224 ///
225 /// BO_ 256 Engine : 8 ECM
226 /// SG_ Temp : 0|8@1+ (1,0) [0|255] "°C" TCM BCM
227 /// "#)?;
228 ///
229 /// let message = dbc.messages().at(0).unwrap();
230 /// let signal = message.signals().at(0).unwrap();
231 /// assert_eq!(signal.receivers().len(), 2);
232 /// # Ok::<(), dbc_rs::Error>(())
233 /// ```
234 #[inline]
235 #[must_use]
236 pub fn len(&self) -> usize {
237 match self {
238 Receivers::Nodes(nodes) => nodes.len(),
239 Receivers::Broadcast | Receivers::None => 0,
240 }
241 }
242
243 /// Returns `true` if there are no specific receiver nodes.
244 ///
245 /// This returns `true` for both `Receivers::Broadcast` and `Receivers::None`,
246 /// as neither has specific node names.
247 ///
248 /// # Examples
249 ///
250 /// ```rust,no_run
251 /// use dbc_rs::Dbc;
252 ///
253 /// let dbc = Dbc::parse(r#"VERSION "1.0"
254 ///
255 /// BU_: ECM
256 ///
257 /// BO_ 256 Engine : 8 ECM
258 /// SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
259 /// "#)?;
260 ///
261 /// let message = dbc.messages().at(0).unwrap();
262 /// let signal = message.signals().at(0).unwrap();
263 /// assert!(signal.receivers().is_empty());
264 /// # Ok::<(), dbc_rs::Error>(())
265 /// ```
266 #[inline]
267 #[must_use]
268 pub fn is_empty(&self) -> bool {
269 self.len() == 0
270 }
271
272 /// Checks if a node name is in the receivers list.
273 ///
274 /// For `Receivers::Broadcast` and `Receivers::None`, this always returns `false`.
275 /// For `Receivers::Nodes`, it checks if the node name is in the list.
276 ///
277 /// # Arguments
278 ///
279 /// * `node` - The node name to check
280 ///
281 /// # Examples
282 ///
283 /// ```rust,no_run
284 /// use dbc_rs::Dbc;
285 ///
286 /// let dbc = Dbc::parse(r#"VERSION "1.0"
287 ///
288 /// BU_: ECM TCM BCM
289 ///
290 /// BO_ 256 Engine : 8 ECM
291 /// SG_ Temp : 0|8@1+ (1,0) [0|255] "°C" TCM BCM
292 /// "#)?;
293 ///
294 /// let message = dbc.messages().at(0).unwrap();
295 /// let signal = message.signals().at(0).unwrap();
296 ///
297 /// assert!(signal.receivers().contains("TCM"));
298 /// assert!(signal.receivers().contains("BCM"));
299 /// assert!(!signal.receivers().contains("ECM"));
300 /// # Ok::<(), dbc_rs::Error>(())
301 /// ```
302 #[inline]
303 #[must_use]
304 pub fn contains(&self, node: &str) -> bool {
305 self.iter().any(|n| n.as_str() == node)
306 }
307
308 /// Gets a receiver node by index.
309 ///
310 /// Returns `None` if:
311 /// - The index is out of bounds
312 /// - The receiver is `Broadcast` or `None`
313 ///
314 /// # Arguments
315 ///
316 /// * `index` - The zero-based index of the receiver node
317 ///
318 /// # Examples
319 ///
320 /// ```rust,no_run
321 /// use dbc_rs::Dbc;
322 ///
323 /// let dbc = Dbc::parse(r#"VERSION "1.0"
324 ///
325 /// BU_: ECM TCM BCM
326 ///
327 /// BO_ 256 Engine : 8 ECM
328 /// SG_ Temp : 0|8@1+ (1,0) [0|255] "°C" TCM BCM
329 /// "#)?;
330 ///
331 /// let message = dbc.messages().at(0).unwrap();
332 /// let signal = message.signals().at(0).unwrap();
333 ///
334 /// assert_eq!(signal.receivers().at(0), Some("TCM"));
335 /// assert_eq!(signal.receivers().at(1), Some("BCM"));
336 /// assert_eq!(signal.receivers().at(2), None);
337 /// # Ok::<(), dbc_rs::Error>(())
338 /// ```
339 #[inline]
340 #[must_use]
341 pub fn at(&self, index: usize) -> Option<&str> {
342 match self {
343 Receivers::Nodes(nodes) => nodes.get(index).map(|s| s.as_str()),
344 Receivers::Broadcast | Receivers::None => None,
345 }
346 }
347}
348
349struct ReceiversIter {
350 nodes: Option<Vec<String<{ MAX_NAME_SIZE }>, { MAX_RECEIVER_NODES }>>,
351 pos: usize,
352}
353
354impl Iterator for ReceiversIter {
355 type Item = String<{ MAX_NAME_SIZE }>;
356 fn next(&mut self) -> Option<Self::Item> {
357 if let Some(nodes) = &self.nodes {
358 if self.pos < nodes.len() {
359 let result: String<{ MAX_NAME_SIZE }> = nodes[self.pos].clone();
360 self.pos += 1;
361 Some(result)
362 } else {
363 None
364 }
365 } else {
366 None
367 }
368 }
369}
370
371#[cfg(test)]
372mod tests {
373 use super::*;
374 use crate::Parser;
375
376 #[test]
377 fn test_parse_receivers_broadcast() {
378 let input = "*";
379 let mut parser = Parser::new(input.as_bytes()).unwrap();
380 let result = Receivers::parse(&mut parser).unwrap();
381 assert_eq!(result, Receivers::Broadcast);
382 }
383
384 #[test]
385 fn test_parse_receivers_none_empty() {
386 // Parser::new returns error for empty input, so use a single space instead
387 // Empty receivers should be handled by Receivers::parse when called from Signal::parse
388 // For this test, we'll test with whitespace-only input
389 let input = " ";
390 let mut parser = Parser::new(input.as_bytes()).unwrap();
391 let result = Receivers::parse(&mut parser).unwrap();
392 assert_eq!(result, Receivers::None);
393 }
394
395 #[test]
396 fn test_parse_receivers_single_node() {
397 let input = "TCM";
398 let mut parser = Parser::new(input.as_bytes()).unwrap();
399 let result = Receivers::parse(&mut parser).unwrap();
400 match &result {
401 Receivers::Nodes(nodes) => {
402 assert_eq!(nodes.len(), 1);
403 let node_count = result.len();
404 assert_eq!(node_count, 1);
405 let first_node = result.iter().next().unwrap();
406 assert_eq!(first_node.as_str(), "TCM");
407 }
408 _ => panic!("Expected Nodes variant"),
409 }
410 }
411
412 #[test]
413 fn test_parse_receivers_multiple_nodes() {
414 let input = "TCM BCM ECM";
415 let mut parser = Parser::new(input.as_bytes()).unwrap();
416 let result = Receivers::parse(&mut parser).unwrap();
417 {
418 let node_count = result.len();
419 assert_eq!(node_count, 3);
420 let mut iter = result.iter();
421 assert_eq!(iter.next().unwrap().as_str(), "TCM");
422 assert_eq!(iter.next().unwrap().as_str(), "BCM");
423 assert_eq!(iter.next().unwrap().as_str(), "ECM");
424 assert!(iter.next().is_none());
425 }
426 }
427
428 #[test]
429 fn test_parse_receivers_whitespace_only() {
430 let input = " ";
431 let mut parser = Parser::new(input.as_bytes()).unwrap();
432 let result = Receivers::parse(&mut parser).unwrap();
433 assert_eq!(result, Receivers::None);
434 }
435
436 #[test]
437 fn test_parse_receivers_with_extra_whitespace() {
438 let input = " TCM BCM ";
439 let mut parser = Parser::new(input.as_bytes()).unwrap();
440 let result = Receivers::parse(&mut parser).unwrap();
441 let node_count = result.len();
442 assert_eq!(node_count, 2);
443 let mut iter = result.iter();
444 let node1 = iter.next().unwrap();
445 assert_eq!(node1.as_str(), "TCM");
446 let node2 = iter.next().unwrap();
447 assert_eq!(node2.as_str(), "BCM");
448 assert!(iter.next().is_none());
449 }
450
451 // Tests that require std (for format! macro)
452 #[cfg(feature = "std")]
453 mod tests_std {
454 use super::*;
455
456 #[test]
457 fn test_parse_receivers_too_many() {
458 // Create a string with 65 receiver nodes (exceeds limit of 64)
459 // Use std::vec::Vec since we need more than 64 bytes
460 let mut receivers_bytes = std::vec::Vec::new();
461 for i in 0..65 {
462 if i > 0 {
463 receivers_bytes.push(b' ');
464 }
465 let node_str = format!("Node{i}");
466 receivers_bytes.extend_from_slice(node_str.as_bytes());
467 }
468 let mut parser = Parser::new(&receivers_bytes).unwrap();
469 let result = Receivers::parse(&mut parser);
470 assert!(result.is_err());
471 match result.unwrap_err() {
472 Error::Receivers(msg) => {
473 assert_eq!(msg, lang::SIGNAL_RECEIVERS_TOO_MANY);
474 }
475 _ => panic!("Expected Error::Receivers"),
476 }
477 }
478
479 #[test]
480 fn test_parse_receivers_at_limit() {
481 // Create a string with exactly 64 receiver nodes (at the limit)
482 // Use std::vec::Vec since we need more than 64 bytes
483 let mut receivers_bytes = std::vec::Vec::new();
484 for i in 0..MAX_RECEIVER_NODES {
485 if i > 0 {
486 receivers_bytes.push(b' ');
487 }
488 let node_str = format!("Node{i}");
489 receivers_bytes.extend_from_slice(node_str.as_bytes());
490 }
491 let mut parser = Parser::new(&receivers_bytes).unwrap();
492 let result = Receivers::parse(&mut parser).unwrap();
493 let node_count = result.len();
494 assert_eq!(node_count, 64);
495 }
496 }
497}