can-dbc 9.0.0

A parser for the DBC format. The DBC format is used to exchange CAN network data.
Documentation
use std::str;

use crate::parser::DbcError;

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum MultiplexIndicator {
    /// Multiplexor switch
    Multiplexor,
    /// Signal is being multiplexed by the multiplexer switch.
    MultiplexedSignal(u64),
    /// Signal is being multiplexed by the multiplexer switch and itself is a multiplexer
    MultiplexorAndMultiplexedSignal(u64),
    /// Normal signal
    Plain,
}

impl TryFrom<&str> for MultiplexIndicator {
    type Error = DbcError;

    fn try_from(text: &str) -> Result<Self, Self::Error> {
        if text == "M" {
            return Ok(Self::Multiplexor);
        }
        if let Some(text) = text.strip_prefix('m') {
            // Multiplexed signal value should be like "m1" or "m1M"
            // Check if it ends with 'M' (multiplexer and multiplexed signal)
            if text.is_empty() {
                // FIXME: is this the right interpretation?
                return Ok(Self::Plain);
            } else if let Some(text) = text.strip_suffix('M') {
                if let Ok(value) = text.parse::<u64>() {
                    return Ok(Self::MultiplexorAndMultiplexedSignal(value));
                }
            } else if let Ok(value) = text.parse::<u64>() {
                return Ok(Self::MultiplexedSignal(value));
            }
        }

        Err(Self::Error::UnknownMultiplexIndicator(text.to_string()))
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn multiplexer_indicator_test() {
        let val: MultiplexIndicator = "m34920".try_into().unwrap();
        assert_eq!(val, MultiplexIndicator::MultiplexedSignal(34920));

        let val: MultiplexIndicator = "M".try_into().unwrap();
        assert_eq!(val, MultiplexIndicator::Multiplexor);

        // Empty string is not a valid multiplexer indicator, so we skip this test
        // let val: MultiplexIndicator = "".try_into().unwrap();
        // assert_eq!(val, MultiplexIndicator::Plain);

        let val: MultiplexIndicator = "m8M".try_into().unwrap();
        assert_eq!(val, MultiplexIndicator::MultiplexorAndMultiplexedSignal(8));
    }
}