midi2 0.11.1

Ergonomic, versatile, strong types wrapping MIDI 2.0 message data.
Documentation
#![doc = include_str!("sysex7/README.md")]

use crate::{detail::common_err_strings, error::InvalidData};

#[derive(Eq, PartialEq, Clone, Debug, derive_more::From, derive_more::Deref)]
#[deref(forward)]
pub enum Packet {
    #[cfg(feature = "channel-voice1")]
    ChannelVoice1(crate::channel_voice1::Packet),
    #[cfg(feature = "channel-voice2")]
    ChannelVoice2(crate::channel_voice2::Packet),
    #[cfg(feature = "flex-data")]
    FlexData(crate::flex_data::Packet),
    #[cfg(feature = "sysex7")]
    Sysex7(crate::sysex7::Packet),
    #[cfg(feature = "sysex8")]
    Sysex8(crate::sysex8::Packet),
    #[cfg(feature = "system-common")]
    SystemCommon(crate::system_common::Packet),
    #[cfg(feature = "ump-stream")]
    UmpStream(crate::ump_stream::Packet),
    #[cfg(feature = "utility")]
    Utility(crate::utility::Packet),
}

impl<'a> core::convert::TryFrom<&'a [u32]> for Packet {
    type Error = crate::error::InvalidData;
    fn try_from(data: &'a [u32]) -> Result<Self, Self::Error> {
        #[cfg(feature = "channel-voice1")]
        use crate::channel_voice1;
        #[cfg(feature = "channel-voice2")]
        use crate::channel_voice2;
        use crate::detail::BitOps;
        #[cfg(feature = "flex-data")]
        use crate::flex_data;
        #[cfg(feature = "sysex7")]
        use crate::sysex7;
        #[cfg(feature = "sysex8")]
        use crate::sysex8;
        #[cfg(feature = "system-common")]
        use crate::system_common;
        #[cfg(feature = "ump-stream")]
        use crate::ump_stream;
        #[cfg(feature = "utility")]
        use crate::utility;

        if data.is_empty() {
            return Err(InvalidData(common_err_strings::ERR_SLICE_TOO_SHORT));
        }

        match u8::from(data[0].nibble(0)) {
            #[cfg(feature = "channel-voice1")]
            channel_voice1::UMP_MESSAGE_TYPE => Ok(channel_voice1::Packet::try_from(data)?.into()),
            #[cfg(feature = "channel-voice2")]
            channel_voice2::UMP_MESSAGE_TYPE => Ok(channel_voice2::Packet::try_from(data)?.into()),
            #[cfg(feature = "flex-data")]
            flex_data::UMP_MESSAGE_TYPE => Ok(flex_data::Packet::try_from(data)?.into()),
            #[cfg(feature = "sysex7")]
            sysex7::UMP_MESSAGE_TYPE => Ok(sysex7::Packet::try_from(data)?.into()),
            #[cfg(feature = "sysex8")]
            sysex8::UMP_MESSAGE_TYPE => Ok(sysex8::Packet::try_from(data)?.into()),
            #[cfg(feature = "system-common")]
            system_common::UMP_MESSAGE_TYPE => Ok(system_common::Packet::try_from(data)?.into()),
            #[cfg(feature = "ump-stream")]
            ump_stream::UMP_MESSAGE_TYPE => Ok(ump_stream::Packet::try_from(data)?.into()),
            #[cfg(feature = "utility")]
            utility::UMP_MESSAGE_TYPE => Ok(utility::Packet::try_from(data)?.into()),
            _ => Err(crate::error::InvalidData(
                common_err_strings::ERR_INCORRECT_UMP_MESSAGE_TYPE,
            )),
        }
    }
}

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

    #[test]
    #[cfg(feature = "utility")]
    fn construction() {
        let data = [0x0];
        assert_eq!(Packet::try_from(&data[..]).unwrap().deref(), &[0x0]);
    }

    #[test]
    #[cfg(feature = "sysex8")]
    fn construction_from_long_slice() {
        let data = [0x5001_0000, 0x0, 0x0, 0x0, 0x0];
        assert_eq!(
            &*Packet::try_from(&data[..]).unwrap(),
            &[0x5001_0000, 0x0, 0x0, 0x0]
        );
    }

    #[test]
    fn construction_from_empty_data() {
        let data = [];
        assert_eq!(
            Packet::try_from(&data[..]),
            Err(InvalidData(common_err_strings::ERR_SLICE_TOO_SHORT))
        );
    }

    #[test]
    fn construction_from_reserved_ump_type_field() {
        let data = [0xE000_0000, 0x0, 0x0, 0x0];
        assert_eq!(
            Packet::try_from(&data[..]),
            Err(InvalidData(
                common_err_strings::ERR_INCORRECT_UMP_MESSAGE_TYPE
            ))
        );
    }
}