1#[cfg(any(feature = "alloc", feature = "kernel"))]
2use crate::compat::{Box, Vec};
3use crate::{
4 Dbc, Message, Nodes, Version,
5 error::{Error, Result},
6};
7
8#[derive(Debug, Default)]
45pub struct DbcBuilder {
46 version: Option<Version<'static>>,
47 nodes: Option<Nodes<'static>>,
48 messages: Vec<Message<'static>>,
49 value_descriptions: crate::dbc::ValueDescriptionsList<'static>,
50}
51
52impl DbcBuilder {
53 pub fn new(dbc: Option<&Dbc<'_>>) -> Self {
97 match dbc {
98 Some(dbc) => Self::from_dbc(dbc),
99 None => Self::default(),
100 }
101 }
102
103 fn from_dbc(dbc: &Dbc<'_>) -> Self {
112 use crate::{
113 MessageBuilder, NodesBuilder, ReceiversBuilder, SignalBuilder, VersionBuilder,
114 };
115
116 let version = dbc.version().map(|v| {
118 VersionBuilder::new()
119 .version(v.as_str())
120 .build()
121 .expect("Version conversion should always succeed")
122 });
123
124 let nodes = {
126 let mut builder = NodesBuilder::new();
127 for node in dbc.nodes().iter() {
128 builder = builder.add_node(node);
129 }
130 builder.build().expect("Nodes conversion should always succeed")
131 };
132
133 let messages: Vec<Message<'static>> = dbc
135 .messages()
136 .iter()
137 .map(|msg| {
138 let mut msg_builder = MessageBuilder::new()
139 .id(msg.id())
140 .name(msg.name())
141 .dlc(msg.dlc())
142 .sender(msg.sender());
143
144 for sig in msg.signals().iter() {
146 let mut sig_builder = SignalBuilder::new()
147 .name(sig.name())
148 .start_bit(sig.start_bit())
149 .length(sig.length())
150 .byte_order(sig.byte_order())
151 .unsigned(sig.is_unsigned())
152 .factor(sig.factor())
153 .offset(sig.offset())
154 .min(sig.min())
155 .max(sig.max());
156
157 if let Some(unit) = sig.unit() {
158 sig_builder = sig_builder.unit(unit);
159 }
160
161 let receivers = match sig.receivers() {
163 crate::Receivers::Broadcast => {
164 ReceiversBuilder::new().broadcast().build().unwrap()
165 }
166 crate::Receivers::None => ReceiversBuilder::new().none().build().unwrap(),
167 crate::Receivers::Nodes(_, _) => {
168 let mut recv_builder = ReceiversBuilder::new();
169 for receiver in sig.receivers().iter() {
170 recv_builder = recv_builder.add_node(receiver);
171 }
172 recv_builder.build().unwrap()
173 }
174 };
175 sig_builder = sig_builder.receivers(receivers);
176
177 msg_builder = msg_builder.add_signal(
178 sig_builder.build().expect("Signal conversion should always succeed"),
179 );
180 }
181
182 msg_builder.build().expect("Message conversion should always succeed")
183 })
184 .collect();
185
186 let mut value_descriptions = crate::dbc::ValueDescriptionsList::new();
188 for ((message_id, signal_name), vd) in dbc.value_descriptions().iter() {
189 let static_signal_name: &'static str = Box::leak(Box::from(signal_name.to_string()));
191 use crate::ValueDescriptionsBuilder;
193 let mut builder = ValueDescriptionsBuilder::new();
194 for (value, desc) in vd.iter() {
195 let static_desc: &'static str = Box::leak(Box::from(desc.to_string()));
196 builder = builder.add_entry(value, static_desc);
197 }
198 let static_vd =
199 builder.build().expect("ValueDescriptions conversion should always succeed");
200 value_descriptions.insert((message_id, static_signal_name), static_vd);
201 }
202
203 Self {
204 version,
205 nodes: Some(nodes),
206 messages,
207 value_descriptions,
208 }
209 }
210
211 #[must_use]
223 pub fn version(mut self, version: Version<'static>) -> Self {
224 self.version = Some(version);
225 self
226 }
227
228 #[must_use]
240 pub fn nodes(mut self, nodes: Nodes<'static>) -> Self {
241 self.nodes = Some(nodes);
242 self
243 }
244
245 #[must_use]
264 pub fn add_message(mut self, message: Message<'static>) -> Self {
265 self.messages.push(message);
266 self
267 }
268
269 #[must_use]
285 pub fn add_messages(mut self, messages: impl IntoIterator<Item = Message<'static>>) -> Self {
286 self.messages.extend(messages);
287 self
288 }
289
290 #[must_use]
304 pub fn messages(mut self, messages: Vec<Message<'static>>) -> Self {
305 self.messages = messages;
306 self
307 }
308
309 #[must_use]
320 pub fn clear_messages(mut self) -> Self {
321 self.messages.clear();
322 self
323 }
324
325 fn extract_fields(
326 self,
327 ) -> Result<(
328 Version<'static>,
329 Nodes<'static>,
330 Vec<Message<'static>>,
331 crate::dbc::ValueDescriptionsList<'static>,
332 )> {
333 let version = self.version.ok_or(Error::dbc(crate::error::lang::DBC_VERSION_REQUIRED))?;
334 let nodes = self.nodes.unwrap_or_default();
336 Ok((version, nodes, self.messages, self.value_descriptions))
337 }
338
339 #[must_use = "validation result should be checked"]
356 pub fn validate(mut self) -> Result<Self> {
357 let value_descriptions = core::mem::take(&mut self.value_descriptions);
359 let (version, nodes, messages, _) = self.extract_fields()?;
360 let messages_options: Vec<Option<Message<'static>>> =
362 messages.into_iter().map(Some).collect();
363 let messages_options_slice: &[Option<Message<'static>>] = &messages_options;
364 Dbc::validate(
365 &nodes,
366 messages_options_slice,
367 messages_options_slice.len(),
368 Some(&value_descriptions),
369 )
370 .map_err(|e| {
371 match e {
374 crate::error::ParseError::Message(msg) => Error::message(msg),
375 _ => Error::from(e),
377 }
378 })?;
379 Ok(Self {
381 version: Some(version),
382 nodes: Some(nodes),
383 messages: messages_options.into_iter().map(|opt| opt.unwrap()).collect(),
384 value_descriptions,
385 })
386 }
387
388 pub fn build(mut self) -> Result<Dbc<'static>> {
405 let value_descriptions = core::mem::take(&mut self.value_descriptions);
407 let (version, nodes, messages, _value_descriptions) = self.extract_fields()?;
408 let messages_options: Vec<Option<Message<'static>>> =
410 messages.into_iter().map(Some).collect();
411 let messages_options_slice: &[Option<Message<'static>>] = &messages_options;
412 Dbc::validate(
414 &nodes,
415 messages_options_slice,
416 messages_options_slice.len(),
417 Some(&value_descriptions),
418 )
419 .map_err(|e| {
420 match e {
423 crate::error::ParseError::Message(msg) => Error::message(msg),
424 _ => Error::from(e),
426 }
427 })?;
428 let messages: Vec<Message<'static>> =
430 messages_options.into_iter().map(|opt| opt.unwrap()).collect();
431 let messages_boxed: Box<[Message<'static>]> = messages.into_boxed_slice();
433 let messages_slice: &'static [Message<'static>] = Box::leak(messages_boxed);
434 Ok(Dbc::new(
435 Some(version),
436 nodes,
437 messages_slice,
438 value_descriptions,
439 ))
440 }
441}
442
443#[cfg(test)]
444mod tests {
445 #![allow(clippy::float_cmp)]
446 use super::DbcBuilder;
447 use crate::{ByteOrder, Dbc, Error, Parser, Version, error::lang};
448 #[cfg(any(feature = "alloc", feature = "kernel"))]
449 use crate::{MessageBuilder, NodesBuilder, ReceiversBuilder, SignalBuilder};
450 #[cfg(any(feature = "alloc", feature = "kernel"))]
451 use alloc::vec;
452
453 #[test]
454 fn test_dbc_builder_valid() {
455 let mut parser = Parser::new(b"VERSION \"1.0\"").unwrap();
456 let version = Version::parse(&mut parser).unwrap();
457 let nodes = NodesBuilder::new().add_node("ECM").build().unwrap();
458 let signal = SignalBuilder::new()
459 .name("RPM")
460 .start_bit(0)
461 .length(16)
462 .byte_order(ByteOrder::BigEndian)
463 .unsigned(true)
464 .factor(1.0)
465 .offset(0.0)
466 .min(0.0)
467 .max(100.0)
468 .receivers(ReceiversBuilder::new().none().build().unwrap())
469 .build()
470 .unwrap();
471 let message = MessageBuilder::new()
472 .id(256)
473 .name("EngineData")
474 .dlc(8)
475 .sender("ECM")
476 .add_signal(signal)
477 .build()
478 .unwrap();
479
480 let dbc = DbcBuilder::new(None)
481 .version(version)
482 .nodes(nodes)
483 .add_message(message)
484 .build()
485 .unwrap();
486
487 assert_eq!(dbc.messages().len(), 1);
488 assert_eq!(dbc.messages().at(0).unwrap().id(), 256);
489 }
490
491 #[test]
492 fn test_dbc_builder_missing_version() {
493 let nodes = NodesBuilder::new().add_node("ECM").build().unwrap();
494 let signal = SignalBuilder::new()
495 .name("RPM")
496 .start_bit(0)
497 .length(16)
498 .byte_order(ByteOrder::BigEndian)
499 .unsigned(true)
500 .factor(1.0)
501 .offset(0.0)
502 .min(0.0)
503 .max(100.0)
504 .receivers(ReceiversBuilder::new().none().build().unwrap())
505 .build()
506 .unwrap();
507 let message = MessageBuilder::new()
508 .id(256)
509 .name("EngineData")
510 .dlc(8)
511 .sender("ECM")
512 .add_signal(signal)
513 .build()
514 .unwrap();
515
516 let result = DbcBuilder::new(None).nodes(nodes).add_message(message).build();
517 assert!(result.is_err());
518 match result.unwrap_err() {
519 Error::Dbc(msg) => assert!(msg.contains(lang::DBC_VERSION_REQUIRED)),
520 _ => panic!("Expected Dbc error"),
521 }
522 }
523
524 #[test]
525 fn test_dbc_builder_missing_nodes() {
526 let mut parser = Parser::new(b"VERSION \"1.0\"").unwrap();
529 let version = Version::parse(&mut parser).unwrap();
530 let signal = SignalBuilder::new()
531 .name("RPM")
532 .start_bit(0)
533 .length(16)
534 .byte_order(ByteOrder::BigEndian)
535 .unsigned(true)
536 .factor(1.0)
537 .offset(0.0)
538 .min(0.0)
539 .max(100.0)
540 .receivers(ReceiversBuilder::new().none().build().unwrap())
541 .build()
542 .unwrap();
543 let message = MessageBuilder::new()
544 .id(256)
545 .name("EngineData")
546 .dlc(8)
547 .sender("ECM")
548 .add_signal(signal)
549 .build()
550 .unwrap();
551
552 let result = DbcBuilder::new(None).version(version).add_message(message).build();
554 assert!(result.is_ok());
555 let dbc = result.unwrap();
556 assert!(dbc.nodes().is_empty());
557 }
558
559 #[test]
560 fn test_dbc_builder_add_messages() {
561 let mut parser = Parser::new(b"VERSION \"1.0\"").unwrap();
562 let version = Version::parse(&mut parser).unwrap();
563 let nodes = NodesBuilder::new().add_node("ECM").build().unwrap();
564 let signal = SignalBuilder::new()
565 .name("RPM")
566 .start_bit(0)
567 .length(16)
568 .byte_order(ByteOrder::BigEndian)
569 .unsigned(true)
570 .factor(1.0)
571 .offset(0.0)
572 .min(0.0)
573 .max(100.0)
574 .receivers(ReceiversBuilder::new().none().build().unwrap())
575 .build()
576 .unwrap();
577 let message1 = MessageBuilder::new()
578 .id(256)
579 .name("EngineData")
580 .dlc(8)
581 .sender("ECM")
582 .add_signal(signal.clone())
583 .build()
584 .unwrap();
585 let message2 = MessageBuilder::new()
586 .id(512)
587 .name("BrakeData")
588 .dlc(4)
589 .sender("ECM")
590 .add_signal(signal)
591 .build()
592 .unwrap();
593
594 let dbc = DbcBuilder::new(None)
595 .version(version)
596 .nodes(nodes)
597 .add_messages(vec![message1, message2])
598 .build()
599 .unwrap();
600
601 assert_eq!(dbc.messages().len(), 2);
602 }
603
604 #[test]
605 fn test_dbc_builder_messages() {
606 let mut parser = Parser::new(b"VERSION \"1.0\"").unwrap();
607 let version = Version::parse(&mut parser).unwrap();
608 let nodes = NodesBuilder::new().add_node("ECM").build().unwrap();
609 let signal = SignalBuilder::new()
610 .name("RPM")
611 .start_bit(0)
612 .length(16)
613 .byte_order(ByteOrder::BigEndian)
614 .unsigned(true)
615 .factor(1.0)
616 .offset(0.0)
617 .min(0.0)
618 .max(100.0)
619 .receivers(ReceiversBuilder::new().none().build().unwrap())
620 .build()
621 .unwrap();
622 let message1 = MessageBuilder::new()
623 .id(256)
624 .name("EngineData")
625 .dlc(8)
626 .sender("ECM")
627 .add_signal(signal.clone())
628 .build()
629 .unwrap();
630 let message2 = MessageBuilder::new()
631 .id(512)
632 .name("BrakeData")
633 .dlc(4)
634 .sender("ECM")
635 .add_signal(signal)
636 .build()
637 .unwrap();
638
639 let dbc = DbcBuilder::new(None)
640 .version(version)
641 .nodes(nodes)
642 .add_message(message1)
643 .add_message(message2)
644 .build()
645 .unwrap();
646
647 assert_eq!(dbc.messages().len(), 2);
648 }
649
650 #[test]
651 fn test_dbc_builder_clear_messages() {
652 let mut parser = Parser::new(b"VERSION \"1.0\"").unwrap();
653 let version = Version::parse(&mut parser).unwrap();
654 let nodes = NodesBuilder::new().add_node("ECM").build().unwrap();
655 let signal = SignalBuilder::new()
656 .name("RPM")
657 .start_bit(0)
658 .length(16)
659 .byte_order(ByteOrder::BigEndian)
660 .unsigned(true)
661 .factor(1.0)
662 .offset(0.0)
663 .min(0.0)
664 .max(100.0)
665 .receivers(ReceiversBuilder::new().none().build().unwrap())
666 .build()
667 .unwrap();
668 let message = MessageBuilder::new()
669 .id(256)
670 .name("EngineData")
671 .dlc(8)
672 .sender("ECM")
673 .add_signal(signal)
674 .build()
675 .unwrap();
676
677 let dbc = DbcBuilder::new(None)
678 .version(version)
679 .nodes(nodes)
680 .add_message(message)
681 .clear_messages()
682 .build()
683 .unwrap();
684
685 assert_eq!(dbc.messages().len(), 0);
686 }
687
688 #[test]
689 fn test_dbc_builder_validate_missing_version() {
690 let nodes = NodesBuilder::new().add_node("ECM").build().unwrap();
691 let result = DbcBuilder::new(None).nodes(nodes).validate();
692 assert!(result.is_err());
693 match result.unwrap_err() {
694 Error::Dbc(msg) => assert!(msg.contains(lang::DBC_VERSION_REQUIRED)),
695 _ => panic!("Expected Dbc error"),
696 }
697 }
698
699 #[test]
700 fn test_dbc_builder_validate_missing_nodes() {
701 let mut parser = Parser::new(b"VERSION \"1.0\"").unwrap();
703 let version = Version::parse(&mut parser).unwrap();
704 let result = DbcBuilder::new(None).version(version).validate();
705 assert!(result.is_ok());
707 }
708
709 #[test]
710 fn test_dbc_builder_validate_valid() {
711 let mut parser = Parser::new(b"VERSION \"1.0\"").unwrap();
712 let version = Version::parse(&mut parser).unwrap();
713 let nodes = NodesBuilder::new().add_node("ECM").build().unwrap();
714 let signal = SignalBuilder::new()
715 .name("RPM")
716 .start_bit(0)
717 .length(16)
718 .byte_order(ByteOrder::BigEndian)
719 .unsigned(true)
720 .factor(1.0)
721 .offset(0.0)
722 .min(0.0)
723 .max(100.0)
724 .receivers(ReceiversBuilder::new().none().build().unwrap())
725 .build()
726 .unwrap();
727 let message = MessageBuilder::new()
728 .id(256)
729 .name("EngineData")
730 .dlc(8)
731 .sender("ECM")
732 .add_signal(signal)
733 .build()
734 .unwrap();
735
736 let result = DbcBuilder::new(None)
737 .version(version)
738 .nodes(nodes)
739 .add_message(message)
740 .validate();
741 assert!(result.is_ok());
742 let validated = result.unwrap();
744 let dbc = validated.build().unwrap();
745 assert_eq!(dbc.messages().len(), 1);
746 }
747
748 #[test]
749 fn test_dbc_builder_from_dbc() {
750 let dbc_content = r#"VERSION "1.0"
752
753BU_: ECM TCM
754
755BO_ 256 Engine : 8 ECM
756 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
757"#;
758 let original_dbc = Dbc::parse(dbc_content).unwrap();
759
760 let modified_dbc = DbcBuilder::new(Some(&original_dbc))
762 .add_message(
763 MessageBuilder::new()
764 .id(512)
765 .name("Brake")
766 .dlc(4)
767 .sender("TCM")
768 .build()
769 .unwrap(),
770 )
771 .build()
772 .unwrap();
773
774 assert_eq!(modified_dbc.version().map(|v| v.as_str()), Some("1.0"));
776 assert_eq!(modified_dbc.nodes().len(), 2);
777 assert!(modified_dbc.nodes().contains("ECM"));
778 assert!(modified_dbc.nodes().contains("TCM"));
779
780 assert_eq!(modified_dbc.messages().len(), 2);
782 assert!(modified_dbc.messages().iter().any(|m| m.id() == 256));
783 assert!(modified_dbc.messages().iter().any(|m| m.id() == 512));
784
785 let engine_msg = modified_dbc.messages().iter().find(|m| m.id() == 256).unwrap();
787 assert_eq!(engine_msg.signals().len(), 1);
788 assert_eq!(engine_msg.signals().at(0).unwrap().name(), "RPM");
789 }
790
791 #[test]
792 fn test_dbc_builder_from_dbc_empty() {
793 let dbc_content = r#"VERSION "1.0"
795
796BU_:
797"#;
798 let original_dbc = Dbc::parse(dbc_content).unwrap();
799
800 let modified_dbc = DbcBuilder::new(Some(&original_dbc))
802 .add_message(
803 MessageBuilder::new().id(256).name("Test").dlc(8).sender("ECM").build().unwrap(),
804 )
805 .build()
806 .unwrap();
807
808 assert_eq!(modified_dbc.version().map(|v| v.as_str()), Some("1.0"));
810 assert!(modified_dbc.nodes().is_empty());
812 assert_eq!(modified_dbc.messages().len(), 1);
814 }
815}