1use crate::{
2 Dbc, Message, MessageBuilder, MessageList, Nodes, NodesBuilder, Receivers, ReceiversBuilder,
3 SignalBuilder, ValueDescriptionsBuilder, Version, VersionBuilder, error::Result,
4};
5use std::collections::BTreeMap;
6
7#[derive(Debug, Default)]
41pub struct DbcBuilder {
42 version: VersionBuilder,
43 nodes: NodesBuilder,
44 messages: Vec<MessageBuilder>,
45 value_descriptions: BTreeMap<(Option<u32>, String), ValueDescriptionsBuilder>,
46}
47
48impl DbcBuilder {
49 pub fn new() -> Self {
68 Self::default()
69 }
70
71 pub fn from_dbc(dbc: &Dbc) -> Self {
92 let version = if let Some(v) = dbc.version() {
94 VersionBuilder::new().version(v.as_str())
95 } else {
96 VersionBuilder::new()
97 };
98
99 let nodes = {
102 let mut builder = NodesBuilder::new();
103 for node in dbc.nodes().iter() {
104 let node_str = node.to_string();
106 builder = builder.add_node(node_str);
108 }
109 builder
110 };
111
112 let messages: Vec<MessageBuilder> = dbc
114 .messages()
115 .iter()
116 .map(|msg| {
117 let mut msg_builder = MessageBuilder::new()
118 .id(msg.id())
119 .name(msg.name())
120 .dlc(msg.dlc())
121 .sender(msg.sender());
122
123 for sig in msg.signals().iter() {
125 let mut sig_builder = SignalBuilder::new()
126 .name(sig.name())
127 .start_bit(sig.start_bit())
128 .length(sig.length())
129 .byte_order(sig.byte_order())
130 .unsigned(sig.is_unsigned())
131 .factor(sig.factor())
132 .offset(sig.offset())
133 .min(sig.min())
134 .max(sig.max());
135
136 if let Some(unit) = sig.unit() {
137 sig_builder = sig_builder.unit(unit);
138 }
139
140 let receivers_builder = match sig.receivers() {
142 Receivers::Broadcast => ReceiversBuilder::new().broadcast(),
143 Receivers::None => ReceiversBuilder::new().none(),
144 Receivers::Nodes(nodes) => {
145 let mut rb = ReceiversBuilder::new();
146 for receiver in nodes.iter() {
148 let receiver_str = receiver.clone();
150 rb = rb.add_node(receiver_str);
152 }
153 rb
154 }
155 };
156 sig_builder = sig_builder.receivers(receivers_builder);
157
158 msg_builder = msg_builder.add_signal(sig_builder);
159 }
160
161 msg_builder
162 })
163 .collect();
164
165 let mut value_descriptions: BTreeMap<(Option<u32>, String), ValueDescriptionsBuilder> =
167 BTreeMap::new();
168 for ((message_id, signal_name), vd) in dbc.value_descriptions().iter() {
169 let mut builder = ValueDescriptionsBuilder::new();
171 for (value, desc) in vd.iter() {
172 builder = builder.add_entry(value, desc);
173 }
174 value_descriptions.insert((message_id, signal_name.to_string()), builder);
175 }
176
177 Self {
178 version,
179 nodes,
180 messages,
181 value_descriptions,
182 }
183 }
184
185 #[must_use]
198 pub fn version(mut self, version: VersionBuilder) -> Self {
199 self.version = version;
200 self
201 }
202
203 #[must_use]
215 pub fn nodes(mut self, nodes: NodesBuilder) -> Self {
216 self.nodes = nodes;
217 self
218 }
219
220 #[must_use]
238 pub fn add_message(mut self, message: MessageBuilder) -> Self {
239 self.messages.push(message);
240 self
241 }
242
243 #[must_use]
258 pub fn add_messages(mut self, messages: impl IntoIterator<Item = MessageBuilder>) -> Self {
259 self.messages.extend(messages);
260 self
261 }
262
263 #[must_use]
274 pub fn clear_messages(mut self) -> Self {
275 self.messages.clear();
276 self
277 }
278
279 #[must_use = "validation result should be checked"]
296 pub fn validate(self) -> Result<()> {
297 let (_version, nodes, messages, value_descriptions) = {
301 let version = self.version.build()?;
302 let nodes = self.nodes.build()?;
303 let messages: std::vec::Vec<Message> = self
304 .messages
305 .into_iter()
306 .map(|builder| builder.build())
307 .collect::<Result<std::vec::Vec<_>>>()?;
308 let mut value_descriptions_map: BTreeMap<
309 (Option<u32>, String),
310 crate::ValueDescriptions,
311 > = BTreeMap::new();
312 for ((message_id, signal_name), vd_builder) in self.value_descriptions {
313 let vd = vd_builder.build()?;
314 value_descriptions_map.insert((message_id, signal_name), vd);
315 }
316 let value_descriptions =
317 crate::dbc::ValueDescriptionsList::from_map(value_descriptions_map);
318 (version, nodes, messages, value_descriptions)
319 };
320
321 Dbc::validate(&nodes, &messages, Some(&value_descriptions))?;
323
324 Ok(())
325 }
326
327 fn extract_fields(
328 self,
329 ) -> Result<(
330 Version,
331 Nodes,
332 MessageList,
333 crate::dbc::ValueDescriptionsList,
334 )> {
335 let version = self.version.build()?;
337
338 let nodes = self.nodes.build()?;
340
341 let messages_vec: std::vec::Vec<Message> = self
344 .messages
345 .into_iter()
346 .map(|builder| builder.build())
347 .collect::<Result<std::vec::Vec<_>>>()?;
348 let messages = MessageList::new(&messages_vec)?;
349
350 let mut value_descriptions_map: BTreeMap<(Option<u32>, String), crate::ValueDescriptions> =
352 BTreeMap::new();
353 for ((message_id, signal_name), vd_builder) in self.value_descriptions {
354 let vd = vd_builder.build()?;
355 value_descriptions_map.insert((message_id, signal_name), vd);
356 }
357 let value_descriptions =
358 crate::dbc::ValueDescriptionsList::from_map(value_descriptions_map);
359
360 Ok((version, nodes, messages, value_descriptions))
361 }
362
363 pub fn build(self) -> Result<Dbc> {
380 let (version, nodes, messages, value_descriptions) = self.extract_fields()?;
381 let messages_slice: std::vec::Vec<Message> = messages.iter().cloned().collect();
384 Dbc::validate(&nodes, &messages_slice, Some(&value_descriptions))?;
385 Ok(Dbc::new(Some(version), nodes, messages, value_descriptions))
386 }
387}
388
389#[cfg(test)]
390mod tests {
391 #![allow(clippy::float_cmp)]
392 use super::DbcBuilder;
393 use crate::{
394 ByteOrder, Dbc, MessageBuilder, NodesBuilder, ReceiversBuilder, SignalBuilder,
395 VersionBuilder,
396 };
397
398 #[test]
399 fn test_dbc_builder_valid() {
400 let version = VersionBuilder::new().version("1.0");
401 let nodes = NodesBuilder::new().add_nodes(["ECM"]);
402 let signal = SignalBuilder::new()
403 .name("RPM")
404 .start_bit(0)
405 .length(16)
406 .byte_order(ByteOrder::BigEndian)
407 .unsigned(true)
408 .factor(1.0)
409 .offset(0.0)
410 .min(0.0)
411 .max(100.0)
412 .receivers(ReceiversBuilder::new().none());
413 let message = MessageBuilder::new()
414 .id(256)
415 .name("EngineData")
416 .dlc(8)
417 .sender("ECM")
418 .add_signal(signal);
419
420 let dbc = DbcBuilder::new()
421 .version(version)
422 .nodes(nodes)
423 .add_message(message)
424 .build()
425 .unwrap();
426
427 assert_eq!(dbc.messages().len(), 1);
428 assert_eq!(dbc.messages().at(0).unwrap().id(), 256);
429 }
430
431 #[test]
432 fn test_dbc_builder_missing_version() {
433 let nodes = NodesBuilder::new().add_nodes(["ECM"]);
434 let signal = SignalBuilder::new()
435 .name("RPM")
436 .start_bit(0)
437 .length(16)
438 .byte_order(ByteOrder::BigEndian)
439 .unsigned(true)
440 .factor(1.0)
441 .offset(0.0)
442 .min(0.0)
443 .max(100.0)
444 .receivers(ReceiversBuilder::new().none());
445 let message = MessageBuilder::new()
446 .id(256)
447 .name("EngineData")
448 .dlc(8)
449 .sender("ECM")
450 .add_signal(signal);
451
452 let result = DbcBuilder::new().nodes(nodes).add_message(message).build();
453 assert!(result.is_ok());
455 let dbc = result.unwrap();
456 assert_eq!(dbc.version().unwrap().as_str(), "");
457 }
458
459 #[test]
460 fn test_dbc_builder_missing_nodes() {
461 let version = VersionBuilder::new().version("1.0");
464 let signal = SignalBuilder::new()
465 .name("RPM")
466 .start_bit(0)
467 .length(16)
468 .byte_order(ByteOrder::BigEndian)
469 .unsigned(true)
470 .factor(1.0)
471 .offset(0.0)
472 .min(0.0)
473 .max(100.0)
474 .receivers(ReceiversBuilder::new().none());
475 let message = MessageBuilder::new()
476 .id(256)
477 .name("EngineData")
478 .dlc(8)
479 .sender("ECM")
480 .add_signal(signal);
481
482 let result = DbcBuilder::new().version(version).add_message(message).build();
484 assert!(result.is_ok());
485 let dbc = result.unwrap();
486 assert!(dbc.nodes().is_empty());
487 }
488
489 #[test]
490 fn test_dbc_builder_add_messages() {
491 let version = VersionBuilder::new().version("1.0");
492 let nodes = NodesBuilder::new().add_nodes(["ECM"]);
493 let signal1 = SignalBuilder::new()
494 .name("RPM")
495 .start_bit(0)
496 .length(16)
497 .byte_order(ByteOrder::BigEndian)
498 .unsigned(true)
499 .factor(1.0)
500 .offset(0.0)
501 .min(0.0)
502 .max(100.0)
503 .receivers(ReceiversBuilder::new().none());
504 let signal2 = SignalBuilder::new()
505 .name("RPM")
506 .start_bit(0)
507 .length(16)
508 .byte_order(ByteOrder::BigEndian)
509 .unsigned(true)
510 .factor(1.0)
511 .offset(0.0)
512 .min(0.0)
513 .max(100.0)
514 .receivers(ReceiversBuilder::new().none());
515 let message1 = MessageBuilder::new()
516 .id(256)
517 .name("EngineData")
518 .dlc(8)
519 .sender("ECM")
520 .add_signal(signal1);
521 let message2 = MessageBuilder::new()
522 .id(512)
523 .name("BrakeData")
524 .dlc(4)
525 .sender("ECM")
526 .add_signal(signal2);
527
528 let dbc = DbcBuilder::new()
529 .version(version)
530 .nodes(nodes)
531 .add_messages(vec![message1, message2])
532 .build()
533 .unwrap();
534
535 assert_eq!(dbc.messages().len(), 2);
536 }
537
538 #[test]
539 fn test_dbc_builder_messages() {
540 let version = VersionBuilder::new().version("1.0");
541 let nodes = NodesBuilder::new().add_nodes(["ECM"]);
542
543 let signal1 = SignalBuilder::new()
544 .name("RPM")
545 .start_bit(0)
546 .length(16)
547 .byte_order(ByteOrder::BigEndian)
548 .unsigned(true)
549 .factor(1.0)
550 .offset(0.0)
551 .min(0.0)
552 .max(100.0)
553 .receivers(ReceiversBuilder::new().none());
554 let message1 = MessageBuilder::new()
555 .id(256)
556 .name("EngineData")
557 .dlc(8)
558 .sender("ECM")
559 .add_signal(signal1);
560
561 let signal2 = SignalBuilder::new()
562 .name("RPM")
563 .start_bit(0)
564 .length(16)
565 .byte_order(ByteOrder::BigEndian)
566 .unsigned(true)
567 .factor(1.0)
568 .offset(0.0)
569 .min(0.0)
570 .max(100.0)
571 .receivers(ReceiversBuilder::new().none());
572 let message2 = MessageBuilder::new()
573 .id(512)
574 .name("EngineData2")
575 .dlc(8)
576 .sender("ECM")
577 .add_signal(signal2);
578
579 let dbc = DbcBuilder::new()
580 .version(version)
581 .nodes(nodes)
582 .add_message(message1)
583 .add_message(message2)
584 .build()
585 .unwrap();
586
587 assert_eq!(dbc.messages().len(), 2);
588 }
589
590 #[test]
591 fn test_dbc_builder_clear_messages() {
592 let version = VersionBuilder::new().version("1.0");
593 let nodes = NodesBuilder::new().add_nodes(["ECM"]);
594 let signal = SignalBuilder::new()
595 .name("RPM")
596 .start_bit(0)
597 .length(16)
598 .byte_order(ByteOrder::BigEndian)
599 .unsigned(true)
600 .factor(1.0)
601 .offset(0.0)
602 .min(0.0)
603 .max(100.0)
604 .receivers(ReceiversBuilder::new().none());
605 let message = MessageBuilder::new()
606 .id(256)
607 .name("EngineData")
608 .dlc(8)
609 .sender("ECM")
610 .add_signal(signal);
611
612 let dbc = DbcBuilder::new()
613 .version(version)
614 .nodes(nodes)
615 .add_message(message)
616 .clear_messages()
617 .build()
618 .unwrap();
619
620 assert_eq!(dbc.messages().len(), 0);
621 }
622
623 #[test]
624 fn test_dbc_builder_validate_missing_version() {
625 let nodes = NodesBuilder::new().add_nodes(["ECM"]);
626 let result = DbcBuilder::new().nodes(nodes).validate();
628 assert!(result.is_ok());
629 }
630
631 #[test]
632 fn test_dbc_builder_validate_missing_nodes() {
633 let version = VersionBuilder::new().version("1.0");
635 let result = DbcBuilder::new().version(version).validate();
636 assert!(result.is_ok());
638 }
639
640 #[test]
641 fn test_dbc_builder_validate_valid() {
642 let version = VersionBuilder::new().version("1.0");
643 let nodes = NodesBuilder::new().add_nodes(["ECM"]);
644 let signal = SignalBuilder::new()
645 .name("RPM")
646 .start_bit(0)
647 .length(16)
648 .byte_order(ByteOrder::BigEndian)
649 .unsigned(true)
650 .factor(1.0)
651 .offset(0.0)
652 .min(0.0)
653 .max(100.0)
654 .receivers(ReceiversBuilder::new().none());
655 let message = MessageBuilder::new()
656 .id(256)
657 .name("EngineData")
658 .dlc(8)
659 .sender("ECM")
660 .add_signal(signal);
661
662 let builder = DbcBuilder::new().version(version).nodes(nodes).add_message(message);
665 let result = builder.validate();
666 assert!(result.is_ok());
667 }
668
669 #[test]
670 fn test_dbc_builder_from_dbc() {
671 let dbc_content = r#"VERSION "1.0"
673
674BU_: ECM TCM
675
676BO_ 256 Engine : 8 ECM
677 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
678"#;
679 let original_dbc = Dbc::parse(dbc_content).unwrap();
680
681 let modified_dbc = DbcBuilder::from_dbc(&original_dbc)
683 .add_message(MessageBuilder::new().id(512).name("Brake").dlc(4).sender("TCM"))
684 .build()
685 .unwrap();
686
687 assert_eq!(modified_dbc.version().map(|v| v.as_str()), Some("1.0"));
689 assert_eq!(modified_dbc.nodes().len(), 2);
690 assert!(modified_dbc.nodes().contains("ECM"));
691 assert!(modified_dbc.nodes().contains("TCM"));
692
693 assert_eq!(modified_dbc.messages().len(), 2);
695 assert!(modified_dbc.messages().iter().any(|m| m.id() == 256));
696 assert!(modified_dbc.messages().iter().any(|m| m.id() == 512));
697
698 let engine_msg = modified_dbc.messages().iter().find(|m| m.id() == 256).unwrap();
700 assert_eq!(engine_msg.signals().len(), 1);
701 assert_eq!(engine_msg.signals().at(0).unwrap().name(), "RPM");
702 }
703
704 #[test]
705 fn test_dbc_builder_from_dbc_empty() {
706 let dbc_content = r#"VERSION "1.0"
708
709BU_:
710"#;
711 let original_dbc = Dbc::parse(dbc_content).unwrap();
712
713 let modified_dbc = DbcBuilder::from_dbc(&original_dbc)
715 .add_message(MessageBuilder::new().id(256).name("Test").dlc(8).sender("ECM"))
716 .build()
717 .unwrap();
718
719 assert_eq!(modified_dbc.version().map(|v| v.as_str()), Some("1.0"));
721 assert!(modified_dbc.nodes().is_empty());
723 assert_eq!(modified_dbc.messages().len(), 1);
725 }
726}