1use crate::{
2 ByteOrder, Error, MAX_NAME_SIZE, Parser, Receivers, Result, compat::String, error::lang,
3};
4
5#[derive(Debug, Clone, PartialEq)]
6pub struct Signal {
7 name: String<{ MAX_NAME_SIZE }>,
8 start_bit: u16,
9 length: u16,
10 byte_order: ByteOrder,
11 unsigned: bool,
12 factor: f64,
13 offset: f64,
14 min: f64,
15 max: f64,
16 unit: Option<String<{ MAX_NAME_SIZE }>>,
17 receivers: Receivers,
18}
19
20impl Signal {
21 pub(crate) fn validate(name: &str, length: u16, min: f64, max: f64) -> Result<()> {
22 if name.trim().is_empty() {
23 return Err(Error::Validation(lang::SIGNAL_NAME_EMPTY));
24 }
25
26 if length == 0 {
32 return Err(Error::Validation(lang::SIGNAL_LENGTH_TOO_SMALL));
33 }
34 if length > 512 {
35 return Err(Error::Validation(lang::SIGNAL_LENGTH_TOO_LARGE));
36 }
37
38 if min > max {
46 return Err(Error::Validation(lang::INVALID_RANGE));
47 }
48
49 Ok(())
50 }
51
52 #[cfg(feature = "std")]
53 #[allow(clippy::too_many_arguments)] pub(crate) fn new(
55 name: String<{ MAX_NAME_SIZE }>,
56 start_bit: u16,
57 length: u16,
58 byte_order: ByteOrder,
59 unsigned: bool,
60 factor: f64,
61 offset: f64,
62 min: f64,
63 max: f64,
64 unit: Option<String<{ MAX_NAME_SIZE }>>,
65 receivers: Receivers,
66 ) -> Self {
67 Self {
69 name,
70 start_bit,
71 length,
72 byte_order,
73 unsigned,
74 factor,
75 offset,
76 min,
77 max,
78 unit,
79 receivers,
80 }
81 }
82
83 fn parse_position<'b>(parser: &mut Parser<'b>) -> Result<(u16, u16, ByteOrder, bool)> {
84 let start_bit = match parser.parse_u32() {
86 Ok(v) => v as u16,
87 Err(_) => {
88 return Err(Error::Signal(lang::SIGNAL_PARSE_INVALID_START_BIT));
89 }
90 };
91
92 if start_bit > 511 {
94 return Err(Error::Signal(lang::SIGNAL_PARSE_INVALID_START_BIT));
95 }
96
97 parser.expect(b"|").map_err(|_| Error::Expected("Expected pipe"))?;
99
100 let length = parser
102 .parse_u32()
103 .map_err(|_| Error::Signal(lang::SIGNAL_PARSE_INVALID_LENGTH))?
104 as u16;
105
106 parser.expect(b"@").map_err(|_| Error::Expected("Expected @"))?;
108
109 let bo_byte = if parser.expect(b"0").is_ok() {
112 b'0'
113 } else if parser.expect(b"1").is_ok() {
114 b'1'
115 } else {
116 return Err(Error::Expected("Expected byte order"));
117 };
118
119 let byte_order = match bo_byte {
120 b'0' => ByteOrder::BigEndian, b'1' => ByteOrder::LittleEndian, _ => return Err(Error::InvalidChar(bo_byte as char)),
123 };
124
125 let sign_byte = if parser.expect(b"+").is_ok() {
127 b'+'
128 } else if parser.expect(b"-").is_ok() {
129 b'-'
130 } else {
131 return Err(Error::Expected("Expected sign (+ or -)"));
132 };
133
134 let unsigned = match sign_byte {
135 b'+' => true,
136 b'-' => false,
137 _ => return Err(Error::InvalidChar(sign_byte as char)),
138 };
139
140 Ok((start_bit, length, byte_order, unsigned))
141 }
142
143 fn parse_factor_offset<'b>(parser: &mut Parser<'b>) -> Result<(f64, f64)> {
144 parser
146 .expect(b"(")
147 .map_err(|_| Error::Expected("Expected opening parenthesis"))?;
148
149 parser.skip_newlines_and_spaces();
151
152 let pos_before = parser.pos();
156 let factor = match parser.parse_f64() {
157 Ok(val) => val,
158 Err(_) => {
159 if parser.pos() == pos_before {
161 0.0 } else {
163 return Err(Error::Signal(lang::SIGNAL_PARSE_INVALID_FACTOR));
165 }
166 }
167 };
168
169 parser.expect(b",").map_err(|_| Error::Expected("Expected comma"))?;
171
172 parser.skip_newlines_and_spaces();
174
175 let pos_before = parser.pos();
177 let offset = match parser.parse_f64() {
178 Ok(val) => val,
179 Err(_) => {
180 if parser.pos() == pos_before {
182 0.0 } else {
184 return Err(Error::Signal(
185 crate::error::lang::SIGNAL_PARSE_INVALID_OFFSET,
186 ));
187 }
188 }
189 };
190
191 parser.skip_newlines_and_spaces();
193
194 parser
196 .expect(b")")
197 .map_err(|_| Error::Expected("Expected closing parenthesis"))?;
198
199 Ok((factor, offset))
200 }
201
202 fn parse_range<'b>(parser: &mut Parser<'b>) -> Result<(f64, f64)> {
203 parser.expect(b"[").map_err(|_| Error::Expected("Expected opening bracket"))?;
205
206 parser.skip_newlines_and_spaces();
208
209 let pos_before = parser.pos();
211 let min = match parser.parse_f64() {
212 Ok(val) => val,
213 Err(_) => {
214 if parser.pos() == pos_before {
216 0.0 } else {
218 return Err(Error::Signal(crate::error::lang::SIGNAL_PARSE_INVALID_MIN));
219 }
220 }
221 };
222
223 parser.expect(b"|").map_err(|_| Error::Expected("Expected pipe"))?;
225
226 parser.skip_newlines_and_spaces();
228
229 let pos_before = parser.pos();
231 let max = match parser.parse_f64() {
232 Ok(val) => val,
233 Err(_) => {
234 if parser.pos() == pos_before {
236 0.0 } else {
238 return Err(Error::Signal(crate::error::lang::SIGNAL_PARSE_INVALID_MAX));
239 }
240 }
241 };
242
243 parser.skip_newlines_and_spaces();
245
246 parser.expect(b"]").map_err(|_| Error::Expected("Expected closing bracket"))?;
248
249 Ok((min, max))
250 }
251
252 fn parse_unit(parser: &mut Parser) -> Result<Option<String<{ MAX_NAME_SIZE }>>> {
253 parser.expect(b"\"").map_err(|_| Error::Expected("Expected opening quote"))?;
255
256 let unit_bytes = parser.take_until_quote(false, MAX_NAME_SIZE).map_err(|e| match e {
258 Error::MaxStrLength(_) => Error::Signal(crate::error::lang::SIGNAL_PARSE_UNIT_TOO_LONG),
259 _ => Error::Expected("Expected closing quote"),
260 })?;
261
262 let unit =
264 core::str::from_utf8(unit_bytes).map_err(|_e| Error::Expected(lang::INVALID_UTF8))?;
265
266 let unit: String<{ MAX_NAME_SIZE }> =
267 String::try_from(unit).map_err(|_| Error::Version(lang::MAX_NAME_SIZE_EXCEEDED))?;
268
269 let unit = if unit.is_empty() { None } else { Some(unit) };
270 Ok(unit)
271 }
272
273 pub(crate) fn parse(parser: &mut Parser) -> Result<Self> {
274 parser
276 .expect(crate::SG_.as_bytes())
277 .map_err(|_| Error::Expected("Expected SG_ keyword"))?;
278
279 parser.skip_newlines_and_spaces();
281
282 let name = parser
284 .parse_identifier()
285 .map_err(|_| Error::Signal(crate::error::lang::SIGNAL_NAME_EMPTY))?;
286
287 parser.skip_newlines_and_spaces();
291
292 if parser.expect(b"m").is_ok() || parser.expect(b"M").is_ok() {
295 loop {
297 let _pos_before = parser.pos();
298 if parser.expect(b"0").is_ok()
300 || parser.expect(b"1").is_ok()
301 || parser.expect(b"2").is_ok()
302 || parser.expect(b"3").is_ok()
303 || parser.expect(b"4").is_ok()
304 || parser.expect(b"5").is_ok()
305 || parser.expect(b"6").is_ok()
306 || parser.expect(b"7").is_ok()
307 || parser.expect(b"8").is_ok()
308 || parser.expect(b"9").is_ok()
309 {
310 } else {
312 break;
314 }
315 }
316 parser.skip_newlines_and_spaces();
318 }
319
320 parser.expect(b":").map_err(|_| Error::Expected("Expected colon"))?;
322
323 parser.skip_newlines_and_spaces();
325
326 let (start_bit, length, byte_order, unsigned) = Self::parse_position(parser)?;
328
329 parser.skip_newlines_and_spaces();
331
332 let (factor, offset) = Self::parse_factor_offset(parser)?;
334
335 parser.skip_newlines_and_spaces();
337
338 let (min, max) = Self::parse_range(parser)?;
340
341 parser.skip_newlines_and_spaces();
343
344 let unit = Self::parse_unit(parser)?;
346
347 let _ = parser.skip_whitespace().ok(); let receivers = Receivers::parse(parser)?;
353
354 Self::validate(name, length, min, max).map_err(|e| {
356 crate::error::map_val_error(e, Error::Signal, || {
357 Error::Signal(crate::error::lang::SIGNAL_ERROR_PREFIX)
358 })
359 })?;
360
361 let name = crate::validate_name(name)?;
362
363 Ok(Self {
365 name,
366 start_bit,
367 length,
368 byte_order,
369 unsigned,
370 factor,
371 offset,
372 min,
373 max,
374 unit,
375 receivers,
376 })
377 }
378
379 #[inline]
380 #[must_use = "return value should be checked"]
381 pub fn name(&self) -> &str {
382 self.name.as_ref()
383 }
384
385 #[inline]
386 #[must_use]
387 pub fn start_bit(&self) -> u16 {
388 self.start_bit
389 }
390
391 #[inline]
392 #[must_use]
393 pub fn length(&self) -> u16 {
394 self.length
395 }
396
397 #[inline]
398 #[must_use]
399 pub fn byte_order(&self) -> ByteOrder {
400 self.byte_order
401 }
402
403 #[inline]
404 #[must_use]
405 pub fn is_unsigned(&self) -> bool {
406 self.unsigned
407 }
408
409 #[inline]
410 #[must_use]
411 pub fn factor(&self) -> f64 {
412 self.factor
413 }
414
415 #[inline]
416 #[must_use]
417 pub fn offset(&self) -> f64 {
418 self.offset
419 }
420
421 #[inline]
422 #[must_use]
423 pub fn min(&self) -> f64 {
424 self.min
425 }
426
427 #[inline]
428 #[must_use]
429 pub fn max(&self) -> f64 {
430 self.max
431 }
432
433 #[inline]
434 #[must_use]
435 pub fn unit(&self) -> Option<&str> {
436 self.unit.as_ref().map(|u| u.as_ref())
437 }
438
439 #[inline]
440 #[must_use]
441 pub fn receivers(&self) -> &Receivers {
442 &self.receivers
443 }
444
445 pub fn decode(&self, data: &[u8]) -> Result<f64> {
482 let start_bit = self.start_bit as usize;
483 let length = self.length as usize;
484 let end_byte = (start_bit + length - 1) / 8;
485
486 if end_byte >= data.len() {
487 return Err(Error::Decoding(lang::SIGNAL_EXTENDS_BEYOND_DATA));
488 }
489
490 let raw_value = match self.byte_order {
492 ByteOrder::LittleEndian => Self::extract_bits_little_endian(data, start_bit, length),
493 ByteOrder::BigEndian => Self::extract_bits_big_endian(data, start_bit, length),
494 };
495
496 let value = if self.unsigned {
498 raw_value as i64
499 } else {
500 let sign_bit = 1u64 << (length - 1);
502 if (raw_value & sign_bit) != 0 {
503 let mask = !((1u64 << length) - 1);
505 (raw_value | mask) as i64
506 } else {
507 raw_value as i64
508 }
509 };
510
511 Ok((value as f64) * self.factor + self.offset)
513 }
514
515 fn extract_bits_little_endian(data: &[u8], start_bit: usize, length: usize) -> u64 {
517 let mut value: u64 = 0;
518 let mut bits_remaining = length;
519 let mut current_bit = start_bit;
520
521 while bits_remaining > 0 {
522 let byte_idx = current_bit / 8;
523 let bit_in_byte = current_bit % 8;
524 let bits_to_take = bits_remaining.min(8 - bit_in_byte);
525
526 let byte = data[byte_idx] as u64;
527 let mask = ((1u64 << bits_to_take) - 1) << bit_in_byte;
528 let extracted = (byte & mask) >> bit_in_byte;
529
530 value |= extracted << (length - bits_remaining);
531
532 bits_remaining -= bits_to_take;
533 current_bit += bits_to_take;
534 }
535
536 value
537 }
538
539 fn extract_bits_big_endian(data: &[u8], start_bit: usize, length: usize) -> u64 {
541 let mut value: u64 = 0;
542 let mut bits_remaining = length;
543 let mut current_bit = start_bit;
544
545 while bits_remaining > 0 {
546 let byte_idx = current_bit / 8;
547 let bit_in_byte = current_bit % 8;
548 let bits_to_take = bits_remaining.min(8 - bit_in_byte);
549
550 let byte = data[byte_idx] as u64;
551 let mask = ((1u64 << bits_to_take) - 1) << bit_in_byte;
552 let extracted = (byte & mask) >> bit_in_byte;
553
554 value |= extracted << (length - bits_remaining);
557
558 bits_remaining -= bits_to_take;
559 current_bit += bits_to_take;
560 }
561
562 value
563 }
564
565 #[cfg(feature = "std")]
566 #[must_use]
567 pub fn to_dbc_string(&self) -> std::string::String {
568 let mut result = std::string::String::with_capacity(100); result.push_str(" SG_ ");
571 result.push_str(self.name());
572 result.push_str(" : ");
573 result.push_str(&self.start_bit().to_string());
574 result.push('|');
575 result.push_str(&self.length().to_string());
576 result.push('@');
577
578 match self.byte_order() {
581 ByteOrder::BigEndian => result.push('0'), ByteOrder::LittleEndian => result.push('1'), }
584
585 if self.is_unsigned() {
587 result.push('+');
588 } else {
589 result.push('-');
590 }
591
592 result.push_str(" (");
594 use core::fmt::Write;
595 write!(result, "{}", self.factor()).unwrap();
596 result.push(',');
597 write!(result, "{}", self.offset()).unwrap();
598 result.push(')');
599
600 result.push_str(" [");
602 write!(result, "{}", self.min()).unwrap();
603 result.push('|');
604 write!(result, "{}", self.max()).unwrap();
605 result.push(']');
606
607 result.push(' ');
609 if let Some(unit) = self.unit() {
610 result.push('"');
611 result.push_str(unit);
612 result.push('"');
613 } else {
614 result.push_str("\"\"");
615 }
616
617 match self.receivers() {
619 Receivers::Broadcast => {
620 result.push(' ');
621 result.push('*');
622 }
623 Receivers::Nodes(nodes) => {
624 if !nodes.is_empty() {
625 result.push(' ');
626 for (i, node) in self.receivers().iter().enumerate() {
627 if i > 0 {
628 result.push(' ');
629 }
630 result.push_str(node.as_str());
631 }
632 }
633 }
634 Receivers::None => {
635 }
637 }
638
639 result
640 }
641}
642
643impl Eq for Signal {}
645
646impl core::hash::Hash for Signal {
648 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
649 self.name.hash(state);
650 self.start_bit.hash(state);
651 self.length.hash(state);
652 self.byte_order.hash(state);
653 self.unsigned.hash(state);
654 self.factor.to_bits().hash(state);
656 self.offset.to_bits().hash(state);
657 self.min.to_bits().hash(state);
658 self.max.to_bits().hash(state);
659 self.unit.hash(state);
660 self.receivers.hash(state);
661 }
662}
663
664#[cfg(feature = "std")]
665impl core::fmt::Display for Signal {
666 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
667 write!(f, "{}", self.to_dbc_string())
668 }
669}
670
671#[cfg(test)]
672mod tests {
673 #![allow(clippy::float_cmp)]
674 use super::*;
675 use crate::{Parser, error::lang};
676
677 #[test]
678 fn test_parse_valid_signal() {
679 let line = r#"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] "rpm" TCM"#;
680 let mut parser = Parser::new(line.as_bytes()).unwrap();
681 let sig = Signal::parse(&mut parser).unwrap();
682 assert_eq!(sig.name(), "RPM");
683 assert_eq!(sig.start_bit(), 0);
684 assert_eq!(sig.length(), 16);
685 assert_eq!(sig.byte_order(), ByteOrder::BigEndian); assert!(sig.is_unsigned());
687 assert_eq!(sig.factor(), 0.25);
688 assert_eq!(sig.offset(), 0.);
689 assert_eq!(sig.min(), 0.);
690 assert_eq!(sig.max(), 8000.);
691 assert_eq!(sig.unit(), Some("rpm"));
692 let mut receivers_iter = sig.receivers().iter();
694 let receiver1 = receivers_iter.next().unwrap();
695 assert_eq!(receiver1.as_str(), "TCM");
696 assert_eq!(receivers_iter.next(), None);
697 }
698
699 #[test]
700 fn test_parse_signal_with_empty_unit_and_broadcast() {
701 let line = r#"SG_ ABSActive : 16|1@0+ (1,0) [0|1] "" *"#;
702 let mut parser = Parser::new(line.as_bytes()).unwrap();
703 let sig = Signal::parse(&mut parser).unwrap();
704 assert_eq!(sig.name(), "ABSActive");
705 assert_eq!(sig.start_bit(), 16);
706 assert_eq!(sig.length(), 1);
707 assert_eq!(sig.byte_order(), ByteOrder::BigEndian); assert!(sig.is_unsigned());
709 assert_eq!(sig.factor(), 1.);
710 assert_eq!(sig.offset(), 0.);
711 assert_eq!(sig.min(), 0.);
712 assert_eq!(sig.max(), 1.);
713 assert_eq!(sig.unit(), None);
714 assert_eq!(sig.receivers(), &Receivers::Broadcast);
715 }
716
717 #[test]
718 fn test_parse_signal_with_negative_offset_and_min() {
719 let line = r#"SG_ Temperature : 16|8@0- (1,-40) [-40|215] "°C" TCM BCM"#;
720 let mut parser = Parser::new(line.as_bytes()).unwrap();
721 let sig = Signal::parse(&mut parser).unwrap();
722 assert_eq!(sig.name(), "Temperature");
723 assert_eq!(sig.start_bit(), 16);
724 assert_eq!(sig.length(), 8);
725 assert_eq!(sig.byte_order(), ByteOrder::BigEndian); assert!(!sig.is_unsigned());
727 assert_eq!(sig.factor(), 1.);
728 assert_eq!(sig.offset(), -40.);
729 assert_eq!(sig.min(), -40.);
730 assert_eq!(sig.max(), 215.);
731 assert_eq!(sig.unit(), Some("°C"));
732 let mut receivers_iter = sig.receivers().iter();
734 let receiver1 = receivers_iter.next().unwrap();
735 assert_eq!(receiver1.as_str(), "TCM");
736 let receiver2 = receivers_iter.next().unwrap();
737 assert_eq!(receiver2.as_str(), "BCM");
738 assert_eq!(receivers_iter.next(), None);
739 }
740
741 #[test]
742 fn test_parse_signal_with_percent_unit() {
743 let line = r#"SG_ ThrottlePosition : 24|8@0+ (0.392157,0) [0|100] "%" *"#;
744 let mut parser = Parser::new(line.as_bytes()).unwrap();
745 let sig = Signal::parse(&mut parser).unwrap();
746 assert_eq!(sig.name(), "ThrottlePosition");
747 assert_eq!(sig.start_bit(), 24);
748 assert_eq!(sig.length(), 8);
749 assert_eq!(sig.byte_order(), ByteOrder::BigEndian); assert!(sig.is_unsigned());
751 assert_eq!(sig.factor(), 0.392_157);
752 assert_eq!(sig.offset(), 0.);
753 assert_eq!(sig.min(), 0.);
754 assert_eq!(sig.max(), 100.);
755 assert_eq!(sig.unit(), Some("%"));
756 assert_eq!(sig.receivers(), &Receivers::Broadcast);
757 }
758
759 #[test]
760 fn test_parse_signal_missing_factors_and_limits() {
761 let line = r#"SG_ Simple : 10|4@0+ ( , ) [ | ] "" *"#;
763 let mut parser = Parser::new(line.as_bytes()).unwrap();
764 let sig = Signal::parse(&mut parser).unwrap();
765 assert_eq!(sig.name(), "Simple");
766 assert_eq!(sig.start_bit(), 10);
767 assert_eq!(sig.length(), 4);
768 assert_eq!(sig.byte_order(), ByteOrder::BigEndian); assert!(sig.is_unsigned());
770 assert_eq!(sig.factor(), 0.);
771 assert_eq!(sig.offset(), 0.);
772 assert_eq!(sig.min(), 0.);
773 assert_eq!(sig.max(), 0.);
774 assert_eq!(sig.unit(), None);
775 assert_eq!(sig.receivers(), &Receivers::Broadcast);
776 }
777
778 #[test]
779 fn test_parse_signal_missing_start_bit() {
780 let line = r#"SG_ RPM : |16@0+ (0.25,0) [0|8000] "rpm" TCM"#;
781 let mut parser = Parser::new(line.as_bytes()).unwrap();
782 let err = Signal::parse(&mut parser).unwrap_err();
783 match err {
784 Error::Signal(msg) => {
785 assert!(
787 msg.contains(lang::SIGNAL_PARSE_INVALID_START_BIT)
788 || msg.contains("Signal 'RPM'")
789 );
790 }
791 _ => panic!("Expected Error::Signal"),
792 }
793 }
794
795 #[test]
796 fn test_parse_signal_invalid_range() {
797 let line = r#"SG_ Test : 0|8@0+ (1,0) [100|50] "unit" *"#;
799 let mut parser = Parser::new(line.as_bytes()).unwrap();
800 let err = Signal::parse(&mut parser).unwrap_err();
801 match err {
802 Error::Signal(msg) => {
803 assert!(msg.contains(lang::INVALID_RANGE));
804 }
805 e => panic!("Expected Error::Signal, got: {:?}", e),
806 }
807 }
808
809 #[test]
810 fn test_parse_signal_overflow() {
811 let line = r#"SG_ Test : 60|10@0+ (1,0) [0|100] "unit" *"#;
815 let mut parser = Parser::new(line.as_bytes()).unwrap();
816 let signal = Signal::parse(&mut parser).unwrap();
817 assert_eq!(signal.start_bit(), 60);
818 assert_eq!(signal.length(), 10);
819 }
821
822 #[test]
823 fn test_parse_signal_length_too_large() {
824 let line = r#"SG_ Test : 0|513@0+ (1,0) [0|100] "unit" *"#;
826 let mut parser = Parser::new(line.as_bytes()).unwrap();
827 let err = Signal::parse(&mut parser).unwrap_err();
828 match err {
829 Error::Signal(msg) => {
830 assert!(
832 msg.contains(lang::SIGNAL_LENGTH_TOO_LARGE)
833 || msg.contains("Signal 'Test'")
834 || msg.contains("513")
835 );
836 }
837 e => panic!("Expected Error::Signal, got: {:?}", e),
838 }
839 }
840
841 #[test]
842 fn test_parse_signal_zero_length() {
843 let line = r#"SG_ Test : 0|0@0+ (1,0) [0|100] "unit" *"#;
845 let mut parser = Parser::new(line.as_bytes()).unwrap();
846 let err = Signal::parse(&mut parser).unwrap_err();
847 match err {
848 Error::Signal(msg) => {
849 assert!(
851 msg.contains(lang::SIGNAL_LENGTH_TOO_SMALL)
852 || msg.contains("Signal 'Test'")
853 || msg.contains("0 bits")
854 );
855 }
856 e => panic!("Expected Error::Signal, got: {:?}", e),
857 }
858 }
859
860 #[test]
861 fn test_parse_signal_missing_length() {
862 let line = r#"SG_ RPM : 0|@0+ (0.25,0) [0|8000] "rpm" TCM"#;
863 let mut parser = Parser::new(line.as_bytes()).unwrap();
864 let err = Signal::parse(&mut parser).unwrap_err();
865 match err {
866 Error::Signal(msg) => assert!(msg.contains(lang::SIGNAL_PARSE_INVALID_LENGTH)),
867 e => panic!("Expected Error::Signal, got: {:?}", e),
868 }
869 }
870
871 #[cfg(feature = "std")]
873 mod tests_with_std {
874 use super::*;
875
876 #[test]
877 fn test_signal_to_dbc_string_round_trip() {
878 let test_cases = vec![
880 (
881 r#"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] "rpm" *"#,
882 " SG_ RPM : 0|16@0+ (0.25,0) [0|8000] \"rpm\" *",
883 ),
884 (
885 r#"SG_ Temperature : 16|8@1- (1,-40) [-40|215] "°C" TCM BCM"#,
886 " SG_ Temperature : 16|8@1- (1,-40) [-40|215] \"°C\" TCM BCM",
887 ),
888 (
889 r#"SG_ Flag : 24|1@0+ (1,0) [0|1] "" *"#,
890 " SG_ Flag : 24|1@0+ (1,0) [0|1] \"\" *",
891 ),
892 ];
893
894 for (input_line, expected_output) in test_cases {
895 let mut parser = Parser::new(input_line.as_bytes()).unwrap();
897 let signal = Signal::parse(&mut parser).unwrap();
898
899 let dbc_string = signal.to_dbc_string();
901 assert_eq!(dbc_string, expected_output);
902
903 let mut parser2 = Parser::new(dbc_string.as_bytes()).unwrap();
905 parser2.skip_newlines_and_spaces();
907 let signal2 = Signal::parse(&mut parser2).unwrap();
908
909 assert_eq!(signal.name(), signal2.name());
911 assert_eq!(signal.start_bit(), signal2.start_bit());
912 assert_eq!(signal.length(), signal2.length());
913 assert_eq!(signal.byte_order(), signal2.byte_order());
914 assert_eq!(signal.is_unsigned(), signal2.is_unsigned());
915 assert_eq!(signal.factor(), signal2.factor());
916 assert_eq!(signal.offset(), signal2.offset());
917 assert_eq!(signal.min(), signal2.min());
918 assert_eq!(signal.max(), signal2.max());
919 assert_eq!(signal.unit(), signal2.unit());
920 }
921 }
922 }
923}