dbc_rs/signal/builder/
mod.rs

1use crate::{ByteOrder, Error, ReceiversBuilder, Result, Signal};
2
3type SignalFields = (
4    String,
5    u16,
6    u16,
7    ByteOrder,
8    bool,
9    f64,
10    f64,
11    f64,
12    f64,
13    Option<String>,
14    ReceiversBuilder,
15);
16
17#[derive(Debug, Clone)]
18pub struct SignalBuilder {
19    name: Option<String>,
20    start_bit: Option<u16>,
21    length: Option<u16>,
22    byte_order: Option<ByteOrder>,
23    unsigned: Option<bool>,
24    factor: Option<f64>,
25    offset: Option<f64>,
26    min: Option<f64>,
27    max: Option<f64>,
28    unit: Option<String>,
29    receivers: ReceiversBuilder,
30}
31
32impl SignalBuilder {
33    pub fn new() -> Self {
34        Self {
35            name: None,
36            start_bit: None,
37            length: None,
38            byte_order: None,
39            unsigned: None,
40            factor: None,
41            offset: None,
42            min: None,
43            max: None,
44            unit: None,
45            receivers: ReceiversBuilder::new(),
46        }
47    }
48
49    #[must_use = "builder method returns modified builder"]
50    pub fn name(mut self, name: impl AsRef<str>) -> Self {
51        self.name = Some(name.as_ref().to_string());
52        self
53    }
54
55    #[must_use = "builder method returns modified builder"]
56    pub fn start_bit(mut self, start_bit: u16) -> Self {
57        self.start_bit = Some(start_bit);
58        self
59    }
60
61    #[must_use = "builder method returns modified builder"]
62    pub fn length(mut self, length: u16) -> Self {
63        self.length = Some(length);
64        self
65    }
66
67    #[must_use = "builder method returns modified builder"]
68    pub fn byte_order(mut self, byte_order: ByteOrder) -> Self {
69        self.byte_order = Some(byte_order);
70        self
71    }
72
73    #[must_use = "builder method returns modified builder"]
74    pub fn unsigned(mut self, unsigned: bool) -> Self {
75        self.unsigned = Some(unsigned);
76        self
77    }
78
79    #[must_use = "builder method returns modified builder"]
80    pub fn factor(mut self, factor: f64) -> Self {
81        self.factor = Some(factor);
82        self
83    }
84
85    #[must_use = "builder method returns modified builder"]
86    pub fn offset(mut self, offset: f64) -> Self {
87        self.offset = Some(offset);
88        self
89    }
90
91    #[must_use = "builder method returns modified builder"]
92    pub fn min(mut self, min: f64) -> Self {
93        self.min = Some(min);
94        self
95    }
96
97    #[must_use = "builder method returns modified builder"]
98    pub fn max(mut self, max: f64) -> Self {
99        self.max = Some(max);
100        self
101    }
102
103    #[must_use = "builder method returns modified builder"]
104    pub fn unit(mut self, unit: impl AsRef<str>) -> Self {
105        self.unit = Some(unit.as_ref().to_string());
106        self
107    }
108
109    #[must_use = "builder method returns modified builder"]
110    pub fn receivers(mut self, receivers: ReceiversBuilder) -> Self {
111        self.receivers = receivers;
112        self
113    }
114
115    fn extract_fields(&self) -> Result<SignalFields> {
116        let name = self.name.clone().ok_or(Error::Signal(Error::SIGNAL_NAME_EMPTY))?;
117        let start_bit = self.start_bit.ok_or(Error::Signal(Error::SIGNAL_START_BIT_REQUIRED))?;
118        let length = self.length.ok_or(Error::Signal(Error::SIGNAL_LENGTH_REQUIRED))?;
119        let byte_order = self.byte_order.ok_or(Error::Signal(Error::SIGNAL_BYTE_ORDER_REQUIRED))?;
120        let unsigned = self.unsigned.ok_or(Error::Signal(Error::SIGNAL_UNSIGNED_REQUIRED))?;
121        let factor = self.factor.ok_or(Error::Signal(Error::SIGNAL_FACTOR_REQUIRED))?;
122        let offset = self.offset.ok_or(Error::Signal(Error::SIGNAL_OFFSET_REQUIRED))?;
123        let min = self.min.ok_or(Error::Signal(Error::SIGNAL_MIN_REQUIRED))?;
124        let max = self.max.ok_or(Error::Signal(Error::SIGNAL_MAX_REQUIRED))?;
125        Ok((
126            name,
127            start_bit,
128            length,
129            byte_order,
130            unsigned,
131            factor,
132            offset,
133            min,
134            max,
135            self.unit.clone(),
136            self.receivers.clone(),
137        ))
138    }
139
140    #[must_use = "validation result should be checked"]
141    pub fn validate(self) -> Result<Self> {
142        let (
143            name,
144            start_bit,
145            length,
146            byte_order,
147            unsigned,
148            factor,
149            offset,
150            min,
151            max,
152            unit,
153            receivers,
154        ) = self.extract_fields()?;
155
156        // Validate start_bit: must be between 0 and 511 (CAN FD maximum is 512 bits)
157        if start_bit > 511 {
158            return Err(Error::Signal(Error::SIGNAL_PARSE_INVALID_START_BIT));
159        }
160
161        // Validate that start_bit + length doesn't exceed CAN FD maximum (512 bits)
162        // Note: This is a basic sanity check. Full validation (including name, min/max,
163        // message DLC bounds, and overlap detection) happens in build() when the signal
164        // is actually constructed, to avoid duplicate validation calls.
165        let end_bit = start_bit + length - 1; // -1 because length includes the start bit
166        if end_bit >= 512 {
167            return Err(Error::Signal(Error::SIGNAL_EXTENDS_BEYOND_MESSAGE));
168        }
169        Ok(Self {
170            name: Some(name),
171            start_bit: Some(start_bit),
172            length: Some(length),
173            byte_order: Some(byte_order),
174            unsigned: Some(unsigned),
175            factor: Some(factor),
176            offset: Some(offset),
177            min: Some(min),
178            max: Some(max),
179            unit,
180            receivers,
181        })
182    }
183}
184
185impl SignalBuilder {
186    pub fn build(self) -> Result<Signal> {
187        let (
188            name,
189            start_bit,
190            length,
191            byte_order,
192            unsigned,
193            factor,
194            offset,
195            min,
196            max,
197            unit,
198            receivers,
199        ) = self.extract_fields()?;
200        // Build receivers first (receivers is already ReceiversBuilder)
201        let built_receivers = receivers.build()?;
202        // Validate before construction
203        Signal::validate(&name, length, min, max)?;
204        // Use Cow::Owned for owned strings (no leak needed)
205        Ok(Signal::new(
206            name.into(),
207            start_bit,
208            length,
209            byte_order,
210            unsigned,
211            factor,
212            offset,
213            min,
214            max,
215            unit.map(|u| u.into()),
216            built_receivers,
217        ))
218    }
219}
220
221impl Default for SignalBuilder {
222    fn default() -> Self {
223        Self::new()
224    }
225}