1use super::Dbc;
2use std::fmt::{Display, Formatter, Result};
3
4impl Dbc {
5 #[must_use = "return value should be used"]
19 pub fn to_dbc_string(&self) -> String {
20 let signal_count: usize = self.messages().iter().map(|m| m.signals().len()).sum();
23 let estimated_capacity = 200 + (self.messages.len() * 50) + (signal_count * 100);
24 let mut result = String::with_capacity(estimated_capacity);
25
26 if let Some(version) = &self.version {
28 result.push_str(&version.to_dbc_string());
29 result.push_str("\n\n");
30 }
31
32 result.push_str(&self.nodes.to_dbc_string());
34 result.push('\n');
35
36 for message in self.messages().iter() {
38 result.push('\n');
39 result.push_str(&message.to_string_full());
40 }
41
42 result
43 }
44}
45
46impl Display for Dbc {
47 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
48 write!(f, "{}", self.to_dbc_string())
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use crate::Dbc;
55
56 #[test]
57 fn test_to_dbc_string() {
58 let dbc = Dbc::parse(
59 r#"VERSION "1.0"
60
61BU_: ECM
62
63BO_ 256 Engine : 8 ECM
64 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
65"#,
66 )
67 .unwrap();
68
69 let dbc_string = dbc.to_dbc_string();
70 assert!(dbc_string.contains("VERSION"));
71 assert!(dbc_string.contains("BU_"));
72 assert!(dbc_string.contains("BO_"));
73 assert!(dbc_string.contains("SG_"));
74 }
75
76 #[test]
77 fn test_display() {
78 let dbc = Dbc::parse(
79 r#"VERSION "1.0"
80
81BU_: ECM
82
83BO_ 256 Engine : 8 ECM
84"#,
85 )
86 .unwrap();
87
88 let display_str = format!("{}", dbc);
89 assert!(display_str.contains("VERSION"));
90 }
91
92 #[test]
93 fn test_save_round_trip() {
94 let original = r#"VERSION "1.0"
95
96BU_: ECM TCM
97
98BO_ 256 EngineData : 8 ECM
99 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
100 SG_ Temperature : 16|8@0- (1,-40) [-40|215] "°C" TCM
101
102BO_ 512 BrakeData : 4 TCM
103 SG_ Pressure : 0|16@0+ (0.1,0) [0|1000] "bar"
104"#;
105
106 let dbc = Dbc::parse(original).unwrap();
107 let saved = dbc.to_dbc_string();
108 let dbc2 = Dbc::parse(&saved).unwrap();
109
110 assert_eq!(
112 dbc.version().map(|v| v.to_string()),
113 dbc2.version().map(|v| v.to_string())
114 );
115 assert_eq!(dbc.messages().len(), dbc2.messages().len());
116
117 for (msg1, msg2) in dbc.messages().iter().zip(dbc2.messages().iter()) {
118 assert_eq!(msg1.id(), msg2.id());
119 assert_eq!(msg1.name(), msg2.name());
120 assert_eq!(msg1.dlc(), msg2.dlc());
121 assert_eq!(msg1.sender(), msg2.sender());
122 assert_eq!(msg1.signals().len(), msg2.signals().len());
123
124 for (sig1, sig2) in msg1.signals().iter().zip(msg2.signals().iter()) {
125 assert_eq!(sig1.name(), sig2.name());
126 assert_eq!(sig1.start_bit(), sig2.start_bit());
127 assert_eq!(sig1.length(), sig2.length());
128 assert_eq!(sig1.byte_order(), sig2.byte_order());
129 assert_eq!(sig1.is_unsigned(), sig2.is_unsigned());
130 assert_eq!(sig1.factor(), sig2.factor());
131 assert_eq!(sig1.offset(), sig2.offset());
132 assert_eq!(sig1.min(), sig2.min());
133 assert_eq!(sig1.max(), sig2.max());
134 assert_eq!(sig1.unit(), sig2.unit());
135 assert_eq!(sig1.receivers(), sig2.receivers());
136 }
137 }
138 }
139
140 #[test]
141 fn test_save_basic() {
142 let dbc_content = r#"VERSION "1.0"
145
146BU_: ECM
147
148BO_ 256 EngineData : 8 ECM
149 SG_ RPM : 0|16@0+ (0.25,0) [0|8000] "rpm" *
150"#;
151 let dbc = Dbc::parse(dbc_content).unwrap();
152
153 let saved = dbc.to_dbc_string();
154 assert!(saved.contains("VERSION \"1.0\""));
155 assert!(saved.contains("BU_: ECM"));
156 assert!(saved.contains("BO_ 256 EngineData : 8 ECM"));
157 assert!(saved.contains("SG_ RPM : 0|16@0+ (0.25,0) [0|8000] \"rpm\" Vector__XXX"));
159 }
160
161 #[test]
162 fn test_save_multiple_messages() {
163 let dbc_content = r#"VERSION "1.0"
165
166BU_: ECM TCM
167
168BO_ 256 EngineData : 8 ECM
169 SG_ RPM : 0|16@0+ (0.25,0) [0|8000] "rpm"
170
171BO_ 512 BrakeData : 4 TCM
172 SG_ Pressure : 0|16@1+ (0.1,0) [0|1000] "bar"
173"#;
174 let dbc = Dbc::parse(dbc_content).unwrap();
175 let saved = dbc.to_dbc_string();
176
177 assert!(saved.contains("BO_ 256 EngineData : 8 ECM"));
179 assert!(saved.contains("BO_ 512 BrakeData : 4 TCM"));
180 assert!(saved.contains("SG_ RPM"));
181 assert!(saved.contains("SG_ Pressure"));
182 }
183}