dbc_rs/signal/builder/
build.rs

1use super::SignalBuilder;
2use crate::{ByteOrder, Error, ReceiversBuilder, Result, Signal, required_field};
3
4type SignalFields = (
5    String,
6    u16,
7    u16,
8    ByteOrder,
9    bool,
10    f64,
11    f64,
12    f64,
13    f64,
14    Option<String>,
15    ReceiversBuilder,
16);
17
18impl SignalBuilder {
19    fn extract_fields(&self) -> Result<SignalFields> {
20        let name = required_field!(self.name.clone(), Error::signal(Error::SIGNAL_NAME_EMPTY))?;
21        let start_bit = required_field!(
22            self.start_bit,
23            Error::signal(Error::SIGNAL_START_BIT_REQUIRED)
24        )?;
25        let length = required_field!(self.length, Error::signal(Error::SIGNAL_LENGTH_REQUIRED))?;
26        let byte_order = required_field!(
27            self.byte_order,
28            Error::signal(Error::SIGNAL_BYTE_ORDER_REQUIRED)
29        )?;
30        let unsigned = required_field!(
31            self.unsigned,
32            Error::signal(Error::SIGNAL_UNSIGNED_REQUIRED)
33        )?;
34        let factor = required_field!(self.factor, Error::signal(Error::SIGNAL_FACTOR_REQUIRED))?;
35        let offset = required_field!(self.offset, Error::signal(Error::SIGNAL_OFFSET_REQUIRED))?;
36        let min = required_field!(self.min, Error::signal(Error::SIGNAL_MIN_REQUIRED))?;
37        let max = required_field!(self.max, Error::signal(Error::SIGNAL_MAX_REQUIRED))?;
38        Ok((
39            name,
40            start_bit,
41            length,
42            byte_order,
43            unsigned,
44            factor,
45            offset,
46            min,
47            max,
48            self.unit.clone(),
49            self.receivers.clone(),
50        ))
51    }
52
53    #[must_use = "validation result should be checked"]
54    pub fn validate(self) -> Result<Self> {
55        let (
56            name,
57            start_bit,
58            length,
59            byte_order,
60            unsigned,
61            factor,
62            offset,
63            min,
64            max,
65            unit,
66            receivers,
67        ) = self.extract_fields()?;
68
69        // Validate start_bit: must be between 0 and 511 (CAN FD maximum is 512 bits)
70        if start_bit > 511 {
71            return Err(Error::signal(Error::SIGNAL_PARSE_INVALID_START_BIT));
72        }
73
74        // Validate that start_bit + length doesn't exceed CAN FD maximum (512 bits)
75        // Note: This is a basic sanity check. Full validation (including name, min/max,
76        // message DLC bounds, and overlap detection) happens in build() when the signal
77        // is actually constructed, to avoid duplicate validation calls.
78        let end_bit = start_bit + length - 1; // -1 because length includes the start bit
79        if end_bit >= 512 {
80            return Err(Error::signal(Error::SIGNAL_EXTENDS_BEYOND_MESSAGE));
81        }
82        Ok(Self {
83            name: Some(name),
84            start_bit: Some(start_bit),
85            length: Some(length),
86            byte_order: Some(byte_order),
87            unsigned: Some(unsigned),
88            factor: Some(factor),
89            offset: Some(offset),
90            min: Some(min),
91            max: Some(max),
92            unit,
93            receivers,
94        })
95    }
96
97    /// Builds and validates the `Signal`.
98    ///
99    /// Consumes the builder and returns a fully constructed and validated [`Signal`].
100    ///
101    /// # Errors
102    ///
103    /// Returns an error if:
104    /// - Any required field is missing (name, start_bit, length, byte_order, unsigned, factor, offset, min, max)
105    /// - Name exceeds maximum length (32 characters)
106    /// - Signal length is invalid (zero or exceeds 64 bits)
107    /// - Min value exceeds max value
108    /// - Receivers fail to build
109    ///
110    /// # Examples
111    ///
112    /// ```rust,no_run
113    /// use dbc_rs::{SignalBuilder, ByteOrder, ReceiversBuilder};
114    ///
115    /// let signal = SignalBuilder::new()
116    ///     .name("EngineSpeed")
117    ///     .start_bit(0)
118    ///     .length(16)
119    ///     .byte_order(ByteOrder::LittleEndian)
120    ///     .unsigned(true)
121    ///     .factor(0.25)
122    ///     .offset(0.0)
123    ///     .min(0.0)
124    ///     .max(8000.0)
125    ///     .unit("rpm")
126    ///     .receivers(ReceiversBuilder::new().add_node("TCM"))
127    ///     .build()?;
128    ///
129    /// assert_eq!(signal.name(), "EngineSpeed");
130    /// assert_eq!(signal.factor(), 0.25);
131    /// # Ok::<(), dbc_rs::Error>(())
132    /// ```
133    pub fn build(self) -> Result<Signal> {
134        let (
135            name,
136            start_bit,
137            length,
138            byte_order,
139            unsigned,
140            factor,
141            offset,
142            min,
143            max,
144            unit,
145            receivers,
146        ) = self.extract_fields()?;
147        // Build receivers first (receivers is already ReceiversBuilder)
148        let built_receivers = receivers.build()?;
149        // Validate before construction
150        Signal::validate(&name, length, min, max)?;
151        // Use Cow::Owned for owned strings (no leak needed)
152        Ok(Signal::new(
153            name.into(),
154            start_bit,
155            length,
156            byte_order,
157            unsigned,
158            factor,
159            offset,
160            min,
161            max,
162            unit.map(|u| u.into()),
163            built_receivers,
164        ))
165    }
166}
167
168#[cfg(test)]
169mod tests {
170    use super::*;
171
172    fn minimal_signal() -> SignalBuilder {
173        SignalBuilder::new()
174            .name("TestSignal")
175            .start_bit(0)
176            .length(8)
177            .byte_order(ByteOrder::LittleEndian)
178            .unsigned(true)
179            .factor(1.0)
180            .offset(0.0)
181            .min(0.0)
182            .max(255.0)
183            .receivers(ReceiversBuilder::new().none())
184    }
185
186    #[test]
187    fn test_signal_builder_new() {
188        let builder = SignalBuilder::new();
189        // Default builder should be empty
190        assert!(builder.build().is_err());
191    }
192
193    #[test]
194    fn test_signal_builder_default() {
195        let builder = SignalBuilder::default();
196        assert!(builder.build().is_err());
197    }
198
199    #[test]
200    fn test_signal_builder_missing_name() {
201        let result = SignalBuilder::new()
202            .start_bit(0)
203            .length(8)
204            .byte_order(ByteOrder::LittleEndian)
205            .unsigned(true)
206            .factor(1.0)
207            .offset(0.0)
208            .min(0.0)
209            .max(255.0)
210            .receivers(ReceiversBuilder::new().none())
211            .build();
212
213        assert!(result.is_err());
214    }
215
216    #[test]
217    fn test_signal_builder_missing_start_bit() {
218        let result = SignalBuilder::new()
219            .name("Test")
220            .length(8)
221            .byte_order(ByteOrder::LittleEndian)
222            .unsigned(true)
223            .factor(1.0)
224            .offset(0.0)
225            .min(0.0)
226            .max(255.0)
227            .receivers(ReceiversBuilder::new().none())
228            .build();
229
230        assert!(result.is_err());
231    }
232
233    #[test]
234    fn test_signal_builder_missing_length() {
235        let result = SignalBuilder::new()
236            .name("Test")
237            .start_bit(0)
238            .byte_order(ByteOrder::LittleEndian)
239            .unsigned(true)
240            .factor(1.0)
241            .offset(0.0)
242            .min(0.0)
243            .max(255.0)
244            .receivers(ReceiversBuilder::new().none())
245            .build();
246
247        assert!(result.is_err());
248    }
249
250    #[test]
251    fn test_signal_builder_missing_byte_order() {
252        let result = SignalBuilder::new()
253            .name("Test")
254            .start_bit(0)
255            .length(8)
256            .unsigned(true)
257            .factor(1.0)
258            .offset(0.0)
259            .min(0.0)
260            .max(255.0)
261            .receivers(ReceiversBuilder::new().none())
262            .build();
263
264        assert!(result.is_err());
265    }
266
267    #[test]
268    fn test_signal_builder_missing_unsigned() {
269        let result = SignalBuilder::new()
270            .name("Test")
271            .start_bit(0)
272            .length(8)
273            .byte_order(ByteOrder::LittleEndian)
274            .factor(1.0)
275            .offset(0.0)
276            .min(0.0)
277            .max(255.0)
278            .receivers(ReceiversBuilder::new().none())
279            .build();
280
281        assert!(result.is_err());
282    }
283
284    #[test]
285    fn test_signal_builder_missing_factor() {
286        let result = SignalBuilder::new()
287            .name("Test")
288            .start_bit(0)
289            .length(8)
290            .byte_order(ByteOrder::LittleEndian)
291            .unsigned(true)
292            .offset(0.0)
293            .min(0.0)
294            .max(255.0)
295            .receivers(ReceiversBuilder::new().none())
296            .build();
297
298        assert!(result.is_err());
299    }
300
301    #[test]
302    fn test_signal_builder_missing_offset() {
303        let result = SignalBuilder::new()
304            .name("Test")
305            .start_bit(0)
306            .length(8)
307            .byte_order(ByteOrder::LittleEndian)
308            .unsigned(true)
309            .factor(1.0)
310            .min(0.0)
311            .max(255.0)
312            .receivers(ReceiversBuilder::new().none())
313            .build();
314
315        assert!(result.is_err());
316    }
317
318    #[test]
319    fn test_signal_builder_missing_min() {
320        let result = SignalBuilder::new()
321            .name("Test")
322            .start_bit(0)
323            .length(8)
324            .byte_order(ByteOrder::LittleEndian)
325            .unsigned(true)
326            .factor(1.0)
327            .offset(0.0)
328            .max(255.0)
329            .receivers(ReceiversBuilder::new().none())
330            .build();
331
332        assert!(result.is_err());
333    }
334
335    #[test]
336    fn test_signal_builder_missing_max() {
337        let result = SignalBuilder::new()
338            .name("Test")
339            .start_bit(0)
340            .length(8)
341            .byte_order(ByteOrder::LittleEndian)
342            .unsigned(true)
343            .factor(1.0)
344            .offset(0.0)
345            .min(0.0)
346            .receivers(ReceiversBuilder::new().none())
347            .build();
348
349        assert!(result.is_err());
350    }
351
352    #[test]
353    fn test_signal_builder_validate_valid() {
354        let builder = minimal_signal();
355        let result = builder.validate();
356        assert!(result.is_ok());
357    }
358
359    #[test]
360    fn test_signal_builder_validate_start_bit_too_large() {
361        let builder = SignalBuilder::new()
362            .name("Test")
363            .start_bit(512) // > 511
364            .length(8)
365            .byte_order(ByteOrder::LittleEndian)
366            .unsigned(true)
367            .factor(1.0)
368            .offset(0.0)
369            .min(0.0)
370            .max(255.0)
371            .receivers(ReceiversBuilder::new().none());
372
373        let result = builder.validate();
374        assert!(result.is_err());
375    }
376
377    #[test]
378    fn test_signal_builder_validate_extends_beyond_512_bits() {
379        let builder = SignalBuilder::new()
380            .name("Test")
381            .start_bit(505)
382            .length(16) // 505 + 16 - 1 = 520 >= 512
383            .byte_order(ByteOrder::LittleEndian)
384            .unsigned(true)
385            .factor(1.0)
386            .offset(0.0)
387            .min(0.0)
388            .max(255.0)
389            .receivers(ReceiversBuilder::new().none());
390
391        let result = builder.validate();
392        assert!(result.is_err());
393    }
394
395    #[test]
396    fn test_signal_builder_validate_at_boundary() {
397        // 504 + 8 - 1 = 511 < 512, should pass
398        let builder = SignalBuilder::new()
399            .name("Test")
400            .start_bit(504)
401            .length(8)
402            .byte_order(ByteOrder::LittleEndian)
403            .unsigned(true)
404            .factor(1.0)
405            .offset(0.0)
406            .min(0.0)
407            .max(255.0)
408            .receivers(ReceiversBuilder::new().none());
409
410        let result = builder.validate();
411        assert!(result.is_ok());
412    }
413
414    #[test]
415    fn test_signal_builder_invalid_min_max_range() {
416        // min > max should fail
417        let result = SignalBuilder::new()
418            .name("Test")
419            .start_bit(0)
420            .length(8)
421            .byte_order(ByteOrder::LittleEndian)
422            .unsigned(true)
423            .factor(1.0)
424            .offset(0.0)
425            .min(100.0)
426            .max(0.0) // min > max
427            .receivers(ReceiversBuilder::new().none())
428            .build();
429
430        assert!(result.is_err());
431    }
432
433    #[test]
434    fn test_signal_builder_zero_length() {
435        let result = SignalBuilder::new()
436            .name("Test")
437            .start_bit(0)
438            .length(0) // Invalid
439            .byte_order(ByteOrder::LittleEndian)
440            .unsigned(true)
441            .factor(1.0)
442            .offset(0.0)
443            .min(0.0)
444            .max(255.0)
445            .receivers(ReceiversBuilder::new().none())
446            .build();
447
448        assert!(result.is_err());
449    }
450
451    #[test]
452    fn test_signal_builder_length_too_large() {
453        let result = SignalBuilder::new()
454            .name("Test")
455            .start_bit(0)
456            .length(513) // > 512
457            .byte_order(ByteOrder::LittleEndian)
458            .unsigned(true)
459            .factor(1.0)
460            .offset(0.0)
461            .min(0.0)
462            .max(255.0)
463            .receivers(ReceiversBuilder::new().none())
464            .build();
465
466        assert!(result.is_err());
467    }
468}