dbc_rs/message/
message_builder.rs1#[cfg(any(feature = "alloc", feature = "kernel"))]
2use crate::compat::{Box, String, Vec, str_to_string};
3use crate::{
4 error::messages,
5 {Error, Message, ParseOptions, Result, Signal},
6};
7
8#[cfg(any(feature = "alloc", feature = "kernel"))]
9#[derive(Debug, Clone, Default)]
10pub struct MessageBuilder {
11 id: Option<u32>,
12 name: Option<String>,
13 dlc: Option<u8>,
14 sender: Option<String>,
15 signals: Vec<Signal<'static>>,
16}
17
18#[cfg(any(feature = "alloc", feature = "kernel"))]
19impl MessageBuilder {
20 pub fn new() -> Self {
21 Self::default()
22 }
23
24 #[must_use]
25 pub fn id(mut self, id: u32) -> Self {
26 self.id = Some(id);
27 self
28 }
29
30 #[must_use]
31 pub fn name(mut self, name: impl AsRef<str>) -> Self {
32 self.name = Some(str_to_string(name));
33 self
34 }
35
36 #[must_use]
37 pub fn dlc(mut self, dlc: u8) -> Self {
38 self.dlc = Some(dlc);
39 self
40 }
41
42 #[must_use]
43 pub fn sender(mut self, sender: impl AsRef<str>) -> Self {
44 self.sender = Some(str_to_string(sender));
45 self
46 }
47
48 #[must_use]
49 pub fn add_signal(mut self, signal: Signal<'static>) -> Self {
50 self.signals.push(signal);
51 self
52 }
53
54 #[must_use]
55 pub fn add_signals(mut self, signals: impl IntoIterator<Item = Signal<'static>>) -> Self {
56 self.signals.extend(signals);
57 self
58 }
59
60 #[must_use]
61 pub fn signals(mut self, signals: Vec<Signal<'static>>) -> Self {
62 self.signals = signals;
63 self
64 }
65
66 #[must_use]
67 pub fn clear_signals(mut self) -> Self {
68 self.signals.clear();
69 self
70 }
71
72 fn extract_fields(self) -> Result<(u32, String, u8, String, Vec<Signal<'static>>)> {
73 let id = self.id.ok_or_else(|| {
74 Error::Message(crate::error::str_to_error_string(
75 messages::MESSAGE_ID_REQUIRED,
76 ))
77 })?;
78 let name = self.name.ok_or_else(|| {
79 Error::Message(crate::error::str_to_error_string(
80 messages::MESSAGE_NAME_EMPTY,
81 ))
82 })?;
83 let dlc = self.dlc.ok_or_else(|| {
84 Error::Message(crate::error::str_to_error_string(
85 messages::MESSAGE_DLC_REQUIRED,
86 ))
87 })?;
88 let sender = self.sender.ok_or_else(|| {
89 Error::Message(crate::error::str_to_error_string(
90 messages::MESSAGE_SENDER_EMPTY,
91 ))
92 })?;
93 Ok((id, name, dlc, sender, self.signals))
94 }
95
96 #[must_use = "validation result should be checked"]
97 pub fn validate(self) -> Result<Self> {
98 let (id, name, dlc, sender, signals) = self.extract_fields()?;
99 let signals_options: Vec<Option<Signal<'static>>> =
101 signals.iter().cloned().map(Some).collect();
102 let signals_options_slice: &[Option<Signal<'static>>] = &signals_options;
103 Message::validate_internal(
104 id,
105 &name,
106 dlc,
107 &sender,
108 signals_options_slice,
109 signals_options_slice.len(),
110 ParseOptions::new(), )
112 .map_err(Error::from)?;
113 Ok(Self {
114 id: Some(id),
115 name: Some(name),
116 dlc: Some(dlc),
117 sender: Some(sender),
118 signals,
119 })
120 }
121
122 pub fn build(self) -> Result<Message<'static>> {
123 let (id, name, dlc, sender, signals) = self.extract_fields()?;
124 let signals_options: Vec<Option<Signal<'static>>> =
126 signals.iter().cloned().map(Some).collect();
127 let signals_options_slice: &[Option<Signal<'static>>] = &signals_options;
128 Message::validate_internal(
130 id,
131 &name,
132 dlc,
133 &sender,
134 signals_options_slice,
135 signals_options_slice.len(),
136 ParseOptions::new(), )
138 .map_err(|e| match e {
139 crate::error::ParseError::Version(msg) => {
140 Error::Dbc(crate::error::str_to_error_string(msg))
141 }
142 _ => Error::ParseError(e),
143 })?;
144 let name_boxed: Box<str> = name.into_boxed_str();
146 let name_static: &'static str = Box::leak(name_boxed);
147 let sender_boxed: Box<str> = sender.into_boxed_str();
148 let sender_static: &'static str = Box::leak(sender_boxed);
149 let signals_boxed: Box<[Signal<'static>]> = signals.into_boxed_slice();
151 let signals_static: &'static [Signal<'static>] = Box::leak(signals_boxed);
152 Ok(Message::new(
153 id,
154 name_static,
155 dlc,
156 sender_static,
157 signals_static,
158 ))
159 }
160}