dbc_rs/message/
serialize.rs

1use super::Message;
2
3#[cfg(feature = "std")]
4impl Message {
5    #[must_use = "return value should be used"]
6    pub fn to_dbc_string(&self) -> std::string::String {
7        format!(
8            "BO_ {} {} : {} {}",
9            self.id(),
10            self.name(),
11            self.dlc(),
12            self.sender()
13        )
14    }
15
16    #[must_use = "return value should be used"]
17    pub fn to_string_full(&self) -> std::string::String {
18        let mut result = std::string::String::with_capacity(200 + (self.signals.len() * 100));
19        result.push_str(&self.to_dbc_string());
20        result.push('\n');
21
22        for signal in self.signals().iter() {
23            result.push_str(&signal.to_dbc_string());
24            result.push('\n');
25        }
26
27        result
28    }
29}
30
31#[cfg(feature = "std")]
32impl core::fmt::Display for Message {
33    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
34        write!(f, "{}", self.to_string_full())
35    }
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41    use crate::{Parser, Signal};
42
43    #[test]
44    fn test_message_to_dbc_string() {
45        let data = b"BO_ 256 EngineData : 8 ECM";
46        let mut parser = Parser::new(data).unwrap();
47        let signals: &[Signal] = &[];
48        let message = Message::parse(&mut parser, signals).unwrap();
49        let dbc_string = message.to_dbc_string();
50        assert_eq!(dbc_string, "BO_ 256 EngineData : 8 ECM");
51    }
52
53    #[test]
54    fn test_message_to_string_full() {
55        let data = b"BO_ 256 EngineData : 8 ECM";
56        let mut parser = Parser::new(data).unwrap();
57
58        let signal1 = Signal::parse(
59            &mut Parser::new(b"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] \"rpm\"").unwrap(),
60        )
61        .unwrap();
62        let signal2 = Signal::parse(
63            &mut Parser::new(b"SG_ Temp : 16|8@0- (1,-40) [-40|215] \"\xC2\xB0C\"").unwrap(),
64        )
65        .unwrap();
66
67        let message = Message::parse(&mut parser, &[signal1, signal2]).unwrap();
68        let dbc_string = message.to_string_full();
69        assert!(dbc_string.contains("BO_ 256 EngineData : 8 ECM"));
70        assert!(dbc_string.contains("SG_ RPM"));
71        assert!(dbc_string.contains("SG_ Temp"));
72    }
73
74    #[test]
75    fn test_message_to_dbc_string_empty_signals() {
76        let data = b"BO_ 256 EngineData : 8 ECM";
77        let mut parser = Parser::new(data).unwrap();
78        let signals: &[Signal] = &[];
79        let message = Message::parse(&mut parser, signals).unwrap();
80
81        let dbc_string = message.to_dbc_string();
82        assert_eq!(dbc_string, "BO_ 256 EngineData : 8 ECM");
83
84        let dbc_string_with_signals = message.to_string_full();
85        assert_eq!(dbc_string_with_signals, "BO_ 256 EngineData : 8 ECM\n");
86    }
87
88    #[test]
89    fn test_message_to_dbc_string_special_characters() {
90        let data = b"BO_ 1234 Test_Message_With_Underscores : 4 Sender_Node";
91        let mut parser = Parser::new(data).unwrap();
92        let signals: &[Signal] = &[];
93        let message = Message::parse(&mut parser, signals).unwrap();
94
95        let dbc_string = message.to_dbc_string();
96        assert_eq!(
97            dbc_string,
98            "BO_ 1234 Test_Message_With_Underscores : 4 Sender_Node"
99        );
100    }
101
102    #[test]
103    fn test_message_to_dbc_string_extended_id() {
104        // Use a valid extended ID (max is 0x1FFF_FFFF = 536870911)
105        let data = b"BO_ 536870911 ExtendedID : 8 ECM";
106        let mut parser = Parser::new(data).unwrap();
107        let signals: &[Signal] = &[];
108        let message = Message::parse(&mut parser, signals).unwrap();
109
110        let dbc_string = message.to_dbc_string();
111        assert_eq!(dbc_string, "BO_ 536870911 ExtendedID : 8 ECM");
112    }
113
114    #[test]
115    fn test_message_to_dbc_string_dlc_edge_cases() {
116        // Test DLC = 1
117        let data = b"BO_ 256 MinDLC : 1 ECM";
118        let mut parser = Parser::new(data).unwrap();
119        let signals: &[Signal] = &[];
120        let message = Message::parse(&mut parser, signals).unwrap();
121        assert_eq!(message.to_dbc_string(), "BO_ 256 MinDLC : 1 ECM");
122
123        // Test DLC = 64 (CAN FD max)
124        let data2 = b"BO_ 257 MaxDLC : 64 ECM";
125        let mut parser2 = Parser::new(data2).unwrap();
126        let signals_empty: &[Signal] = &[];
127        let message2 = Message::parse(&mut parser2, signals_empty).unwrap();
128        assert_eq!(message2.to_dbc_string(), "BO_ 257 MaxDLC : 64 ECM");
129    }
130
131    #[test]
132    fn test_message_display_trait() {
133        let data = b"BO_ 256 EngineData : 8 ECM";
134        let mut parser = Parser::new(data).unwrap();
135
136        // Parse signal from DBC string instead of using builder
137        let signal = Signal::parse(
138            &mut Parser::new(b"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] \"rpm\" *").unwrap(),
139        )
140        .unwrap();
141
142        let message = Message::parse(&mut parser, &[signal]).unwrap();
143
144        let display_str = format!("{}", message);
145        assert!(display_str.contains("BO_ 256 EngineData : 8 ECM"));
146        assert!(display_str.contains("SG_ RPM"));
147    }
148
149    #[test]
150    fn test_message_to_string_full_multiple() {
151        let data = b"BO_ 256 EngineData : 8 ECM";
152        let mut parser = Parser::new(data).unwrap();
153
154        // Parse signals from DBC strings instead of using builders
155        let signal1 = Signal::parse(
156            &mut Parser::new(b"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] \"rpm\" *").unwrap(),
157        )
158        .unwrap();
159
160        let signal2 = Signal::parse(
161            &mut Parser::new(b"SG_ Temp : 16|8@0- (1,-40) [-40|215] \"\xC2\xB0C\" *").unwrap(),
162        )
163        .unwrap();
164
165        let message = Message::parse(&mut parser, &[signal1, signal2]).unwrap();
166
167        let dbc_string = message.to_string_full();
168        assert!(dbc_string.contains("BO_ 256 EngineData : 8 ECM"));
169        assert!(dbc_string.contains("SG_ RPM"));
170        assert!(dbc_string.contains("SG_ Temp"));
171        // Should have newlines between signals
172        let lines: Vec<&str> = dbc_string.lines().collect();
173        assert!(lines.len() >= 3); // Message line + at least 2 signal lines
174    }
175
176    #[test]
177    fn test_message_can_2_0a_dlc_limits() {
178        // CAN 2.0A: DLC can be 1-8 bytes (8-64 bits)
179        // Test valid DLC values
180        for dlc in 1..=8 {
181            let data = format!("BO_ 256 EngineData : {} ECM", dlc);
182            let mut parser = Parser::new(data.as_bytes()).unwrap();
183            let signals: &[Signal] = &[];
184            let message = Message::parse(&mut parser, signals).unwrap();
185            assert_eq!(message.dlc(), dlc);
186        }
187    }
188
189    #[test]
190    fn test_message_can_2_0b_dlc_limits() {
191        // CAN 2.0B: DLC can be 1-8 bytes (8-64 bits)
192        // Test valid DLC values
193        for dlc in 1..=8 {
194            let data = format!("BO_ 256 EngineData : {} ECM", dlc);
195            let mut parser = Parser::new(data.as_bytes()).unwrap();
196            let signals: &[Signal] = &[];
197            let message = Message::parse(&mut parser, signals).unwrap();
198            assert_eq!(message.dlc(), dlc);
199        }
200    }
201
202    #[test]
203    fn test_message_can_fd_dlc_limits() {
204        // CAN FD: DLC can be 1-64 bytes (8-512 bits)
205        // Test valid DLC values up to 64
206        for dlc in [1, 8, 12, 16, 20, 24, 32, 48, 64] {
207            let data = format!("BO_ 256 EngineData : {} ECM", dlc);
208            let mut parser = Parser::new(data.as_bytes()).unwrap();
209            let signals: &[Signal] = &[];
210            let message = Message::parse(&mut parser, signals).unwrap();
211            assert_eq!(message.dlc(), dlc);
212        }
213    }
214
215    #[test]
216    fn test_message_signals_iterator_collect() {
217        let data = b"BO_ 256 EngineData : 8 ECM";
218        let mut parser = Parser::new(data).unwrap();
219
220        let signal1 =
221            Signal::parse(&mut Parser::new(b"SG_ Signal1 : 0|8@0+ (1,0) [0|255] \"\"").unwrap())
222                .unwrap();
223        let signal2 =
224            Signal::parse(&mut Parser::new(b"SG_ Signal2 : 8|8@0+ (1,0) [0|255] \"\"").unwrap())
225                .unwrap();
226        let signal3 =
227            Signal::parse(&mut Parser::new(b"SG_ Signal3 : 16|8@0+ (1,0) [0|255] \"\"").unwrap())
228                .unwrap();
229
230        let message = Message::parse(&mut parser, &[signal1, signal2, signal3]).unwrap();
231
232        // Test that iterator can be used multiple times
233        let names: Vec<&str> = message.signals().iter().map(|s| s.name()).collect();
234        assert_eq!(names, vec!["Signal1", "Signal2", "Signal3"]);
235    }
236}