dbc-rs 0.4.2

Database CAN (DBC) parsing and editing library
Documentation
use super::MessageBuilder;
use crate::{SignalBuilder, builder_setter, builder_string_setter};
use std::vec::Vec;

impl MessageBuilder {
    /// Creates a new `MessageBuilder` with no fields set.
    ///
    /// # Examples
    ///
    /// ```rust,no_run
    /// use dbc_rs::MessageBuilder;
    ///
    /// let builder = MessageBuilder::new();
    /// // Must set id, name, dlc, and sender before building
    /// # Ok::<(), dbc_rs::Error>(())
    /// ```
    pub fn new() -> Self {
        Self {
            id: None,
            name: None,
            dlc: None,
            sender: None,
            signals: Vec::new(),
            comment: None,
        }
    }

    // Scalar field setters generated by macros
    builder_setter!(
        id,
        u32,
        "Sets the CAN message ID (11-bit or 29-bit identifier)."
    );
    builder_setter!(
        dlc,
        u8,
        "Sets the Data Length Code (DLC) - the number of data bytes in the message (0-8 for standard CAN, 0-64 for CAN FD)."
    );

    // String field setters generated by macros
    builder_string_setter!(name, "Sets the message name.");
    builder_string_setter!(
        sender,
        "Sets the sender (transmitter) ECU node name for this message."
    );
    builder_string_setter!(
        comment,
        "Sets the comment text for this message (from CM_ BO_ entry)."
    );

    /// Adds a signal to the message.
    ///
    /// # Arguments
    ///
    /// * `signal` - A `SignalBuilder` to add to this message
    ///
    /// # Examples
    ///
    /// ```rust,no_run
    /// use dbc_rs::{MessageBuilder, SignalBuilder, ByteOrder};
    ///
    /// let signal = SignalBuilder::new()
    ///     .name("EngineSpeed")
    ///     .start_bit(0)
    ///     .length(16)
    ///     .byte_order(ByteOrder::LittleEndian);
    ///
    /// let builder = MessageBuilder::new()
    ///     .add_signal(signal);
    /// # Ok::<(), dbc_rs::Error>(())
    /// ```
    #[must_use = "builder method returns modified builder"]
    pub fn add_signal(mut self, signal: SignalBuilder) -> Self {
        self.signals.push(signal);
        self
    }

    /// Adds multiple signals to the message.
    ///
    /// # Arguments
    ///
    /// * `signals` - An iterator of `SignalBuilder` items to add
    ///
    /// # Examples
    ///
    /// ```rust,no_run
    /// use dbc_rs::{MessageBuilder, SignalBuilder, ByteOrder};
    ///
    /// let signals = vec![
    ///     SignalBuilder::new().name("Signal1").start_bit(0).length(8).byte_order(ByteOrder::LittleEndian),
    ///     SignalBuilder::new().name("Signal2").start_bit(8).length(8).byte_order(ByteOrder::LittleEndian),
    /// ];
    ///
    /// let builder = MessageBuilder::new()
    ///     .add_signals(signals);
    /// # Ok::<(), dbc_rs::Error>(())
    /// ```
    #[must_use = "builder method returns modified builder"]
    pub fn add_signals(mut self, signals: impl IntoIterator<Item = SignalBuilder>) -> Self {
        self.signals.extend(signals);
        self
    }

    /// Replaces all signals in the message with the provided signals.
    ///
    /// Clears any existing signals and adds the new ones.
    ///
    /// # Arguments
    ///
    /// * `signals` - A vector of `SignalBuilder` items to set
    ///
    /// # Examples
    ///
    /// ```rust,no_run
    /// use dbc_rs::{MessageBuilder, SignalBuilder, ByteOrder};
    ///
    /// let new_signals = vec![
    ///     SignalBuilder::new().name("NewSignal").start_bit(0).length(8).byte_order(ByteOrder::LittleEndian),
    /// ];
    ///
    /// let builder = MessageBuilder::new()
    ///     .signals(new_signals);
    /// # Ok::<(), dbc_rs::Error>(())
    /// ```
    #[must_use = "builder method returns modified builder"]
    pub fn signals(mut self, signals: Vec<SignalBuilder>) -> Self {
        self.signals = signals;
        self
    }

    /// Removes all signals from the message.
    ///
    /// # Examples
    ///
    /// ```rust,no_run
    /// use dbc_rs::MessageBuilder;
    ///
    /// let builder = MessageBuilder::new()
    ///     .clear_signals();
    /// # Ok::<(), dbc_rs::Error>(())
    /// ```
    #[must_use = "builder method returns modified builder"]
    pub fn clear_signals(mut self) -> Self {
        self.signals.clear();
        self
    }
}

impl Default for MessageBuilder {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{ByteOrder, ReceiversBuilder};

    fn minimal_signal() -> SignalBuilder {
        SignalBuilder::new()
            .name("TestSignal")
            .start_bit(0)
            .length(8)
            .byte_order(ByteOrder::LittleEndian)
            .unsigned(true)
            .factor(1.0)
            .offset(0.0)
            .min(0.0)
            .max(255.0)
            .receivers(ReceiversBuilder::new().none())
    }

    fn minimal_message() -> MessageBuilder {
        MessageBuilder::new().id(256).name("TestMessage").dlc(8).sender("ECM")
    }

    #[test]
    fn test_message_builder_with_signal() {
        let message = minimal_message().add_signal(minimal_signal()).build().unwrap();

        assert_eq!(message.signals().len(), 1);
        assert_eq!(message.signals().at(0).unwrap().name(), "TestSignal");
    }

    #[test]
    fn test_message_builder_add_signals() {
        let sig1 = minimal_signal().name("Signal1");
        let sig2 = minimal_signal().name("Signal2").start_bit(8);

        let message = minimal_message().add_signals(vec![sig1, sig2]).build().unwrap();

        assert_eq!(message.signals().len(), 2);
    }

    #[test]
    fn test_message_builder_signals() {
        let sig1 = minimal_signal().name("Signal1");
        let sig2 = minimal_signal().name("Signal2").start_bit(8);

        let message = minimal_message().signals(vec![sig1, sig2]).build().unwrap();

        assert_eq!(message.signals().len(), 2);
    }

    #[test]
    fn test_message_builder_clear_signals() {
        let message =
            minimal_message().add_signal(minimal_signal()).clear_signals().build().unwrap();

        assert_eq!(message.signals().len(), 0);
    }
}