midi2 0.11.1

Ergonomic, versatile, strong types wrapping MIDI 2.0 message data.
Documentation
use crate::{
    buffer::{
        Buffer, BufferMut, SpecialiseU32, SpecialiseU8, UnitPrivate, UNIT_ID_U32, UNIT_ID_U8,
    },
    detail::{
        property::{Property, ReadProperty, WriteProperty},
        schema, BitOps,
    },
    ux::*,
};

pub struct UmpMessageTypeProperty<const TYPE: u8>;

impl<const TYPE: u8, B: Buffer> Property<B> for UmpMessageTypeProperty<TYPE> {
    type Type = ();
}

impl<'a, const TYPE: u8, B: Buffer> ReadProperty<'a, B> for UmpMessageTypeProperty<TYPE> {
    fn read(_buffer: &'a B) -> Self::Type {}
    fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> {
        if <B::Unit as UnitPrivate>::UNIT_ID == UNIT_ID_U32 {
            let b = buffer.buffer().specialise_u32()[0];
            if b.nibble(0) != crate::ux::u4::new(TYPE) {
                return Err(crate::error::InvalidData("Incorrect ump message type"));
            }
        }
        Ok(())
    }
}

impl<const TYPE: u8, B: Buffer + crate::buffer::BufferMut> WriteProperty<B>
    for UmpMessageTypeProperty<TYPE>
{
    fn write(buffer: &mut B, _v: Self::Type) {
        if <B::Unit as UnitPrivate>::UNIT_ID == UNIT_ID_U32 {
            buffer.buffer_mut().specialise_u32_mut()[0].set_nibble(0, crate::ux::u4::new(TYPE));
        }
    }
    fn validate(_value: &Self::Type) -> Result<(), crate::error::InvalidData> {
        Ok(())
    }
    fn default() -> Self::Type {}
}

pub struct ChannelVoiceStatusProperty<const STATUS: u8>;

impl<const STATUS: u8, B: Buffer> Property<B> for ChannelVoiceStatusProperty<STATUS> {
    type Type = ();
}

impl<'a, const STATUS: u8, B: Buffer> ReadProperty<'a, B> for ChannelVoiceStatusProperty<STATUS> {
    fn read(_buffer: &'a B) -> Self::Type {}
    fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> {
        let status = match <B::Unit as UnitPrivate>::UNIT_ID {
            UNIT_ID_U32 => {
                let b = buffer.buffer().specialise_u32()[0];
                b.nibble(2)
            }
            UNIT_ID_U8 => {
                let b = buffer.buffer().specialise_u8()[0];
                b.nibble(0)
            }
            _ => unreachable!(),
        };
        if status == u4::new(STATUS) {
            Ok(())
        } else {
            Err(crate::error::InvalidData("Incorrect message status"))
        }
    }
}

impl<const STATUS: u8, B: Buffer + crate::buffer::BufferMut> WriteProperty<B>
    for ChannelVoiceStatusProperty<STATUS>
{
    fn write(buffer: &mut B, _v: Self::Type) {
        match <B::Unit as UnitPrivate>::UNIT_ID {
            UNIT_ID_U32 => {
                buffer.buffer_mut().specialise_u32_mut()[0]
                    .set_nibble(2, crate::ux::u4::new(STATUS));
            }
            UNIT_ID_U8 => {
                buffer.buffer_mut().specialise_u8_mut()[0]
                    .set_nibble(0, crate::ux::u4::new(STATUS));
            }
            _ => unreachable!(),
        }
    }
    fn validate(_value: &Self::Type) -> Result<(), crate::error::InvalidData> {
        Ok(())
    }
    fn default() -> Self::Type {}
}

pub type ChannelProperty = HybridSchemaProperty<
    u4,
    schema::Bytes<0x0F, 0x0, 0x0>,
    schema::Ump<0x000F_0000, 0x0, 0x0, 0x0>,
>;
pub type GroupProperty = UmpSchemaProperty<u4, schema::Ump<0x0F00_0000, 0x0, 0x0, 0x0>>;

pub struct HybridSchemaProperty<T, B: schema::BytesSchema, U: schema::UmpSchema>(
    core::marker::PhantomData<(T, B, U)>,
);

impl<
        B: Buffer,
        BytesSchema: schema::BytesSchema,
        UmpSchema: schema::UmpSchema,
        T: Default + schema::UmpSchemaRepr<UmpSchema> + schema::BytesSchemaRepr<BytesSchema>,
    > Property<B> for HybridSchemaProperty<T, BytesSchema, UmpSchema>
{
    type Type = T;
}

impl<
        'a,
        B: Buffer,
        BytesSchema: schema::BytesSchema,
        UmpSchema: schema::UmpSchema,
        T: Default + schema::UmpSchemaRepr<UmpSchema> + schema::BytesSchemaRepr<BytesSchema>,
    > ReadProperty<'a, B> for HybridSchemaProperty<T, BytesSchema, UmpSchema>
{
    fn read(buffer: &'a B) -> Self::Type {
        match <B::Unit as UnitPrivate>::UNIT_ID {
            UNIT_ID_U32 => {
                <T as schema::UmpSchemaRepr<UmpSchema>>::read(buffer.buffer().specialise_u32())
            }
            UNIT_ID_U8 => {
                <T as schema::BytesSchemaRepr<BytesSchema>>::read(buffer.buffer().specialise_u8())
            }
            _ => unreachable!(),
        }
    }
    fn validate(_buffer: &B) -> Result<(), crate::error::InvalidData> {
        Ok(())
    }
}

impl<
        B: Buffer + BufferMut,
        BytesSchema: schema::BytesSchema,
        UmpSchema: schema::UmpSchema,
        T: Default + schema::UmpSchemaRepr<UmpSchema> + schema::BytesSchemaRepr<BytesSchema>,
    > WriteProperty<B> for HybridSchemaProperty<T, BytesSchema, UmpSchema>
{
    fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> {
        Ok(())
    }
    fn write(buffer: &mut B, v: Self::Type) {
        match <B::Unit as UnitPrivate>::UNIT_ID {
            UNIT_ID_U32 => <T as schema::UmpSchemaRepr<UmpSchema>>::write(
                buffer.buffer_mut().specialise_u32_mut(),
                v,
            ),
            UNIT_ID_U8 => <T as schema::BytesSchemaRepr<BytesSchema>>::write(
                buffer.buffer_mut().specialise_u8_mut(),
                v,
            ),
            _ => unreachable!(),
        }
    }
    fn default() -> Self::Type {
        Default::default()
    }
}

pub struct UmpSchemaProperty<T, B: schema::UmpSchema>(core::marker::PhantomData<(T, B)>);

impl<B: Buffer, UmpSchema: schema::UmpSchema, T: Default + schema::UmpSchemaRepr<UmpSchema>>
    Property<B> for UmpSchemaProperty<T, UmpSchema>
{
    type Type = T;
}

impl<
        'a,
        B: Buffer,
        UmpSchema: schema::UmpSchema,
        T: Default + schema::UmpSchemaRepr<UmpSchema>,
    > ReadProperty<'a, B> for UmpSchemaProperty<T, UmpSchema>
{
    fn read(buffer: &'a B) -> Self::Type {
        match <B::Unit as UnitPrivate>::UNIT_ID {
            UNIT_ID_U32 => {
                <T as schema::UmpSchemaRepr<UmpSchema>>::read(buffer.buffer().specialise_u32())
            }
            UNIT_ID_U8 => Default::default(),
            _ => unreachable!(),
        }
    }
    fn validate(_buffer: &B) -> Result<(), crate::error::InvalidData> {
        Ok(())
    }
}

impl<
        B: Buffer + BufferMut,
        UmpSchema: schema::UmpSchema,
        T: Default + schema::UmpSchemaRepr<UmpSchema>,
    > WriteProperty<B> for UmpSchemaProperty<T, UmpSchema>
{
    fn write(buffer: &mut B, v: Self::Type) {
        if <B::Unit as UnitPrivate>::UNIT_ID == UNIT_ID_U32 {
            <T as schema::UmpSchemaRepr<UmpSchema>>::write(
                buffer.buffer_mut().specialise_u32_mut(),
                v,
            )
        }
    }
    fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> {
        Ok(())
    }
    fn default() -> Self::Type {
        Default::default()
    }
}