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