mod no_op {
use crate::detail::common_properties;
use crate::utility;
pub const STATUS: u8 = 0b0000;
#[midi2_proc::generate_message(Via(crate::utility::Utility), FixedSize, MinSizeUmp(1))]
struct NoOp {
#[property(common_properties::UmpMessageTypeProperty<{utility::UMP_MESSAGE_TYPE}>)]
ump_type: (),
#[property(common_properties::ChannelVoiceStatusProperty<STATUS>)]
status: (),
#[property(utility::DataProperty)]
time_data: u16,
}
}
mod clock {
use crate::detail::common_properties;
use crate::utility;
pub const STATUS: u8 = 0b0001;
#[midi2_proc::generate_message(Via(crate::utility::Utility), FixedSize, MinSizeUmp(1))]
struct Clock {
#[property(common_properties::UmpMessageTypeProperty<{utility::UMP_MESSAGE_TYPE}>)]
ump_type: (),
#[property(common_properties::ChannelVoiceStatusProperty<STATUS>)]
status: (),
#[property(utility::DataProperty)]
time_data: u16,
}
}
mod timestamp {
use crate::detail::common_properties;
use crate::utility;
pub const STATUS: u8 = 0b0010;
#[midi2_proc::generate_message(Via(crate::utility::Utility), FixedSize, MinSizeUmp(1))]
struct Timestamp {
#[property(common_properties::UmpMessageTypeProperty<{utility::UMP_MESSAGE_TYPE}>)]
ump_type: (),
#[property(common_properties::ChannelVoiceStatusProperty<STATUS>)]
status: (),
#[property(utility::DataProperty)]
time_data: u16,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::traits::RebufferInto;
use pretty_assertions::assert_eq;
#[test]
fn from_data() {
assert_eq!(
Timestamp::try_from(&[0x0020_1234][..]),
Ok(Timestamp(&[0x0020_1234][..]))
);
}
#[test]
fn time_data() {
assert_eq!(
Timestamp::try_from(&[0x0020_1234][..]).unwrap().time_data(),
0x1234,
);
}
#[test]
fn new() {
let message = Timestamp::<std::vec::Vec<u32>>::new();
assert_eq!(message, Timestamp(std::vec![0x0020_0000]));
}
#[test]
fn try_new() {
let message = Timestamp::<[u32; 1]>::try_new();
assert_eq!(message, Ok(Timestamp([0x0020_0000])));
}
#[test]
fn try_new_fail() {
let message = Timestamp::<[u32; 0]>::try_new();
assert_eq!(message, Err(crate::error::BufferOverflow));
}
#[test]
fn new_arr() {
let message = Timestamp::<[u32; 4]>::new();
assert_eq!(message, Timestamp([0x0020_0000, 0x0, 0x0, 0x0]));
}
#[test]
fn rebuffer_into() {
let message = Timestamp::<[u32; 4]>::new();
let rebuffered: Timestamp<std::vec::Vec<u32>> = message.rebuffer_into();
assert_eq!(rebuffered.data(), Timestamp(std::vec![0x0020_0000]).data());
}
}
}
mod delta_clockstamp {
use crate::detail::common_properties;
use crate::utility;
use crate::ux::u20;
pub const STATUS: u8 = 0b0100;
#[midi2_proc::generate_message(Via(crate::utility::Utility), FixedSize, MinSizeUmp(1))]
struct DeltaClockstamp {
#[property(common_properties::UmpMessageTypeProperty<{utility::UMP_MESSAGE_TYPE}>)]
ump_type: (),
#[property(common_properties::ChannelVoiceStatusProperty<STATUS>)]
status: (),
#[property(DataProperty)]
time_data: u20,
}
struct DataProperty;
impl<B: crate::buffer::Ump> crate::detail::property::Property<B> for DataProperty {
type Type = u20;
}
impl<'a, B: crate::buffer::Ump> crate::detail::property::ReadProperty<'a, B> for DataProperty {
fn read(buffer: &'a B) -> Self::Type {
u20::new(buffer.buffer()[0] & 0x000F_FFFF)
}
fn validate(_buffer: &B) -> Result<(), crate::error::InvalidData> {
Ok(())
}
}
impl<B: crate::buffer::Ump + crate::buffer::BufferMut> crate::detail::property::WriteProperty<B>
for DataProperty
{
fn write(buffer: &mut B, value: Self::Type) {
buffer.buffer_mut()[0] &= !0x000F_FFFF;
buffer.buffer_mut()[0] |= u32::from(value);
}
fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> {
Ok(())
}
fn default() -> Self::Type {
Default::default()
}
}
}
mod delta_clockstamp_tpq {
use crate::detail::common_properties;
use crate::utility;
pub const STATUS: u8 = 0b0011;
#[midi2_proc::generate_message(Via(crate::utility::Utility), FixedSize, MinSizeUmp(1))]
struct DeltaClockstampTpq {
#[property(common_properties::UmpMessageTypeProperty<{utility::UMP_MESSAGE_TYPE}>)]
ump_type: (),
#[property(common_properties::ChannelVoiceStatusProperty<STATUS>)]
status: (),
#[property(utility::DataProperty)]
time_data: u16,
}
}
pub(crate) const UMP_MESSAGE_TYPE: u8 = 0x0;
pub use clock::Clock;
pub use delta_clockstamp::DeltaClockstamp;
pub use delta_clockstamp_tpq::DeltaClockstampTpq;
pub use no_op::NoOp;
pub use packet::Packet;
pub use timestamp::Timestamp;
struct DataProperty;
impl<B: crate::buffer::Ump> crate::detail::property::Property<B> for DataProperty {
type Type = u16;
}
impl<'a, B: crate::buffer::Ump> crate::detail::property::ReadProperty<'a, B> for DataProperty {
fn read(buffer: &'a B) -> Self::Type {
use crate::detail::BitOps;
buffer.buffer()[0].word(1)
}
fn validate(_buffer: &B) -> Result<(), crate::error::InvalidData> {
Ok(())
}
}
impl<B: crate::buffer::Ump + crate::buffer::BufferMut> crate::detail::property::WriteProperty<B>
for DataProperty
{
fn write(buffer: &mut B, value: Self::Type) {
use crate::detail::BitOps;
buffer.buffer_mut()[0].set_word(1, value);
}
fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> {
Ok(())
}
fn default() -> Self::Type {
Default::default()
}
}
#[derive(
derive_more::From,
midi2_proc::Data,
midi2_proc::Packets,
midi2_proc::RebufferFrom,
midi2_proc::RebufferFromArray,
midi2_proc::TryRebufferFrom,
Clone,
Copy,
Debug,
PartialEq,
Eq,
)]
#[non_exhaustive]
pub enum Utility<B: crate::buffer::Ump> {
NoOp(no_op::NoOp<B>),
Clock(clock::Clock<B>),
Timestamp(timestamp::Timestamp<B>),
DeltaClockstamp(delta_clockstamp::DeltaClockstamp<B>),
DeltaClockstampTpq(delta_clockstamp_tpq::DeltaClockstampTpq<B>),
}
impl<'a> core::convert::TryFrom<&'a [u32]> for Utility<&'a [u32]> {
type Error = crate::error::InvalidData;
fn try_from(buffer: &'a [u32]) -> Result<Self, Self::Error> {
if buffer.is_empty() {
return Err(crate::error::InvalidData(
crate::detail::common_err_strings::ERR_SLICE_TOO_SHORT,
));
};
Ok(match status(buffer) {
no_op::STATUS => no_op::NoOp::try_from(buffer)?.into(),
clock::STATUS => clock::Clock::try_from(buffer)?.into(),
timestamp::STATUS => timestamp::Timestamp::try_from(buffer)?.into(),
delta_clockstamp::STATUS => delta_clockstamp::DeltaClockstamp::try_from(buffer)?.into(),
delta_clockstamp_tpq::STATUS => {
delta_clockstamp_tpq::DeltaClockstampTpq::try_from(buffer)?.into()
}
_ => Err(crate::error::InvalidData("Unknown utility message status"))?,
})
}
}
fn status<U: crate::buffer::Unit>(buffer: &[U]) -> u8 {
use crate::detail::BitOps;
match <U as crate::buffer::UnitPrivate>::UNIT_ID {
crate::buffer::UNIT_ID_U8 => {
<U as crate::buffer::UnitPrivate>::specialise_buffer_u8(buffer)[0].nibble(0)
}
crate::buffer::UNIT_ID_U32 => {
<U as crate::buffer::UnitPrivate>::specialise_buffer_u32(buffer)[0].nibble(2)
}
_ => unreachable!(),
}
.into()
}
mod packet;
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn from_data() {
assert_eq!(
Utility::try_from(&[0x0010_1234][..]),
Ok(Utility::Clock(
clock::Clock::try_from(&[0x0010_1234][..]).unwrap()
))
);
}
#[test]
fn packets() {
use crate::Packets;
let message = Utility::try_from(&[0x0010_1234][..]).unwrap();
let mut packets = message.packets();
assert_eq!(&*packets.next().unwrap(), &[0x0010_1234][..]);
assert_eq!(packets.next(), None);
}
#[test]
fn rebuffer_from() {
use crate::ArrayRebufferFrom;
let message = Utility::try_from(&[0x0010_1234][..]).unwrap();
let _ = Utility::<[u32; 1]>::array_rebuffer_from(message);
}
#[test]
fn delta_clock_stamp_try_from() {
DeltaClockstamp::try_from(&[0x0040_0000][..]).unwrap();
}
#[test]
fn delta_clock_stamp_u20() {
use crate::ux::u20;
let dc = DeltaClockstamp::try_from(&[0x004A_BCDE][..]).unwrap();
assert_eq!(dc.time_data(), u20::new(0xABCDE));
let buffer: [u32; 4] = [0, 0, 0, 0];
let mut dc = DeltaClockstamp::try_new_with_buffer(buffer).unwrap();
dc.set_time_data(u20::new(0x1_2345));
assert_eq!(dc.time_data(), u20::new(0x1_2345));
}
#[test]
fn delta_clock_stamp_tpq_try_from() {
DeltaClockstampTpq::try_from(&[0x0030_0000][..]).unwrap();
}
#[test]
fn time_stamp_try_from() {
Timestamp::try_from(&[0x0020_0000][..]).unwrap();
}
}