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(feature = "alloc"))]
46    messages: [Option<Message<'a>>; MAX_MESSAGES],
47    #[cfg(feature = "alloc")]
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(feature = "alloc"))]
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(feature = "alloc")]
72        {
73            use alloc::vec::Vec;
74            let mut messages_vec = Vec::with_capacity(count);
75            for message in messages.iter().take(count) {
76                messages_vec.push(Some(message.clone()));
77            }
78            Self {
79                messages: messages_vec.into_boxed_slice(),
80                message_count: count,
81            }
82        }
83    }
84
85    /// Create Messages from a slice of `Option<Message>` and count
86    pub(crate) fn from_options_slice(
87        messages: &[Option<Message<'a>>],
88        message_count: usize,
89    ) -> Self {
90        let count = message_count.min(MAX_MESSAGES).min(messages.len());
91
92        #[cfg(not(feature = "alloc"))]
93        {
94            let mut messages_array: [Option<Message<'a>>; MAX_MESSAGES] =
95                [const { None }; MAX_MESSAGES];
96            for (i, message_opt) in messages.iter().take(count).enumerate() {
97                messages_array[i] = message_opt.clone();
98            }
99            Self {
100                messages: messages_array,
101                message_count: count,
102            }
103        }
104
105        #[cfg(feature = "alloc")]
106        {
107            use alloc::vec::Vec;
108            let mut messages_vec = Vec::with_capacity(count);
109            for message_opt in messages.iter().take(count) {
110                messages_vec.push(message_opt.clone());
111            }
112            Self {
113                messages: messages_vec.into_boxed_slice(),
114                message_count: count,
115            }
116        }
117    }
118
119    /// Get an iterator over the messages
120    ///
121    /// # Examples
122    ///
123    /// ```
124    /// use dbc_rs::Dbc;
125    ///
126    /// let dbc = Dbc::parse("VERSION \"1.0\"\n\nBU_: ECM\n\nBO_ 256 Engine : 8 ECM")?;
127    /// for message in dbc.messages().iter() {
128    ///     println!("Message: {} (ID: {})", message.name(), message.id());
129    /// }
130    /// # Ok::<(), dbc_rs::Error>(())
131    /// ```
132    #[inline]
133    #[must_use = "iterator is lazy and does nothing unless consumed"]
134    pub fn iter(&self) -> impl Iterator<Item = &Message<'a>> + '_ {
135        let messages_slice: &[Option<Message<'a>>] = &self.messages;
136        MessagesIter {
137            messages: messages_slice,
138            count: self.message_count,
139            pos: 0,
140        }
141    }
142
143    /// Get the number of messages
144    ///
145    /// # Examples
146    ///
147    /// ```
148    /// use dbc_rs::Dbc;
149    ///
150    /// let dbc = Dbc::parse("VERSION \"1.0\"\n\nBU_: ECM\n\nBO_ 256 Engine : 8 ECM")?;
151    /// assert_eq!(dbc.messages().len(), 1);
152    /// # Ok::<(), dbc_rs::Error>(())
153    /// ```
154    #[inline]
155    #[must_use]
156    pub fn len(&self) -> usize {
157        self.message_count
158    }
159
160    /// Returns `true` if there are no messages
161    ///
162    /// # Examples
163    ///
164    /// ```
165    /// use dbc_rs::Dbc;
166    ///
167    /// let dbc = Dbc::parse("VERSION \"1.0\"\n\nBU_: ECM")?;
168    /// assert!(dbc.messages().is_empty());
169    /// # Ok::<(), dbc_rs::Error>(())
170    /// ```
171    #[inline]
172    #[must_use]
173    pub fn is_empty(&self) -> bool {
174        self.len() == 0
175    }
176
177    /// Get a message by index, or None if index is out of bounds
178    ///
179    /// # Examples
180    ///
181    /// ```
182    /// use dbc_rs::Dbc;
183    ///
184    /// let dbc = Dbc::parse("VERSION \"1.0\"\n\nBU_: ECM\n\nBO_ 256 Engine : 8 ECM")?;
185    /// if let Some(message) = dbc.messages().at(0) {
186    ///     println!("First message: {}", message.name());
187    /// }
188    /// # Ok::<(), dbc_rs::Error>(())
189    /// ```
190    #[inline]
191    #[must_use]
192    pub fn at(&self, index: usize) -> Option<&Message<'a>> {
193        if index >= self.message_count {
194            return None;
195        }
196        self.messages[index].as_ref()
197    }
198
199    /// Find a message by name, or None if not found
200    ///
201    /// # Examples
202    ///
203    /// ```
204    /// use dbc_rs::Dbc;
205    ///
206    /// let dbc = Dbc::parse("VERSION \"1.0\"\n\nBU_: ECM\n\nBO_ 256 Engine : 8 ECM")?;
207    /// if let Some(message) = dbc.messages().find("Engine") {
208    ///     println!("Found message: {} (ID: {})", message.name(), message.id());
209    /// }
210    /// # Ok::<(), dbc_rs::Error>(())
211    /// ```
212    #[must_use]
213    pub fn find(&self, name: &str) -> Option<&Message<'a>> {
214        self.iter().find(|m| m.name() == name)
215    }
216
217    /// Get the maximum capacity (for limit checking during parsing)
218    pub(crate) const fn max_capacity() -> usize {
219        MAX_MESSAGES
220    }
221
222    /// Create a temporary buffer for parsing (no alloc in no_std)
223    /// Returns a buffer that can hold up to MAX_MESSAGES messages
224    #[cfg(not(feature = "alloc"))]
225    pub(crate) fn new_parse_buffer<'b>() -> [Option<Message<'b>>; MAX_MESSAGES] {
226        [const { None }; MAX_MESSAGES]
227    }
228
229    /// Count messages and signals per message without storing (first pass of two-pass parsing)
230    /// Returns message_count (signal counts are not needed after counting pass)
231    pub(crate) fn count_messages_and_signals<'b>(
232        parser: &mut crate::Parser<'b>,
233    ) -> crate::error::ParseResult<usize> {
234        use crate::{
235            BA_, BA_DEF_, BA_DEF_DEF_, BO_, BO_TX_BU_, BS_, BU_, CM_, EV_, NS_, SG_, SIG_GROUP_,
236            SIG_VALTYPE_, VAL_, VAL_TABLE_, VERSION,
237        };
238
239        // Use fixed-size array for counting (no alloc)
240        let mut message_count = 0;
241
242        loop {
243            parser.skip_newlines_and_spaces();
244            if parser.starts_with(b"//") {
245                parser.skip_to_end_of_line();
246                continue;
247            }
248
249            let keyword_result = parser.find_next_keyword();
250            let keyword = match keyword_result {
251                Ok(kw) => kw,
252                Err(crate::error::ParseError::UnexpectedEof) => break,
253                Err(crate::error::ParseError::Expected(_)) => {
254                    if parser.starts_with(b"//") {
255                        parser.skip_to_end_of_line();
256                        continue;
257                    }
258                    return Err(keyword_result.unwrap_err());
259                }
260                Err(e) => return Err(e),
261            };
262
263            match keyword {
264                NS_ => {
265                    parser.skip_newlines_and_spaces();
266                    let _ = parser.expect(b":").ok();
267                    loop {
268                        parser.skip_newlines_and_spaces();
269                        if parser.is_empty() {
270                            break;
271                        }
272                        if parser.starts_with(b" ") || parser.starts_with(b"\t") {
273                            parser.skip_to_end_of_line();
274                            continue;
275                        }
276                        if parser.starts_with(b"//") {
277                            parser.skip_to_end_of_line();
278                            continue;
279                        }
280                        if parser.starts_with(BS_.as_bytes())
281                            || parser.starts_with(BU_.as_bytes())
282                            || parser.starts_with(BO_.as_bytes())
283                            || parser.starts_with(SG_.as_bytes())
284                            || parser.starts_with(VERSION.as_bytes())
285                        {
286                            break;
287                        }
288                        parser.skip_to_end_of_line();
289                    }
290                    continue;
291                }
292                CM_ | BS_ | VAL_TABLE_ | BA_DEF_ | BA_DEF_DEF_ | BA_ | VAL_ | SIG_GROUP_
293                | SIG_VALTYPE_ | EV_ | BO_TX_BU_ => {
294                    parser.skip_to_end_of_line();
295                    continue;
296                }
297                VERSION | BU_ => {
298                    // Skip VERSION and BU_ lines (we'll parse them in second pass)
299                    parser.skip_to_end_of_line();
300                    continue;
301                }
302                BO_ => {
303                    // Count this message
304                    if message_count >= MAX_MESSAGES {
305                        return Err(crate::error::ParseError::Version(
306                            crate::error::messages::NODES_TOO_MANY,
307                        ));
308                    }
309
310                    // Skip message header (ID, name, DLC, sender)
311                    parser.skip_newlines_and_spaces();
312                    let _ = parser.parse_u32().ok();
313                    parser.skip_newlines_and_spaces();
314                    let _ = parser.parse_identifier().ok();
315                    parser.skip_newlines_and_spaces();
316                    let _ = parser.expect(b":").ok();
317                    parser.skip_newlines_and_spaces();
318                    let _ = parser.parse_u8().ok();
319                    parser.skip_newlines_and_spaces();
320                    let _ = parser.parse_identifier().ok();
321                    parser.skip_to_end_of_line();
322
323                    // Count signals for this message
324                    let mut signal_count = 0;
325                    loop {
326                        parser.skip_newlines_and_spaces();
327                        if parser.starts_with(crate::SG_.as_bytes()) {
328                            if let Some(next_byte) = parser.peek_byte_at(3) {
329                                if matches!(next_byte, b' ' | b'\n' | b'\r' | b'\t') {
330                                    if signal_count >= crate::Signals::max_capacity() {
331                                        return Err(crate::error::ParseError::Version(
332                                            crate::error::messages::SIGNAL_RECEIVERS_TOO_MANY,
333                                        ));
334                                    }
335                                    signal_count += 1;
336                                    let _ = parser.find_next_keyword().ok();
337                                    // Skip the signal line
338                                    parser.skip_to_end_of_line();
339                                    continue;
340                                }
341                            }
342                        }
343                        break;
344                    }
345
346                    message_count += 1;
347                    continue;
348                }
349                SG_ => {
350                    // Standalone signal, skip it
351                    let _ = crate::Signal::parse(parser).ok();
352                    continue;
353                }
354                _ => {
355                    parser.skip_to_end_of_line();
356                    continue;
357                }
358            }
359        }
360
361        Ok(message_count)
362    }
363}