dbc_rs/receivers/
receivers.rs

1use crate::{Parser, error::ParseError, error::ParseResult, error::messages};
2
3#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4#[allow(clippy::large_enum_variant)] // Nodes variant is large but necessary for no_std
5pub enum Receivers<'a> {
6    Broadcast,
7    Nodes([Option<&'a str>; 64], usize), // Stores array and count directly
8    None,
9}
10
11impl<'a> Receivers<'a> {
12    pub(crate) fn new_broadcast() -> Self {
13        Receivers::Broadcast
14    }
15
16    pub(crate) fn new_none() -> Self {
17        Receivers::None
18    }
19
20    pub(crate) fn new_nodes(nodes: &[&'a str]) -> Self {
21        // Validation should have been done prior (by builder or parse)
22        const MAX_RECEIVER_NODES: usize = 64;
23        let mut node_array: [Option<&'a str>; MAX_RECEIVER_NODES] =
24            [const { None }; MAX_RECEIVER_NODES];
25        let count = nodes.len();
26        for (i, node) in nodes.iter().enumerate() {
27            node_array[i] = Some(*node);
28        }
29        Receivers::Nodes(node_array, count)
30    }
31
32    pub(crate) fn parse<'b: 'a>(parser: &mut Parser<'b>) -> ParseResult<Self> {
33        const MAX_RECEIVER_NODES: usize = 64;
34
35        // Skip any leading spaces (but not newlines - newlines indicate end of line)
36        // If we get UnexpectedEof, we're at EOF, so return None
37        match parser.skip_whitespace() {
38            Ok(_) => {}
39            Err(ParseError::UnexpectedEof) => return Ok(Self::new_none()),
40            Err(_) => {} // Other errors (like Expected) mean there's no whitespace, continue
41        }
42
43        // Check if next character is '*' (broadcast marker)
44        if parser.expect(b"*").is_ok() {
45            return Ok(Self::new_broadcast());
46        }
47
48        // Check if we're at a newline (end of signal line)
49        if parser.expect(b"\n").is_ok() || parser.expect(b"\r").is_ok() {
50            return Ok(Self::new_none());
51        }
52
53        // Parse space-separated identifiers into fixed-size array
54        let mut nodes = [None; MAX_RECEIVER_NODES];
55        let mut count = 0;
56
57        loop {
58            // Skip spaces (but not newlines)
59            // If we get UnexpectedEof, we're at EOF, so break
60            match parser.skip_whitespace() {
61                Ok(_) => {}
62                Err(ParseError::UnexpectedEof) => break,
63                Err(_) => {} // Other errors mean there's no whitespace, continue
64            }
65
66            // Check if we're at a newline (end of signal line)
67            if parser.expect(b"\n").is_ok() || parser.expect(b"\r").is_ok() {
68                break;
69            }
70
71            // Try to parse an identifier
72            // parse_identifier() stops at newlines without consuming them
73            let pos_before = parser.pos();
74            match parser.parse_identifier() {
75                Ok(node) => {
76                    if count >= MAX_RECEIVER_NODES {
77                        return Err(ParseError::Version(messages::SIGNAL_RECEIVERS_TOO_MANY));
78                    }
79                    nodes[count] = Some(node);
80                    count += 1;
81                }
82                Err(ParseError::UnexpectedEof) => break,
83                Err(_) => {
84                    // Failed to parse - if position didn't change, we're at newline or invalid char
85                    if parser.pos() == pos_before {
86                        break;
87                    }
88                    // Position changed but parsing failed - invalid character, also break
89                    break;
90                }
91            }
92        }
93
94        if count == 0 {
95            Ok(Self::new_none())
96        } else {
97            // Collect node names into a slice for new_nodes
98            let mut node_refs: [&'b str; 64] = [""; 64];
99            for i in 0..count {
100                if let Some(node) = nodes[i] {
101                    node_refs[i] = node;
102                }
103            }
104            // Validate before construction
105            const MAX_RECEIVER_NODES: usize = 64;
106            if count > MAX_RECEIVER_NODES {
107                return Err(ParseError::Version(messages::SIGNAL_RECEIVERS_TOO_MANY));
108            }
109            // Construct directly (validation already done)
110            Ok(Self::new_nodes(&node_refs[..count]))
111        }
112    }
113
114    /// Get an iterator over the nodes
115    ///
116    /// # Examples
117    ///
118    /// ```
119    /// use dbc_rs::{Dbc, Signal};
120    ///
121    /// let dbc = Dbc::parse("VERSION \"1.0\"\n\nBU_: ECM TCM\n\nBO_ 256 Engine : 8 ECM\n SG_ RPM : 0|16@1+ (0.25,0) [0|8000] \"rpm\" ECM TCM")?;
122    /// let message = dbc.messages().at(0).unwrap();
123    /// let signal = message.signals().at(0).unwrap();
124    /// for receiver in signal.receivers().iter() {
125    ///     println!("Receiver: {}", receiver);
126    /// }
127    /// # Ok::<(), dbc_rs::Error>(())
128    /// ```
129    #[inline]
130    #[must_use = "iterator is lazy and does nothing unless consumed"]
131    pub fn iter(&self) -> impl Iterator<Item = &'a str> + '_ {
132        struct NodeIter<'a> {
133            arr: [Option<&'a str>; 64],
134            count: usize,
135            pos: usize,
136        }
137        impl<'a> Iterator for NodeIter<'a> {
138            type Item = &'a str;
139            fn next(&mut self) -> Option<Self::Item> {
140                while self.pos < self.count {
141                    let result = self.arr[self.pos];
142                    self.pos += 1;
143                    if let Some(node) = result {
144                        return Some(node);
145                    }
146                }
147                None
148            }
149        }
150
151        match self {
152            Receivers::Nodes(arr, count) => NodeIter {
153                arr: *arr,
154                count: *count,
155                pos: 0,
156            },
157            _ => NodeIter {
158                arr: [None; 64],
159                count: 0,
160                pos: 0,
161            },
162        }
163    }
164
165    /// Get the number of nodes (only valid for Receivers::Nodes variant)
166    ///
167    /// # Examples
168    ///
169    /// ```
170    /// use dbc_rs::Dbc;
171    ///
172    /// let dbc = Dbc::parse("VERSION \"1.0\"\n\nBU_: ECM TCM\n\nBO_ 256 Engine : 8 ECM\n SG_ RPM : 0|16@1+ (0.25,0) [0|8000] \"rpm\" ECM TCM")?;
173    /// let message = dbc.messages().at(0).unwrap();
174    /// let signal = message.signals().at(0).unwrap();
175    /// assert_eq!(signal.receivers().len(), 2);
176    /// # Ok::<(), dbc_rs::Error>(())
177    /// ```
178    #[inline]
179    #[must_use]
180    pub fn len(&self) -> usize {
181        match self {
182            Receivers::Nodes(_, count) => *count,
183            Receivers::Broadcast | Receivers::None => 0,
184        }
185    }
186
187    /// Returns `true` if there are no receiver nodes
188    ///
189    /// # Examples
190    ///
191    /// ```
192    /// use dbc_rs::Dbc;
193    ///
194    /// let dbc = Dbc::parse("VERSION \"1.0\"\n\nBU_: ECM\n\nBO_ 256 Engine : 8 ECM\n SG_ RPM : 0|16@1+ (0.25,0) [0|8000] \"rpm\"")?;
195    /// let message = dbc.messages().at(0).unwrap();
196    /// let signal = message.signals().at(0).unwrap();
197    /// assert!(signal.receivers().is_empty());
198    /// # Ok::<(), dbc_rs::Error>(())
199    /// ```
200    #[inline]
201    #[must_use]
202    pub fn is_empty(&self) -> bool {
203        self.len() == 0
204    }
205
206    /// Check if a node is in the receivers list
207    ///
208    /// # Examples
209    ///
210    /// ```
211    /// use dbc_rs::Dbc;
212    ///
213    /// let dbc = Dbc::parse("VERSION \"1.0\"\n\nBU_: ECM TCM\n\nBO_ 256 Engine : 8 ECM\n SG_ RPM : 0|16@1+ (0.25,0) [0|8000] \"rpm\" ECM TCM")?;
214    /// let message = dbc.messages().at(0).unwrap();
215    /// let signal = message.signals().at(0).unwrap();
216    /// assert!(signal.receivers().contains("ECM"));
217    /// assert!(!signal.receivers().contains("BCM"));
218    /// # Ok::<(), dbc_rs::Error>(())
219    /// ```
220    #[inline]
221    #[must_use]
222    pub fn contains(&self, node: &str) -> bool {
223        self.iter().any(|n| n == node)
224    }
225
226    /// Get a node by index, or None if index is out of bounds
227    ///
228    /// # Examples
229    ///
230    /// ```
231    /// use dbc_rs::Dbc;
232    ///
233    /// let dbc = Dbc::parse("VERSION \"1.0\"\n\nBU_: ECM TCM\n\nBO_ 256 Engine : 8 ECM\n SG_ RPM : 0|16@1+ (0.25,0) [0|8000] \"rpm\" ECM TCM")?;
234    /// let message = dbc.messages().at(0).unwrap();
235    /// let signal = message.signals().at(0).unwrap();
236    /// if let Some(receiver) = signal.receivers().at(0) {
237    ///     assert_eq!(receiver, "ECM");
238    /// }
239    /// # Ok::<(), dbc_rs::Error>(())
240    /// ```
241    #[inline]
242    #[must_use]
243    pub fn at(&self, index: usize) -> Option<&'a str> {
244        match self {
245            Receivers::Nodes(arr, count) => {
246                if index >= *count {
247                    return None;
248                }
249                arr[index]
250            }
251            Receivers::Broadcast | Receivers::None => None,
252        }
253    }
254}
255
256#[cfg(test)]
257mod tests {
258    use super::*;
259    use crate::{Parser, error::ParseError, error::lang};
260
261    #[test]
262    fn test_parse_receivers_broadcast() {
263        let input = "*";
264        let mut parser = Parser::new(input.as_bytes()).unwrap();
265        let result = Receivers::parse(&mut parser).unwrap();
266        assert_eq!(result, Receivers::Broadcast);
267    }
268
269    #[test]
270    fn test_parse_receivers_none_empty() {
271        // Parser::new returns error for empty input, so use a single space instead
272        // Empty receivers should be handled by Receivers::parse when called from Signal::parse
273        // For this test, we'll test with whitespace-only input
274        let input = " ";
275        let mut parser = Parser::new(input.as_bytes()).unwrap();
276        let result = Receivers::parse(&mut parser).unwrap();
277        assert_eq!(result, Receivers::None);
278    }
279
280    #[test]
281    fn test_parse_receivers_single_node() {
282        let input = "TCM";
283        let mut parser = Parser::new(input.as_bytes()).unwrap();
284        let result = Receivers::parse(&mut parser).unwrap();
285        match result {
286            Receivers::Nodes(_, count) => {
287                assert_eq!(count, 1);
288                let node_count = result.len();
289                assert_eq!(node_count, 1);
290                let first_node = result.iter().next().unwrap();
291                assert_eq!(first_node, "TCM");
292            }
293            _ => panic!("Expected Nodes variant"),
294        }
295    }
296
297    #[test]
298    fn test_parse_receivers_multiple_nodes() {
299        let input = "TCM BCM ECM";
300        let mut parser = Parser::new(input.as_bytes()).unwrap();
301        let result = Receivers::parse(&mut parser).unwrap();
302        {
303            let node_count = result.len();
304            assert_eq!(node_count, 3);
305            let nodes: Vec<&str> = result.iter().collect();
306            assert_eq!(nodes[0], "TCM");
307            assert_eq!(nodes[1], "BCM");
308            assert_eq!(nodes[2], "ECM");
309        }
310    }
311
312    #[test]
313    fn test_parse_receivers_whitespace_only() {
314        let input = "   ";
315        let mut parser = Parser::new(input.as_bytes()).unwrap();
316        let result = Receivers::parse(&mut parser).unwrap();
317        assert_eq!(result, Receivers::None);
318    }
319
320    #[test]
321    fn test_parse_receivers_with_extra_whitespace() {
322        let input = "  TCM   BCM  ";
323        let mut parser = Parser::new(input.as_bytes()).unwrap();
324        let result = Receivers::parse(&mut parser).unwrap();
325        {
326            let node_count = result.len();
327            assert_eq!(node_count, 2);
328            let nodes: Vec<&str> = result.iter().collect();
329            assert_eq!(nodes[0], "TCM");
330            assert_eq!(nodes[1], "BCM");
331        }
332    }
333
334    #[test]
335    fn test_parse_receivers_too_many() {
336        // Create a string with 65 receiver nodes (exceeds limit of 64)
337        // Use a simple approach: create byte array directly
338        let mut receivers_bytes = Vec::new();
339        for i in 0..65 {
340            if i > 0 {
341                receivers_bytes.push(b' ');
342            }
343            let node_str = format!("Node{i}");
344            receivers_bytes.extend_from_slice(node_str.as_bytes());
345        }
346        let mut parser = Parser::new(&receivers_bytes).unwrap();
347        let result = Receivers::parse(&mut parser);
348        assert!(result.is_err());
349        match result.unwrap_err() {
350            ParseError::Version(msg) => {
351                assert!(msg.contains(lang::SIGNAL_RECEIVERS_TOO_MANY));
352            }
353            _ => panic!("Expected ParseError"),
354        }
355    }
356
357    #[test]
358    fn test_parse_receivers_at_limit() {
359        // Create a string with exactly 64 receiver nodes (at the limit)
360        // Use a simple approach: create byte array directly
361        let mut receivers_bytes = Vec::new();
362        for i in 0..64 {
363            if i > 0 {
364                receivers_bytes.push(b' ');
365            }
366            let node_str = format!("Node{i}");
367            receivers_bytes.extend_from_slice(node_str.as_bytes());
368        }
369        let mut parser = Parser::new(&receivers_bytes).unwrap();
370        let result = Receivers::parse(&mut parser).unwrap();
371        let node_count = result.len();
372        assert_eq!(node_count, 64);
373    }
374}