1use crate::{
2 BitTiming, Dbc, Error, ExtendedMultiplexing, MAX_EXTENDED_MULTIPLEXING, MAX_MESSAGES,
3 MAX_NODES, MAX_SIGNALS_PER_MESSAGE, Message, Nodes, Parser, Result, Signal, ValueDescriptions,
4 Version,
5 compat::{BTreeMap, Comment, Name, ValueDescEntries, Vec},
6 dbc::{Messages, Validate, ValueDescriptionsMap},
7};
8#[cfg(feature = "attributes")]
9use crate::{
10 MAX_ATTRIBUTE_DEFINITIONS, MAX_ATTRIBUTE_VALUES,
11 attribute::{
12 AttributeDefinition, AttributeTarget, AttributeValue,
13 parse::{parse_attribute_assignment, parse_attribute_default},
14 },
15 dbc::{AttributeDefaultsMap, AttributeDefinitionsMap, AttributeValuesMap},
16};
17
18impl Dbc {
19 pub fn parse(data: &str) -> Result<Self> {
38 let mut parser = Parser::new(data.as_bytes())?;
39
40 let mut messages_buffer: Vec<Message, { MAX_MESSAGES }> = Vec::new();
41
42 let mut message_count_actual = 0;
43
44 use crate::{
46 BA_, BA_DEF_, BA_DEF_DEF_, BO_, BO_TX_BU_, BS_, BU_, CM_, EV_, NS_, SG_, SG_MUL_VAL_,
47 SIG_GROUP_, SIG_VALTYPE_, VAL_, VAL_TABLE_, VERSION,
48 };
49
50 let mut version: Option<Version> = None;
51 let mut bit_timing: Option<BitTiming> = None;
52 let mut nodes: Option<Nodes> = None;
53
54 type ValueDescBufferEntry = (Option<u32>, Name, ValueDescEntries);
56 type ValueDescBuffer = Vec<ValueDescBufferEntry, { MAX_MESSAGES }>;
57 type ExtMuxBuffer = Vec<ExtendedMultiplexing, { MAX_EXTENDED_MULTIPLEXING }>;
58
59 type MessageCommentBuffer = Vec<(u32, Comment), { MAX_MESSAGES }>;
62 type SignalCommentBuffer = Vec<(u32, Name, Comment), { MAX_MESSAGES * 4 }>;
64
65 let mut value_descriptions_buffer: ValueDescBuffer = ValueDescBuffer::new();
66 let mut extended_multiplexing_buffer: ExtMuxBuffer = ExtMuxBuffer::new();
67
68 let mut db_comment: Option<Comment> = None;
70 type NodeCommentBuffer = Vec<(Name, Comment), { MAX_NODES }>;
72 let mut node_comments_buffer: NodeCommentBuffer = NodeCommentBuffer::new();
73 let mut message_comments_buffer: MessageCommentBuffer = MessageCommentBuffer::new();
74 let mut signal_comments_buffer: SignalCommentBuffer = SignalCommentBuffer::new();
75
76 #[cfg(feature = "attributes")]
78 type AttrDefBuffer = Vec<AttributeDefinition, { MAX_ATTRIBUTE_DEFINITIONS }>;
79 #[cfg(feature = "attributes")]
80 type AttrDefaultBuffer = Vec<(Name, AttributeValue), { MAX_ATTRIBUTE_DEFINITIONS }>;
81 #[cfg(feature = "attributes")]
82 type AttrValueBuffer =
83 Vec<(Name, AttributeTarget, AttributeValue), { MAX_ATTRIBUTE_VALUES }>;
84
85 #[cfg(feature = "attributes")]
86 let mut attribute_definitions_buffer: AttrDefBuffer = AttrDefBuffer::new();
87 #[cfg(feature = "attributes")]
88 let mut attribute_defaults_buffer: AttrDefaultBuffer = AttrDefaultBuffer::new();
89 #[cfg(feature = "attributes")]
90 let mut attribute_values_buffer: AttrValueBuffer = AttrValueBuffer::new();
91
92 loop {
93 parser.skip_newlines_and_spaces();
95 if parser.starts_with(b"//") {
96 parser.skip_to_end_of_line();
97 continue;
98 }
99
100 let keyword_result = parser.peek_next_keyword();
101 let keyword = match keyword_result {
102 Ok(kw) => kw,
103 Err(Error::UnexpectedEof { .. }) => break,
104 Err(Error::Expected { .. }) => {
105 if parser.starts_with(b"//") {
106 parser.skip_to_end_of_line();
107 continue;
108 }
109 return Err(keyword_result.unwrap_err());
110 }
111 Err(e) => return Err(e),
112 };
113
114 let pos_at_keyword = parser.pos();
116
117 match keyword {
118 NS_ => {
119 let line = parser.line();
121 parser
122 .expect(crate::NS_.as_bytes())
123 .map_err(|_| Error::expected_at("Failed to consume NS_ keyword", line))?;
124 parser.skip_newlines_and_spaces();
125 let _ = parser.expect(b":").ok();
126 loop {
127 parser.skip_newlines_and_spaces();
128 if parser.is_empty() {
129 break;
130 }
131 if parser.starts_with(b" ") || parser.starts_with(b"\t") {
132 parser.skip_to_end_of_line();
133 continue;
134 }
135 if parser.starts_with(b"//") {
136 parser.skip_to_end_of_line();
137 continue;
138 }
139 if parser.starts_with(BS_.as_bytes())
140 || parser.starts_with(BU_.as_bytes())
141 || parser.starts_with(BO_.as_bytes())
142 || parser.starts_with(SG_.as_bytes())
143 || parser.starts_with(VERSION.as_bytes())
144 {
145 break;
146 }
147 parser.skip_to_end_of_line();
148 }
149 continue;
150 }
151 BS_ => {
152 let parsed = BitTiming::parse(&mut parser)?;
154 if !parsed.is_empty() {
156 bit_timing = Some(parsed);
157 }
158 parser.skip_to_end_of_line();
159 continue;
160 }
161 #[cfg(feature = "attributes")]
162 BA_DEF_ => {
163 let _ = parser.expect(BA_DEF_.as_bytes()).ok();
165 if let Some(def) = AttributeDefinition::parse(&mut parser) {
166 let _ = attribute_definitions_buffer.push(def);
167 }
168 parser.skip_to_end_of_line();
169 continue;
170 }
171 #[cfg(feature = "attributes")]
172 BA_DEF_DEF_ => {
173 let _ = parser.expect(BA_DEF_DEF_.as_bytes()).ok();
175 if let Some((name, value)) = parse_attribute_default(&mut parser) {
176 let _ = attribute_defaults_buffer.push((name, value));
177 }
178 parser.skip_to_end_of_line();
179 continue;
180 }
181 #[cfg(feature = "attributes")]
182 BA_ => {
183 let _ = parser.expect(BA_.as_bytes()).ok();
185 if let Some((name, target, value)) = parse_attribute_assignment(&mut parser) {
186 let _ = attribute_values_buffer.push((name, target, value));
187 }
188 parser.skip_to_end_of_line();
189 continue;
190 }
191 #[cfg(not(feature = "attributes"))]
192 BA_DEF_ | BA_DEF_DEF_ | BA_ => {
193 let _ = parser.expect(keyword.as_bytes()).ok();
195 parser.skip_to_end_of_line();
196 continue;
197 }
198 VAL_TABLE_ | SIG_GROUP_ | SIG_VALTYPE_ | EV_ | BO_TX_BU_ => {
199 let _ = parser.expect(keyword.as_bytes()).ok();
212 parser.skip_to_end_of_line();
213 continue;
214 }
215 CM_ => {
216 let _ = parser.expect(crate::CM_.as_bytes()).ok();
223 parser.skip_newlines_and_spaces();
224
225 if parser.starts_with(b"\"") {
227 if parser.expect(b"\"").is_ok() {
229 if let Ok(comment_bytes) = parser.take_until_quote(false, 1024) {
230 if let Ok(comment_str) = core::str::from_utf8(comment_bytes) {
231 if let Ok(comment) = Comment::try_from(comment_str) {
232 db_comment = Some(comment);
233 }
234 }
235 }
236 }
237 parser.skip_to_end_of_line();
238 } else if parser.starts_with(BU_.as_bytes()) {
239 let _ = parser.expect(BU_.as_bytes()).ok();
241 parser.skip_newlines_and_spaces();
242 if let Ok(node_name_bytes) = parser.parse_identifier() {
243 if let Ok(node_name) = Name::try_from(node_name_bytes) {
244 parser.skip_newlines_and_spaces();
245 if parser.expect(b"\"").is_ok() {
246 if let Ok(comment_bytes) = parser.take_until_quote(false, 1024)
247 {
248 if let Ok(comment_str) = core::str::from_utf8(comment_bytes)
249 {
250 if let Ok(comment) = Comment::try_from(comment_str) {
251 let _ =
252 node_comments_buffer.push((node_name, comment));
253 }
254 }
255 }
256 }
257 }
258 }
259 parser.skip_to_end_of_line();
260 } else if parser.starts_with(BO_.as_bytes()) {
261 let _ = parser.expect(BO_.as_bytes()).ok();
263 parser.skip_newlines_and_spaces();
264 if let Ok(message_id) = parser.parse_u32() {
265 parser.skip_newlines_and_spaces();
266 if parser.expect(b"\"").is_ok() {
267 if let Ok(comment_bytes) = parser.take_until_quote(false, 1024) {
268 if let Ok(comment_str) = core::str::from_utf8(comment_bytes) {
269 if let Ok(comment) = Comment::try_from(comment_str) {
270 let _ =
271 message_comments_buffer.push((message_id, comment));
272 }
273 }
274 }
275 }
276 }
277 parser.skip_to_end_of_line();
278 } else if parser.starts_with(SG_.as_bytes()) {
279 let _ = parser.expect(SG_.as_bytes()).ok();
281 parser.skip_newlines_and_spaces();
282 if let Ok(message_id) = parser.parse_u32() {
283 parser.skip_newlines_and_spaces();
284 if let Ok(signal_name_bytes) = parser.parse_identifier() {
285 if let Ok(signal_name) = Name::try_from(signal_name_bytes) {
286 parser.skip_newlines_and_spaces();
287 if parser.expect(b"\"").is_ok() {
288 if let Ok(comment_bytes) =
289 parser.take_until_quote(false, 1024)
290 {
291 if let Ok(comment_str) =
292 core::str::from_utf8(comment_bytes)
293 {
294 if let Ok(comment) = Comment::try_from(comment_str)
295 {
296 let _ = signal_comments_buffer.push((
297 message_id,
298 signal_name,
299 comment,
300 ));
301 }
302 }
303 }
304 }
305 }
306 }
307 }
308 parser.skip_to_end_of_line();
309 } else {
310 parser.skip_to_end_of_line();
312 }
313 continue;
314 }
315 SG_MUL_VAL_ => {
316 let line = parser.line();
318 parser.expect(SG_MUL_VAL_.as_bytes()).map_err(|_| {
319 Error::expected_at("Failed to consume SG_MUL_VAL_ keyword", line)
320 })?;
321
322 if let Some(ext_mux) = ExtendedMultiplexing::parse(&mut parser) {
324 if extended_multiplexing_buffer.push(ext_mux).is_err() {
325 return Err(Error::Validation(Error::EXTENDED_MULTIPLEXING_TOO_MANY));
327 }
328 } else {
329 parser.skip_to_end_of_line();
331 }
332 continue;
333 }
334 VAL_ => {
335 let _ = parser.expect(crate::VAL_.as_bytes()).ok();
337 parser.skip_newlines_and_spaces();
341 let message_id = match parser.parse_i64() {
342 Ok(id) => {
343 if id == -1 {
345 None
346 } else if id >= 0 && id <= u32::MAX as i64 {
347 Some(id as u32)
348 } else {
349 parser.skip_to_end_of_line();
350 continue;
351 }
352 }
353 Err(_) => {
354 parser.skip_to_end_of_line();
355 continue;
356 }
357 };
358 parser.skip_newlines_and_spaces();
359 let signal_name = match parser.parse_identifier() {
360 Ok(name) => match Name::try_from(name) {
361 Ok(s) => s,
362 Err(_) => {
363 parser.skip_to_end_of_line();
364 continue;
365 }
366 },
367 Err(_) => {
368 parser.skip_to_end_of_line();
369 continue;
370 }
371 };
372 let mut entries: ValueDescEntries = ValueDescEntries::new();
374 loop {
375 parser.skip_newlines_and_spaces();
376 if parser.starts_with(b";") {
378 parser.expect(b";").ok();
379 break;
380 }
381 let value = match parser.parse_i64() {
385 Ok(v) => {
386 if v == -1 { 0xFFFF_FFFFu64 } else { v as u64 }
388 }
389 Err(_) => {
390 parser.skip_to_end_of_line();
391 break;
392 }
393 };
394 parser.skip_newlines_and_spaces();
395 if parser.expect(b"\"").is_err() {
397 parser.skip_to_end_of_line();
398 break;
399 }
400 let description_bytes = match parser.take_until_quote(false, 1024) {
401 Ok(bytes) => bytes,
402 Err(_) => {
403 parser.skip_to_end_of_line();
404 break;
405 }
406 };
407 let description = match core::str::from_utf8(description_bytes)
408 .ok()
409 .and_then(|s| Name::try_from(s).ok())
410 {
411 Some(desc) => desc,
412 None => {
413 parser.skip_to_end_of_line();
414 break;
415 }
416 };
417 let _ = entries.push((value, description));
418 }
419 if !entries.is_empty() {
420 let _ = value_descriptions_buffer.push((message_id, signal_name, entries));
421 }
422 continue;
423 }
424 VERSION => {
425 version = Some(Version::parse(&mut parser)?);
427 continue;
428 }
429 BU_ => {
430 parser.skip_to_end_of_line();
432 let bu_input = &data.as_bytes()[pos_at_keyword..parser.pos()];
433 let mut bu_parser = Parser::new(bu_input)?;
434 nodes = Some(Nodes::parse(&mut bu_parser)?);
435 continue;
436 }
437 BO_ => {
438 if message_count_actual >= MAX_MESSAGES {
440 return Err(parser.err_nodes(Error::NODES_TOO_MANY));
441 }
442
443 let message_start_pos = pos_at_keyword;
445
446 let header_line_end = {
449 let mut temp_parser = Parser::new(&data.as_bytes()[pos_at_keyword..])?;
451 temp_parser.expect(crate::BO_.as_bytes()).ok();
453 temp_parser.skip_whitespace().ok();
454 temp_parser.parse_u32().ok(); temp_parser.skip_whitespace().ok();
456 temp_parser.parse_identifier().ok(); temp_parser.skip_whitespace().ok();
458 temp_parser.expect(b":").ok(); temp_parser.skip_whitespace().ok();
460 temp_parser.parse_u8().ok(); temp_parser.skip_whitespace().ok();
462 temp_parser.parse_identifier().ok(); pos_at_keyword + temp_parser.pos()
464 };
465
466 parser.skip_to_end_of_line(); let mut signals_array: Vec<Signal, { MAX_SIGNALS_PER_MESSAGE }> = Vec::new();
470
471 loop {
473 parser.skip_newlines_and_spaces();
474
475 let keyword_result = parser.peek_next_keyword();
478 let keyword = match keyword_result {
479 Ok(kw) => kw,
480 Err(Error::UnexpectedEof { .. }) => break,
481 Err(_) => break, };
483
484 if keyword != SG_ {
486 break; }
488
489 if signals_array.len() >= MAX_SIGNALS_PER_MESSAGE {
491 return Err(parser.err_message(Error::MESSAGE_TOO_MANY_SIGNALS));
492 }
493
494 match Signal::parse(&mut parser) {
496 Ok(signal) => {
497 signals_array.push(signal).map_err(|_| {
498 parser.err_receivers(Error::SIGNAL_RECEIVERS_TOO_MANY)
499 })?;
500 if parser.at_newline() {
503 parser.skip_to_end_of_line();
504 }
505 }
506 Err(_) => {
507 parser.skip_to_end_of_line();
509 break;
510 }
511 }
512 }
513
514 let message_input = &data.as_bytes()[message_start_pos..header_line_end];
518 let mut message_parser = Parser::new(message_input)?;
519
520 let message = Message::parse(&mut message_parser, signals_array.as_slice())?;
522
523 messages_buffer
524 .push(message)
525 .map_err(|_| parser.err_message(Error::NODES_TOO_MANY))?;
526 message_count_actual += 1;
527 continue;
528 }
529 SG_ => {
530 parser.skip_to_end_of_line();
532 continue;
533 }
534 _ => {
535 parser.skip_to_end_of_line();
536 continue;
537 }
538 }
539 }
540
541 let mut nodes = nodes.unwrap_or_default();
543
544 for (node_name, comment) in node_comments_buffer {
546 nodes.set_node_comment(node_name.as_str(), comment);
547 }
548
549 let version = version.or_else(|| {
551 static EMPTY_VERSION: &[u8] = b"VERSION \"\"";
552 let mut parser = Parser::new(EMPTY_VERSION).ok()?;
553 Version::parse(&mut parser).ok()
554 });
555
556 let value_descriptions_map = {
558 let mut map: BTreeMap<(Option<u32>, Name), ValueDescriptions, { MAX_MESSAGES }> =
559 BTreeMap::new();
560 for (message_id, signal_name, entries) in value_descriptions_buffer {
561 let key = (message_id, signal_name);
562 let value_descriptions = ValueDescriptions::new(entries);
563 let _ = map.insert(key, value_descriptions);
564 }
565 ValueDescriptionsMap::new(map)
566 };
567
568 #[cfg(feature = "attributes")]
570 let (attribute_definitions, attribute_defaults, attribute_values) = {
571 use crate::attribute::AttributeDefinitions;
572
573 let attribute_definitions = AttributeDefinitionsMap::from_vec({
574 let mut defs: AttributeDefinitions = AttributeDefinitions::new();
575 for def in attribute_definitions_buffer {
576 let _ = defs.push(def);
577 }
578 defs
579 });
580
581 let attribute_defaults = AttributeDefaultsMap::from_map({
582 let mut map: BTreeMap<Name, AttributeValue, { MAX_ATTRIBUTE_DEFINITIONS }> =
583 BTreeMap::new();
584 for (name, value) in attribute_defaults_buffer {
585 let _ = map.insert(name, value);
586 }
587 map
588 });
589
590 let attribute_values = AttributeValuesMap::from_map({
591 let mut map: BTreeMap<
592 (Name, AttributeTarget),
593 AttributeValue,
594 { MAX_ATTRIBUTE_VALUES },
595 > = BTreeMap::new();
596 for (name, target, value) in attribute_values_buffer {
597 let _ = map.insert((name, target), value);
598 }
599 map
600 });
601
602 (attribute_definitions, attribute_defaults, attribute_values)
603 };
604
605 for (message_id, comment) in message_comments_buffer {
608 for msg in messages_buffer.iter_mut() {
609 if msg.id() == message_id || msg.id_with_flag() == message_id {
610 msg.set_comment(comment);
611 break;
612 }
613 }
614 }
615
616 for (message_id, signal_name, comment) in signal_comments_buffer {
618 for msg in messages_buffer.iter_mut() {
619 if msg.id() == message_id || msg.id_with_flag() == message_id {
620 if let Some(signal) = msg.signals_mut().find_mut(signal_name.as_str()) {
621 signal.set_comment(comment);
622 }
623 break;
624 }
625 }
626 }
627
628 Validate::validate(
630 &nodes,
631 messages_buffer.as_slice(),
632 Some(&value_descriptions_map),
633 Some(extended_multiplexing_buffer.as_slice()),
634 )
635 .map_err(|e| {
636 crate::error::map_val_error(e, Error::message, || {
637 Error::message(Error::MESSAGE_ERROR_PREFIX)
638 })
639 })?;
640
641 let messages = Messages::from_vec(messages_buffer)?;
643
644 #[cfg(feature = "attributes")]
645 return Ok(Dbc::new(
646 version,
647 bit_timing,
648 nodes,
649 messages,
650 value_descriptions_map,
651 extended_multiplexing_buffer,
652 db_comment,
653 attribute_definitions,
654 attribute_defaults,
655 attribute_values,
656 ));
657
658 #[cfg(not(feature = "attributes"))]
659 Ok(Dbc::new(
660 version,
661 bit_timing,
662 nodes,
663 messages,
664 value_descriptions_map,
665 extended_multiplexing_buffer,
666 db_comment,
667 ))
668 }
669
670 pub fn parse_bytes(data: &[u8]) -> Result<Self> {
683 let content =
684 core::str::from_utf8(data).map_err(|_e| Error::expected(Error::INVALID_UTF8))?;
685 Dbc::parse(content)
686 }
687}
688
689#[cfg(test)]
690mod tests {
691 use crate::Dbc;
692
693 #[test]
694 fn test_parse_basic() {
695 let dbc_content = r#"VERSION "1.0"
696
697BU_: ECM
698
699BO_ 256 Engine : 8 ECM
700 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
701"#;
702 let dbc = Dbc::parse(dbc_content).unwrap();
703 assert_eq!(dbc.version().map(|v| v.as_str()), Some("1.0"));
704 assert!(dbc.nodes().contains("ECM"));
705 assert_eq!(dbc.messages().len(), 1);
706 }
707
708 #[test]
709 fn test_parse_bytes() {
710 let dbc_bytes = b"VERSION \"1.0\"\n\nBU_: ECM\n\nBO_ 256 Engine : 8 ECM";
711 let dbc = Dbc::parse_bytes(dbc_bytes).unwrap();
712 assert_eq!(dbc.version().map(|v| v.as_str()), Some("1.0"));
713 assert!(dbc.nodes().contains("ECM"));
714 assert_eq!(dbc.messages().len(), 1);
715 }
716
717 #[test]
718 fn test_parse_empty_nodes() {
719 let dbc_content = r#"VERSION "1.0"
720
721BU_:
722
723BO_ 256 Engine : 8 ECM
724"#;
725 let dbc = Dbc::parse(dbc_content).unwrap();
726 assert!(dbc.nodes().is_empty());
727 }
728
729 #[test]
730 fn test_parse_no_version() {
731 let dbc_content = r#"BU_: ECM
732
733BO_ 256 Engine : 8 ECM
734"#;
735 let dbc = Dbc::parse(dbc_content).unwrap();
736 assert!(dbc.version().is_some());
738 }
739
740 #[test]
741 fn parses_real_dbc() {
742 let data = r#"VERSION "1.0"
743
744BU_: ECM TCM
745
746BO_ 256 Engine : 8 ECM
747 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
748 SG_ Temp : 16|8@1- (1,-40) [-40|215] "°C"
749
750BO_ 512 Brake : 4 TCM
751 SG_ Pressure : 0|16@1+ (0.1,0) [0|1000] "bar""#;
752
753 let dbc = Dbc::parse(data).unwrap();
754 assert_eq!(dbc.messages().len(), 2);
755 let mut messages_iter = dbc.messages().iter();
756 let msg0 = messages_iter.next().unwrap();
757 assert_eq!(msg0.signals().len(), 2);
758 let mut signals_iter = msg0.signals().iter();
759 assert_eq!(signals_iter.next().unwrap().name(), "RPM");
760 assert_eq!(signals_iter.next().unwrap().name(), "Temp");
761 let msg1 = messages_iter.next().unwrap();
762 assert_eq!(msg1.signals().len(), 1);
763 assert_eq!(msg1.signals().iter().next().unwrap().name(), "Pressure");
764 }
765
766 #[test]
767 fn test_parse_duplicate_message_id() {
768 use crate::Error;
769 let data = r#"VERSION "1.0"
771
772BU_: ECM
773
774BO_ 256 EngineData1 : 8 ECM
775 SG_ RPM : 0|16@0+ (0.25,0) [0|8000] "rpm"
776
777BO_ 256 EngineData2 : 8 ECM
778 SG_ Temp : 16|8@0- (1,-40) [-40|215] "°C"
779"#;
780
781 let result = Dbc::parse(data);
782 assert!(result.is_err());
783 match result.unwrap_err() {
784 Error::Message { msg, .. } => {
785 assert!(msg.contains(Error::DUPLICATE_MESSAGE_ID));
786 }
787 _ => panic!("Expected Error::Message"),
788 }
789 }
790
791 #[test]
792 fn test_parse_sender_not_in_nodes() {
793 use crate::Error;
794 let data = r#"VERSION "1.0"
796
797BU_: ECM
798
799BO_ 256 EngineData : 8 TCM
800 SG_ RPM : 0|16@0+ (0.25,0) [0|8000] "rpm"
801"#;
802
803 let result = Dbc::parse(data);
804 assert!(result.is_err());
805 match result.unwrap_err() {
806 Error::Message { msg, .. } => {
807 assert!(msg.contains(Error::SENDER_NOT_IN_NODES));
808 }
809 _ => panic!("Expected Error::Message"),
810 }
811 }
812
813 #[test]
814 fn test_parse_empty_file() {
815 use crate::Error;
816 let result = Dbc::parse("");
818 assert!(result.is_err());
819 match result.unwrap_err() {
820 Error::UnexpectedEof { .. } => {
821 }
823 _ => panic!("Expected Error::UnexpectedEof"),
824 }
825 }
826
827 #[test]
828 fn test_parse_bytes_invalid_utf8() {
829 use crate::Error;
830 let invalid_bytes = &[0xFF, 0xFE, 0xFD];
832 let result = Dbc::parse_bytes(invalid_bytes);
833 assert!(result.is_err());
834 match result.unwrap_err() {
835 Error::Expected { msg, .. } => {
836 assert_eq!(msg, Error::INVALID_UTF8);
837 }
838 _ => panic!("Expected Error::Expected with INVALID_UTF8"),
839 }
840 }
841
842 #[test]
843 fn test_parse_without_version_with_comment() {
844 let data = r#"// This is a comment
846BU_: ECM
847
848BO_ 256 Engine : 8 ECM
849 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
850"#;
851 let dbc = Dbc::parse(data).unwrap();
852 assert_eq!(dbc.version().map(|v| v.as_str()), Some(""));
853 }
854
855 #[test]
856 fn test_parse_with_strict_boundary_check() {
857 let data = r#"VERSION "1.0"
859
860BU_: ECM
861
862BO_ 256 Test : 8 ECM
863 SG_ CHECKSUM : 63|8@1+ (1,0) [0|255] ""
864"#;
865
866 let result = Dbc::parse(data);
868 assert!(result.is_err());
869 }
870
871 #[cfg(feature = "std")]
872 #[test]
873 fn test_parse_val_value_descriptions() {
874 let data = r#"VERSION ""
875
876NS_ :
877
878BS_:
879
880BU_: Node1 Node2
881
882BO_ 100 Message1 : 8 Node1
883 SG_ Signal : 32|8@1- (1,0) [-1|4] "Gear" Node2
884
885VAL_ 100 Signal -1 "Reverse" 0 "Neutral" 1 "First" 2 "Second" 3 "Third" 4 "Fourth" ;
886"#;
887
888 let dbc = match Dbc::parse(data) {
889 Ok(dbc) => dbc,
890 Err(e) => panic!("Failed to parse DBC: {:?}", e),
891 };
892
893 assert_eq!(dbc.messages().len(), 1);
895 let message = dbc.messages().iter().find(|m| m.id() == 100).unwrap();
896 assert_eq!(message.name(), "Message1");
897 assert_eq!(message.sender(), "Node1");
898
899 let value_descriptions = dbc
901 .value_descriptions_for_signal(100, "Signal")
902 .expect("Value descriptions should exist");
903 assert_eq!(value_descriptions.get(0xFFFFFFFF), Some("Reverse")); assert_eq!(value_descriptions.get(0), Some("Neutral"));
905 assert_eq!(value_descriptions.get(1), Some("First"));
906 assert_eq!(value_descriptions.get(2), Some("Second"));
907 assert_eq!(value_descriptions.get(3), Some("Third"));
908 assert_eq!(value_descriptions.get(4), Some("Fourth"));
909 }
910
911 #[cfg(feature = "std")]
912 #[test]
913 fn test_parse_val_global_value_descriptions() {
914 let data = r#"VERSION "1.0"
916
917NS_ :
918
919 VAL_
920
921BS_:
922
923BU_: ECU DASH
924
925BO_ 256 EngineData: 8 ECU
926 SG_ EngineRPM : 0|16@1+ (0.125,0) [0|8000] "rpm" Vector__XXX
927 SG_ DI_gear : 24|3@1+ (1,0) [0|7] "" Vector__XXX
928
929BO_ 512 DashboardDisplay: 8 DASH
930 SG_ DI_gear : 0|3@1+ (1,0) [0|7] "" Vector__XXX
931 SG_ SpeedDisplay : 8|16@1+ (0.01,0) [0|300] "km/h" Vector__XXX
932
933VAL_ -1 DI_gear 0 "INVALID" 1 "P" 2 "R" 3 "N" 4 "D" 5 "S" 6 "L" 7 "SNA" ;
934"#;
935
936 let dbc = match Dbc::parse(data) {
937 Ok(dbc) => dbc,
938 Err(e) => panic!("Failed to parse DBC: {:?}", e),
939 };
940
941 assert_eq!(dbc.messages().len(), 2);
943
944 let engine_msg = dbc.messages().iter().find(|m| m.id() == 256).unwrap();
946 assert_eq!(engine_msg.name(), "EngineData");
947 assert_eq!(engine_msg.sender(), "ECU");
948 let di_gear_signal1 = engine_msg.signals().find("DI_gear").unwrap();
949 assert_eq!(di_gear_signal1.name(), "DI_gear");
950 assert_eq!(di_gear_signal1.start_bit(), 24);
951
952 let dash_msg = dbc.messages().iter().find(|m| m.id() == 512).unwrap();
954 assert_eq!(dash_msg.name(), "DashboardDisplay");
955 assert_eq!(dash_msg.sender(), "DASH");
956 let di_gear_signal2 = dash_msg.signals().find("DI_gear").unwrap();
957 assert_eq!(di_gear_signal2.name(), "DI_gear");
958 assert_eq!(di_gear_signal2.start_bit(), 0);
959
960 let value_descriptions1 = dbc
962 .value_descriptions_for_signal(256, "DI_gear")
963 .expect("Global value descriptions should exist for DI_gear in message 256");
964
965 assert_eq!(value_descriptions1.get(0), Some("INVALID"));
966 assert_eq!(value_descriptions1.get(1), Some("P"));
967 assert_eq!(value_descriptions1.get(2), Some("R"));
968 assert_eq!(value_descriptions1.get(3), Some("N"));
969 assert_eq!(value_descriptions1.get(4), Some("D"));
970 assert_eq!(value_descriptions1.get(5), Some("S"));
971 assert_eq!(value_descriptions1.get(6), Some("L"));
972 assert_eq!(value_descriptions1.get(7), Some("SNA"));
973
974 let value_descriptions2 = dbc
976 .value_descriptions_for_signal(512, "DI_gear")
977 .expect("Global value descriptions should exist for DI_gear in message 512");
978
979 assert_eq!(value_descriptions2.get(0), Some("INVALID"));
981 assert_eq!(value_descriptions2.get(1), Some("P"));
982 assert_eq!(value_descriptions2.get(2), Some("R"));
983 assert_eq!(value_descriptions2.get(3), Some("N"));
984 assert_eq!(value_descriptions2.get(4), Some("D"));
985 assert_eq!(value_descriptions2.get(5), Some("S"));
986 assert_eq!(value_descriptions2.get(6), Some("L"));
987 assert_eq!(value_descriptions2.get(7), Some("SNA"));
988
989 assert_eq!(value_descriptions1.len(), value_descriptions2.len());
992 assert_eq!(value_descriptions1.len(), 8);
993
994 assert_eq!(dbc.value_descriptions_for_signal(256, "EngineRPM"), None);
996 assert_eq!(dbc.value_descriptions_for_signal(512, "SpeedDisplay"), None);
997 }
998
999 #[test]
1008 fn test_spec_section_8_3_dlc_zero_is_valid() {
1009 let data = r#"VERSION "1.0"
1011
1012BU_: ECM
1013
1014BO_ 256 ControlMessage : 0 ECM
1015"#;
1016 let dbc = Dbc::parse(data).unwrap();
1017 assert_eq!(dbc.messages().len(), 1);
1018 let msg = dbc.messages().iter().next().unwrap();
1019 assert_eq!(msg.dlc(), 0);
1020 }
1021
1022 #[test]
1026 fn test_spec_section_8_1_extended_can_id_format() {
1027 let data = r#"VERSION "1.0"
1030
1031BU_: ECM
1032
1033BO_ 2147484820 ExtendedMessage : 8 ECM
1034"#;
1035 let dbc = Dbc::parse(data).unwrap();
1036 assert_eq!(dbc.messages().len(), 1);
1037 let msg = dbc.messages().iter().next().unwrap();
1038 assert_eq!(msg.id(), 0x494); assert!(msg.is_extended()); }
1042
1043 #[test]
1045 fn test_spec_section_8_1_max_extended_id() {
1046 let data = r#"VERSION "1.0"
1048
1049BU_: ECM
1050
1051BO_ 2684354559 MaxExtendedId : 8 ECM
1052"#;
1053 let dbc = Dbc::parse(data).unwrap();
1054 assert_eq!(dbc.messages().len(), 1);
1055 let msg = dbc.messages().iter().next().unwrap();
1056 assert_eq!(msg.id(), 0x1FFFFFFF);
1058 assert!(msg.is_extended());
1059 }
1060
1061 #[test]
1064 fn test_spec_section_8_4_vector_xxx_transmitter() {
1065 let data = r#"VERSION "1.0"
1066
1067BU_: Gateway
1068
1069BO_ 256 UnknownSender : 8 Vector__XXX
1070 SG_ Signal1 : 0|8@1+ (1,0) [0|255] "" Gateway
1071"#;
1072 let dbc = Dbc::parse(data).unwrap();
1073 assert_eq!(dbc.messages().len(), 1);
1074 let msg = dbc.messages().iter().next().unwrap();
1075 assert_eq!(msg.sender(), "Vector__XXX");
1076 }
1077
1078 #[test]
1081 fn test_spec_section_9_5_receivers_comma_separated() {
1082 use crate::{Parser, Signal};
1086
1087 let signal = Signal::parse(
1089 &mut Parser::new(b"SG_ RPM : 0|16@1+ (0.25,0) [0|8000] \"rpm\" Gateway,Dashboard")
1090 .unwrap(),
1091 )
1092 .unwrap();
1093 assert_eq!(signal.receivers().len(), 2);
1094 let mut receivers = signal.receivers().iter();
1095 assert_eq!(receivers.next(), Some("Gateway"));
1096 assert_eq!(receivers.next(), Some("Dashboard"));
1097 }
1098
1099 #[test]
1102 fn test_spec_section_9_4_multiplexer_indicators() {
1103 let data = r#"VERSION "1.0"
1104
1105BU_: ECM Gateway
1106
1107BO_ 400 MultiplexedMsg : 8 ECM
1108 SG_ MuxSwitch M : 0|8@1+ (1,0) [0|255] "" Gateway
1109 SG_ Signal_0 m0 : 8|16@1+ (0.1,0) [0|1000] "kPa" Gateway
1110 SG_ Signal_1 m1 : 8|16@1+ (0.01,0) [0|100] "degC" Gateway
1111"#;
1112 let dbc = Dbc::parse(data).unwrap();
1113 let msg = dbc.messages().iter().next().unwrap();
1114
1115 let mux_switch = msg.signals().find("MuxSwitch").unwrap();
1117 let signal_0 = msg.signals().find("Signal_0").unwrap();
1118 let signal_1 = msg.signals().find("Signal_1").unwrap();
1119
1120 assert!(mux_switch.is_multiplexer_switch());
1122 assert_eq!(mux_switch.multiplexer_switch_value(), None);
1123
1124 assert!(!signal_0.is_multiplexer_switch());
1126 assert_eq!(signal_0.multiplexer_switch_value(), Some(0));
1127
1128 assert!(!signal_1.is_multiplexer_switch());
1129 assert_eq!(signal_1.multiplexer_switch_value(), Some(1));
1130 }
1131
1132 #[test]
1133 fn test_error_includes_line_number() {
1134 let data = r#"VERSION "1.0"
1136
1137BU_: ECM
1138
1139BO_ invalid EngineData : 8 ECM
1140"#;
1141
1142 let result = Dbc::parse(data);
1143 assert!(result.is_err());
1144 let err = result.unwrap_err();
1145 assert!(err.line().is_some(), "Error should include line number");
1147 }
1148
1149 #[test]
1155 fn test_parse_cm_database_comment() {
1156 let data = r#"VERSION "1.0"
1157
1158BU_: ECM
1159
1160BO_ 256 Engine : 8 ECM
1161
1162CM_ "This is the database comment";
1163"#;
1164 let dbc = Dbc::parse(data).unwrap();
1165 assert_eq!(dbc.comment(), Some("This is the database comment"));
1166 }
1167
1168 #[test]
1170 fn test_parse_cm_node_comment() {
1171 let data = r#"VERSION "1.0"
1172
1173BU_: ECM
1174
1175BO_ 256 Engine : 8 ECM
1176
1177CM_ BU_ ECM "Engine Control Module";
1178"#;
1179 let dbc = Dbc::parse(data).unwrap();
1180 assert_eq!(dbc.node_comment("ECM"), Some("Engine Control Module"));
1181 }
1182
1183 #[test]
1185 fn test_parse_cm_message_comment() {
1186 let data = r#"VERSION "1.0"
1187
1188BU_: ECM
1189
1190BO_ 256 Engine : 8 ECM
1191
1192CM_ BO_ 256 "Engine status message";
1193"#;
1194 let dbc = Dbc::parse(data).unwrap();
1195 let msg = dbc.messages().iter().next().unwrap();
1196 assert_eq!(msg.comment(), Some("Engine status message"));
1197 }
1198
1199 #[test]
1201 fn test_parse_cm_signal_comment() {
1202 let data = r#"VERSION "1.0"
1203
1204BU_: ECM
1205
1206BO_ 256 Engine : 8 ECM
1207 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
1208
1209CM_ SG_ 256 RPM "Engine rotations per minute";
1210"#;
1211 let dbc = Dbc::parse(data).unwrap();
1212 let msg = dbc.messages().iter().next().unwrap();
1213 let signal = msg.signals().find("RPM").unwrap();
1214 assert_eq!(signal.comment(), Some("Engine rotations per minute"));
1215 }
1216
1217 #[test]
1219 fn test_parse_cm_multiple_comments() {
1220 let data = r#"VERSION "1.0"
1221
1222BU_: ECM TCM
1223
1224BO_ 256 Engine : 8 ECM
1225 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
1226
1227BO_ 512 Trans : 8 TCM
1228 SG_ Gear : 0|8@1+ (1,0) [0|6] ""
1229
1230CM_ "Vehicle CAN database";
1231CM_ BU_ ECM "Engine Control Module";
1232CM_ BU_ TCM "Transmission Control Module";
1233CM_ BO_ 256 "Engine status message";
1234CM_ BO_ 512 "Transmission status";
1235CM_ SG_ 256 RPM "Engine rotations per minute";
1236CM_ SG_ 512 Gear "Current gear position";
1237"#;
1238 let dbc = Dbc::parse(data).unwrap();
1239
1240 assert_eq!(dbc.comment(), Some("Vehicle CAN database"));
1242
1243 assert_eq!(dbc.node_comment("ECM"), Some("Engine Control Module"));
1245 assert_eq!(dbc.node_comment("TCM"), Some("Transmission Control Module"));
1246
1247 let engine = dbc.messages().iter().find(|m| m.id() == 256).unwrap();
1249 let trans = dbc.messages().iter().find(|m| m.id() == 512).unwrap();
1250 assert_eq!(engine.comment(), Some("Engine status message"));
1251 assert_eq!(trans.comment(), Some("Transmission status"));
1252
1253 let rpm = engine.signals().find("RPM").unwrap();
1255 let gear = trans.signals().find("Gear").unwrap();
1256 assert_eq!(rpm.comment(), Some("Engine rotations per minute"));
1257 assert_eq!(gear.comment(), Some("Current gear position"));
1258 }
1259
1260 #[test]
1262 fn test_parse_cm_before_entity() {
1263 let data = r#"VERSION "1.0"
1264
1265BU_: ECM
1266
1267CM_ BO_ 256 "Engine status message";
1268CM_ SG_ 256 RPM "Engine RPM";
1269
1270BO_ 256 Engine : 8 ECM
1271 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
1272"#;
1273 let dbc = Dbc::parse(data).unwrap();
1274 let msg = dbc.messages().iter().next().unwrap();
1275 assert_eq!(msg.comment(), Some("Engine status message"));
1276 let signal = msg.signals().find("RPM").unwrap();
1277 assert_eq!(signal.comment(), Some("Engine RPM"));
1278 }
1279
1280 #[test]
1282 fn test_parse_cm_last_wins() {
1283 let data = r#"VERSION "1.0"
1284
1285BU_: ECM
1286
1287BO_ 256 Engine : 8 ECM
1288 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
1289
1290CM_ BO_ 256 "First message comment";
1291CM_ BO_ 256 "Second message comment";
1292CM_ SG_ 256 RPM "First signal comment";
1293CM_ SG_ 256 RPM "Second signal comment";
1294CM_ BU_ ECM "First node comment";
1295CM_ BU_ ECM "Second node comment";
1296"#;
1297 let dbc = Dbc::parse(data).unwrap();
1298
1299 let msg = dbc.messages().iter().next().unwrap();
1301 assert_eq!(msg.comment(), Some("Second message comment"));
1302 let signal = msg.signals().find("RPM").unwrap();
1303 assert_eq!(signal.comment(), Some("Second signal comment"));
1304 assert_eq!(dbc.node_comment("ECM"), Some("Second node comment"));
1305 }
1306
1307 #[test]
1309 #[cfg(feature = "std")]
1310 fn test_parse_cm_round_trip() {
1311 let data = r#"VERSION "1.0"
1312
1313BU_: ECM TCM
1314
1315BO_ 256 Engine : 8 ECM
1316 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
1317
1318CM_ "Database comment";
1319CM_ BU_ ECM "Engine Control Module";
1320CM_ BO_ 256 "Engine status message";
1321CM_ SG_ 256 RPM "Engine rotations per minute";
1322"#;
1323 let dbc = Dbc::parse(data).unwrap();
1324
1325 let serialized = dbc.to_dbc_string();
1327 let dbc2 = Dbc::parse(&serialized).unwrap();
1328
1329 assert_eq!(dbc2.comment(), Some("Database comment"));
1331 assert_eq!(dbc2.node_comment("ECM"), Some("Engine Control Module"));
1332 let msg = dbc2.messages().iter().next().unwrap();
1333 assert_eq!(msg.comment(), Some("Engine status message"));
1334 let signal = msg.signals().find("RPM").unwrap();
1335 assert_eq!(signal.comment(), Some("Engine rotations per minute"));
1336 }
1337
1338 #[test]
1340 #[cfg(feature = "std")]
1341 fn test_serialize_cm_comments() {
1342 let data = r#"VERSION "1.0"
1343
1344BU_: ECM
1345
1346BO_ 256 Engine : 8 ECM
1347 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
1348
1349CM_ "Database comment";
1350CM_ BU_ ECM "Engine Control Module";
1351CM_ BO_ 256 "Engine status";
1352CM_ SG_ 256 RPM "RPM signal";
1353"#;
1354 let dbc = Dbc::parse(data).unwrap();
1355 let serialized = dbc.to_dbc_string();
1356
1357 assert!(serialized.contains("CM_ \"Database comment\";"));
1359 assert!(serialized.contains("CM_ BU_ ECM \"Engine Control Module\";"));
1360 assert!(serialized.contains("CM_ BO_ 256 \"Engine status\";"));
1361 assert!(serialized.contains("CM_ SG_ 256 RPM \"RPM signal\";"));
1362 }
1363}