dbc_rs/dbc/
messages.rs

1use crate::Message;
2
3/// Iterator over messages in a Messages collection
4struct MessagesIter<'a, 'b> {
5    messages: &'b [Option<Message<'a>>],
6    count: usize,
7    pos: usize,
8}
9
10impl<'a, 'b> Iterator for MessagesIter<'a, 'b> {
11    type Item = &'b Message<'a>;
12
13    #[inline]
14    fn next(&mut self) -> Option<Self::Item> {
15        while self.pos < self.count {
16            let result = self.messages[self.pos].as_ref();
17            self.pos += 1;
18            if let Some(msg) = result {
19                return Some(msg);
20            }
21        }
22        None
23    }
24}
25
26// Maximum messages per DBC
27//
28// Defaults to 10000, but can be overridden at build time by setting the `DBC_MAX_MESSAGES`
29// environment variable:
30// ```bash
31// DBC_MAX_MESSAGES=5000 cargo build
32// ```
33//
34// The value must be a valid positive integer. If not set or invalid, defaults to 10000.
35// This constant is generated by build.rs at compile time.
36include!(concat!(env!("OUT_DIR"), "/limits.rs"));
37
38/// Encapsulates the messages array and count for a DBC
39///
40/// Storage strategy:
41/// - `no_std`: Uses fixed-size array `[Option<Message>; MAX_MESSAGES]`
42/// - `alloc`: Uses heap-allocated `Box<[Option<Message>]>` for dynamic sizing
43#[derive(Debug, Clone, PartialEq, Eq, Hash)]
44pub struct Messages<'a> {
45    #[cfg(not(any(feature = "alloc", feature = "kernel")))]
46    messages: [Option<Message<'a>>; MAX_MESSAGES],
47    #[cfg(any(feature = "alloc", feature = "kernel"))]
48    messages: alloc::boxed::Box<[Option<Message<'a>>]>,
49    message_count: usize,
50}
51
52impl<'a> Messages<'a> {
53    /// Create Messages from a slice of messages by cloning them
54    #[allow(dead_code)] // Only used by builders (std-only)
55    pub(crate) fn from_messages_slice(messages: &[Message<'a>]) -> Self {
56        let count = messages.len().min(MAX_MESSAGES);
57
58        #[cfg(not(any(feature = "alloc", feature = "kernel")))]
59        {
60            let mut messages_array: [Option<Message<'a>>; MAX_MESSAGES] =
61                [const { None }; MAX_MESSAGES];
62            for (i, message) in messages.iter().take(MAX_MESSAGES).enumerate() {
63                messages_array[i] = Some(message.clone());
64            }
65            Self {
66                messages: messages_array,
67                message_count: count,
68            }
69        }
70
71        #[cfg(any(feature = "alloc", feature = "kernel"))]
72        {
73            use crate::compat::vec_with_capacity;
74            use alloc::vec::Vec;
75            let mut messages_vec: Vec<Option<Message<'a>>> = vec_with_capacity(count);
76            for message in messages.iter().take(count) {
77                messages_vec.push(Some(message.clone()));
78            }
79            Self {
80                messages: messages_vec.into_boxed_slice(),
81                message_count: count,
82            }
83        }
84    }
85
86    /// Create Messages from a slice of `Option<Message>` and count
87    pub(crate) fn from_options_slice(
88        messages: &[Option<Message<'a>>],
89        message_count: usize,
90    ) -> Self {
91        let count = message_count.min(MAX_MESSAGES).min(messages.len());
92
93        #[cfg(not(any(feature = "alloc", feature = "kernel")))]
94        {
95            let mut messages_array: [Option<Message<'a>>; MAX_MESSAGES] =
96                [const { None }; MAX_MESSAGES];
97            for (i, message_opt) in messages.iter().take(count).enumerate() {
98                messages_array[i] = message_opt.clone();
99            }
100            Self {
101                messages: messages_array,
102                message_count: count,
103            }
104        }
105
106        #[cfg(any(feature = "alloc", feature = "kernel"))]
107        {
108            use crate::compat::vec_with_capacity;
109            use alloc::vec::Vec;
110            let mut messages_vec: Vec<Option<Message<'a>>> = vec_with_capacity(count);
111            for message_opt in messages.iter().take(count) {
112                messages_vec.push(message_opt.clone());
113            }
114            Self {
115                messages: messages_vec.into_boxed_slice(),
116                message_count: count,
117            }
118        }
119    }
120
121    /// Get an iterator over the messages
122    ///
123    /// # Examples
124    ///
125    /// ```rust,no_run
126    /// use dbc_rs::Dbc;
127    ///
128    /// let dbc = Dbc::parse("VERSION \"1.0\"\n\nBU_: ECM\n\nBO_ 256 Engine : 8 ECM")?;
129    /// let mut iter = dbc.messages().iter();
130    /// let message = iter.next().unwrap();
131    /// assert_eq!(message.name(), "Engine");
132    /// assert_eq!(message.id(), 256);
133    /// assert!(iter.next().is_none());
134    /// # Ok::<(), dbc_rs::Error>(())
135    /// ```
136    #[inline]
137    #[must_use = "iterator is lazy and does nothing unless consumed"]
138    pub fn iter(&self) -> impl Iterator<Item = &Message<'a>> + '_ {
139        let messages_slice: &[Option<Message<'a>>] = &self.messages;
140        MessagesIter {
141            messages: messages_slice,
142            count: self.message_count,
143            pos: 0,
144        }
145    }
146
147    /// Get the number of messages
148    ///
149    /// # Examples
150    ///
151    /// ```rust,no_run
152    /// use dbc_rs::Dbc;
153    ///
154    /// let dbc = Dbc::parse("VERSION \"1.0\"\n\nBU_: ECM\n\nBO_ 256 Engine : 8 ECM")?;
155    /// assert_eq!(dbc.messages().len(), 1);
156    /// # Ok::<(), dbc_rs::Error>(())
157    /// ```
158    #[inline]
159    #[must_use]
160    pub fn len(&self) -> usize {
161        self.message_count
162    }
163
164    /// Returns `true` if there are no messages
165    ///
166    /// # Examples
167    ///
168    /// ```rust,no_run
169    /// use dbc_rs::Dbc;
170    ///
171    /// let dbc = Dbc::parse("VERSION \"1.0\"\n\nBU_: ECM")?;
172    /// assert!(dbc.messages().is_empty());
173    /// # Ok::<(), dbc_rs::Error>(())
174    /// ```
175    #[inline]
176    #[must_use]
177    pub fn is_empty(&self) -> bool {
178        self.len() == 0
179    }
180
181    /// Get a message by index, or None if index is out of bounds
182    ///
183    /// # Examples
184    ///
185    /// ```rust,no_run
186    /// use dbc_rs::Dbc;
187    ///
188    /// let dbc = Dbc::parse("VERSION \"1.0\"\n\nBU_: ECM\n\nBO_ 256 Engine : 8 ECM")?;
189    /// if let Some(message) = dbc.messages().at(0) {
190    ///     assert_eq!(message.name(), "Engine");
191    /// }
192    /// # Ok::<(), dbc_rs::Error>(())
193    /// ```
194    #[inline]
195    #[must_use]
196    pub fn at(&self, index: usize) -> Option<&Message<'a>> {
197        if index >= self.message_count {
198            return None;
199        }
200        self.messages[index].as_ref()
201    }
202
203    /// Find a message by name, or None if not found
204    ///
205    /// # Examples
206    ///
207    /// ```rust,no_run
208    /// use dbc_rs::Dbc;
209    ///
210    /// let dbc = Dbc::parse("VERSION \"1.0\"\n\nBU_: ECM\n\nBO_ 256 Engine : 8 ECM")?;
211    /// if let Some(message) = dbc.messages().find("Engine") {
212    ///     assert_eq!(message.name(), "Engine");
213    ///     assert_eq!(message.id(), 256);
214    /// }
215    /// # Ok::<(), dbc_rs::Error>(())
216    /// ```
217    #[must_use]
218    pub fn find(&self, name: &str) -> Option<&Message<'a>> {
219        self.iter().find(|m| m.name() == name)
220    }
221
222    /// Get the maximum capacity (for limit checking during parsing)
223    pub(crate) const fn max_capacity() -> usize {
224        MAX_MESSAGES
225    }
226
227    /// Create a temporary buffer for parsing (no alloc in no_std)
228    /// Returns a buffer that can hold up to MAX_MESSAGES messages
229    #[cfg(not(any(feature = "alloc", feature = "kernel")))]
230    pub(crate) fn new_parse_buffer<'b>() -> [Option<Message<'b>>; MAX_MESSAGES] {
231        [const { None }; MAX_MESSAGES]
232    }
233
234    /// Count messages and signals per message without storing (first pass of two-pass parsing)
235    /// Returns message_count (signal counts are not needed after counting pass)
236    pub(crate) fn count_messages_and_signals<'b>(
237        parser: &mut crate::Parser<'b>,
238    ) -> crate::error::ParseResult<usize> {
239        use crate::{
240            BA_, BA_DEF_, BA_DEF_DEF_, BO_, BO_TX_BU_, BS_, BU_, CM_, EV_, NS_, SG_, SIG_GROUP_,
241            SIG_VALTYPE_, VAL_, VAL_TABLE_, VERSION,
242        };
243
244        // Use fixed-size array for counting (no alloc)
245        let mut message_count = 0;
246
247        loop {
248            parser.skip_newlines_and_spaces();
249            if parser.starts_with(b"//") {
250                parser.skip_to_end_of_line();
251                continue;
252            }
253
254            let keyword_result = parser.find_next_keyword();
255            let keyword = match keyword_result {
256                Ok(kw) => kw,
257                Err(crate::error::ParseError::UnexpectedEof) => break,
258                Err(crate::error::ParseError::Expected(_)) => {
259                    if parser.starts_with(b"//") {
260                        parser.skip_to_end_of_line();
261                        continue;
262                    }
263                    return Err(keyword_result.unwrap_err());
264                }
265                Err(e) => return Err(e),
266            };
267
268            match keyword {
269                NS_ => {
270                    parser.skip_newlines_and_spaces();
271                    let _ = parser.expect(b":").ok();
272                    loop {
273                        parser.skip_newlines_and_spaces();
274                        if parser.is_empty() {
275                            break;
276                        }
277                        if parser.starts_with(b" ") || parser.starts_with(b"\t") {
278                            parser.skip_to_end_of_line();
279                            continue;
280                        }
281                        if parser.starts_with(b"//") {
282                            parser.skip_to_end_of_line();
283                            continue;
284                        }
285                        if parser.starts_with(BS_.as_bytes())
286                            || parser.starts_with(BU_.as_bytes())
287                            || parser.starts_with(BO_.as_bytes())
288                            || parser.starts_with(SG_.as_bytes())
289                            || parser.starts_with(VERSION.as_bytes())
290                        {
291                            break;
292                        }
293                        parser.skip_to_end_of_line();
294                    }
295                    continue;
296                }
297                CM_ | BS_ | VAL_TABLE_ | BA_DEF_ | BA_DEF_DEF_ | BA_ | VAL_ | SIG_GROUP_
298                | SIG_VALTYPE_ | EV_ | BO_TX_BU_ => {
299                    parser.skip_to_end_of_line();
300                    continue;
301                }
302                VERSION | BU_ => {
303                    // Skip VERSION and BU_ lines (we'll parse them in second pass)
304                    parser.skip_to_end_of_line();
305                    continue;
306                }
307                BO_ => {
308                    // Count this message
309                    if message_count >= MAX_MESSAGES {
310                        return Err(crate::error::ParseError::Version(
311                            crate::error::messages::NODES_TOO_MANY,
312                        ));
313                    }
314
315                    // Skip message header (ID, name, DLC, sender)
316                    parser.skip_newlines_and_spaces();
317                    let _ = parser.parse_u32().ok();
318                    parser.skip_newlines_and_spaces();
319                    let _ = parser.parse_identifier().ok();
320                    parser.skip_newlines_and_spaces();
321                    let _ = parser.expect(b":").ok();
322                    parser.skip_newlines_and_spaces();
323                    let _ = parser.parse_u8().ok();
324                    parser.skip_newlines_and_spaces();
325                    let _ = parser.parse_identifier().ok();
326                    parser.skip_to_end_of_line();
327
328                    // Count signals for this message
329                    let mut signal_count = 0;
330                    loop {
331                        parser.skip_newlines_and_spaces();
332                        if parser.starts_with(crate::SG_.as_bytes()) {
333                            if let Some(next_byte) = parser.peek_byte_at(3) {
334                                if matches!(next_byte, b' ' | b'\n' | b'\r' | b'\t') {
335                                    if signal_count >= crate::Signals::max_capacity() {
336                                        return Err(crate::error::ParseError::Version(
337                                            crate::error::messages::SIGNAL_RECEIVERS_TOO_MANY,
338                                        ));
339                                    }
340                                    signal_count += 1;
341                                    let _ = parser.find_next_keyword().ok();
342                                    // Skip the signal line
343                                    parser.skip_to_end_of_line();
344                                    continue;
345                                }
346                            }
347                        }
348                        break;
349                    }
350
351                    message_count += 1;
352                    continue;
353                }
354                SG_ => {
355                    // Standalone signal, skip it
356                    let _ = crate::Signal::parse(parser).ok();
357                    continue;
358                }
359                _ => {
360                    parser.skip_to_end_of_line();
361                    continue;
362                }
363            }
364        }
365
366        Ok(message_count)
367    }
368}