1use crate::{
2 ByteOrder, Parser, Signal,
3 error::{ParseError, ParseResult},
4};
5
6use super::Signals;
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash)]
36pub struct Message<'a> {
37 id: u32,
38 name: &'a str,
39 dlc: u8,
40 sender: &'a str,
41 signals: Signals<'a>,
42}
43
44impl<'a> Message<'a> {
45 #[allow(clippy::similar_names)] fn calculate_bit_range(start_bit: u16, length: u16, byte_order: ByteOrder) -> (u16, u16) {
47 let start = start_bit;
48 let len = length;
49
50 match byte_order {
51 ByteOrder::LittleEndian => {
52 (start, start + len - 1)
55 }
56 ByteOrder::BigEndian => {
57 let byte_num = start / 8;
70 let bit_in_byte = start % 8;
71 let physical_msb = byte_num * 8 + (7 - bit_in_byte);
72
73 let lsb_be_bit = start + len - 1;
76 let lsb_byte_num = lsb_be_bit / 8;
77 let lsb_bit_in_byte = lsb_be_bit % 8;
78 let physical_lsb = lsb_byte_num * 8 + (7 - lsb_bit_in_byte);
79
80 if physical_lsb <= physical_msb {
82 (physical_lsb, physical_msb)
83 } else {
84 (physical_msb, physical_lsb)
85 }
86 }
87 }
88 }
89
90 #[allow(clippy::similar_names)] pub(crate) fn validate_internal(
92 id: u32,
93 name: &str,
94 dlc: u8,
95 sender: &str,
96 signals: &[Option<Signal<'a>>],
97 signal_count: usize,
98 options: crate::ParseOptions,
99 ) -> ParseResult<()> {
100 const MAX_EXTENDED_ID: u32 = 0x1FFF_FFFF; const MAX_SIGNALS_PER_MESSAGE: usize = crate::Signals::max_capacity();
112 if signal_count > MAX_SIGNALS_PER_MESSAGE {
113 return Err(ParseError::Version(
114 crate::error::lang::MESSAGE_TOO_MANY_SIGNALS,
115 ));
116 }
117
118 if name.trim().is_empty() {
119 return Err(ParseError::Version(crate::error::lang::MESSAGE_NAME_EMPTY));
120 }
121
122 if sender.trim().is_empty() {
123 return Err(ParseError::Version(
124 crate::error::lang::MESSAGE_SENDER_EMPTY,
125 ));
126 }
127
128 if dlc == 0 {
133 #[cfg(feature = "alloc")]
134 {
135 use crate::error::messages;
136 let msg = messages::message_dlc_too_small(name, id, dlc);
137 return Err(ParseError::Version(Box::leak(msg.into_boxed_str())));
138 }
139 #[cfg(not(feature = "alloc"))]
140 {
141 return Err(ParseError::Version(
142 crate::error::lang::MESSAGE_DLC_TOO_SMALL,
143 ));
144 }
145 }
146 if dlc > 64 {
147 #[cfg(feature = "alloc")]
148 {
149 use crate::error::messages;
150 let msg = messages::message_dlc_too_large(name, id, dlc);
151 return Err(ParseError::Version(Box::leak(msg.into_boxed_str())));
152 }
153 #[cfg(not(feature = "alloc"))]
154 {
155 return Err(ParseError::Version(
156 crate::error::lang::MESSAGE_DLC_TOO_LARGE,
157 ));
158 }
159 }
160
161 if id > MAX_EXTENDED_ID {
165 #[cfg(feature = "alloc")]
166 {
167 use crate::error::messages;
168 let msg = messages::message_id_out_of_range(id);
169 return Err(ParseError::Version(Box::leak(msg.into_boxed_str())));
170 }
171 #[cfg(not(feature = "alloc"))]
172 {
173 return Err(ParseError::Version(
174 crate::error::lang::MESSAGE_ID_OUT_OF_RANGE,
175 ));
176 }
177 }
178
179 let max_bits = u16::from(dlc) * 8;
185 for signal in signals.iter().take(signal_count).filter_map(|opt| opt.as_ref()) {
186 let (lsb, msb) =
188 Self::calculate_bit_range(signal.start_bit(), signal.length(), signal.byte_order());
189 let signal_max_bit = lsb.max(msb);
192 if signal_max_bit >= max_bits {
193 if options.strict_boundary_check {
195 #[cfg(feature = "alloc")]
196 {
197 use crate::error::messages;
198 let msg = messages::signal_extends_beyond_message(
199 signal.name(),
200 signal.start_bit(),
201 signal.length(),
202 signal_max_bit,
203 max_bits,
204 dlc,
205 );
206 return Err(ParseError::Version(Box::leak(msg.into_boxed_str())));
207 }
208 #[cfg(not(feature = "alloc"))]
209 {
210 return Err(ParseError::Version(
211 crate::error::lang::SIGNAL_LENGTH_TOO_LARGE,
212 ));
213 }
214 }
215 }
217 }
218
219 let signals_slice = &signals[..signal_count];
225 for (i, sig1_opt) in signals_slice.iter().enumerate() {
226 let sig1 = match sig1_opt {
227 Some(s) => s,
228 None => continue, };
230 let (sig1_lsb, sig1_msb) =
231 Self::calculate_bit_range(sig1.start_bit(), sig1.length(), sig1.byte_order());
232
233 for sig2_opt in signals_slice.iter().skip(i + 1) {
234 let sig2 = match sig2_opt {
235 Some(s) => s,
236 None => continue, };
238 let (sig2_lsb, sig2_msb) =
239 Self::calculate_bit_range(sig2.start_bit(), sig2.length(), sig2.byte_order());
240
241 if sig1_lsb <= sig2_msb && sig2_lsb <= sig1_msb {
245 #[cfg(feature = "alloc")]
246 {
247 use crate::error::messages;
248 let msg = messages::signal_overlap(sig1.name(), sig2.name(), name);
249 return Err(ParseError::Version(Box::leak(msg.into_boxed_str())));
250 }
251 #[cfg(not(feature = "alloc"))]
252 {
253 return Err(ParseError::Version(crate::error::lang::SIGNAL_OVERLAP));
254 }
255 }
256 }
257 }
258
259 Ok(())
260 }
261
262 #[allow(dead_code)] pub(crate) fn new(
264 id: u32,
265 name: &'a str,
266 dlc: u8,
267 sender: &'a str,
268 signals: &'a [Signal<'a>],
269 ) -> Self {
270 Self {
272 id,
273 name,
274 dlc,
275 sender,
276 signals: Signals::from_signals_slice(signals),
277 }
278 }
279
280 fn new_from_options(
281 id: u32,
282 name: &'a str,
283 dlc: u8,
284 sender: &'a str,
285 signals: &[Option<Signal<'a>>],
286 signal_count: usize,
287 ) -> Self {
288 Self {
290 id,
291 name,
292 dlc,
293 sender,
294 signals: Signals::from_options_slice(signals, signal_count),
295 }
296 }
297
298 pub(crate) fn parse<'b: 'a>(
299 parser: &mut Parser<'b>,
300 signals: &[Option<Signal<'a>>],
301 signal_count: usize,
302 options: crate::ParseOptions,
303 ) -> ParseResult<Self> {
304 if parser.expect(crate::BO_.as_bytes()).is_err() {
306 }
308
309 let _ = parser.skip_whitespace();
311
312 let id = parser
314 .parse_u32()
315 .map_err(|_| ParseError::Version(crate::error::lang::MESSAGE_INVALID_ID))?;
316
317 parser
319 .skip_whitespace()
320 .map_err(|_| ParseError::Expected("Expected whitespace"))?;
321
322 let name = parser
324 .parse_identifier()
325 .map_err(|_| ParseError::Version(crate::error::lang::MESSAGE_NAME_EMPTY))?;
326
327 let _ = parser.skip_whitespace();
329
330 parser.expect(b":").map_err(|_| ParseError::Expected("Expected colon"))?;
332
333 let _ = parser.skip_whitespace();
335
336 let dlc = parser
338 .parse_u8()
339 .map_err(|_| ParseError::Version(crate::error::lang::MESSAGE_INVALID_DLC))?;
340
341 parser
343 .skip_whitespace()
344 .map_err(|_| ParseError::Expected("Expected whitespace"))?;
345
346 let sender = parser
348 .parse_identifier()
349 .map_err(|_| ParseError::Version(crate::error::lang::MESSAGE_SENDER_EMPTY))?;
350
351 parser.skip_newlines_and_spaces();
353 if !parser.is_empty() {
354 return Err(ParseError::Expected(
355 "Unexpected content after message sender",
356 ));
357 }
358
359 Self::validate_internal(
361 id,
362 name,
363 dlc,
364 sender,
365 &signals[..signal_count],
366 signal_count,
367 options,
368 )?;
369 Ok(Self::new_from_options(
371 id,
372 name,
373 dlc,
374 sender,
375 signals,
376 signal_count,
377 ))
378 }
379
380 #[inline]
393 #[must_use]
394 pub fn id(&self) -> u32 {
395 self.id
396 }
397
398 #[inline]
411 #[must_use]
412 pub fn name(&self) -> &'a str {
413 self.name
414 }
415
416 #[inline]
432 #[must_use]
433 pub fn dlc(&self) -> u8 {
434 self.dlc
435 }
436
437 #[inline]
438 #[must_use]
439 pub fn sender(&self) -> &'a str {
440 self.sender
441 }
442
443 #[inline]
445 #[must_use]
446 pub fn signals(&self) -> &Signals<'a> {
447 &self.signals
448 }
449
450 #[cfg(feature = "alloc")]
451 #[must_use]
452 pub fn to_dbc_string(&self) -> String {
453 format!(
454 "BO_ {} {} : {} {}",
455 self.id(),
456 self.name(),
457 self.dlc(),
458 self.sender()
459 )
460 }
461
462 #[cfg(feature = "alloc")]
463 #[must_use]
464 pub fn to_dbc_string_with_signals(&self) -> String {
465 let mut result = String::with_capacity(200 + (self.signals.len() * 100));
466 result.push_str(&self.to_dbc_string());
467 result.push('\n');
468
469 for signal in self.signals().iter() {
470 result.push_str(&signal.to_dbc_string());
471 result.push('\n');
472 }
473
474 result
475 }
476}
477
478#[cfg(feature = "alloc")]
479impl<'a> core::fmt::Display for Message<'a> {
480 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
481 write!(f, "{}", self.to_dbc_string_with_signals())
482 }
483}
484
485#[cfg(test)]
486mod tests {
487 #![allow(clippy::float_cmp)]
488 use super::*;
489 use crate::{
490 ByteOrder, Error, Parser, Receivers,
491 error::{ParseError, lang},
492 };
493 #[cfg(feature = "alloc")]
494 use crate::{MessageBuilder, SignalBuilder};
495
496 #[test]
497 #[cfg(feature = "alloc")]
498 fn test_message_new_valid() {
499 let signal = SignalBuilder::new()
500 .name("RPM")
501 .start_bit(0)
502 .length(16)
503 .byte_order(ByteOrder::BigEndian)
504 .unsigned(true)
505 .factor(0.25)
506 .offset(0.0)
507 .min(0.0)
508 .max(8000.0)
509 .unit("rpm")
510 .receivers(Receivers::Broadcast)
511 .build()
512 .unwrap();
513
514 let message = MessageBuilder::new()
515 .id(256)
516 .name("EngineData")
517 .dlc(8)
518 .sender("ECM")
519 .add_signal(signal)
520 .build()
521 .unwrap();
522 assert_eq!(message.id(), 256);
523 assert_eq!(message.name(), "EngineData");
524 assert_eq!(message.dlc(), 8);
525 assert_eq!(message.sender(), "ECM");
526 assert_eq!(message.signals().len(), 1);
527 }
528
529 #[test]
530 #[cfg(feature = "alloc")]
531 fn test_message_new_empty_name() {
532 let signal = SignalBuilder::new()
533 .name("RPM")
534 .start_bit(0)
535 .length(16)
536 .byte_order(ByteOrder::BigEndian)
537 .unsigned(true)
538 .factor(1.0)
539 .offset(0.0)
540 .min(0.0)
541 .max(100.0)
542 .receivers(Receivers::None)
543 .build()
544 .unwrap();
545
546 let result = MessageBuilder::new()
547 .id(256)
548 .name("")
549 .dlc(8)
550 .sender("ECM")
551 .add_signal(signal)
552 .build();
553 assert!(result.is_err());
554 match result.unwrap_err() {
555 Error::Dbc(msg) => {
556 assert!(msg.contains(lang::MESSAGE_NAME_EMPTY));
557 }
558 _ => panic!("Expected Error::Dbc"),
559 }
560 }
561
562 #[test]
563 #[cfg(feature = "alloc")]
564 fn test_message_new_empty_sender() {
565 let signal = SignalBuilder::new()
566 .name("RPM")
567 .start_bit(0)
568 .length(16)
569 .byte_order(ByteOrder::BigEndian)
570 .unsigned(true)
571 .factor(1.0)
572 .offset(0.0)
573 .min(0.0)
574 .max(100.0)
575 .receivers(Receivers::None)
576 .build()
577 .unwrap();
578
579 let result = MessageBuilder::new()
580 .id(256)
581 .name("EngineData")
582 .dlc(8)
583 .sender("")
584 .add_signal(signal)
585 .build();
586 assert!(result.is_err());
587 match result.unwrap_err() {
588 Error::Dbc(msg) => {
589 assert!(msg.contains(lang::MESSAGE_SENDER_EMPTY));
590 }
591 _ => panic!("Expected Error::Dbc"),
592 }
593 }
594
595 #[test]
596 #[cfg(feature = "alloc")]
597 fn test_message_new_dlc_too_large() {
598 let signal = SignalBuilder::new()
599 .name("RPM")
600 .start_bit(0)
601 .length(16)
602 .byte_order(ByteOrder::BigEndian)
603 .unsigned(true)
604 .factor(1.0)
605 .offset(0.0)
606 .min(0.0)
607 .max(100.0)
608 .receivers(Receivers::None)
609 .build()
610 .unwrap();
611
612 let result = MessageBuilder::new()
613 .id(256)
614 .name("EngineData")
615 .dlc(65) .sender("ECM")
617 .add_signal(signal)
618 .build();
619 assert!(result.is_err());
620 match result.unwrap_err() {
621 Error::Dbc(msg) => {
622 assert!(
624 msg.contains(lang::MESSAGE_DLC_TOO_LARGE)
625 || msg.contains("Message 'EngineData'")
626 || msg.contains("DLC 65")
627 );
628 }
629 _ => panic!("Expected Error::Dbc"),
630 }
631 }
632
633 #[test]
634 #[cfg(feature = "alloc")]
635 fn test_message_new_dlc_zero() {
636 let signal = SignalBuilder::new()
637 .name("RPM")
638 .start_bit(0)
639 .length(16)
640 .byte_order(ByteOrder::BigEndian)
641 .unsigned(true)
642 .factor(1.0)
643 .offset(0.0)
644 .min(0.0)
645 .max(100.0)
646 .receivers(Receivers::None)
647 .build()
648 .unwrap();
649
650 let result = MessageBuilder::new()
651 .id(256)
652 .name("EngineData")
653 .dlc(0) .sender("ECM")
655 .add_signal(signal)
656 .build();
657 assert!(result.is_err());
658 match result.unwrap_err() {
659 Error::Dbc(msg) => {
660 assert!(
662 msg.contains(lang::MESSAGE_DLC_TOO_SMALL)
663 || msg.contains("Message 'EngineData'")
664 || msg.contains("DLC 0")
665 );
666 }
667 _ => panic!("Expected Error::Dbc"),
668 }
669 }
670
671 #[test]
672 #[cfg(feature = "alloc")]
673 fn test_message_new_id_out_of_range() {
674 let signal = SignalBuilder::new()
675 .name("RPM")
676 .start_bit(0)
677 .length(16)
678 .byte_order(ByteOrder::BigEndian)
679 .unsigned(true)
680 .factor(1.0)
681 .offset(0.0)
682 .min(0.0)
683 .max(100.0)
684 .receivers(Receivers::None)
685 .build()
686 .unwrap();
687
688 let result = MessageBuilder::new()
690 .id(0x2000_0000) .name("EngineData")
692 .dlc(8)
693 .sender("ECM")
694 .add_signal(signal)
695 .build();
696 assert!(result.is_err());
697 match result.unwrap_err() {
698 Error::Dbc(msg) => {
699 let template_text =
701 lang::FORMAT_MESSAGE_ID_OUT_OF_RANGE.split("{}").next().unwrap();
702 assert!(msg.contains(template_text.trim_end()));
703 }
704 _ => panic!("Expected Error::Dbc"),
705 }
706 }
707
708 #[test]
709 #[cfg(feature = "alloc")]
710 fn test_message_new_signal_overlap() {
711 let signal1 = SignalBuilder::new()
712 .name("Signal1")
713 .start_bit(0)
714 .length(8)
715 .byte_order(ByteOrder::LittleEndian)
716 .unsigned(true)
717 .factor(1.0)
718 .offset(0.0)
719 .min(0.0)
720 .max(255.0)
721 .receivers(Receivers::None)
722 .build()
723 .unwrap();
724
725 let signal2 = SignalBuilder::new()
726 .name("Signal2")
727 .start_bit(4) .length(8)
729 .byte_order(ByteOrder::LittleEndian)
730 .unsigned(true)
731 .factor(1.0)
732 .offset(0.0)
733 .min(0.0)
734 .max(255.0)
735 .receivers(Receivers::None)
736 .build()
737 .unwrap();
738
739 let result = MessageBuilder::new()
740 .id(256)
741 .name("EngineData")
742 .dlc(8)
743 .sender("ECM")
744 .add_signal(signal1)
745 .add_signal(signal2)
746 .build();
747 assert!(result.is_err());
748 match result.unwrap_err() {
749 Error::Dbc(msg) => {
750 let template_text = lang::FORMAT_SIGNAL_OVERLAP.split("{}").next().unwrap();
752 assert!(msg.contains(template_text.trim_end()));
753 }
754 _ => panic!("Expected Error::Dbc"),
755 }
756 }
757
758 #[test]
759 #[cfg(feature = "alloc")]
760 fn test_message_new_signal_extends_beyond_message() {
761 let signal = SignalBuilder::new()
762 .name("Signal1")
763 .start_bit(0)
764 .length(72) .byte_order(ByteOrder::LittleEndian)
766 .unsigned(true)
767 .factor(1.0)
768 .offset(0.0)
769 .min(0.0)
770 .max(255.0)
771 .receivers(Receivers::None)
772 .build()
773 .unwrap();
774
775 let result = MessageBuilder::new()
776 .id(256)
777 .name("EngineData")
778 .dlc(8) .sender("ECM")
780 .add_signal(signal)
781 .build();
782 assert!(result.is_err());
783 match result.unwrap_err() {
784 Error::Dbc(msg) => {
785 let template_text =
787 lang::FORMAT_SIGNAL_EXTENDS_BEYOND_MESSAGE.split("{}").next().unwrap();
788 assert!(msg.contains(template_text.trim_end_matches(':').trim_end()));
789 }
790 _ => panic!("Expected Error::Dbc"),
791 }
792 }
793
794 #[test]
795 #[cfg(feature = "alloc")]
796 fn test_message_new_too_many_signals() {
797 let mut builder = MessageBuilder::new().id(256).name("EngineData").dlc(8).sender("ECM");
798
799 for i in 0..65 {
801 let sig_name = format!("Signal{i}");
803 builder = builder.add_signal(
804 SignalBuilder::new()
805 .name(&sig_name)
806 .start_bit(i as u16)
807 .length(1)
808 .byte_order(ByteOrder::LittleEndian)
809 .unsigned(true)
810 .factor(1.0)
811 .offset(0.0)
812 .min(0.0)
813 .max(1.0)
814 .receivers(Receivers::None)
815 .build()
816 .unwrap(),
817 );
818 }
819
820 let result = builder.build();
821 assert!(result.is_err());
822 match result.unwrap_err() {
823 Error::Dbc(msg) => {
824 assert!(msg.contains(lang::MESSAGE_TOO_MANY_SIGNALS));
825 }
826 _ => panic!("Expected Error::Dbc"),
827 }
828 }
829
830 #[test]
831 fn test_message_parse_valid() {
832 let data = b"BO_ 256 EngineData : 8 ECM";
833 let mut parser = Parser::new(data).unwrap();
834 const MAX_CAP: usize = crate::Signals::max_capacity();
835 let signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
836 let message = Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new()).unwrap();
837 assert_eq!(message.id(), 256);
838 assert_eq!(message.name(), "EngineData");
839 assert_eq!(message.dlc(), 8);
840 assert_eq!(message.sender(), "ECM");
841 assert_eq!(message.signals().len(), 0);
842 }
843
844 #[test]
845 fn test_message_parse_invalid_id() {
846 let data = b"BO_ invalid EngineData : 8 ECM";
847 let mut parser = Parser::new(data).unwrap();
848 const MAX_CAP: usize = crate::Signals::max_capacity();
849 let signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
850 let result = Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new());
851 assert!(result.is_err());
852 match result.unwrap_err() {
853 ParseError::Version(_) => {
854 }
856 _ => panic!("Expected ParseError::Version"),
857 }
858 }
859
860 #[test]
861 fn test_message_parse_empty_name() {
862 let data = b"BO_ 256 : 8 ECM";
863 let mut parser = Parser::new(data).unwrap();
864 const MAX_CAP: usize = crate::Signals::max_capacity();
865 let signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
866 let result = Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new());
867 assert!(result.is_err());
868 match result.unwrap_err() {
869 ParseError::Version(_) => {
870 }
872 _ => panic!("Expected ParseError::Version"),
873 }
874 }
875
876 #[test]
877 fn test_message_parse_invalid_dlc() {
878 let data = b"BO_ 256 EngineData : invalid ECM";
879 let mut parser = Parser::new(data).unwrap();
880 const MAX_CAP: usize = crate::Signals::max_capacity();
881 let signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
882 let result = Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new());
883 assert!(result.is_err());
884 match result.unwrap_err() {
885 ParseError::Version(_) => {
886 }
888 _ => panic!("Expected ParseError::Version"),
889 }
890 }
891
892 #[test]
893 fn test_message_parse_empty_sender() {
894 let data = b"BO_ 256 EngineData : 8 ";
895 let mut parser = Parser::new(data).unwrap();
896 const MAX_CAP: usize = crate::Signals::max_capacity();
897 let signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
898 let result = Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new());
899 assert!(result.is_err());
900 match result.unwrap_err() {
901 ParseError::Version(_) => {
902 }
904 _ => panic!("Expected ParseError::Version"),
905 }
906 }
907
908 #[test]
909 fn test_message_parse_with_signals() {
910 let data = b"BO_ 256 EngineData : 8 ECM";
911 let mut parser = Parser::new(data).unwrap();
912
913 let signal1 = Signal::parse(
915 &mut Parser::new(b"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] \"rpm\"").unwrap(),
916 )
917 .unwrap();
918 let signal2 = Signal::parse(
919 &mut Parser::new(b"SG_ Temp : 16|8@0- (1,-40) [-40|215] \"\xC2\xB0C\"").unwrap(),
920 )
921 .unwrap();
922
923 const MAX_CAP: usize = crate::Signals::max_capacity();
924 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
925 signals[0] = Some(signal1);
926 signals[1] = Some(signal2);
927
928 let message = Message::parse(&mut parser, &signals, 2, crate::ParseOptions::new()).unwrap();
929 assert_eq!(message.id(), 256);
930 assert_eq!(message.name(), "EngineData");
931 assert_eq!(message.dlc(), 8);
932 assert_eq!(message.sender(), "ECM");
933 assert_eq!(message.signals().len(), 2);
934 }
935
936 #[test]
937 fn test_message_signals_iterator() {
938 let data = b"BO_ 256 EngineData : 8 ECM";
939 let mut parser = Parser::new(data).unwrap();
940
941 let signal1 = Signal::parse(
943 &mut Parser::new(b"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] \"rpm\"").unwrap(),
944 )
945 .unwrap();
946 let signal2 = Signal::parse(
947 &mut Parser::new(b"SG_ Temp : 16|8@0- (1,-40) [-40|215] \"\xC2\xB0C\"").unwrap(),
948 )
949 .unwrap();
950
951 const MAX_CAP: usize = crate::Signals::max_capacity();
952 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
953 signals[0] = Some(signal1);
954 signals[1] = Some(signal2);
955
956 let message = Message::parse(&mut parser, &signals, 2, crate::ParseOptions::new()).unwrap();
957 let mut signals_iter = message.signals().iter();
958 assert_eq!(signals_iter.next().unwrap().name(), "RPM");
959 assert_eq!(signals_iter.next().unwrap().name(), "Temp");
960 assert!(signals_iter.next().is_none());
961 }
962
963 #[test]
964 fn test_message_signal_count() {
965 let data = b"BO_ 256 EngineData : 8 ECM";
966 let mut parser = Parser::new(data).unwrap();
967
968 let signals: [Option<Signal>; crate::Signals::max_capacity()] =
969 [const { None }; crate::Signals::max_capacity()];
970 let message = Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new()).unwrap();
971 assert_eq!(message.signals().len(), 0);
972
973 let data2 = b"BO_ 256 EngineData : 8 ECM";
975 let mut parser2 = Parser::new(data2).unwrap();
976 let signal1 = Signal::parse(
977 &mut Parser::new(b"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] \"rpm\"").unwrap(),
978 )
979 .unwrap();
980 const MAX_CAP: usize = crate::Signals::max_capacity();
981 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
982 signals[0] = Some(signal1);
983 let message =
984 Message::parse(&mut parser2, &signals, 1, crate::ParseOptions::new()).unwrap();
985 assert_eq!(message.signals().len(), 1);
986 }
987
988 #[test]
989 fn test_message_signal_at() {
990 let data = b"BO_ 256 EngineData : 8 ECM";
991 let mut parser = Parser::new(data).unwrap();
992
993 let signal1 = Signal::parse(
994 &mut Parser::new(b"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] \"rpm\"").unwrap(),
995 )
996 .unwrap();
997 let signal2 = Signal::parse(
998 &mut Parser::new(b"SG_ Temp : 16|8@0- (1,-40) [-40|215] \"\xC2\xB0C\"").unwrap(),
999 )
1000 .unwrap();
1001
1002 const MAX_CAP: usize = crate::Signals::max_capacity();
1003 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
1004 signals[0] = Some(signal1);
1005 signals[1] = Some(signal2);
1006
1007 let message = Message::parse(&mut parser, &signals, 2, crate::ParseOptions::new()).unwrap();
1008 assert_eq!(message.signals().at(0).unwrap().name(), "RPM");
1009 assert_eq!(message.signals().at(1).unwrap().name(), "Temp");
1010 assert!(message.signals().at(2).is_none());
1011 }
1012
1013 #[test]
1014 fn test_message_find_signal() {
1015 let data = b"BO_ 256 EngineData : 8 ECM";
1016 let mut parser = Parser::new(data).unwrap();
1017
1018 let signal1 = Signal::parse(
1019 &mut Parser::new(b"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] \"rpm\"").unwrap(),
1020 )
1021 .unwrap();
1022 let signal2 = Signal::parse(
1023 &mut Parser::new(b"SG_ Temp : 16|8@0- (1,-40) [-40|215] \"\xC2\xB0C\"").unwrap(),
1024 )
1025 .unwrap();
1026
1027 const MAX_CAP: usize = crate::Signals::max_capacity();
1028 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
1029 signals[0] = Some(signal1);
1030 signals[1] = Some(signal2);
1031
1032 let message = Message::parse(&mut parser, &signals, 2, crate::ParseOptions::new()).unwrap();
1033 assert_eq!(message.signals().find("RPM").unwrap().name(), "RPM");
1034 assert_eq!(message.signals().find("Temp").unwrap().name(), "Temp");
1035 assert!(message.signals().find("Nonexistent").is_none());
1036 }
1037
1038 #[test]
1039 #[cfg(feature = "alloc")]
1040 fn test_message_to_dbc_string() {
1041 let data = b"BO_ 256 EngineData : 8 ECM";
1042 let mut parser = Parser::new(data).unwrap();
1043 const MAX_CAP: usize = crate::Signals::max_capacity();
1044 let signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
1045 let message = Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new()).unwrap();
1046 let dbc_string = message.to_dbc_string();
1047 assert_eq!(dbc_string, "BO_ 256 EngineData : 8 ECM");
1048 }
1049
1050 #[test]
1051 #[cfg(feature = "alloc")]
1052 fn test_message_to_dbc_string_with_signals() {
1053 let data = b"BO_ 256 EngineData : 8 ECM";
1054 let mut parser = Parser::new(data).unwrap();
1055
1056 let signal1 = Signal::parse(
1057 &mut Parser::new(b"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] \"rpm\"").unwrap(),
1058 )
1059 .unwrap();
1060 let signal2 = Signal::parse(
1061 &mut Parser::new(b"SG_ Temp : 16|8@0- (1,-40) [-40|215] \"\xC2\xB0C\"").unwrap(),
1062 )
1063 .unwrap();
1064
1065 const MAX_CAP: usize = crate::Signals::max_capacity();
1066 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
1067 signals[0] = Some(signal1);
1068 signals[1] = Some(signal2);
1069
1070 let message = Message::parse(&mut parser, &signals, 2, crate::ParseOptions::new()).unwrap();
1071 let dbc_string = message.to_dbc_string_with_signals();
1072 assert!(dbc_string.contains("BO_ 256 EngineData : 8 ECM"));
1073 assert!(dbc_string.contains("SG_ RPM"));
1074 assert!(dbc_string.contains("SG_ Temp"));
1075 }
1076
1077 #[test]
1078 fn test_message_can_2_0a_dlc_limits() {
1079 for dlc in 1..=8 {
1082 let data = format!("BO_ 256 EngineData : {} ECM", dlc);
1083 let mut parser = Parser::new(data.as_bytes()).unwrap();
1084 const MAX_CAP: usize = crate::Signals::max_capacity();
1085 let signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
1086 let message =
1087 Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new()).unwrap();
1088 assert_eq!(message.dlc(), dlc);
1089 }
1090 }
1091
1092 #[test]
1093 fn test_message_can_2_0b_dlc_limits() {
1094 for dlc in 1..=8 {
1097 let data = format!("BO_ 256 EngineData : {} ECM", dlc);
1098 let mut parser = Parser::new(data.as_bytes()).unwrap();
1099 const MAX_CAP: usize = crate::Signals::max_capacity();
1100 let signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
1101 let message =
1102 Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new()).unwrap();
1103 assert_eq!(message.dlc(), dlc);
1104 }
1105 }
1106
1107 #[test]
1108 fn test_message_can_fd_dlc_limits() {
1109 for dlc in [1, 8, 12, 16, 20, 24, 32, 48, 64] {
1112 let data = format!("BO_ 256 EngineData : {} ECM", dlc);
1113 let mut parser = Parser::new(data.as_bytes()).unwrap();
1114 const MAX_CAP: usize = crate::Signals::max_capacity();
1115 let signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
1116 let message =
1117 Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new()).unwrap();
1118 assert_eq!(message.dlc(), dlc);
1119 }
1120 }
1121
1122 #[test]
1123 fn test_message_multiple_signals_boundary_validation() {
1124 let data = b"BO_ 256 EngineData : 8 ECM";
1126 let mut parser = Parser::new(data).unwrap();
1127
1128 let signal1 =
1131 Signal::parse(&mut Parser::new(b"SG_ Signal1 : 0|16@0+ (1,0) [0|65535] \"\"").unwrap())
1132 .unwrap();
1133 let signal2 = Signal::parse(
1135 &mut Parser::new(b"SG_ Signal2 : 16|16@0+ (1,0) [0|65535] \"\"").unwrap(),
1136 )
1137 .unwrap();
1138 let signal3 = Signal::parse(
1140 &mut Parser::new(b"SG_ Signal3 : 32|16@0+ (1,0) [0|65535] \"\"").unwrap(),
1141 )
1142 .unwrap();
1143 let signal4 = Signal::parse(
1145 &mut Parser::new(b"SG_ Signal4 : 48|16@0+ (1,0) [0|65535] \"\"").unwrap(),
1146 )
1147 .unwrap();
1148
1149 const MAX_CAP: usize = crate::Signals::max_capacity();
1150 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
1151 signals[0] = Some(signal1);
1152 signals[1] = Some(signal2);
1153 signals[2] = Some(signal3);
1154 signals[3] = Some(signal4);
1155
1156 let message = Message::parse(&mut parser, &signals, 4, crate::ParseOptions::new()).unwrap();
1157 assert_eq!(message.signals().len(), 4);
1158 }
1159
1160 #[test]
1161 fn test_message_big_endian_bit_range_calculation() {
1162 let data = b"BO_ 256 EngineData : 8 ECM";
1168 let mut parser = Parser::new(data).unwrap();
1169
1170 let signal =
1172 Signal::parse(&mut Parser::new(b"SG_ Signal1 : 0|8@1+ (1,0) [0|255] \"\"").unwrap())
1173 .unwrap();
1174
1175 const MAX_CAP: usize = crate::Signals::max_capacity();
1176 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
1177 signals[0] = Some(signal);
1178
1179 let message = Message::parse(&mut parser, &signals, 1, crate::ParseOptions::new()).unwrap();
1180 assert_eq!(message.signals().len(), 1);
1182 }
1183
1184 #[test]
1185 fn test_message_little_endian_bit_range_calculation() {
1186 let data = b"BO_ 256 EngineData : 8 ECM";
1189 let mut parser = Parser::new(data).unwrap();
1190
1191 let signal =
1193 Signal::parse(&mut Parser::new(b"SG_ Signal1 : 0|8@0+ (1,0) [0|255] \"\"").unwrap())
1194 .unwrap();
1195
1196 const MAX_CAP: usize = crate::Signals::max_capacity();
1197 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
1198 signals[0] = Some(signal);
1199
1200 let message = Message::parse(&mut parser, &signals, 1, crate::ParseOptions::new()).unwrap();
1201 assert_eq!(message.signals().len(), 1);
1203 }
1204
1205 #[test]
1206 #[cfg(feature = "alloc")]
1207 fn test_message_signal_overlap_big_endian() {
1208 let signal1 = SignalBuilder::new()
1210 .name("Signal1")
1211 .start_bit(0) .length(8)
1213 .byte_order(ByteOrder::BigEndian)
1214 .unsigned(true)
1215 .factor(1.0)
1216 .offset(0.0)
1217 .min(0.0)
1218 .max(255.0)
1219 .receivers(Receivers::None)
1220 .build()
1221 .unwrap();
1222
1223 let signal2 = SignalBuilder::new()
1224 .name("Signal2")
1225 .start_bit(4) .length(8)
1227 .byte_order(ByteOrder::BigEndian)
1228 .unsigned(true)
1229 .factor(1.0)
1230 .offset(0.0)
1231 .min(0.0)
1232 .max(255.0)
1233 .receivers(Receivers::None)
1234 .build()
1235 .unwrap();
1236
1237 let result = MessageBuilder::new()
1238 .id(256)
1239 .name("EngineData")
1240 .dlc(8)
1241 .sender("ECM")
1242 .add_signal(signal1)
1243 .add_signal(signal2)
1244 .build();
1245 assert!(result.is_err());
1246 match result.unwrap_err() {
1247 Error::Dbc(msg) => {
1248 let template_text = lang::FORMAT_SIGNAL_OVERLAP.split("{}").next().unwrap();
1250 assert!(msg.contains(template_text.trim_end()));
1251 }
1252 _ => panic!("Expected Error::Dbc"),
1253 }
1254 }
1255
1256 #[test]
1257 #[cfg(feature = "alloc")]
1258 fn test_message_signal_extends_beyond_message_big_endian() {
1259 let signal = SignalBuilder::new()
1261 .name("Signal1")
1262 .start_bit(56) .length(16) .byte_order(ByteOrder::BigEndian)
1265 .unsigned(true)
1266 .factor(1.0)
1267 .offset(0.0)
1268 .min(0.0)
1269 .max(65535.0)
1270 .receivers(Receivers::None)
1271 .build()
1272 .unwrap();
1273
1274 let result = MessageBuilder::new()
1275 .id(256)
1276 .name("EngineData")
1277 .dlc(8) .sender("ECM")
1279 .add_signal(signal)
1280 .build();
1281 assert!(result.is_err());
1282 match result.unwrap_err() {
1283 Error::Dbc(msg) => {
1284 let template_text =
1286 lang::FORMAT_SIGNAL_EXTENDS_BEYOND_MESSAGE.split("{}").next().unwrap();
1287 assert!(msg.contains(template_text.trim_end_matches(':').trim_end()));
1288 }
1289 _ => panic!("Expected Error::Dbc"),
1290 }
1291 }
1292
1293 #[test]
1294 fn test_parse_with_lenient_boundary_check() {
1295 let data = b"BO_ 256 Test : 8 ECM";
1297 let mut parser = Parser::new(data).unwrap();
1298
1299 let signal =
1301 Signal::parse(&mut Parser::new(b"SG_ CHECKSUM : 63|8@1+ (1,0) [0|255] \"\"").unwrap())
1302 .unwrap();
1303
1304 const MAX_CAP: usize = crate::Signals::max_capacity();
1305 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
1306 signals[0] = Some(signal);
1307
1308 let result = Message::parse(&mut parser, &signals, 1, crate::ParseOptions::new());
1310 assert!(result.is_err());
1311
1312 let mut parser2 = Parser::new(data).unwrap();
1314 let message =
1315 Message::parse(&mut parser2, &signals, 1, crate::ParseOptions::lenient()).unwrap();
1316 assert_eq!(message.signals().len(), 1);
1317 assert_eq!(message.signals().at(0).unwrap().name(), "CHECKSUM");
1318 }
1319}