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