1#[cfg(any(feature = "alloc", feature = "kernel"))]
2use crate::compat::{Box, Vec};
3use crate::{
4 Dbc, Message, Nodes, Version,
5 error::{Error, Result, messages},
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}
50
51impl DbcBuilder {
52 pub fn new(dbc: Option<&Dbc<'_>>) -> Self {
96 match dbc {
97 Some(dbc) => Self::from_dbc(dbc),
98 None => Self::default(),
99 }
100 }
101
102 fn from_dbc(dbc: &Dbc<'_>) -> Self {
111 use crate::{
112 MessageBuilder, NodesBuilder, ReceiversBuilder, SignalBuilder, VersionBuilder,
113 };
114
115 let version = dbc.version().map(|v| {
117 VersionBuilder::new()
118 .version(v.as_str())
119 .build()
120 .expect("Version conversion should always succeed")
121 });
122
123 let nodes = {
125 let mut builder = NodesBuilder::new();
126 for node in dbc.nodes().iter() {
127 builder = builder.add_node(node);
128 }
129 builder.build().expect("Nodes conversion should always succeed")
130 };
131
132 let messages: Vec<Message<'static>> = dbc
134 .messages()
135 .iter()
136 .map(|msg| {
137 let mut msg_builder = MessageBuilder::new()
138 .id(msg.id())
139 .name(msg.name())
140 .dlc(msg.dlc())
141 .sender(msg.sender());
142
143 for sig in msg.signals().iter() {
145 let mut sig_builder = SignalBuilder::new()
146 .name(sig.name())
147 .start_bit(sig.start_bit())
148 .length(sig.length())
149 .byte_order(sig.byte_order())
150 .unsigned(sig.is_unsigned())
151 .factor(sig.factor())
152 .offset(sig.offset())
153 .min(sig.min())
154 .max(sig.max());
155
156 if let Some(unit) = sig.unit() {
157 sig_builder = sig_builder.unit(unit);
158 }
159
160 let receivers = match sig.receivers() {
162 crate::Receivers::Broadcast => {
163 ReceiversBuilder::new().broadcast().build().unwrap()
164 }
165 crate::Receivers::None => ReceiversBuilder::new().none().build().unwrap(),
166 crate::Receivers::Nodes(_, _) => {
167 let mut recv_builder = ReceiversBuilder::new();
168 for receiver in sig.receivers().iter() {
169 recv_builder = recv_builder.add_node(receiver);
170 }
171 recv_builder.build().unwrap()
172 }
173 };
174 sig_builder = sig_builder.receivers(receivers);
175
176 msg_builder = msg_builder.add_signal(
177 sig_builder.build().expect("Signal conversion should always succeed"),
178 );
179 }
180
181 msg_builder.build().expect("Message conversion should always succeed")
182 })
183 .collect();
184
185 Self {
186 version,
187 nodes: Some(nodes),
188 messages,
189 }
190 }
191
192 #[must_use]
204 pub fn version(mut self, version: Version<'static>) -> Self {
205 self.version = Some(version);
206 self
207 }
208
209 #[must_use]
221 pub fn nodes(mut self, nodes: Nodes<'static>) -> Self {
222 self.nodes = Some(nodes);
223 self
224 }
225
226 #[must_use]
245 pub fn add_message(mut self, message: Message<'static>) -> Self {
246 self.messages.push(message);
247 self
248 }
249
250 #[must_use]
266 pub fn add_messages(mut self, messages: impl IntoIterator<Item = Message<'static>>) -> Self {
267 self.messages.extend(messages);
268 self
269 }
270
271 #[must_use]
285 pub fn messages(mut self, messages: Vec<Message<'static>>) -> Self {
286 self.messages = messages;
287 self
288 }
289
290 #[must_use]
301 pub fn clear_messages(mut self) -> Self {
302 self.messages.clear();
303 self
304 }
305
306 fn extract_fields(self) -> Result<(Version<'static>, Nodes<'static>, Vec<Message<'static>>)> {
307 let version = self.version.ok_or_else(|| {
308 Error::Dbc(crate::error::str_to_error_string(
309 messages::DBC_VERSION_REQUIRED,
310 ))
311 })?;
312 let nodes = self.nodes.unwrap_or_default();
314 Ok((version, nodes, self.messages))
315 }
316
317 #[must_use = "validation result should be checked"]
334 pub fn validate(self) -> Result<Self> {
335 let (version, nodes, messages) = self.extract_fields()?;
336 let messages_options: Vec<Option<Message<'static>>> =
338 messages.into_iter().map(Some).collect();
339 let messages_options_slice: &[Option<Message<'static>>] = &messages_options;
340 Dbc::validate(
341 Some(&version),
342 &nodes,
343 messages_options_slice,
344 messages_options_slice.len(),
345 )
346 .map_err(|e| match e {
347 crate::error::ParseError::Version(msg) => {
348 Error::Dbc(crate::error::str_to_error_string(msg))
349 }
350 _ => Error::from(e),
351 })?;
352 Ok(Self {
353 version: Some(version),
354 nodes: Some(nodes),
355 messages: messages_options.into_iter().map(|opt| opt.unwrap()).collect(),
356 })
357 }
358
359 pub fn build(self) -> Result<Dbc<'static>> {
376 let (version, nodes, messages) = self.extract_fields()?;
377 let messages_options: Vec<Option<Message<'static>>> =
379 messages.into_iter().map(Some).collect();
380 let messages_options_slice: &[Option<Message<'static>>] = &messages_options;
381 Dbc::validate(
383 Some(&version),
384 &nodes,
385 messages_options_slice,
386 messages_options_slice.len(),
387 )
388 .map_err(|e| match e {
389 crate::error::ParseError::Version(msg) => {
390 Error::Dbc(crate::error::str_to_error_string(msg))
391 }
392 _ => Error::from(e),
393 })?;
394 let messages: Vec<Message<'static>> =
396 messages_options.into_iter().map(|opt| opt.unwrap()).collect();
397 let messages_boxed: Box<[Message<'static>]> = messages.into_boxed_slice();
399 let messages_slice: &'static [Message<'static>] = Box::leak(messages_boxed);
400 Ok(Dbc::new(Some(version), nodes, messages_slice))
401 }
402}
403
404#[cfg(test)]
405mod tests {
406 #![allow(clippy::float_cmp)]
407 use super::DbcBuilder;
408 use crate::{ByteOrder, Dbc, Error, Parser, Version, error::lang};
409 #[cfg(any(feature = "alloc", feature = "kernel"))]
410 use crate::{MessageBuilder, NodesBuilder, ReceiversBuilder, SignalBuilder};
411 #[cfg(any(feature = "alloc", feature = "kernel"))]
412 use alloc::vec;
413
414 #[test]
415 fn test_dbc_builder_valid() {
416 let mut parser = Parser::new(b"VERSION \"1.0\"").unwrap();
417 let version = Version::parse(&mut parser).unwrap();
418 let nodes = NodesBuilder::new().add_node("ECM").build().unwrap();
419 let signal = SignalBuilder::new()
420 .name("RPM")
421 .start_bit(0)
422 .length(16)
423 .byte_order(ByteOrder::BigEndian)
424 .unsigned(true)
425 .factor(1.0)
426 .offset(0.0)
427 .min(0.0)
428 .max(100.0)
429 .receivers(ReceiversBuilder::new().none().build().unwrap())
430 .build()
431 .unwrap();
432 let message = MessageBuilder::new()
433 .id(256)
434 .name("EngineData")
435 .dlc(8)
436 .sender("ECM")
437 .add_signal(signal)
438 .build()
439 .unwrap();
440
441 let dbc = DbcBuilder::new(None)
442 .version(version)
443 .nodes(nodes)
444 .add_message(message)
445 .build()
446 .unwrap();
447
448 assert_eq!(dbc.messages().len(), 1);
449 assert_eq!(dbc.messages().at(0).unwrap().id(), 256);
450 }
451
452 #[test]
453 fn test_dbc_builder_missing_version() {
454 let nodes = NodesBuilder::new().add_node("ECM").build().unwrap();
455 let signal = SignalBuilder::new()
456 .name("RPM")
457 .start_bit(0)
458 .length(16)
459 .byte_order(ByteOrder::BigEndian)
460 .unsigned(true)
461 .factor(1.0)
462 .offset(0.0)
463 .min(0.0)
464 .max(100.0)
465 .receivers(ReceiversBuilder::new().none().build().unwrap())
466 .build()
467 .unwrap();
468 let message = MessageBuilder::new()
469 .id(256)
470 .name("EngineData")
471 .dlc(8)
472 .sender("ECM")
473 .add_signal(signal)
474 .build()
475 .unwrap();
476
477 let result = DbcBuilder::new(None).nodes(nodes).add_message(message).build();
478 assert!(result.is_err());
479 match result.unwrap_err() {
480 Error::Dbc(msg) => assert!(msg.contains(lang::DBC_VERSION_REQUIRED)),
481 _ => panic!("Expected Dbc error"),
482 }
483 }
484
485 #[test]
486 fn test_dbc_builder_missing_nodes() {
487 let mut parser = Parser::new(b"VERSION \"1.0\"").unwrap();
490 let version = Version::parse(&mut parser).unwrap();
491 let signal = SignalBuilder::new()
492 .name("RPM")
493 .start_bit(0)
494 .length(16)
495 .byte_order(ByteOrder::BigEndian)
496 .unsigned(true)
497 .factor(1.0)
498 .offset(0.0)
499 .min(0.0)
500 .max(100.0)
501 .receivers(ReceiversBuilder::new().none().build().unwrap())
502 .build()
503 .unwrap();
504 let message = MessageBuilder::new()
505 .id(256)
506 .name("EngineData")
507 .dlc(8)
508 .sender("ECM")
509 .add_signal(signal)
510 .build()
511 .unwrap();
512
513 let result = DbcBuilder::new(None).version(version).add_message(message).build();
515 assert!(result.is_ok());
516 let dbc = result.unwrap();
517 assert!(dbc.nodes().is_empty());
518 }
519
520 #[test]
521 fn test_dbc_builder_add_messages() {
522 let mut parser = Parser::new(b"VERSION \"1.0\"").unwrap();
523 let version = Version::parse(&mut parser).unwrap();
524 let nodes = NodesBuilder::new().add_node("ECM").build().unwrap();
525 let signal = SignalBuilder::new()
526 .name("RPM")
527 .start_bit(0)
528 .length(16)
529 .byte_order(ByteOrder::BigEndian)
530 .unsigned(true)
531 .factor(1.0)
532 .offset(0.0)
533 .min(0.0)
534 .max(100.0)
535 .receivers(ReceiversBuilder::new().none().build().unwrap())
536 .build()
537 .unwrap();
538 let message1 = MessageBuilder::new()
539 .id(256)
540 .name("EngineData")
541 .dlc(8)
542 .sender("ECM")
543 .add_signal(signal.clone())
544 .build()
545 .unwrap();
546 let message2 = MessageBuilder::new()
547 .id(512)
548 .name("BrakeData")
549 .dlc(4)
550 .sender("ECM")
551 .add_signal(signal)
552 .build()
553 .unwrap();
554
555 let dbc = DbcBuilder::new(None)
556 .version(version)
557 .nodes(nodes)
558 .add_messages(vec![message1, message2])
559 .build()
560 .unwrap();
561
562 assert_eq!(dbc.messages().len(), 2);
563 }
564
565 #[test]
566 fn test_dbc_builder_messages() {
567 let mut parser = Parser::new(b"VERSION \"1.0\"").unwrap();
568 let version = Version::parse(&mut parser).unwrap();
569 let nodes = NodesBuilder::new().add_node("ECM").build().unwrap();
570 let signal = SignalBuilder::new()
571 .name("RPM")
572 .start_bit(0)
573 .length(16)
574 .byte_order(ByteOrder::BigEndian)
575 .unsigned(true)
576 .factor(1.0)
577 .offset(0.0)
578 .min(0.0)
579 .max(100.0)
580 .receivers(ReceiversBuilder::new().none().build().unwrap())
581 .build()
582 .unwrap();
583 let message1 = MessageBuilder::new()
584 .id(256)
585 .name("EngineData")
586 .dlc(8)
587 .sender("ECM")
588 .add_signal(signal.clone())
589 .build()
590 .unwrap();
591 let message2 = MessageBuilder::new()
592 .id(512)
593 .name("BrakeData")
594 .dlc(4)
595 .sender("ECM")
596 .add_signal(signal)
597 .build()
598 .unwrap();
599
600 let dbc = DbcBuilder::new(None)
601 .version(version)
602 .nodes(nodes)
603 .add_message(message1)
604 .add_message(message2)
605 .build()
606 .unwrap();
607
608 assert_eq!(dbc.messages().len(), 2);
609 }
610
611 #[test]
612 fn test_dbc_builder_clear_messages() {
613 let mut parser = Parser::new(b"VERSION \"1.0\"").unwrap();
614 let version = Version::parse(&mut parser).unwrap();
615 let nodes = NodesBuilder::new().add_node("ECM").build().unwrap();
616 let signal = SignalBuilder::new()
617 .name("RPM")
618 .start_bit(0)
619 .length(16)
620 .byte_order(ByteOrder::BigEndian)
621 .unsigned(true)
622 .factor(1.0)
623 .offset(0.0)
624 .min(0.0)
625 .max(100.0)
626 .receivers(ReceiversBuilder::new().none().build().unwrap())
627 .build()
628 .unwrap();
629 let message = MessageBuilder::new()
630 .id(256)
631 .name("EngineData")
632 .dlc(8)
633 .sender("ECM")
634 .add_signal(signal)
635 .build()
636 .unwrap();
637
638 let dbc = DbcBuilder::new(None)
639 .version(version)
640 .nodes(nodes)
641 .add_message(message)
642 .clear_messages()
643 .build()
644 .unwrap();
645
646 assert_eq!(dbc.messages().len(), 0);
647 }
648
649 #[test]
650 fn test_dbc_builder_validate_missing_version() {
651 let nodes = NodesBuilder::new().add_node("ECM").build().unwrap();
652 let result = DbcBuilder::new(None).nodes(nodes).validate();
653 assert!(result.is_err());
654 match result.unwrap_err() {
655 Error::Dbc(msg) => assert!(msg.contains(lang::DBC_VERSION_REQUIRED)),
656 _ => panic!("Expected Dbc error"),
657 }
658 }
659
660 #[test]
661 fn test_dbc_builder_validate_missing_nodes() {
662 let mut parser = Parser::new(b"VERSION \"1.0\"").unwrap();
664 let version = Version::parse(&mut parser).unwrap();
665 let result = DbcBuilder::new(None).version(version).validate();
666 assert!(result.is_ok());
668 }
669
670 #[test]
671 fn test_dbc_builder_validate_valid() {
672 let mut parser = Parser::new(b"VERSION \"1.0\"").unwrap();
673 let version = Version::parse(&mut parser).unwrap();
674 let nodes = NodesBuilder::new().add_node("ECM").build().unwrap();
675 let signal = SignalBuilder::new()
676 .name("RPM")
677 .start_bit(0)
678 .length(16)
679 .byte_order(ByteOrder::BigEndian)
680 .unsigned(true)
681 .factor(1.0)
682 .offset(0.0)
683 .min(0.0)
684 .max(100.0)
685 .receivers(ReceiversBuilder::new().none().build().unwrap())
686 .build()
687 .unwrap();
688 let message = MessageBuilder::new()
689 .id(256)
690 .name("EngineData")
691 .dlc(8)
692 .sender("ECM")
693 .add_signal(signal)
694 .build()
695 .unwrap();
696
697 let result = DbcBuilder::new(None)
698 .version(version)
699 .nodes(nodes)
700 .add_message(message)
701 .validate();
702 assert!(result.is_ok());
703 let validated = result.unwrap();
705 let dbc = validated.build().unwrap();
706 assert_eq!(dbc.messages().len(), 1);
707 }
708
709 #[test]
710 fn test_dbc_builder_from_dbc() {
711 let dbc_content = r#"VERSION "1.0"
713
714BU_: ECM TCM
715
716BO_ 256 Engine : 8 ECM
717 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
718"#;
719 let original_dbc = Dbc::parse(dbc_content).unwrap();
720
721 let modified_dbc = DbcBuilder::new(Some(&original_dbc))
723 .add_message(
724 MessageBuilder::new()
725 .id(512)
726 .name("Brake")
727 .dlc(4)
728 .sender("TCM")
729 .build()
730 .unwrap(),
731 )
732 .build()
733 .unwrap();
734
735 assert_eq!(modified_dbc.version().map(|v| v.as_str()), Some("1.0"));
737 assert_eq!(modified_dbc.nodes().len(), 2);
738 assert!(modified_dbc.nodes().contains("ECM"));
739 assert!(modified_dbc.nodes().contains("TCM"));
740
741 assert_eq!(modified_dbc.messages().len(), 2);
743 assert!(modified_dbc.messages().iter().any(|m| m.id() == 256));
744 assert!(modified_dbc.messages().iter().any(|m| m.id() == 512));
745
746 let engine_msg = modified_dbc.messages().iter().find(|m| m.id() == 256).unwrap();
748 assert_eq!(engine_msg.signals().len(), 1);
749 assert_eq!(engine_msg.signals().at(0).unwrap().name(), "RPM");
750 }
751
752 #[test]
753 fn test_dbc_builder_from_dbc_empty() {
754 let dbc_content = r#"VERSION "1.0"
756
757BU_:
758"#;
759 let original_dbc = Dbc::parse(dbc_content).unwrap();
760
761 let modified_dbc = DbcBuilder::new(Some(&original_dbc))
763 .add_message(
764 MessageBuilder::new().id(256).name("Test").dlc(8).sender("ECM").build().unwrap(),
765 )
766 .build()
767 .unwrap();
768
769 assert_eq!(modified_dbc.version().map(|v| v.as_str()), Some("1.0"));
771 assert!(modified_dbc.nodes().is_empty());
773 assert_eq!(modified_dbc.messages().len(), 1);
775 }
776}