midi2 0.11.1

Ergonomic, versatile, strong types wrapping MIDI 2.0 message data.
Documentation
use crate::{error, ump_stream};

#[derive(Eq, PartialEq, Clone, midi2_proc::Debug)]
pub struct Packet(pub(crate) [u32; 4]);

impl crate::traits::BufferAccess<[u32; 4]> for Packet {
    fn buffer_access(&self) -> &[u32; 4] {
        &self.0
    }
    fn buffer_access_mut(&mut self) -> &mut [u32; 4]
    where
        [u32; 4]: crate::buffer::BufferMut,
    {
        &mut self.0
    }
}

impl<'a> core::convert::TryFrom<&'a [u32]> for Packet {
    type Error = error::InvalidData;
    fn try_from(data: &'a [u32]) -> Result<Self, Self::Error> {
        if data.is_empty() {
            return Err(error::InvalidData(
                crate::detail::common_err_strings::ERR_SLICE_TOO_SHORT,
            ));
        }

        use crate::detail::BitOps;
        if u8::from(data[0].nibble(0)) != ump_stream::UMP_MESSAGE_TYPE {
            return Err(error::InvalidData(
                crate::detail::common_err_strings::ERR_INCORRECT_UMP_MESSAGE_TYPE,
            ));
        }

        Ok(Packet({
            let mut buffer = [0x0; 4];
            let sz = 4.min(data.len());
            buffer[..sz].copy_from_slice(&data[..sz]);
            buffer
        }))
    }
}

impl core::ops::Deref for Packet {
    type Target = [u32];
    fn deref(&self) -> &Self::Target {
        &self.0[..]
    }
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Format {
    Complete,
    Start,
    Continue,
    End,
}

impl Packet {
    pub fn format(&self) -> Format {
        format_from_data(&self.0[..])
    }
}

fn format_from_data(data: &[u32]) -> Format {
    use crate::detail::BitOps;
    use Format::*;
    match u8::from(data[0].crumb(2)) {
        0x0 => Complete,
        0x1 => Start,
        0x2 => Continue,
        0x3 => End,
        _ => unreachable!(),
    }
}

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

    #[test]
    fn construction() {
        assert!(Packet::try_from(&[0xF000_0000][..]).is_ok())
    }

    #[test]
    fn construction_long_slice() {
        assert!(Packet::try_from(&[0xF000_0000, 0x0, 0x0, 0x0][..]).is_ok())
    }

    #[test]
    fn construction_very_long_slice() {
        assert!(Packet::try_from(&[0xF000_0000, 0x0, 0x0, 0x0, 0x0][..]).is_ok())
    }

    #[test]
    fn construction_short_slice() {
        assert_eq!(
            Packet::try_from(&[][..]),
            Err(error::InvalidData(
                crate::detail::common_err_strings::ERR_SLICE_TOO_SHORT
            )),
        )
    }

    #[test]
    fn construction_incorrect_ump_message_type() {
        assert_eq!(
            Packet::try_from(&[0x0000_0000, 0x0000_0000, 0x0000_0000, 0x0000_0000][..]),
            Err(error::InvalidData(
                crate::detail::common_err_strings::ERR_INCORRECT_UMP_MESSAGE_TYPE
            )),
        )
    }

    #[test]
    fn complete_format() {
        assert_eq!(
            Packet::try_from(&[0xF000_0000, 0x0000_0000, 0x0000_0000, 0x0000_0000][..])
                .unwrap()
                .format(),
            Format::Complete,
        )
    }

    #[test]
    fn start_format() {
        assert_eq!(
            Packet::try_from(&[0xF400_0000, 0x0000_0000, 0x0000_0000, 0x0000_0000][..])
                .unwrap()
                .format(),
            Format::Start,
        )
    }

    #[test]
    fn continue_format() {
        assert_eq!(
            Packet::try_from(&[0xF800_0000, 0x0000_0000, 0x0000_0000, 0x0000_0000][..])
                .unwrap()
                .format(),
            Format::Continue,
        )
    }

    #[test]
    fn end_format() {
        assert_eq!(
            Packet::try_from(&[0xFC00_0000, 0x0000_0000, 0x0000_0000, 0x0000_0000][..])
                .unwrap()
                .format(),
            Format::End,
        )
    }
}