1use crate::{Dbc, Message};
30use std::collections::HashMap;
31use std::sync::Arc;
32
33#[derive(Debug, Clone)]
40pub struct FastDbc {
41 inner: Arc<FastDbcInner>,
43}
44
45#[derive(Debug)]
47struct FastDbcInner {
48 dbc: Dbc,
50 index: HashMap<u32, usize>,
52 max_signals: usize,
54 total_signals: usize,
56}
57
58impl FastDbc {
59 pub fn new(dbc: Dbc) -> Self {
63 let mut index = HashMap::with_capacity(dbc.messages().len());
64 let mut max_signals = 0;
65 let mut total_signals = 0;
66
67 for (i, msg) in dbc.messages().iter().enumerate() {
68 index.insert(msg.id_with_flag(), i);
70 let sig_count = msg.signals().len();
71 max_signals = max_signals.max(sig_count);
72 total_signals += sig_count;
73 }
74
75 Self {
76 inner: Arc::new(FastDbcInner {
77 dbc,
78 index,
79 max_signals,
80 total_signals,
81 }),
82 }
83 }
84
85 #[inline]
92 pub fn get(&self, id: u32) -> Option<&Message> {
93 self.inner.index.get(&id).and_then(|&idx| self.inner.dbc.messages().at(idx))
94 }
95
96 #[inline]
100 pub fn get_extended(&self, id: u32) -> Option<&Message> {
101 let extended_id = id | Message::EXTENDED_ID_FLAG;
102 self.inner
103 .index
104 .get(&extended_id)
105 .and_then(|&idx| self.inner.dbc.messages().at(idx))
106 }
107
108 #[inline]
112 pub fn get_any(&self, id: u32) -> Option<&Message> {
113 self.inner
115 .index
116 .get(&id)
117 .or_else(|| self.inner.index.get(&(id | Message::EXTENDED_ID_FLAG)))
118 .and_then(|&idx| self.inner.dbc.messages().at(idx))
119 }
120
121 #[inline]
136 pub fn decode_into(&self, id: u32, data: &[u8], out: &mut [f64]) -> Option<usize> {
137 let msg = self.get(id)?;
138 let count = msg.decode_into(data, out);
139 if count > 0 { Some(count) } else { None }
140 }
141
142 #[inline]
144 pub fn decode_extended_into(&self, id: u32, data: &[u8], out: &mut [f64]) -> Option<usize> {
145 let msg = self.get_extended(id)?;
146 let count = msg.decode_into(data, out);
147 if count > 0 { Some(count) } else { None }
148 }
149
150 #[inline]
152 pub fn decode_raw_into(&self, id: u32, data: &[u8], out: &mut [i64]) -> Option<usize> {
153 let msg = self.get(id)?;
154 let count = msg.decode_raw_into(data, out);
155 if count > 0 { Some(count) } else { None }
156 }
157
158 #[inline]
162 pub fn max_signals(&self) -> usize {
163 self.inner.max_signals
164 }
165
166 #[inline]
168 pub fn total_signals(&self) -> usize {
169 self.inner.total_signals
170 }
171
172 #[inline]
174 pub fn message_count(&self) -> usize {
175 self.inner.dbc.messages().len()
176 }
177
178 #[inline]
180 pub fn contains(&self, id: u32) -> bool {
181 self.inner.index.contains_key(&id)
182 }
183
184 #[inline]
186 pub fn contains_extended(&self, id: u32) -> bool {
187 self.inner.index.contains_key(&(id | Message::EXTENDED_ID_FLAG))
188 }
189
190 #[inline]
192 pub fn dbc(&self) -> &Dbc {
193 &self.inner.dbc
194 }
195
196 #[inline]
200 pub fn into_dbc(self) -> Dbc {
201 match Arc::try_unwrap(self.inner) {
202 Ok(inner) => inner.dbc,
203 Err(arc) => arc.dbc.clone(),
204 }
205 }
206
207 pub fn ids(&self) -> impl Iterator<Item = u32> + '_ {
209 self.inner.index.keys().copied()
210 }
211}
212
213impl From<Dbc> for FastDbc {
214 fn from(dbc: Dbc) -> Self {
215 Self::new(dbc)
216 }
217}
218
219#[cfg(test)]
220mod tests {
221 use super::*;
222
223 #[test]
224 fn test_fast_dbc_basic() {
225 let dbc = Dbc::parse(
226 r#"VERSION "1.0"
227
228BU_: ECM
229
230BO_ 256 Engine : 8 ECM
231 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
232 SG_ Temp : 16|8@1- (1,-40) [-40|215] "C" *
233"#,
234 )
235 .unwrap();
236
237 let fast = FastDbc::new(dbc);
238
239 assert_eq!(fast.message_count(), 1);
240 assert_eq!(fast.max_signals(), 2);
241 assert_eq!(fast.total_signals(), 2);
242 assert!(fast.contains(256));
243 assert!(!fast.contains(512));
244
245 let msg = fast.get(256).unwrap();
246 assert_eq!(msg.name(), "Engine");
247 }
248
249 #[test]
250 fn test_fast_dbc_decode_into() {
251 let dbc = Dbc::parse(
252 r#"VERSION "1.0"
253
254BU_: ECM
255
256BO_ 256 Engine : 8 ECM
257 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
258 SG_ Temp : 16|8@1- (1,-40) [-40|215] "C" *
259"#,
260 )
261 .unwrap();
262
263 let fast = FastDbc::new(dbc);
264
265 let payload = [0x40, 0x1F, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00];
267 let mut values = vec![0.0f64; fast.max_signals()];
268
269 let count = fast.decode_into(256, &payload, &mut values).unwrap();
270
271 assert_eq!(count, 2);
272 assert_eq!(values[0], 2000.0);
273 assert_eq!(values[1], 50.0);
274 }
275
276 #[test]
277 fn test_fast_dbc_message_not_found() {
278 let dbc = Dbc::parse(
279 r#"VERSION "1.0"
280
281BU_: ECM
282
283BO_ 256 Engine : 8 ECM
284 SG_ RPM : 0|16@1+ (1,0) [0|8000] "rpm" *
285"#,
286 )
287 .unwrap();
288
289 let fast = FastDbc::new(dbc);
290 let payload = [0x00; 8];
291 let mut values = [0.0f64; 8];
292
293 assert!(fast.decode_into(512, &payload, &mut values).is_none());
294 }
295
296 #[test]
297 fn test_fast_dbc_extended_id() {
298 let dbc = Dbc::parse(
299 r#"VERSION "1.0"
300
301BU_: ECM
302
303BO_ 2147484672 ExtendedMsg : 8 ECM
304 SG_ Speed : 0|16@1+ (0.1,0) [0|6553.5] "km/h" *
305"#,
306 )
307 .unwrap();
308 let fast = FastDbc::new(dbc);
311
312 assert!(!fast.contains(0x400));
314 assert!(fast.get(0x400).is_none());
315
316 assert!(fast.contains_extended(0x400));
318 let msg = fast.get_extended(0x400).unwrap();
319 assert_eq!(msg.name(), "ExtendedMsg");
320
321 let payload = [0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
323 let mut values = [0.0f64; 8];
324
325 let count = fast.decode_extended_into(0x400, &payload, &mut values).unwrap();
326 assert_eq!(count, 1);
327 assert_eq!(values[0], 100.0); }
329
330 #[test]
331 fn test_fast_dbc_multiple_messages() {
332 let dbc = Dbc::parse(
333 r#"VERSION "1.0"
334
335BU_: ECM
336
337BO_ 256 Msg1 : 8 ECM
338 SG_ Sig1 : 0|8@1+ (1,0) [0|255] "" *
339 SG_ Sig2 : 8|8@1+ (1,0) [0|255] "" *
340
341BO_ 512 Msg2 : 8 ECM
342 SG_ SigA : 0|16@1+ (1,0) [0|65535] "" *
343
344BO_ 768 Msg3 : 8 ECM
345 SG_ SigX : 0|8@1+ (1,0) [0|255] "" *
346 SG_ SigY : 8|8@1+ (1,0) [0|255] "" *
347 SG_ SigZ : 16|8@1+ (1,0) [0|255] "" *
348"#,
349 )
350 .unwrap();
351
352 let fast = FastDbc::new(dbc);
353
354 assert_eq!(fast.message_count(), 3);
355 assert_eq!(fast.max_signals(), 3); assert_eq!(fast.total_signals(), 6);
357
358 assert!(fast.contains(256));
359 assert!(fast.contains(512));
360 assert!(fast.contains(768));
361 }
362
363 #[test]
364 fn test_fast_dbc_from_trait() {
365 let dbc = Dbc::parse(
366 r#"VERSION "1.0"
367
368BU_: ECM
369
370BO_ 256 Engine : 8 ECM
371"#,
372 )
373 .unwrap();
374
375 let fast: FastDbc = dbc.into();
376 assert_eq!(fast.message_count(), 1);
377 }
378
379 #[test]
380 fn test_fast_dbc_into_dbc() {
381 let dbc = Dbc::parse(
382 r#"VERSION "1.0"
383
384BU_: ECM
385
386BO_ 256 Engine : 8 ECM
387"#,
388 )
389 .unwrap();
390
391 let fast = FastDbc::new(dbc);
392 let dbc_back = fast.into_dbc();
393
394 assert_eq!(dbc_back.messages().len(), 1);
395 }
396}