dbc_rs/signal/builder/
impls.rs

1use super::SignalBuilder;
2use super::{ByteOrder, ReceiversBuilder};
3use crate::{builder_setter, builder_string_setter};
4
5impl SignalBuilder {
6    /// Creates a new `SignalBuilder` with no fields set.
7    ///
8    /// # Examples
9    ///
10    /// ```rust,no_run
11    /// use dbc_rs::SignalBuilder;
12    ///
13    /// let builder = SignalBuilder::new();
14    /// // Must set name, start_bit, length, and byte_order before building
15    /// # Ok::<(), dbc_rs::Error>(())
16    /// ```
17    pub fn new() -> Self {
18        Self {
19            name: None,
20            start_bit: None,
21            length: None,
22            byte_order: None,
23            unsigned: None,
24            factor: None,
25            offset: None,
26            min: None,
27            max: None,
28            unit: None,
29            receivers: ReceiversBuilder::new(),
30            comment: None,
31        }
32    }
33
34    // String field setters generated by macros
35    builder_string_setter!(name, "Sets the signal name.");
36    builder_string_setter!(
37        unit,
38        "Sets the unit of measurement for this signal (e.g., \"km/h\", \"rpm\", \"°C\")."
39    );
40    builder_string_setter!(
41        comment,
42        "Sets the comment text for this signal (from CM_ SG_ entry)."
43    );
44
45    // Scalar field setters generated by macros
46    builder_setter!(
47        start_bit,
48        u16,
49        "Sets the start bit position of the signal in the CAN message payload."
50    );
51    builder_setter!(length, u16, "Sets the length of the signal in bits.");
52    builder_setter!(
53        byte_order,
54        ByteOrder,
55        "Sets the byte order (endianness) of the signal."
56    );
57    builder_setter!(
58        unsigned,
59        bool,
60        "Sets whether the signal is unsigned (`true`) or signed (`false`)."
61    );
62    builder_setter!(
63        factor,
64        f64,
65        "Sets the scaling factor for converting raw values to physical values (physical = raw * factor + offset)."
66    );
67    builder_setter!(
68        offset,
69        f64,
70        "Sets the offset for converting raw values to physical values (physical = raw * factor + offset)."
71    );
72    builder_setter!(min, f64, "Sets the minimum physical value for this signal.");
73    builder_setter!(max, f64, "Sets the maximum physical value for this signal.");
74
75    /// Sets the receivers (ECU nodes) that subscribe to this signal.
76    ///
77    /// # Arguments
78    ///
79    /// * `receivers` - A `ReceiversBuilder` specifying which nodes receive this signal
80    ///
81    /// # Examples
82    ///
83    /// ```rust,no_run
84    /// use dbc_rs::{SignalBuilder, ReceiversBuilder};
85    ///
86    /// let receivers = ReceiversBuilder::new()
87    ///     .add_node("ECU1")
88    ///     .add_node("ECU2");
89    ///
90    /// let builder = SignalBuilder::new()
91    ///     .receivers(receivers);
92    /// # Ok::<(), dbc_rs::Error>(())
93    /// ```
94    #[must_use = "builder method returns modified builder"]
95    pub fn receivers(mut self, receivers: ReceiversBuilder) -> Self {
96        self.receivers = receivers;
97        self
98    }
99}
100
101impl Default for SignalBuilder {
102    fn default() -> Self {
103        Self::new()
104    }
105}
106
107#[cfg(test)]
108mod tests {
109    use super::*;
110
111    fn minimal_signal() -> SignalBuilder {
112        SignalBuilder::new()
113            .name("TestSignal")
114            .start_bit(0)
115            .length(8)
116            .byte_order(ByteOrder::LittleEndian)
117            .unsigned(true)
118            .factor(1.0)
119            .offset(0.0)
120            .min(0.0)
121            .max(255.0)
122            .receivers(ReceiversBuilder::new().none())
123    }
124
125    #[test]
126    fn test_signal_builder_minimal() {
127        let signal = minimal_signal().build().unwrap();
128
129        assert_eq!(signal.name(), "TestSignal");
130        assert_eq!(signal.start_bit(), 0);
131        assert_eq!(signal.length(), 8);
132        assert_eq!(signal.byte_order(), ByteOrder::LittleEndian);
133        assert!(signal.is_unsigned());
134        assert_eq!(signal.factor(), 1.0);
135        assert_eq!(signal.offset(), 0.0);
136        assert_eq!(signal.min(), 0.0);
137        assert_eq!(signal.max(), 255.0);
138        assert!(signal.unit().is_none());
139    }
140
141    #[test]
142    fn test_signal_builder_with_unit() {
143        let signal = minimal_signal().unit("rpm").build().unwrap();
144        assert_eq!(signal.unit(), Some("rpm"));
145    }
146
147    #[test]
148    fn test_signal_builder_signed() {
149        let signal = minimal_signal().unsigned(false).build().unwrap();
150        assert!(!signal.is_unsigned());
151    }
152
153    #[test]
154    fn test_signal_builder_big_endian() {
155        let signal = minimal_signal().byte_order(ByteOrder::BigEndian).build().unwrap();
156        assert_eq!(signal.byte_order(), ByteOrder::BigEndian);
157    }
158
159    #[test]
160    fn test_signal_builder_with_receivers() {
161        let signal = minimal_signal()
162            .receivers(ReceiversBuilder::new().add_node("ECM").add_node("TCM"))
163            .build()
164            .unwrap();
165
166        assert_eq!(signal.receivers().len(), 2);
167    }
168
169    #[test]
170    fn test_signal_builder_with_comment() {
171        let signal = minimal_signal()
172            .comment("Engine speed calculated over 720 degrees")
173            .build()
174            .unwrap();
175
176        assert_eq!(
177            signal.comment(),
178            Some("Engine speed calculated over 720 degrees")
179        );
180    }
181
182    #[test]
183    fn test_signal_builder_without_comment() {
184        let signal = minimal_signal().build().unwrap();
185        assert_eq!(signal.comment(), None);
186    }
187}