dbc_rs/dbc/builder/
impls.rs

1use super::DbcBuilder;
2use crate::{
3    BitTimingBuilder, Dbc, ExtendedMultiplexingBuilder, MessageBuilder, NodesBuilder, Receivers,
4    ReceiversBuilder, SignalBuilder, ValueDescriptionsBuilder, VersionBuilder,
5};
6use std::collections::BTreeMap;
7
8impl DbcBuilder {
9    /// Creates a new empty `DbcBuilder`.
10    ///
11    /// # Examples
12    ///
13    /// ```rust,no_run
14    /// use dbc_rs::{DbcBuilder, VersionBuilder, NodesBuilder, MessageBuilder};
15    ///
16    /// let dbc = DbcBuilder::new()
17    ///     .version(VersionBuilder::new().version("1.0"))
18    ///     .nodes(NodesBuilder::new().add_node("ECM"))
19    ///     .add_message(MessageBuilder::new()
20    ///         .id(512)
21    ///         .name("Brake")
22    ///         .dlc(4)
23    ///         .sender("ECM"))
24    ///     .build()?;
25    /// # Ok::<(), dbc_rs::Error>(())
26    /// ```
27    pub fn new() -> Self {
28        Self {
29            version: VersionBuilder::new(),
30            bit_timing: None,
31            nodes: NodesBuilder::new(),
32            messages: Vec::new(),
33            value_descriptions: BTreeMap::new(),
34            extended_multiplexing: Vec::new(),
35            comment: None,
36        }
37    }
38
39    /// Sets the version for the DBC file.
40    ///
41    /// # Examples
42    ///
43    /// ```rust,no_run
44    /// use dbc_rs::{DbcBuilder, VersionBuilder};
45    ///
46    /// let vb = VersionBuilder::new().version("1.0");
47    /// let builder = DbcBuilder::new()
48    ///     .version(vb);
49    /// # Ok::<(), dbc_rs::Error>(())
50    /// ```
51    #[must_use = "builder method returns modified builder"]
52    pub fn version(mut self, version: VersionBuilder) -> Self {
53        self.version = version;
54        self
55    }
56
57    /// Sets the bit timing configuration for the DBC file.
58    ///
59    /// The BS_ section in DBC files specifies CAN bus timing parameters.
60    /// This section is typically empty as bit timing is obsolete in modern CAN systems.
61    ///
62    /// # Examples
63    ///
64    /// ```rust,no_run
65    /// use dbc_rs::{DbcBuilder, BitTimingBuilder};
66    ///
67    /// let builder = DbcBuilder::new()
68    ///     .bit_timing(BitTimingBuilder::new().baudrate(500000));
69    /// # Ok::<(), dbc_rs::Error>(())
70    /// ```
71    #[must_use = "builder method returns modified builder"]
72    pub fn bit_timing(mut self, bit_timing: BitTimingBuilder) -> Self {
73        self.bit_timing = Some(bit_timing);
74        self
75    }
76
77    /// Sets the nodes (ECUs) for the DBC file.
78    ///
79    /// # Examples
80    ///
81    /// ```rust,no_run
82    /// use dbc_rs::{DbcBuilder, NodesBuilder};
83    ///
84    /// let builder = DbcBuilder::new()
85    ///     .nodes(NodesBuilder::new().add_node("ECM"));
86    /// # Ok::<(), dbc_rs::Error>(())
87    /// ```
88    #[must_use = "builder method returns modified builder"]
89    pub fn nodes(mut self, nodes: NodesBuilder) -> Self {
90        self.nodes = nodes;
91        self
92    }
93
94    /// Adds a message to the DBC file.
95    ///
96    /// # Examples
97    ///
98    /// ```rust,no_run
99    /// use dbc_rs::{DbcBuilder, MessageBuilder};
100    ///
101    /// let message = MessageBuilder::new()
102    ///     .id(256)
103    ///     .name("EngineData")
104    ///     .dlc(8)
105    ///     .sender("ECM");
106    ///
107    /// let builder = DbcBuilder::new()
108    ///     .add_message(message);
109    /// # Ok::<(), dbc_rs::Error>(())
110    /// ```
111    #[must_use = "builder method returns modified builder"]
112    pub fn add_message(mut self, message: MessageBuilder) -> Self {
113        self.messages.push(message);
114        self
115    }
116
117    /// Adds multiple messages to the DBC file.
118    ///
119    /// # Examples
120    ///
121    /// ```rust,no_run
122    /// use dbc_rs::{DbcBuilder, MessageBuilder};
123    ///
124    /// let msg1 = MessageBuilder::new().id(256).name("Msg1").dlc(8).sender("ECM");
125    /// let msg2 = MessageBuilder::new().id(512).name("Msg2").dlc(4).sender("TCM");
126    ///
127    /// let builder = DbcBuilder::new()
128    ///     .add_messages(vec![msg1, msg2]);
129    /// # Ok::<(), dbc_rs::Error>(())
130    /// ```
131    #[must_use = "builder method returns modified builder"]
132    pub fn add_messages(mut self, messages: impl IntoIterator<Item = MessageBuilder>) -> Self {
133        self.messages.extend(messages);
134        self
135    }
136
137    /// Clears all messages from the builder.
138    ///
139    /// # Examples
140    ///
141    /// ```rust,no_run
142    /// use dbc_rs::DbcBuilder;
143    ///
144    /// let builder = DbcBuilder::new()
145    ///     .clear_messages();
146    /// ```
147    #[must_use = "builder method returns modified builder"]
148    pub fn clear_messages(mut self) -> Self {
149        self.messages.clear();
150        self
151    }
152
153    /// Adds value descriptions for a signal in a message.
154    ///
155    /// Value descriptions (VAL_) map numeric signal values to human-readable text.
156    ///
157    /// # Arguments
158    ///
159    /// * `message_id` - The CAN message ID containing the signal
160    /// * `signal_name` - The name of the signal
161    /// * `value_descriptions` - The value descriptions builder
162    ///
163    /// # Examples
164    ///
165    /// ```rust,no_run
166    /// use dbc_rs::{DbcBuilder, ValueDescriptionsBuilder};
167    ///
168    /// let value_desc = ValueDescriptionsBuilder::new()
169    ///     .add_entry(0, "Park")
170    ///     .add_entry(1, "Drive");
171    ///
172    /// let builder = DbcBuilder::new()
173    ///     .add_value_description(256, "Gear", value_desc);
174    /// # Ok::<(), dbc_rs::Error>(())
175    /// ```
176    #[must_use = "builder method returns modified builder"]
177    pub fn add_value_description(
178        mut self,
179        message_id: u32,
180        signal_name: impl AsRef<str>,
181        value_descriptions: ValueDescriptionsBuilder,
182    ) -> Self {
183        self.value_descriptions.insert(
184            (Some(message_id), signal_name.as_ref().to_string()),
185            value_descriptions,
186        );
187        self
188    }
189
190    /// Adds global value descriptions for a signal (applies to all messages with this signal).
191    ///
192    /// Global value descriptions (VAL_ with message_id -1) apply to signals with the given
193    /// name in any message.
194    ///
195    /// # Arguments
196    ///
197    /// * `signal_name` - The name of the signal
198    /// * `value_descriptions` - The value descriptions builder
199    ///
200    /// # Examples
201    ///
202    /// ```rust,no_run
203    /// use dbc_rs::{DbcBuilder, ValueDescriptionsBuilder};
204    ///
205    /// let value_desc = ValueDescriptionsBuilder::new()
206    ///     .add_entry(0, "Off")
207    ///     .add_entry(1, "On");
208    ///
209    /// let builder = DbcBuilder::new()
210    ///     .add_global_value_description("Status", value_desc);
211    /// # Ok::<(), dbc_rs::Error>(())
212    /// ```
213    #[must_use = "builder method returns modified builder"]
214    pub fn add_global_value_description(
215        mut self,
216        signal_name: impl AsRef<str>,
217        value_descriptions: ValueDescriptionsBuilder,
218    ) -> Self {
219        self.value_descriptions
220            .insert((None, signal_name.as_ref().to_string()), value_descriptions);
221        self
222    }
223
224    /// Clears all value descriptions from the builder.
225    ///
226    /// # Examples
227    ///
228    /// ```rust,no_run
229    /// use dbc_rs::DbcBuilder;
230    ///
231    /// let builder = DbcBuilder::new()
232    ///     .clear_value_descriptions();
233    /// ```
234    #[must_use = "builder method returns modified builder"]
235    pub fn clear_value_descriptions(mut self) -> Self {
236        self.value_descriptions.clear();
237        self
238    }
239
240    /// Adds an extended multiplexing entry to the DBC file.
241    ///
242    /// Extended multiplexing (SG_MUL_VAL_) entries define which multiplexer switch
243    /// values activate specific multiplexed signals, allowing for range-based activation.
244    ///
245    /// # Examples
246    ///
247    /// ```rust,no_run
248    /// use dbc_rs::{DbcBuilder, ExtendedMultiplexingBuilder};
249    ///
250    /// let ext_mux = ExtendedMultiplexingBuilder::new()
251    ///     .message_id(500)
252    ///     .signal_name("Signal_A")
253    ///     .multiplexer_switch("Mux1")
254    ///     .add_value_range(0, 5);
255    ///
256    /// let builder = DbcBuilder::new()
257    ///     .add_extended_multiplexing(ext_mux);
258    /// # Ok::<(), dbc_rs::Error>(())
259    /// ```
260    #[must_use = "builder method returns modified builder"]
261    pub fn add_extended_multiplexing(mut self, ext_mux: ExtendedMultiplexingBuilder) -> Self {
262        self.extended_multiplexing.push(ext_mux);
263        self
264    }
265
266    /// Adds multiple extended multiplexing entries to the DBC file.
267    ///
268    /// # Examples
269    ///
270    /// ```rust,no_run
271    /// use dbc_rs::{DbcBuilder, ExtendedMultiplexingBuilder};
272    ///
273    /// let ext_mux1 = ExtendedMultiplexingBuilder::new()
274    ///     .message_id(500)
275    ///     .signal_name("Signal_A")
276    ///     .multiplexer_switch("Mux1")
277    ///     .add_value_range(0, 5);
278    /// let ext_mux2 = ExtendedMultiplexingBuilder::new()
279    ///     .message_id(500)
280    ///     .signal_name("Signal_B")
281    ///     .multiplexer_switch("Mux1")
282    ///     .add_value_range(10, 15);
283    ///
284    /// let builder = DbcBuilder::new()
285    ///     .add_extended_multiplexings(vec![ext_mux1, ext_mux2]);
286    /// # Ok::<(), dbc_rs::Error>(())
287    /// ```
288    #[must_use = "builder method returns modified builder"]
289    pub fn add_extended_multiplexings(
290        mut self,
291        ext_muxes: impl IntoIterator<Item = ExtendedMultiplexingBuilder>,
292    ) -> Self {
293        self.extended_multiplexing.extend(ext_muxes);
294        self
295    }
296
297    /// Clears all extended multiplexing entries from the builder.
298    ///
299    /// # Examples
300    ///
301    /// ```rust,no_run
302    /// use dbc_rs::DbcBuilder;
303    ///
304    /// let builder = DbcBuilder::new()
305    ///     .clear_extended_multiplexing();
306    /// ```
307    #[must_use = "builder method returns modified builder"]
308    pub fn clear_extended_multiplexing(mut self) -> Self {
309        self.extended_multiplexing.clear();
310        self
311    }
312
313    /// Sets the database-level comment (general CM_ entry).
314    ///
315    /// # Examples
316    ///
317    /// ```rust,no_run
318    /// use dbc_rs::DbcBuilder;
319    ///
320    /// let builder = DbcBuilder::new()
321    ///     .comment("CAN database for powertrain");
322    /// ```
323    #[must_use = "builder method returns modified builder"]
324    pub fn comment(mut self, comment: impl AsRef<str>) -> Self {
325        self.comment = Some(comment.as_ref().to_string());
326        self
327    }
328
329    /// Creates a `DbcBuilder` from an existing `Dbc`.
330    ///
331    /// This allows you to modify an existing DBC file by creating a builder
332    /// initialized with all data from the provided DBC.
333    ///
334    /// # Arguments
335    ///
336    /// * `dbc` - The existing `Dbc` to create a builder from
337    ///
338    /// # Examples
339    ///
340    /// ```rust,no_run
341    /// use dbc_rs::{Dbc, DbcBuilder, MessageBuilder};
342    ///
343    /// let original = Dbc::parse(r#"VERSION "1.0"\nBU_: ECM\n"#)?;
344    /// let modified = DbcBuilder::from_dbc(&original)
345    ///     .add_message(MessageBuilder::new().id(256).name("Msg").dlc(8).sender("ECM"))
346    ///     .build()?;
347    /// # Ok::<(), dbc_rs::Error>(())
348    /// ```
349    pub fn from_dbc(dbc: &Dbc) -> Self {
350        // Convert version to builder (store builder, not final type)
351        let version = if let Some(v) = dbc.version() {
352            VersionBuilder::new().version(v.as_str())
353        } else {
354            VersionBuilder::new()
355        };
356
357        // Copy bit timing - convert to builder
358        let bit_timing = dbc.bit_timing().map(|bt| {
359            let mut builder = BitTimingBuilder::new();
360            if let Some(baudrate) = bt.baudrate() {
361                builder = builder.baudrate(baudrate);
362            }
363            if let Some(btr1) = bt.btr1() {
364                builder = builder.btr1(btr1);
365            }
366            if let Some(btr2) = bt.btr2() {
367                builder = builder.btr2(btr2);
368            }
369            builder
370        });
371
372        // Convert nodes to builder (store builder, not final type)
373        // Note: We unwrap here because we're converting from a valid Dbc, so names should already fit MAX_NAME_SIZE
374        let nodes = {
375            let mut builder = NodesBuilder::new();
376            for node in dbc.nodes().iter() {
377                // Convert compat::String to std::string::String for the builder
378                let node_str = node.to_string();
379                // Should never fail for valid Dbc - unwrap is safe
380                builder = builder.add_node(node_str);
381            }
382            builder
383        };
384
385        // Convert messages to builders (store builders, not final types)
386        let messages: Vec<MessageBuilder> = dbc
387            .messages()
388            .iter()
389            .map(|msg| {
390                let mut msg_builder = MessageBuilder::new()
391                    .id(msg.id())
392                    .name(msg.name())
393                    .dlc(msg.dlc())
394                    .sender(msg.sender());
395
396                // Convert signals using SignalBuilder
397                for sig in msg.signals().iter() {
398                    let mut sig_builder = SignalBuilder::new()
399                        .name(sig.name())
400                        .start_bit(sig.start_bit())
401                        .length(sig.length())
402                        .byte_order(sig.byte_order())
403                        .unsigned(sig.is_unsigned())
404                        .factor(sig.factor())
405                        .offset(sig.offset())
406                        .min(sig.min())
407                        .max(sig.max());
408
409                    if let Some(unit) = sig.unit() {
410                        sig_builder = sig_builder.unit(unit);
411                    }
412
413                    // Convert receivers using ReceiversBuilder
414                    let receivers_builder = match sig.receivers() {
415                        Receivers::None => ReceiversBuilder::new().none(),
416                        Receivers::Nodes(nodes) => {
417                            let mut rb = ReceiversBuilder::new();
418                            // nodes is Vec<String<{MAX_NAME_SIZE}>>, iterate directly
419                            for receiver in nodes.iter() {
420                                // receiver is &String<{MAX_NAME_SIZE}>, clone it
421                                let receiver_str = receiver.clone();
422                                // Should never fail for valid Dbc - unwrap is safe
423                                rb = rb.add_node(receiver_str);
424                            }
425                            rb
426                        }
427                    };
428                    sig_builder = sig_builder.receivers(receivers_builder);
429
430                    msg_builder = msg_builder.add_signal(sig_builder);
431                }
432
433                msg_builder
434            })
435            .collect();
436
437        // Convert value descriptions from Dbc to builder format (store builders, not final types)
438        let mut value_descriptions: BTreeMap<(Option<u32>, String), ValueDescriptionsBuilder> =
439            BTreeMap::new();
440        for ((message_id, signal_name), vd) in dbc.value_descriptions().iter() {
441            // Store as String and ValueDescriptionsBuilder (no leak)
442            let mut builder = ValueDescriptionsBuilder::new();
443            for (value, desc) in vd.iter() {
444                builder = builder.add_entry(value, desc);
445            }
446            value_descriptions.insert((message_id, signal_name.to_string()), builder);
447        }
448
449        // Convert extended multiplexing entries to builders
450        let extended_multiplexing: Vec<ExtendedMultiplexingBuilder> = dbc
451            .extended_multiplexing()
452            .iter()
453            .map(|ext_mux| {
454                let mut builder = ExtendedMultiplexingBuilder::new()
455                    .message_id(ext_mux.message_id())
456                    .signal_name(ext_mux.signal_name())
457                    .multiplexer_switch(ext_mux.multiplexer_switch());
458
459                // Add all value ranges
460                for (min, max) in ext_mux.value_ranges() {
461                    builder = builder.add_value_range(*min, *max);
462                }
463
464                builder
465            })
466            .collect();
467
468        // Copy comment if present
469        let comment = dbc.comment().map(|c| c.to_string());
470
471        Self {
472            version,
473            bit_timing,
474            nodes,
475            messages,
476            value_descriptions,
477            extended_multiplexing,
478            comment,
479        }
480    }
481}
482
483#[cfg(test)]
484mod tests {
485    #![allow(clippy::float_cmp)]
486    use super::DbcBuilder;
487    use crate::{
488        ByteOrder, Dbc, ExtendedMultiplexingBuilder, MessageBuilder, NodesBuilder,
489        ReceiversBuilder, SignalBuilder, VersionBuilder,
490    };
491
492    #[test]
493    fn test_dbc_builder_add_messages() {
494        let version = VersionBuilder::new().version("1.0");
495        let nodes = NodesBuilder::new().add_nodes(["ECM"]);
496        let signal1 = SignalBuilder::new()
497            .name("RPM")
498            .start_bit(0)
499            .length(16)
500            .byte_order(ByteOrder::BigEndian)
501            .unsigned(true)
502            .factor(1.0)
503            .offset(0.0)
504            .min(0.0)
505            .max(100.0)
506            .receivers(ReceiversBuilder::new().none());
507        let signal2 = SignalBuilder::new()
508            .name("RPM")
509            .start_bit(0)
510            .length(16)
511            .byte_order(ByteOrder::BigEndian)
512            .unsigned(true)
513            .factor(1.0)
514            .offset(0.0)
515            .min(0.0)
516            .max(100.0)
517            .receivers(ReceiversBuilder::new().none());
518        let message1 = MessageBuilder::new()
519            .id(256)
520            .name("EngineData")
521            .dlc(8)
522            .sender("ECM")
523            .add_signal(signal1);
524        let message2 = MessageBuilder::new()
525            .id(512)
526            .name("BrakeData")
527            .dlc(4)
528            .sender("ECM")
529            .add_signal(signal2);
530
531        let dbc = DbcBuilder::new()
532            .version(version)
533            .nodes(nodes)
534            .add_messages(vec![message1, message2])
535            .build()
536            .unwrap();
537
538        assert_eq!(dbc.messages().len(), 2);
539    }
540
541    #[test]
542    fn test_dbc_builder_messages() {
543        let version = VersionBuilder::new().version("1.0");
544        let nodes = NodesBuilder::new().add_nodes(["ECM"]);
545
546        let signal1 = SignalBuilder::new()
547            .name("RPM")
548            .start_bit(0)
549            .length(16)
550            .byte_order(ByteOrder::BigEndian)
551            .unsigned(true)
552            .factor(1.0)
553            .offset(0.0)
554            .min(0.0)
555            .max(100.0)
556            .receivers(ReceiversBuilder::new().none());
557        let message1 = MessageBuilder::new()
558            .id(256)
559            .name("EngineData")
560            .dlc(8)
561            .sender("ECM")
562            .add_signal(signal1);
563
564        let signal2 = SignalBuilder::new()
565            .name("RPM")
566            .start_bit(0)
567            .length(16)
568            .byte_order(ByteOrder::BigEndian)
569            .unsigned(true)
570            .factor(1.0)
571            .offset(0.0)
572            .min(0.0)
573            .max(100.0)
574            .receivers(ReceiversBuilder::new().none());
575        let message2 = MessageBuilder::new()
576            .id(512)
577            .name("EngineData2")
578            .dlc(8)
579            .sender("ECM")
580            .add_signal(signal2);
581
582        let dbc = DbcBuilder::new()
583            .version(version)
584            .nodes(nodes)
585            .add_message(message1)
586            .add_message(message2)
587            .build()
588            .unwrap();
589
590        assert_eq!(dbc.messages().len(), 2);
591    }
592
593    #[test]
594    fn test_dbc_builder_clear_messages() {
595        let version = VersionBuilder::new().version("1.0");
596        let nodes = NodesBuilder::new().add_nodes(["ECM"]);
597        let signal = SignalBuilder::new()
598            .name("RPM")
599            .start_bit(0)
600            .length(16)
601            .byte_order(ByteOrder::BigEndian)
602            .unsigned(true)
603            .factor(1.0)
604            .offset(0.0)
605            .min(0.0)
606            .max(100.0)
607            .receivers(ReceiversBuilder::new().none());
608        let message = MessageBuilder::new()
609            .id(256)
610            .name("EngineData")
611            .dlc(8)
612            .sender("ECM")
613            .add_signal(signal);
614
615        let dbc = DbcBuilder::new()
616            .version(version)
617            .nodes(nodes)
618            .add_message(message)
619            .clear_messages()
620            .build()
621            .unwrap();
622
623        assert_eq!(dbc.messages().len(), 0);
624    }
625
626    #[test]
627    fn test_dbc_builder_from_dbc() {
628        // Parse an existing DBC
629        let dbc_content = r#"VERSION "1.0"
630
631BU_: ECM TCM
632
633BO_ 256 Engine : 8 ECM
634 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
635"#;
636        let original_dbc = Dbc::parse(dbc_content).unwrap();
637
638        // Create builder from existing DBC
639        let modified_dbc = DbcBuilder::from_dbc(&original_dbc)
640            .add_message(MessageBuilder::new().id(512).name("Brake").dlc(4).sender("TCM"))
641            .build()
642            .unwrap();
643
644        // Verify original data is preserved
645        assert_eq!(modified_dbc.version().map(|v| v.as_str()), Some("1.0"));
646        assert_eq!(modified_dbc.nodes().len(), 2);
647        assert!(modified_dbc.nodes().contains("ECM"));
648        assert!(modified_dbc.nodes().contains("TCM"));
649
650        // Verify original message is present
651        assert_eq!(modified_dbc.messages().len(), 2);
652        assert!(modified_dbc.messages().iter().any(|m| m.id() == 256));
653        assert!(modified_dbc.messages().iter().any(|m| m.id() == 512));
654
655        // Verify original message's signal is preserved
656        let engine_msg = modified_dbc.messages().iter().find(|m| m.id() == 256).unwrap();
657        assert_eq!(engine_msg.signals().len(), 1);
658        assert_eq!(engine_msg.signals().at(0).unwrap().name(), "RPM");
659    }
660
661    #[test]
662    fn test_dbc_builder_from_dbc_empty() {
663        // Parse a minimal DBC
664        let dbc_content = r#"VERSION "1.0"
665
666BU_:
667"#;
668        let original_dbc = Dbc::parse(dbc_content).unwrap();
669
670        // Create builder from existing DBC
671        let modified_dbc = DbcBuilder::from_dbc(&original_dbc)
672            .add_message(MessageBuilder::new().id(256).name("Test").dlc(8).sender("ECM"))
673            .build()
674            .unwrap();
675
676        // Verify version is preserved
677        assert_eq!(modified_dbc.version().map(|v| v.as_str()), Some("1.0"));
678        // Empty nodes are preserved
679        assert!(modified_dbc.nodes().is_empty());
680        // New message is added
681        assert_eq!(modified_dbc.messages().len(), 1);
682    }
683
684    #[test]
685    fn test_dbc_builder_from_dbc_with_extended_multiplexing() {
686        // Parse a DBC with extended multiplexing
687        let dbc_content = r#"VERSION "1.0"
688
689BU_: ECM
690
691BO_ 500 MuxMessage : 8 ECM
692 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
693 SG_ SignalA m0 : 16|16@1+ (0.1,0) [0|100] ""
694
695SG_MUL_VAL_ 500 SignalA Mux1 0-5,10-15 ;
696"#;
697        let original_dbc = Dbc::parse(dbc_content).unwrap();
698
699        // Verify original has extended multiplexing
700        assert_eq!(original_dbc.extended_multiplexing().len(), 1);
701
702        // Create builder from existing DBC and modify it
703        let modified_dbc = DbcBuilder::from_dbc(&original_dbc)
704            .add_extended_multiplexing(
705                ExtendedMultiplexingBuilder::new()
706                    .message_id(500)
707                    .signal_name("SignalA")
708                    .multiplexer_switch("Mux1")
709                    .add_value_range(20, 25),
710            )
711            .build()
712            .unwrap();
713
714        // Verify extended multiplexing is preserved and new one added
715        assert_eq!(modified_dbc.extended_multiplexing().len(), 2);
716
717        // Check original entry
718        let original_entry = &modified_dbc.extended_multiplexing()[0];
719        assert_eq!(original_entry.signal_name(), "SignalA");
720        assert_eq!(original_entry.value_ranges().len(), 2);
721        assert_eq!(original_entry.value_ranges()[0], (0, 5));
722        assert_eq!(original_entry.value_ranges()[1], (10, 15));
723
724        // Check new entry
725        let new_entry = &modified_dbc.extended_multiplexing()[1];
726        assert_eq!(new_entry.signal_name(), "SignalA");
727        assert_eq!(new_entry.value_ranges().len(), 1);
728        assert_eq!(new_entry.value_ranges()[0], (20, 25));
729    }
730}
731
732impl Default for DbcBuilder {
733    fn default() -> Self {
734        Self::new()
735    }
736}