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, version_error_from_string};
136 let msg = messages::message_dlc_too_small(name, id, dlc);
137 return Err(version_error_from_string(msg));
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, version_error_from_string};
150 let msg = messages::message_dlc_too_large(name, id, dlc);
151 return Err(version_error_from_string(msg));
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, version_error_from_string};
168 let msg = messages::message_id_out_of_range(id);
169 return Err(version_error_from_string(msg));
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 use crate::error::version_error_from_string;
207 return Err(version_error_from_string(msg));
208 }
209 #[cfg(not(feature = "alloc"))]
210 {
211 return Err(ParseError::Version(
212 crate::error::lang::SIGNAL_LENGTH_TOO_LARGE,
213 ));
214 }
215 }
216 }
218 }
219
220 let signals_slice = &signals[..signal_count];
226 for (i, sig1_opt) in signals_slice.iter().enumerate() {
227 let sig1 = match sig1_opt {
228 Some(s) => s,
229 None => continue, };
231 let (sig1_lsb, sig1_msb) =
232 Self::calculate_bit_range(sig1.start_bit(), sig1.length(), sig1.byte_order());
233
234 for sig2_opt in signals_slice.iter().skip(i + 1) {
235 let sig2 = match sig2_opt {
236 Some(s) => s,
237 None => continue, };
239 let (sig2_lsb, sig2_msb) =
240 Self::calculate_bit_range(sig2.start_bit(), sig2.length(), sig2.byte_order());
241
242 if sig1_lsb <= sig2_msb && sig2_lsb <= sig1_msb {
246 #[cfg(feature = "alloc")]
247 {
248 use crate::error::{messages, version_error_from_string};
249 let msg = messages::signal_overlap(sig1.name(), sig2.name(), name);
250 return Err(version_error_from_string(msg));
251 }
252 #[cfg(not(feature = "alloc"))]
253 {
254 return Err(ParseError::Version(crate::error::lang::SIGNAL_OVERLAP));
255 }
256 }
257 }
258 }
259
260 Ok(())
261 }
262
263 #[allow(dead_code)] pub(crate) fn new(
265 id: u32,
266 name: &'a str,
267 dlc: u8,
268 sender: &'a str,
269 signals: &'a [Signal<'a>],
270 ) -> Self {
271 Self {
273 id,
274 name,
275 dlc,
276 sender,
277 signals: Signals::from_signals_slice(signals),
278 }
279 }
280
281 fn new_from_options(
282 id: u32,
283 name: &'a str,
284 dlc: u8,
285 sender: &'a str,
286 signals: &[Option<Signal<'a>>],
287 signal_count: usize,
288 ) -> Self {
289 Self {
291 id,
292 name,
293 dlc,
294 sender,
295 signals: Signals::from_options_slice(signals, signal_count),
296 }
297 }
298
299 pub(crate) fn parse<'b: 'a>(
300 parser: &mut Parser<'b>,
301 signals: &[Option<Signal<'a>>],
302 signal_count: usize,
303 options: crate::ParseOptions,
304 ) -> ParseResult<Self> {
305 if parser.expect(crate::BO_.as_bytes()).is_err() {
307 }
309
310 let _ = parser.skip_whitespace();
312
313 let id = parser
315 .parse_u32()
316 .map_err(|_| ParseError::Version(crate::error::lang::MESSAGE_INVALID_ID))?;
317
318 parser
320 .skip_whitespace()
321 .map_err(|_| ParseError::Expected("Expected whitespace"))?;
322
323 let name = parser
325 .parse_identifier()
326 .map_err(|_| ParseError::Version(crate::error::lang::MESSAGE_NAME_EMPTY))?;
327
328 let _ = parser.skip_whitespace();
330
331 parser.expect(b":").map_err(|_| ParseError::Expected("Expected colon"))?;
333
334 let _ = parser.skip_whitespace();
336
337 let dlc = parser
339 .parse_u8()
340 .map_err(|_| ParseError::Version(crate::error::lang::MESSAGE_INVALID_DLC))?;
341
342 parser
344 .skip_whitespace()
345 .map_err(|_| ParseError::Expected("Expected whitespace"))?;
346
347 let sender = parser
349 .parse_identifier()
350 .map_err(|_| ParseError::Version(crate::error::lang::MESSAGE_SENDER_EMPTY))?;
351
352 parser.skip_newlines_and_spaces();
354 if !parser.is_empty() {
355 return Err(ParseError::Expected(
356 "Unexpected content after message sender",
357 ));
358 }
359
360 Self::validate_internal(
362 id,
363 name,
364 dlc,
365 sender,
366 &signals[..signal_count],
367 signal_count,
368 options,
369 )?;
370 Ok(Self::new_from_options(
372 id,
373 name,
374 dlc,
375 sender,
376 signals,
377 signal_count,
378 ))
379 }
380
381 #[inline]
394 #[must_use]
395 pub fn id(&self) -> u32 {
396 self.id
397 }
398
399 #[inline]
412 #[must_use]
413 pub fn name(&self) -> &'a str {
414 self.name
415 }
416
417 #[inline]
433 #[must_use]
434 pub fn dlc(&self) -> u8 {
435 self.dlc
436 }
437
438 #[inline]
439 #[must_use]
440 pub fn sender(&self) -> &'a str {
441 self.sender
442 }
443
444 #[inline]
446 #[must_use]
447 pub fn signals(&self) -> &Signals<'a> {
448 &self.signals
449 }
450
451 #[cfg(feature = "alloc")]
452 #[must_use]
453 pub fn to_dbc_string(&self) -> alloc::string::String {
454 use alloc::format;
455 format!(
456 "BO_ {} {} : {} {}",
457 self.id(),
458 self.name(),
459 self.dlc(),
460 self.sender()
461 )
462 }
463
464 #[cfg(feature = "alloc")]
465 #[must_use]
466 pub fn to_dbc_string_with_signals(&self) -> alloc::string::String {
467 use alloc::string::String;
468 let mut result = String::with_capacity(200 + (self.signals.len() * 100));
469 result.push_str(&self.to_dbc_string());
470 result.push('\n');
471
472 for signal in self.signals().iter() {
473 result.push_str(&signal.to_dbc_string());
474 result.push('\n');
475 }
476
477 result
478 }
479}
480
481#[cfg(feature = "alloc")]
482impl<'a> core::fmt::Display for Message<'a> {
483 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
484 write!(f, "{}", self.to_dbc_string_with_signals())
485 }
486}
487
488#[cfg(test)]
489mod tests {
490 #![allow(clippy::float_cmp)]
491 use super::*;
492 use crate::{Parser, error::ParseError};
493 #[cfg(any(feature = "alloc", feature = "kernel"))]
494 use alloc::{format, vec};
495 #[test]
502 fn test_message_parse_valid() {
503 let data = b"BO_ 256 EngineData : 8 ECM";
504 let mut parser = Parser::new(data).unwrap();
505 const MAX_CAP: usize = crate::Signals::max_capacity();
506 let signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
507 let message = Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new()).unwrap();
508 assert_eq!(message.id(), 256);
509 assert_eq!(message.name(), "EngineData");
510 assert_eq!(message.dlc(), 8);
511 assert_eq!(message.sender(), "ECM");
512 assert_eq!(message.signals().len(), 0);
513 }
514
515 #[test]
516 fn test_message_parse_invalid_id() {
517 let data = b"BO_ invalid EngineData : 8 ECM";
518 let mut parser = Parser::new(data).unwrap();
519 const MAX_CAP: usize = crate::Signals::max_capacity();
520 let signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
521 let result = Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new());
522 assert!(result.is_err());
523 match result.unwrap_err() {
524 ParseError::Version(_) => {
525 }
527 _ => panic!("Expected ParseError::Version"),
528 }
529 }
530
531 #[test]
532 fn test_message_parse_empty_name() {
533 let data = b"BO_ 256 : 8 ECM";
534 let mut parser = Parser::new(data).unwrap();
535 const MAX_CAP: usize = crate::Signals::max_capacity();
536 let signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
537 let result = Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new());
538 assert!(result.is_err());
539 match result.unwrap_err() {
540 ParseError::Version(_) => {
541 }
543 _ => panic!("Expected ParseError::Version"),
544 }
545 }
546
547 #[test]
548 fn test_message_parse_invalid_dlc() {
549 let data = b"BO_ 256 EngineData : invalid ECM";
550 let mut parser = Parser::new(data).unwrap();
551 const MAX_CAP: usize = crate::Signals::max_capacity();
552 let signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
553 let result = Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new());
554 assert!(result.is_err());
555 match result.unwrap_err() {
556 ParseError::Version(_) => {
557 }
559 _ => panic!("Expected ParseError::Version"),
560 }
561 }
562
563 #[test]
564 fn test_message_parse_empty_sender() {
565 let data = b"BO_ 256 EngineData : 8 ";
566 let mut parser = Parser::new(data).unwrap();
567 const MAX_CAP: usize = crate::Signals::max_capacity();
568 let signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
569 let result = Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new());
570 assert!(result.is_err());
571 match result.unwrap_err() {
572 ParseError::Version(_) => {
573 }
575 _ => panic!("Expected ParseError::Version"),
576 }
577 }
578
579 #[test]
580 fn test_message_parse_with_signals() {
581 let data = b"BO_ 256 EngineData : 8 ECM";
582 let mut parser = Parser::new(data).unwrap();
583
584 let signal1 = Signal::parse(
586 &mut Parser::new(b"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] \"rpm\"").unwrap(),
587 )
588 .unwrap();
589 let signal2 = Signal::parse(
590 &mut Parser::new(b"SG_ Temp : 16|8@0- (1,-40) [-40|215] \"\xC2\xB0C\"").unwrap(),
591 )
592 .unwrap();
593
594 const MAX_CAP: usize = crate::Signals::max_capacity();
595 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
596 signals[0] = Some(signal1);
597 signals[1] = Some(signal2);
598
599 let message = Message::parse(&mut parser, &signals, 2, crate::ParseOptions::new()).unwrap();
600 assert_eq!(message.id(), 256);
601 assert_eq!(message.name(), "EngineData");
602 assert_eq!(message.dlc(), 8);
603 assert_eq!(message.sender(), "ECM");
604 assert_eq!(message.signals().len(), 2);
605 }
606
607 #[test]
608 fn test_message_signals_iterator() {
609 let data = b"BO_ 256 EngineData : 8 ECM";
610 let mut parser = Parser::new(data).unwrap();
611
612 let signal1 = Signal::parse(
614 &mut Parser::new(b"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] \"rpm\"").unwrap(),
615 )
616 .unwrap();
617 let signal2 = Signal::parse(
618 &mut Parser::new(b"SG_ Temp : 16|8@0- (1,-40) [-40|215] \"\xC2\xB0C\"").unwrap(),
619 )
620 .unwrap();
621
622 const MAX_CAP: usize = crate::Signals::max_capacity();
623 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
624 signals[0] = Some(signal1);
625 signals[1] = Some(signal2);
626
627 let message = Message::parse(&mut parser, &signals, 2, crate::ParseOptions::new()).unwrap();
628 let mut signals_iter = message.signals().iter();
629 assert_eq!(signals_iter.next().unwrap().name(), "RPM");
630 assert_eq!(signals_iter.next().unwrap().name(), "Temp");
631 assert!(signals_iter.next().is_none());
632 }
633
634 #[test]
635 fn test_message_signal_count() {
636 let data = b"BO_ 256 EngineData : 8 ECM";
637 let mut parser = Parser::new(data).unwrap();
638
639 let signals: [Option<Signal>; crate::Signals::max_capacity()] =
640 [const { None }; crate::Signals::max_capacity()];
641 let message = Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new()).unwrap();
642 assert_eq!(message.signals().len(), 0);
643
644 let data2 = b"BO_ 256 EngineData : 8 ECM";
646 let mut parser2 = Parser::new(data2).unwrap();
647 let signal1 = Signal::parse(
648 &mut Parser::new(b"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] \"rpm\"").unwrap(),
649 )
650 .unwrap();
651 const MAX_CAP: usize = crate::Signals::max_capacity();
652 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
653 signals[0] = Some(signal1);
654 let message =
655 Message::parse(&mut parser2, &signals, 1, crate::ParseOptions::new()).unwrap();
656 assert_eq!(message.signals().len(), 1);
657 }
658
659 #[test]
660 fn test_message_signal_at() {
661 let data = b"BO_ 256 EngineData : 8 ECM";
662 let mut parser = Parser::new(data).unwrap();
663
664 let signal1 = Signal::parse(
665 &mut Parser::new(b"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] \"rpm\"").unwrap(),
666 )
667 .unwrap();
668 let signal2 = Signal::parse(
669 &mut Parser::new(b"SG_ Temp : 16|8@0- (1,-40) [-40|215] \"\xC2\xB0C\"").unwrap(),
670 )
671 .unwrap();
672
673 const MAX_CAP: usize = crate::Signals::max_capacity();
674 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
675 signals[0] = Some(signal1);
676 signals[1] = Some(signal2);
677
678 let message = Message::parse(&mut parser, &signals, 2, crate::ParseOptions::new()).unwrap();
679 assert_eq!(message.signals().at(0).unwrap().name(), "RPM");
680 assert_eq!(message.signals().at(1).unwrap().name(), "Temp");
681 assert!(message.signals().at(2).is_none());
682 }
683
684 #[test]
685 fn test_message_find_signal() {
686 let data = b"BO_ 256 EngineData : 8 ECM";
687 let mut parser = Parser::new(data).unwrap();
688
689 let signal1 = Signal::parse(
690 &mut Parser::new(b"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] \"rpm\"").unwrap(),
691 )
692 .unwrap();
693 let signal2 = Signal::parse(
694 &mut Parser::new(b"SG_ Temp : 16|8@0- (1,-40) [-40|215] \"\xC2\xB0C\"").unwrap(),
695 )
696 .unwrap();
697
698 const MAX_CAP: usize = crate::Signals::max_capacity();
699 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
700 signals[0] = Some(signal1);
701 signals[1] = Some(signal2);
702
703 let message = Message::parse(&mut parser, &signals, 2, crate::ParseOptions::new()).unwrap();
704 assert_eq!(message.signals().find("RPM").unwrap().name(), "RPM");
705 assert_eq!(message.signals().find("Temp").unwrap().name(), "Temp");
706 assert!(message.signals().find("Nonexistent").is_none());
707 }
708
709 #[test]
710 #[cfg(feature = "alloc")]
711 fn test_message_to_dbc_string() {
712 let data = b"BO_ 256 EngineData : 8 ECM";
713 let mut parser = Parser::new(data).unwrap();
714 const MAX_CAP: usize = crate::Signals::max_capacity();
715 let signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
716 let message = Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new()).unwrap();
717 let dbc_string = message.to_dbc_string();
718 assert_eq!(dbc_string, "BO_ 256 EngineData : 8 ECM");
719 }
720
721 #[test]
722 #[cfg(feature = "alloc")]
723 fn test_message_to_dbc_string_with_signals() {
724 let data = b"BO_ 256 EngineData : 8 ECM";
725 let mut parser = Parser::new(data).unwrap();
726
727 let signal1 = Signal::parse(
728 &mut Parser::new(b"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] \"rpm\"").unwrap(),
729 )
730 .unwrap();
731 let signal2 = Signal::parse(
732 &mut Parser::new(b"SG_ Temp : 16|8@0- (1,-40) [-40|215] \"\xC2\xB0C\"").unwrap(),
733 )
734 .unwrap();
735
736 const MAX_CAP: usize = crate::Signals::max_capacity();
737 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
738 signals[0] = Some(signal1);
739 signals[1] = Some(signal2);
740
741 let message = Message::parse(&mut parser, &signals, 2, crate::ParseOptions::new()).unwrap();
742 let dbc_string = message.to_dbc_string_with_signals();
743 assert!(dbc_string.contains("BO_ 256 EngineData : 8 ECM"));
744 assert!(dbc_string.contains("SG_ RPM"));
745 assert!(dbc_string.contains("SG_ Temp"));
746 }
747
748 #[test]
749 #[cfg(any(feature = "alloc", feature = "kernel"))]
750 fn test_message_can_2_0a_dlc_limits() {
751 use alloc::format;
752 for dlc in 1..=8 {
755 let data = format!("BO_ 256 EngineData : {} ECM", dlc);
756 let mut parser = Parser::new(data.as_bytes()).unwrap();
757 const MAX_CAP: usize = crate::Signals::max_capacity();
758 let signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
759 let message =
760 Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new()).unwrap();
761 assert_eq!(message.dlc(), dlc);
762 }
763 }
764
765 #[test]
766 #[cfg(any(feature = "alloc", feature = "kernel"))]
767 fn test_message_can_2_0b_dlc_limits() {
768 use alloc::format;
769 for dlc in 1..=8 {
772 let data = format!("BO_ 256 EngineData : {} ECM", dlc);
773 let mut parser = Parser::new(data.as_bytes()).unwrap();
774 const MAX_CAP: usize = crate::Signals::max_capacity();
775 let signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
776 let message =
777 Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new()).unwrap();
778 assert_eq!(message.dlc(), dlc);
779 }
780 }
781
782 #[test]
783 #[cfg(any(feature = "alloc", feature = "kernel"))]
784 fn test_message_can_fd_dlc_limits() {
785 use alloc::format;
786 for dlc in [1, 8, 12, 16, 20, 24, 32, 48, 64] {
789 let data = format!("BO_ 256 EngineData : {} ECM", dlc);
790 let mut parser = Parser::new(data.as_bytes()).unwrap();
791 const MAX_CAP: usize = crate::Signals::max_capacity();
792 let signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
793 let message =
794 Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new()).unwrap();
795 assert_eq!(message.dlc(), dlc);
796 }
797 }
798
799 #[test]
800 fn test_message_multiple_signals_boundary_validation() {
801 let data = b"BO_ 256 EngineData : 8 ECM";
803 let mut parser = Parser::new(data).unwrap();
804
805 let signal1 =
808 Signal::parse(&mut Parser::new(b"SG_ Signal1 : 0|16@0+ (1,0) [0|65535] \"\"").unwrap())
809 .unwrap();
810 let signal2 = Signal::parse(
812 &mut Parser::new(b"SG_ Signal2 : 16|16@0+ (1,0) [0|65535] \"\"").unwrap(),
813 )
814 .unwrap();
815 let signal3 = Signal::parse(
817 &mut Parser::new(b"SG_ Signal3 : 32|16@0+ (1,0) [0|65535] \"\"").unwrap(),
818 )
819 .unwrap();
820 let signal4 = Signal::parse(
822 &mut Parser::new(b"SG_ Signal4 : 48|16@0+ (1,0) [0|65535] \"\"").unwrap(),
823 )
824 .unwrap();
825
826 const MAX_CAP: usize = crate::Signals::max_capacity();
827 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
828 signals[0] = Some(signal1);
829 signals[1] = Some(signal2);
830 signals[2] = Some(signal3);
831 signals[3] = Some(signal4);
832
833 let message = Message::parse(&mut parser, &signals, 4, crate::ParseOptions::new()).unwrap();
834 assert_eq!(message.signals().len(), 4);
835 }
836
837 #[test]
838 fn test_message_big_endian_bit_range_calculation() {
839 let data = b"BO_ 256 EngineData : 8 ECM";
845 let mut parser = Parser::new(data).unwrap();
846
847 let signal =
849 Signal::parse(&mut Parser::new(b"SG_ Signal1 : 0|8@1+ (1,0) [0|255] \"\"").unwrap())
850 .unwrap();
851
852 const MAX_CAP: usize = crate::Signals::max_capacity();
853 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
854 signals[0] = Some(signal);
855
856 let message = Message::parse(&mut parser, &signals, 1, crate::ParseOptions::new()).unwrap();
857 assert_eq!(message.signals().len(), 1);
859 }
860
861 #[test]
862 fn test_message_little_endian_bit_range_calculation() {
863 let data = b"BO_ 256 EngineData : 8 ECM";
866 let mut parser = Parser::new(data).unwrap();
867
868 let signal =
870 Signal::parse(&mut Parser::new(b"SG_ Signal1 : 0|8@0+ (1,0) [0|255] \"\"").unwrap())
871 .unwrap();
872
873 const MAX_CAP: usize = crate::Signals::max_capacity();
874 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
875 signals[0] = Some(signal);
876
877 let message = Message::parse(&mut parser, &signals, 1, crate::ParseOptions::new()).unwrap();
878 assert_eq!(message.signals().len(), 1);
880 }
881
882 #[test]
885 fn test_parse_with_lenient_boundary_check() {
886 let data = b"BO_ 256 Test : 8 ECM";
888 let mut parser = Parser::new(data).unwrap();
889
890 let signal =
892 Signal::parse(&mut Parser::new(b"SG_ CHECKSUM : 63|8@1+ (1,0) [0|255] \"\"").unwrap())
893 .unwrap();
894
895 const MAX_CAP: usize = crate::Signals::max_capacity();
896 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
897 signals[0] = Some(signal);
898
899 let result = Message::parse(&mut parser, &signals, 1, crate::ParseOptions::new());
901 assert!(result.is_err());
902
903 let mut parser2 = Parser::new(data).unwrap();
905 let message =
906 Message::parse(&mut parser2, &signals, 1, crate::ParseOptions::lenient()).unwrap();
907 assert_eq!(message.signals().len(), 1);
908 assert_eq!(message.signals().at(0).unwrap().name(), "CHECKSUM");
909 }
910
911 #[test]
912 #[cfg(feature = "alloc")]
913 fn test_message_to_dbc_string_empty_signals() {
914 let data = b"BO_ 256 EngineData : 8 ECM";
915 let mut parser = Parser::new(data).unwrap();
916 let signals: [Option<Signal>; crate::Signals::max_capacity()] =
917 [const { None }; crate::Signals::max_capacity()];
918 let message = Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new()).unwrap();
919
920 let dbc_string = message.to_dbc_string();
921 assert_eq!(dbc_string, "BO_ 256 EngineData : 8 ECM");
922
923 let dbc_string_with_signals = message.to_dbc_string_with_signals();
924 assert_eq!(dbc_string_with_signals, "BO_ 256 EngineData : 8 ECM\n");
925 }
926
927 #[test]
928 #[cfg(feature = "alloc")]
929 fn test_message_to_dbc_string_special_characters() {
930 let data = b"BO_ 1234 Test_Message_With_Underscores : 4 Sender_Node";
931 let mut parser = Parser::new(data).unwrap();
932 let signals: [Option<Signal>; crate::Signals::max_capacity()] =
933 [const { None }; crate::Signals::max_capacity()];
934 let message = Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new()).unwrap();
935
936 let dbc_string = message.to_dbc_string();
937 assert_eq!(
938 dbc_string,
939 "BO_ 1234 Test_Message_With_Underscores : 4 Sender_Node"
940 );
941 }
942
943 #[test]
944 #[cfg(feature = "alloc")]
945 fn test_message_to_dbc_string_extended_id() {
946 let data = b"BO_ 536870911 ExtendedID : 8 ECM";
948 let mut parser = Parser::new(data).unwrap();
949 let signals: [Option<Signal>; crate::Signals::max_capacity()] =
950 [const { None }; crate::Signals::max_capacity()];
951 let message = Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new()).unwrap();
952
953 let dbc_string = message.to_dbc_string();
954 assert_eq!(dbc_string, "BO_ 536870911 ExtendedID : 8 ECM");
955 }
956
957 #[test]
958 #[cfg(feature = "alloc")]
959 fn test_message_to_dbc_string_dlc_edge_cases() {
960 let data = b"BO_ 256 MinDLC : 1 ECM";
962 let mut parser = Parser::new(data).unwrap();
963 let signals: [Option<Signal>; crate::Signals::max_capacity()] =
964 [const { None }; crate::Signals::max_capacity()];
965 let message = Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new()).unwrap();
966 assert_eq!(message.to_dbc_string(), "BO_ 256 MinDLC : 1 ECM");
967
968 let data2 = b"BO_ 257 MaxDLC : 64 ECM";
970 let mut parser2 = Parser::new(data2).unwrap();
971 let message2 =
972 Message::parse(&mut parser2, &signals, 0, crate::ParseOptions::new()).unwrap();
973 assert_eq!(message2.to_dbc_string(), "BO_ 257 MaxDLC : 64 ECM");
974 }
975
976 #[test]
977 fn test_message_signals_is_empty() {
978 let data = b"BO_ 256 EngineData : 8 ECM";
979 let mut parser = Parser::new(data).unwrap();
980 let signals: [Option<Signal>; crate::Signals::max_capacity()] =
981 [const { None }; crate::Signals::max_capacity()];
982 let message = Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new()).unwrap();
983 assert!(message.signals().is_empty());
984 assert_eq!(message.signals().len(), 0);
985 }
986
987 #[test]
988 fn test_message_signals_at_out_of_bounds() {
989 let data = b"BO_ 256 EngineData : 8 ECM";
990 let mut parser = Parser::new(data).unwrap();
991
992 let signal = Signal::parse(
993 &mut Parser::new(b"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] \"rpm\"").unwrap(),
994 )
995 .unwrap();
996
997 const MAX_CAP: usize = crate::Signals::max_capacity();
998 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
999 signals[0] = Some(signal);
1000
1001 let message = Message::parse(&mut parser, &signals, 1, crate::ParseOptions::new()).unwrap();
1002
1003 assert!(message.signals().at(0).is_some());
1005 assert_eq!(message.signals().at(0).unwrap().name(), "RPM");
1006
1007 assert!(message.signals().at(1).is_none());
1009 assert!(message.signals().at(100).is_none());
1010 assert!(message.signals().at(usize::MAX).is_none());
1011 }
1012
1013 #[test]
1014 fn test_message_signals_find_case_sensitive() {
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
1034 assert!(message.signals().find("RPM").is_some());
1036 assert_eq!(message.signals().find("RPM").unwrap().name(), "RPM");
1037
1038 assert!(message.signals().find("rpm").is_none());
1040 assert!(message.signals().find("Rpm").is_none());
1041
1042 assert!(message.signals().find("Temp").is_some());
1044 assert_eq!(message.signals().find("Temp").unwrap().name(), "Temp");
1045
1046 assert!(message.signals().find("Nonexistent").is_none());
1048 assert!(message.signals().find("").is_none());
1049 }
1050
1051 #[test]
1052 fn test_message_signals_find_empty_collection() {
1053 let data = b"BO_ 256 EngineData : 8 ECM";
1054 let mut parser = Parser::new(data).unwrap();
1055 let signals: [Option<Signal>; crate::Signals::max_capacity()] =
1056 [const { None }; crate::Signals::max_capacity()];
1057 let message = Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new()).unwrap();
1058
1059 assert!(message.signals().find("RPM").is_none());
1060 assert!(message.signals().find("").is_none());
1061 }
1062
1063 #[test]
1064 #[cfg(feature = "alloc")]
1065 fn test_message_display_trait() {
1066 use alloc::format;
1067 let data = b"BO_ 256 EngineData : 8 ECM";
1068 let mut parser = Parser::new(data).unwrap();
1069
1070 let signal = Signal::parse(
1072 &mut Parser::new(b"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] \"rpm\" *").unwrap(),
1073 )
1074 .unwrap();
1075
1076 const MAX_CAP: usize = crate::Signals::max_capacity();
1077 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
1078 signals[0] = Some(signal);
1079
1080 let message = Message::parse(&mut parser, &signals, 1, crate::ParseOptions::new()).unwrap();
1081
1082 let display_str = format!("{}", message);
1083 assert!(display_str.contains("BO_ 256 EngineData : 8 ECM"));
1084 assert!(display_str.contains("SG_ RPM"));
1085 }
1086
1087 #[test]
1088 #[cfg(feature = "alloc")]
1089 fn test_message_to_dbc_string_with_signals_multiple() {
1090 let data = b"BO_ 256 EngineData : 8 ECM";
1091 let mut parser = Parser::new(data).unwrap();
1092
1093 let signal1 = Signal::parse(
1095 &mut Parser::new(b"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] \"rpm\" *").unwrap(),
1096 )
1097 .unwrap();
1098
1099 let signal2 = Signal::parse(
1100 &mut Parser::new(b"SG_ Temp : 16|8@0- (1,-40) [-40|215] \"\xC2\xB0C\" *").unwrap(),
1101 )
1102 .unwrap();
1103
1104 const MAX_CAP: usize = crate::Signals::max_capacity();
1105 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
1106 signals[0] = Some(signal1);
1107 signals[1] = Some(signal2);
1108
1109 let message = Message::parse(&mut parser, &signals, 2, crate::ParseOptions::new()).unwrap();
1110
1111 let dbc_string = message.to_dbc_string_with_signals();
1112 assert!(dbc_string.contains("BO_ 256 EngineData : 8 ECM"));
1113 assert!(dbc_string.contains("SG_ RPM"));
1114 assert!(dbc_string.contains("SG_ Temp"));
1115 #[cfg(any(feature = "alloc", feature = "kernel"))]
1117 use crate::compat::Vec;
1118 let lines: Vec<&str> = dbc_string.lines().collect();
1119 assert!(lines.len() >= 3); }
1121
1122 #[test]
1123 fn test_message_getters_edge_cases() {
1124 let data = b"BO_ 0 A : 1 B";
1126 let mut parser = Parser::new(data).unwrap();
1127 let signals: [Option<Signal>; crate::Signals::max_capacity()] =
1128 [const { None }; crate::Signals::max_capacity()];
1129 let message = Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new()).unwrap();
1130
1131 assert_eq!(message.id(), 0);
1132 assert_eq!(message.name(), "A");
1133 assert_eq!(message.dlc(), 1);
1134 assert_eq!(message.sender(), "B");
1135 }
1136
1137 #[test]
1138 fn test_message_signals_iterator_empty() {
1139 let data = b"BO_ 256 EngineData : 8 ECM";
1140 let mut parser = Parser::new(data).unwrap();
1141 let signals: [Option<Signal>; crate::Signals::max_capacity()] =
1142 [const { None }; crate::Signals::max_capacity()];
1143 let message = Message::parse(&mut parser, &signals, 0, crate::ParseOptions::new()).unwrap();
1144
1145 let mut iter = message.signals().iter();
1146 assert!(iter.next().is_none());
1147 }
1148
1149 #[test]
1150 fn test_message_signals_iterator_multiple() {
1151 let data = b"BO_ 256 EngineData : 8 ECM";
1152 let mut parser = Parser::new(data).unwrap();
1153
1154 let signal1 =
1155 Signal::parse(&mut Parser::new(b"SG_ Signal1 : 0|8@0+ (1,0) [0|255] \"\"").unwrap())
1156 .unwrap();
1157 let signal2 =
1158 Signal::parse(&mut Parser::new(b"SG_ Signal2 : 8|8@0+ (1,0) [0|255] \"\"").unwrap())
1159 .unwrap();
1160 let signal3 =
1161 Signal::parse(&mut Parser::new(b"SG_ Signal3 : 16|8@0+ (1,0) [0|255] \"\"").unwrap())
1162 .unwrap();
1163
1164 const MAX_CAP: usize = crate::Signals::max_capacity();
1165 let mut signals: [Option<Signal>; MAX_CAP] = [const { None }; MAX_CAP];
1166 signals[0] = Some(signal1);
1167 signals[1] = Some(signal2);
1168 signals[2] = Some(signal3);
1169
1170 let message = Message::parse(&mut parser, &signals, 3, crate::ParseOptions::new()).unwrap();
1171
1172 let mut iter = message.signals().iter();
1173 assert_eq!(iter.next().unwrap().name(), "Signal1");
1174 assert_eq!(iter.next().unwrap().name(), "Signal2");
1175 assert_eq!(iter.next().unwrap().name(), "Signal3");
1176 assert!(iter.next().is_none());
1177
1178 #[cfg(any(feature = "alloc", feature = "kernel"))]
1180 {
1181 use crate::compat::Vec;
1182 use alloc::vec;
1183 let names: Vec<&str> = message.signals().iter().map(|s| s.name()).collect();
1184 #[cfg(feature = "kernel")]
1186 let names: alloc::vec::Vec<&str> = names.into();
1187 assert_eq!(names, vec!["Signal1", "Signal2", "Signal3"]);
1188 }
1189 }
1190}