From e69a9e1a1bcbf48875294123ab97f3e7abdd364d Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Sun, 12 May 2024 07:23:52 +0200 Subject: [PATCH 01/25] chore: fmt --- midi2_proc/src/generate_message.rs | 5 +-- src/channel_voice1/channel_pressure.rs | 7 +++- src/channel_voice1/key_pressure.rs | 7 +++- src/channel_voice1/note_off.rs | 7 +++- src/channel_voice1/note_on.rs | 7 +++- src/channel_voice1/pitch_bend.rs | 7 +++- src/channel_voice1/program_change.rs | 7 +++- src/system_common/mod.rs | 49 ++++++++++++++++++---- src/system_common/song_position_pointer.rs | 7 +++- src/system_common/song_select.rs | 7 +++- src/system_common/time_code.rs | 7 +++- src/utility/mod.rs | 4 +- 12 files changed, 100 insertions(+), 21 deletions(-) diff --git a/midi2_proc/src/generate_message.rs b/midi2_proc/src/generate_message.rs index 627fd69..6ef808b 100644 --- a/midi2_proc/src/generate_message.rs +++ b/midi2_proc/src/generate_message.rs @@ -171,12 +171,11 @@ fn parse_via_args(input: syn::parse::ParseStream) -> syn::Type { .parse() .expect("Bracketed expression should follow size arg"); - let syn::Expr::Path(path) = *expr - else { + let syn::Expr::Path(path) = *expr else { panic!("Via argument should contain a path type"); }; - syn::Type::Path(syn::TypePath{ + syn::Type::Path(syn::TypePath { qself: path.qself, path: path.path, }) diff --git a/src/channel_voice1/channel_pressure.rs b/src/channel_voice1/channel_pressure.rs index 2807c0b..9056b08 100644 --- a/src/channel_voice1/channel_pressure.rs +++ b/src/channel_voice1/channel_pressure.rs @@ -5,7 +5,12 @@ use crate::{ pub(crate) const STATUS: u8 = 0b1101; -#[midi2_proc::generate_message(Via(crate::channel_voice1::ChannelVoice1), FixedSize, MinSizeUmp(1), MinSizeBytes(2))] +#[midi2_proc::generate_message( + Via(crate::channel_voice1::ChannelVoice1), + FixedSize, + MinSizeUmp(1), + MinSizeBytes(2) +)] struct ChannelPressure { #[property(common_properties::UmpMessageTypeProperty)] ump_type: (), diff --git a/src/channel_voice1/key_pressure.rs b/src/channel_voice1/key_pressure.rs index edd0b83..e298b40 100644 --- a/src/channel_voice1/key_pressure.rs +++ b/src/channel_voice1/key_pressure.rs @@ -5,7 +5,12 @@ use crate::{ pub(crate) const STATUS: u8 = 0b1010; -#[midi2_proc::generate_message(Via(crate::channel_voice1::ChannelVoice1), FixedSize, MinSizeUmp(1), MinSizeBytes(3))] +#[midi2_proc::generate_message( + Via(crate::channel_voice1::ChannelVoice1), + FixedSize, + MinSizeUmp(1), + MinSizeBytes(3) +)] struct KeyPressure { #[property(common_properties::UmpMessageTypeProperty)] ump_type: (), diff --git a/src/channel_voice1/note_off.rs b/src/channel_voice1/note_off.rs index c1641ad..68821ee 100644 --- a/src/channel_voice1/note_off.rs +++ b/src/channel_voice1/note_off.rs @@ -5,7 +5,12 @@ use crate::{ pub(crate) const STATUS: u8 = 0b1000; -#[midi2_proc::generate_message(Via(crate::channel_voice1::ChannelVoice1), FixedSize, MinSizeUmp(1), MinSizeBytes(3))] +#[midi2_proc::generate_message( + Via(crate::channel_voice1::ChannelVoice1), + FixedSize, + MinSizeUmp(1), + MinSizeBytes(3) +)] struct NoteOff { #[property(common_properties::UmpMessageTypeProperty)] ump_type: (), diff --git a/src/channel_voice1/note_on.rs b/src/channel_voice1/note_on.rs index d77a240..58a6fea 100644 --- a/src/channel_voice1/note_on.rs +++ b/src/channel_voice1/note_on.rs @@ -5,7 +5,12 @@ use crate::{ pub(crate) const STATUS: u8 = 0b1001; -#[midi2_proc::generate_message(Via(crate::channel_voice1::ChannelVoice1), FixedSize, MinSizeUmp(1), MinSizeBytes(3))] +#[midi2_proc::generate_message( + Via(crate::channel_voice1::ChannelVoice1), + FixedSize, + MinSizeUmp(1), + MinSizeBytes(3) +)] struct NoteOn { #[property(common_properties::UmpMessageTypeProperty)] ump_type: (), diff --git a/src/channel_voice1/pitch_bend.rs b/src/channel_voice1/pitch_bend.rs index 9124bf9..a2c6e1a 100644 --- a/src/channel_voice1/pitch_bend.rs +++ b/src/channel_voice1/pitch_bend.rs @@ -5,7 +5,12 @@ use crate::{ pub(crate) const STATUS: u8 = 0b1110; -#[midi2_proc::generate_message(Via(crate::channel_voice1::ChannelVoice1), FixedSize, MinSizeUmp(1), MinSizeBytes(3))] +#[midi2_proc::generate_message( + Via(crate::channel_voice1::ChannelVoice1), + FixedSize, + MinSizeUmp(1), + MinSizeBytes(3) +)] struct PitchBend { #[property(common_properties::UmpMessageTypeProperty)] ump_type: (), diff --git a/src/channel_voice1/program_change.rs b/src/channel_voice1/program_change.rs index 9c66c8f..06fa89a 100644 --- a/src/channel_voice1/program_change.rs +++ b/src/channel_voice1/program_change.rs @@ -5,7 +5,12 @@ use crate::{ pub(crate) const STATUS: u8 = 0b1100; -#[midi2_proc::generate_message(Via(crate::channel_voice1::ChannelVoice1), FixedSize, MinSizeUmp(1), MinSizeBytes(2))] +#[midi2_proc::generate_message( + Via(crate::channel_voice1::ChannelVoice1), + FixedSize, + MinSizeUmp(1), + MinSizeBytes(2) +)] struct ProgramChange { #[property(common_properties::UmpMessageTypeProperty)] ump_type: (), diff --git a/src/system_common/mod.rs b/src/system_common/mod.rs index 7f43bcc..08bc399 100644 --- a/src/system_common/mod.rs +++ b/src/system_common/mod.rs @@ -12,7 +12,12 @@ mod tune_request { system_common::{self, UMP_MESSAGE_TYPE}, }; pub(crate) const STATUS: u8 = 0xF6; - #[midi2_proc::generate_message(Via(system_common::SystemCommon), FixedSize, MinSizeUmp(1), MinSizeBytes(2))] + #[midi2_proc::generate_message( + Via(system_common::SystemCommon), + FixedSize, + MinSizeUmp(1), + MinSizeBytes(2) + )] struct TuneRequest { #[property(common_properties::UmpMessageTypeProperty)] ump_type: (), @@ -28,7 +33,12 @@ mod timing_clock { system_common::{self, UMP_MESSAGE_TYPE}, }; pub(crate) const STATUS: u8 = 0xF8; - #[midi2_proc::generate_message(Via(system_common::SystemCommon), FixedSize, MinSizeUmp(1), MinSizeBytes(2))] + #[midi2_proc::generate_message( + Via(system_common::SystemCommon), + FixedSize, + MinSizeUmp(1), + MinSizeBytes(2) + )] struct TimingClock { #[property(common_properties::UmpMessageTypeProperty)] ump_type: (), @@ -44,7 +54,12 @@ mod start { system_common::{self, UMP_MESSAGE_TYPE}, }; pub(crate) const STATUS: u8 = 0xFA; - #[midi2_proc::generate_message(Via(system_common::SystemCommon), FixedSize, MinSizeUmp(1), MinSizeBytes(2))] + #[midi2_proc::generate_message( + Via(system_common::SystemCommon), + FixedSize, + MinSizeUmp(1), + MinSizeBytes(2) + )] struct Start { #[property(common_properties::UmpMessageTypeProperty)] ump_type: (), @@ -60,7 +75,12 @@ mod cont { system_common::{self, UMP_MESSAGE_TYPE}, }; pub(crate) const STATUS: u8 = 0xFB; - #[midi2_proc::generate_message(Via(system_common::SystemCommon), FixedSize, MinSizeUmp(1), MinSizeBytes(2))] + #[midi2_proc::generate_message( + Via(system_common::SystemCommon), + FixedSize, + MinSizeUmp(1), + MinSizeBytes(2) + )] struct Continue { #[property(common_properties::UmpMessageTypeProperty)] ump_type: (), @@ -76,7 +96,12 @@ mod stop { system_common::{self, UMP_MESSAGE_TYPE}, }; pub(crate) const STATUS: u8 = 0xFC; - #[midi2_proc::generate_message(Via(system_common::SystemCommon), FixedSize, MinSizeUmp(1), MinSizeBytes(2))] + #[midi2_proc::generate_message( + Via(system_common::SystemCommon), + FixedSize, + MinSizeUmp(1), + MinSizeBytes(2) + )] struct Stop { #[property(common_properties::UmpMessageTypeProperty)] ump_type: (), @@ -92,7 +117,12 @@ mod active_sensing { system_common::{self, UMP_MESSAGE_TYPE}, }; pub(crate) const STATUS: u8 = 0xFE; - #[midi2_proc::generate_message(Via(system_common::SystemCommon), FixedSize, MinSizeUmp(1), MinSizeBytes(2))] + #[midi2_proc::generate_message( + Via(system_common::SystemCommon), + FixedSize, + MinSizeUmp(1), + MinSizeBytes(2) + )] struct ActiveSensing { #[property(common_properties::UmpMessageTypeProperty)] ump_type: (), @@ -108,7 +138,12 @@ mod reset { system_common::{self, UMP_MESSAGE_TYPE}, }; pub(crate) const STATUS: u8 = 0xFF; - #[midi2_proc::generate_message(Via(system_common::SystemCommon), FixedSize, MinSizeUmp(1), MinSizeBytes(2))] + #[midi2_proc::generate_message( + Via(system_common::SystemCommon), + FixedSize, + MinSizeUmp(1), + MinSizeBytes(2) + )] struct Reset { #[property(common_properties::UmpMessageTypeProperty)] ump_type: (), diff --git a/src/system_common/song_position_pointer.rs b/src/system_common/song_position_pointer.rs index de56700..3aaa83d 100644 --- a/src/system_common/song_position_pointer.rs +++ b/src/system_common/song_position_pointer.rs @@ -5,7 +5,12 @@ use crate::{ pub const STATUS: u8 = 0xF2; -#[midi2_proc::generate_message(Via(system_common::SystemCommon), FixedSize, MinSizeUmp(1), MinSizeBytes(2))] +#[midi2_proc::generate_message( + Via(system_common::SystemCommon), + FixedSize, + MinSizeUmp(1), + MinSizeBytes(2) +)] struct SongPositionPointer { #[property(common_properties::UmpMessageTypeProperty)] ump_type: (), diff --git a/src/system_common/song_select.rs b/src/system_common/song_select.rs index 8ee25af..e39cf3e 100644 --- a/src/system_common/song_select.rs +++ b/src/system_common/song_select.rs @@ -5,7 +5,12 @@ use crate::{ pub const STATUS: u8 = 0xF3; -#[midi2_proc::generate_message(Via(system_common::SystemCommon), FixedSize, MinSizeUmp(1), MinSizeBytes(2))] +#[midi2_proc::generate_message( + Via(system_common::SystemCommon), + FixedSize, + MinSizeUmp(1), + MinSizeBytes(2) +)] struct SongSelect { #[property(common_properties::UmpMessageTypeProperty)] ump_type: (), diff --git a/src/system_common/time_code.rs b/src/system_common/time_code.rs index cd38f61..4d68a90 100644 --- a/src/system_common/time_code.rs +++ b/src/system_common/time_code.rs @@ -5,7 +5,12 @@ use crate::{ pub const STATUS: u8 = 0xF1; -#[midi2_proc::generate_message(Via(system_common::SystemCommon), FixedSize, MinSizeUmp(1), MinSizeBytes(3))] +#[midi2_proc::generate_message( + Via(system_common::SystemCommon), + FixedSize, + MinSizeUmp(1), + MinSizeBytes(3) +)] struct TimeCode { #[property(common_properties::UmpMessageTypeProperty)] ump_type: (), diff --git a/src/utility/mod.rs b/src/utility/mod.rs index c93f324..6224bd6 100644 --- a/src/utility/mod.rs +++ b/src/utility/mod.rs @@ -125,11 +125,11 @@ mod delta_clockstamp_tpq { pub(crate) const UMP_MESSAGE_TYPE: u8 = 0x0; -pub use no_op::NoOp; pub use clock::Clock; -pub use timestamp::Timestamp; pub use delta_clockstamp::DeltaClockstamp; pub use delta_clockstamp_tpq::DeltaClockstampTPQ; +pub use no_op::NoOp; +pub use timestamp::Timestamp; struct DataProperty; From 738c9557aeacd640793f702138dffbe36b04158f Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Sun, 12 May 2024 13:31:19 +0200 Subject: [PATCH 02/25] feat: min size uses const eval --- midi2_proc/src/generate_message.rs | 20 +++++++++----------- src/sysex7/mod.rs | 2 +- src/traits.rs | 2 +- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/midi2_proc/src/generate_message.rs b/midi2_proc/src/generate_message.rs index 6ef808b..876e2c3 100644 --- a/midi2_proc/src/generate_message.rs +++ b/midi2_proc/src/generate_message.rs @@ -374,7 +374,7 @@ fn size_impl(root_ident: &syn::Ident, args: &GenerateMessageArgs) -> TokenStream quote! { impl crate::traits::Size for #root_ident { fn size(&self) -> usize { - >::min_size() + >::MIN_SIZE } } } @@ -396,9 +396,7 @@ fn min_size_impl(root_ident: &syn::Ident, args: &GenerateMessageArgs) -> TokenSt let constraint = generic_buffer_constraint(args); quote! { impl crate::traits::MinSize for #root_ident { - fn min_size() -> usize { - #body - } + const MIN_SIZE: usize = #body; } } } @@ -459,7 +457,7 @@ fn try_from_slice_impl( impl<'a, #generic_unit> core::convert::TryFrom<&'a [#unit_type]> for #root_ident<&'a [#unit_type]> { type Error = crate::error::Error; fn try_from(buffer: &'a [#unit_type]) -> core::result::Result { - if buffer.len() < >::min_size() { + if buffer.len() < >::MIN_SIZE { return Err(crate::error::Error::InvalidData("Slice is too short")); } #validation_steps @@ -518,7 +516,7 @@ fn new_impl( pub fn new() -> #root_ident { let mut buffer = ::default(); - buffer.resize(>::min_size()); + buffer.resize(>::MIN_SIZE); #initialise_properties #root_ident::(buffer) } @@ -543,7 +541,7 @@ fn try_new_impl( pub fn try_new() -> core::result::Result<#root_ident, crate::error::BufferOverflow> { let mut buffer = ::default(); - buffer.try_resize(>::min_size())?; + buffer.try_resize(>::MIN_SIZE)?; #initialise_properties Ok(#root_ident::(buffer)) } @@ -622,7 +620,7 @@ fn from_bytes_impl(root_ident: &syn::Ident, properties: &Vec) -> Token { fn from_bytes(other: #root_ident) -> Self { let mut buffer = ::default(); - buffer.resize(<#root_ident as crate::traits::MinSize>::min_size()); + buffer.resize(<#root_ident as crate::traits::MinSize>::MIN_SIZE); #convert_properties Self(buffer) } @@ -643,7 +641,7 @@ fn try_from_bytes_impl(root_ident: &syn::Ident, properties: &Vec) -> T { fn try_from_bytes(other: #root_ident) -> core::result::Result { let mut buffer = ::default(); - buffer.try_resize(<#root_ident as crate::traits::MinSize>::min_size())?; + buffer.try_resize(<#root_ident as crate::traits::MinSize>::MIN_SIZE)?; #convert_properties Ok(Self(buffer)) } @@ -681,7 +679,7 @@ fn from_ump_impl(root_ident: &syn::Ident, properties: &Vec) -> TokenSt { fn from_ump(other: #root_ident) -> Self { let mut buffer = ::default(); - buffer.resize(<#root_ident as crate::traits::MinSize>::min_size()); + buffer.resize(<#root_ident as crate::traits::MinSize>::MIN_SIZE); #convert_properties Self(buffer) } @@ -702,7 +700,7 @@ fn try_from_ump_impl(root_ident: &syn::Ident, properties: &Vec) -> Tok { fn try_from_ump(other: #root_ident) -> core::result::Result { let mut buffer = ::default(); - buffer.try_resize(<#root_ident as crate::traits::MinSize>::min_size())?; + buffer.try_resize(<#root_ident as crate::traits::MinSize>::MIN_SIZE)?; #convert_properties Ok(Self(buffer)) } diff --git a/src/sysex7/mod.rs b/src/sysex7/mod.rs index fbd35a7..5a261bc 100644 --- a/src/sysex7/mod.rs +++ b/src/sysex7/mod.rs @@ -388,7 +388,7 @@ fn try_from_other< let mut buffer = ::default(); try_resize( &mut buffer, - as crate::traits::MinSize>::min_size(), + as crate::traits::MinSize>::MIN_SIZE, )?; convert_generated_properties(&other.0, &mut buffer); diff --git a/src/traits.rs b/src/traits.rs index 0024cb1..9c8652e 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -170,7 +170,7 @@ pub(crate) trait SysexInternal: Sysex { } pub(crate) trait MinSize { - fn min_size() -> usize; + const MIN_SIZE: usize; } pub(crate) trait Size { From d04ca57a5c4ec175627c205c4018f5363304120d Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Sun, 12 May 2024 14:05:55 +0200 Subject: [PATCH 03/25] feat: improved array new impls --- midi2_proc/src/generate_message.rs | 32 ++++++++++++++++++++++++++ src/channel_voice2/channel_pressure.rs | 18 ++++++++++++++- src/flex_data/unknown_metadata_text.rs | 2 +- src/traits.rs | 10 ++++++++ src/ump_stream/endpoint_name.rs | 2 +- src/ump_stream/function_block_name.rs | 2 +- src/ump_stream/product_instance_id.rs | 2 +- 7 files changed, 63 insertions(+), 5 deletions(-) diff --git a/midi2_proc/src/generate_message.rs b/midi2_proc/src/generate_message.rs index 876e2c3..265dbe1 100644 --- a/midi2_proc/src/generate_message.rs +++ b/midi2_proc/src/generate_message.rs @@ -524,6 +524,36 @@ fn new_impl( } } +fn new_array_impl( + root_ident: &syn::Ident, + args: &GenerateMessageArgs, + properties: &Vec, +) -> TokenStream { + let generics = match args.representation() { + Representation::UmpOrBytes => quote!{ , U: crate::buffer::Unit }, + _ => TokenStream::new(), + }; + let unit_type = match args.representation() { + Representation::Ump => quote!{ u32 }, + Representation::Bytes => quote!{ u8 }, + Representation::UmpOrBytes => quote!{ U }, + }; + let buffer_type = quote! { [#unit_type; SIZE] }; + let initialise_properties = initialise_property_statements(properties, quote! { #buffer_type }); + quote! { + impl #root_ident<#buffer_type> + { + pub fn new() -> #root_ident<#buffer_type> + { + let _valid = >::VALID; + let mut buffer = [<#unit_type as crate::buffer::Unit>::zero(); SIZE]; + #initialise_properties + #root_ident(buffer) + } + } + } +} + fn try_new_impl( root_ident: &syn::Ident, args: &GenerateMessageArgs, @@ -744,6 +774,7 @@ pub fn generate_message(attrs: TokenStream1, item: TokenStream1) -> TokenStream1 let rebuffer_from_impl = rebuffer_from_impl(root_ident, &args); let try_rebuffer_from_impl = try_rebuffer_from_impl(root_ident, &args); let new_impl = new_impl(root_ident, &args, &properties); + let new_array_impl = new_array_impl(root_ident, &args, &properties); let try_new_impl = try_new_impl(root_ident, &args, &properties); let clone_impl = clone_impl(root_ident, &args); @@ -760,6 +791,7 @@ pub fn generate_message(attrs: TokenStream1, item: TokenStream1) -> TokenStream1 #rebuffer_from_impl #try_rebuffer_from_impl #new_impl + #new_array_impl #try_new_impl #clone_impl }); diff --git a/src/channel_voice2/channel_pressure.rs b/src/channel_voice2/channel_pressure.rs index ffeae35..16820bb 100644 --- a/src/channel_voice2/channel_pressure.rs +++ b/src/channel_voice2/channel_pressure.rs @@ -33,7 +33,7 @@ mod tests { fn setter() { use crate::traits::{Channeled, Grouped}; - let mut message = ChannelPressure::new_arr(); + let mut message = ChannelPressure::<[u32; 4]>::new(); message.set_group(u4::new(0xE)); message.set_channel(u4::new(0xD)); message.set_channel_pressure_data(0xDE0DE0F2); @@ -44,6 +44,22 @@ mod tests { ); } + #[test] + fn new_arr_3() { + assert_eq!( + ChannelPressure::<[u32; 3]>::new(), + ChannelPressure([0x40D0_0000, 0x0, 0x0]), + ); + } + + #[test] + fn new_arr_2() { + assert_eq!( + ChannelPressure::<[u32; 2]>::new(), + ChannelPressure([0x40D0_0000, 0x0]), + ); + } + #[test] fn channel_pressure_data() { assert_eq!( diff --git a/src/flex_data/unknown_metadata_text.rs b/src/flex_data/unknown_metadata_text.rs index 910c716..c9d77c7 100644 --- a/src/flex_data/unknown_metadata_text.rs +++ b/src/flex_data/unknown_metadata_text.rs @@ -423,7 +423,7 @@ mod tests { #[test] fn set_string_multiple_of_12_length() { - let mut message = UnknownMetadataText::new(); + let mut message = UnknownMetadataText::>::new(); message.set_text("Digital Audio Workstation - DAW36-16"); assert_eq!( message, diff --git a/src/traits.rs b/src/traits.rs index 9c8652e..2f435a8 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -173,6 +173,16 @@ pub(crate) trait MinSize { const MIN_SIZE: usize; } +pub(crate) trait ArraySizeValid: MinSize { + const VALID: (); +} + +impl> ArraySizeValid for M { + const VALID: () = if SIZE < >::MIN_SIZE { + panic!("Array is shorter than minimum message size"); + }; +} + pub(crate) trait Size { fn size(&self) -> usize; } diff --git a/src/ump_stream/endpoint_name.rs b/src/ump_stream/endpoint_name.rs index ea2dd94..86143ac 100644 --- a/src/ump_stream/endpoint_name.rs +++ b/src/ump_stream/endpoint_name.rs @@ -67,7 +67,7 @@ mod tests { #[test] fn set_name_and_clear_name() { - let mut message = EndpointName::new(); + let mut message = EndpointName::>::new(); message.set_name("Gimme some signal 🔊 🙌"); message.set_name(""); assert_eq!( diff --git a/src/ump_stream/function_block_name.rs b/src/ump_stream/function_block_name.rs index df28d8e..3f6d263 100644 --- a/src/ump_stream/function_block_name.rs +++ b/src/ump_stream/function_block_name.rs @@ -130,7 +130,7 @@ mod tests { #[test] fn set_name() { - let mut message = FunctionBlockName::new(); + let mut message = FunctionBlockName::>::new(); message.set_name("SynthWave🌊²"); message.set_function_block(0x09); assert_eq!( diff --git a/src/ump_stream/product_instance_id.rs b/src/ump_stream/product_instance_id.rs index f0e098e..5bb9666 100644 --- a/src/ump_stream/product_instance_id.rs +++ b/src/ump_stream/product_instance_id.rs @@ -36,7 +36,7 @@ mod tests { #[test] fn set_id() { - let mut message = ProductInstanceId::new(); + let mut message = ProductInstanceId::>::new(); message.set_id("PianoPulse"); assert_eq!( message, From c985e55618f1ae6a5612d49da3f433dca0ed1c5c Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Sun, 12 May 2024 14:21:23 +0200 Subject: [PATCH 04/25] feat!: improve array constructors * all array-backed messages have non-fallible constructors for arrays greater than the message's minimum size --- :: | 0 ::new | 0 README.md | 6 +- midi2_proc/src/generate_message.rs | 58 ++----------------- src/channel_voice1/channel_pressure.rs | 8 +-- src/channel_voice1/control_change.rs | 4 +- src/channel_voice1/key_pressure.rs | 2 +- src/channel_voice1/note_off.rs | 2 +- src/channel_voice1/note_on.rs | 2 +- src/channel_voice1/pitch_bend.rs | 2 +- src/channel_voice1/program_change.rs | 2 +- src/channel_voice2/assignable_controller.rs | 2 +- .../assignable_per_note_controller.rs | 2 +- src/channel_voice2/channel_pitch_bend.rs | 2 +- src/channel_voice2/control_change.rs | 2 +- src/channel_voice2/key_pressure.rs | 2 +- src/channel_voice2/note_off.rs | 4 +- src/channel_voice2/note_on.rs | 6 +- src/channel_voice2/per_note_management.rs | 2 +- src/channel_voice2/per_note_pitch_bend.rs | 2 +- src/channel_voice2/program_change.rs | 4 +- src/channel_voice2/registered_controller.rs | 2 +- .../registered_per_note_controller.rs | 2 +- .../relative_assignable_controller.rs | 2 +- .../relative_registered_controller.rs | 2 +- src/flex_data/set_chord_name.rs | 2 +- src/flex_data/set_key_signature.rs | 8 +-- src/flex_data/set_metronome.rs | 2 +- src/flex_data/set_tempo.rs | 2 +- src/flex_data/set_time_signature.rs | 2 +- src/message.rs | 12 ++-- src/system_common/README.md | 4 +- src/system_common/song_position_pointer.rs | 4 +- src/system_common/song_select.rs | 4 +- src/system_common/time_code.rs | 4 +- src/ump_stream/device_identity.rs | 2 +- src/ump_stream/end_of_clip.rs | 2 +- src/ump_stream/endpoint_discovery.rs | 2 +- src/ump_stream/endpoint_info.rs | 2 +- src/ump_stream/function_block_discovery.rs | 2 +- src/ump_stream/function_block_info.rs | 2 +- src/ump_stream/start_of_clip.rs | 2 +- .../stream_configuration_notification.rs | 2 +- .../stream_configuration_request.rs | 2 +- src/utility/mod.rs | 4 +- 45 files changed, 69 insertions(+), 119 deletions(-) create mode 100644 :: create mode 100644 ::new diff --git a/:: b/:: new file mode 100644 index 0000000..e69de29 diff --git a/::new b/::new new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md index 3b526f7..a9f1e64 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ A strongly typed message wrapper is provided for every message in the MIDI 2.0 s use midi2::prelude::*; // Messages have a simple setter / getter interface -let mut note_on = channel_voice2::NoteOn::new_arr(); +let mut note_on = channel_voice2::NoteOn::<[u32; 4]>::new(); note_on.set_group(u4::new(0x8)); note_on.set_channel(u4::new(0xA)); note_on.set_note(u7::new(0x5E)); @@ -242,7 +242,7 @@ To do this simply use a backing buffer over `u8` instead of `u32`! ✨🎩 ```rust use midi2::prelude::*; -let mut message = channel_voice1::ChannelPressure::new_arr_bytes(); +let mut message = channel_voice1::ChannelPressure::<[u8; 3]>::new(); message.set_channel(u4::new(0x6)); message.set_pressure(u7::new(0x09)); @@ -257,7 +257,7 @@ use midi2::{ channel_voice1::ChannelPressure, }; -let message = ChannelPressure::new_arr_bytes(); +let message = ChannelPressure::<[u8; 3]>::new(); let message: ChannelPressure<[u32; 4]> = message.try_into_ump(). expect("Buffer is large enough"); diff --git a/midi2_proc/src/generate_message.rs b/midi2_proc/src/generate_message.rs index 265dbe1..8db90e4 100644 --- a/midi2_proc/src/generate_message.rs +++ b/midi2_proc/src/generate_message.rs @@ -325,50 +325,6 @@ fn std_only_attribute(property: &Property) -> TokenStream { } } -fn message_new_arr_impl( - root_ident: &syn::Ident, - args: &GenerateMessageArgs, - properties: &Vec, -) -> TokenStream { - let arr_type = match args.representation() { - Representation::Bytes => arr_type_bytes(), - Representation::Ump => arr_type_ump(), - Representation::UmpOrBytes => arr_type_ump(), - }; - let set_defaults = initialise_property_statements(properties, arr_type.clone()); - quote! { - impl #root_ident<#arr_type> { - pub fn new_arr() -> Self { - let mut buffer: #arr_type = core::default::Default::default(); - #set_defaults - #root_ident(buffer) - } - } - } -} - -fn secondary_new_arr_impl(root_ident: &syn::Ident, properties: &Vec) -> TokenStream { - let arr_type = arr_type_bytes(); - let set_defaults = initialise_property_statements(properties, arr_type.clone()); - quote! { - impl #root_ident<#arr_type> { - pub fn new_arr_bytes() -> Self { - let mut buffer: #arr_type = core::default::Default::default(); - #set_defaults - #root_ident(buffer) - } - } - } -} - -fn arr_type_ump() -> TokenStream { - quote! { [u32; 4] } -} - -fn arr_type_bytes() -> TokenStream { - quote! { [u8; 3] } -} - fn size_impl(root_ident: &syn::Ident, args: &GenerateMessageArgs) -> TokenStream { let constraint = generic_buffer_constraint(args); quote! { @@ -530,13 +486,13 @@ fn new_array_impl( properties: &Vec, ) -> TokenStream { let generics = match args.representation() { - Representation::UmpOrBytes => quote!{ , U: crate::buffer::Unit }, + Representation::UmpOrBytes => quote! { , U: crate::buffer::Unit }, _ => TokenStream::new(), }; let unit_type = match args.representation() { - Representation::Ump => quote!{ u32 }, - Representation::Bytes => quote!{ u8 }, - Representation::UmpOrBytes => quote!{ U }, + Representation::Ump => quote! { u32 }, + Representation::Bytes => quote! { u8 }, + Representation::UmpOrBytes => quote! { U }, }; let buffer_type = quote! { [#unit_type; SIZE] }; let initialise_properties = initialise_property_statements(properties, quote! { #buffer_type }); @@ -796,12 +752,6 @@ pub fn generate_message(attrs: TokenStream1, item: TokenStream1) -> TokenStream1 #clone_impl }); - if args.fixed_size { - tokens.extend(message_new_arr_impl(root_ident, &args, &properties)); - if let Representation::UmpOrBytes = args.representation() { - tokens.extend(secondary_new_arr_impl(root_ident, &properties)); - } - } if args.fixed_size { tokens.extend(size_impl(root_ident, &args)) } diff --git a/src/channel_voice1/channel_pressure.rs b/src/channel_voice1/channel_pressure.rs index 9056b08..3c8f679 100644 --- a/src/channel_voice1/channel_pressure.rs +++ b/src/channel_voice1/channel_pressure.rs @@ -41,7 +41,7 @@ mod tests { #[test] fn setters() { - let mut message = ChannelPressure::new_arr(); + let mut message = ChannelPressure::<[u32; 4]>::new(); message.set_group(u4::new(0xF)); message.set_channel(u4::new(0x6)); message.set_pressure(u7::new(0x09)); @@ -50,7 +50,7 @@ mod tests { #[test] fn setters_bytes() { - let mut message = ChannelPressure::new_arr_bytes(); + let mut message = ChannelPressure::<[u8; 3]>::new(); message.set_channel(u4::new(0x6)); message.set_pressure(u7::new(0x09)); assert_eq!(message, ChannelPressure([0xD6, 0x09, 0x0])); @@ -194,7 +194,7 @@ mod tests { fn new_with_custom_buffer() { assert_eq!( ChannelPressure::>::new(), - ChannelPressure::new_arr().rebuffer_into(), + ChannelPressure::<[u32; 4]>::new().rebuffer_into(), ) } @@ -359,7 +359,7 @@ mod rebuffer_tests { #[test] fn clone() { - let message = ChannelPressure::new_arr(); + let message = ChannelPressure::<[u32; 4]>::new(); let clone = message.clone(); assert_eq!(message, clone); } diff --git a/src/channel_voice1/control_change.rs b/src/channel_voice1/control_change.rs index dd9cc14..892ee6b 100644 --- a/src/channel_voice1/control_change.rs +++ b/src/channel_voice1/control_change.rs @@ -45,7 +45,7 @@ mod tests { #[test] fn setters() { - let mut message = ControlChange::new_arr(); + let mut message = ControlChange::<[u32; 4]>::new(); message.set_group(u4::new(0xA)); message.set_channel(u4::new(0x7)); message.set_control(u7::new(0x36)); @@ -55,7 +55,7 @@ mod tests { #[test] fn setters_bytes() { - let mut message = ControlChange::new_arr_bytes(); + let mut message = ControlChange::<[u8; 3]>::new(); message.set_channel(u4::new(0x7)); message.set_control(u7::new(0x36)); message.set_control_data(u7::new(0x37)); diff --git a/src/channel_voice1/key_pressure.rs b/src/channel_voice1/key_pressure.rs index e298b40..bf85b01 100644 --- a/src/channel_voice1/key_pressure.rs +++ b/src/channel_voice1/key_pressure.rs @@ -45,7 +45,7 @@ mod tests { #[test] fn setters() { - let mut message = KeyPressure::new_arr(); + let mut message = KeyPressure::<[u32; 4]>::new(); message.set_group(u4::new(0xA)); message.set_channel(u4::new(0x3)); message.set_note(u7::new(0x7F)); diff --git a/src/channel_voice1/note_off.rs b/src/channel_voice1/note_off.rs index 68821ee..f7566e7 100644 --- a/src/channel_voice1/note_off.rs +++ b/src/channel_voice1/note_off.rs @@ -62,7 +62,7 @@ mod tests { #[test] fn builder() { - let mut message = NoteOff::new_arr(); + let mut message = NoteOff::<[u32; 4]>::new(); message.set_group(u4::new(0x1)); message.set_channel(u4::new(0xA)); message.set_note(u7::new(0x68)); diff --git a/src/channel_voice1/note_on.rs b/src/channel_voice1/note_on.rs index 58a6fea..8dfbca1 100644 --- a/src/channel_voice1/note_on.rs +++ b/src/channel_voice1/note_on.rs @@ -45,7 +45,7 @@ mod tests { #[test] fn setters() { - let mut message = NoteOn::new_arr(); + let mut message = NoteOn::<[u32; 4]>::new(); message.set_group(u4::new(0xD)); message.set_channel(u4::new(0xE)); message.set_note(u7::new(0x75)); diff --git a/src/channel_voice1/pitch_bend.rs b/src/channel_voice1/pitch_bend.rs index a2c6e1a..e858e16 100644 --- a/src/channel_voice1/pitch_bend.rs +++ b/src/channel_voice1/pitch_bend.rs @@ -39,7 +39,7 @@ mod tests { #[test] fn builder() { - let mut message = PitchBend::new_arr(); + let mut message = PitchBend::<[u32; 4]>::new(); message.set_group(u4::new(0x1)); message.set_channel(u4::new(0xE)); message.set_bend(u14::new(0x147)); diff --git a/src/channel_voice1/program_change.rs b/src/channel_voice1/program_change.rs index 06fa89a..db8bbea 100644 --- a/src/channel_voice1/program_change.rs +++ b/src/channel_voice1/program_change.rs @@ -39,7 +39,7 @@ mod tests { #[test] fn builder() { - let mut message = ProgramChange::new_arr(); + let mut message = ProgramChange::<[u32; 4]>::new(); message.set_group(u4::new(0x4)); message.set_channel(u4::new(0x7)); message.set_program(u7::new(0x63)); diff --git a/src/channel_voice2/assignable_controller.rs b/src/channel_voice2/assignable_controller.rs index 8e42dcd..2888fa1 100644 --- a/src/channel_voice2/assignable_controller.rs +++ b/src/channel_voice2/assignable_controller.rs @@ -33,7 +33,7 @@ mod tests { fn setters() { use crate::traits::{Channeled, Grouped}; - let mut message = AssignableController::new_arr(); + let mut message = AssignableController::<[u32; 4]>::new(); message.set_group(u4::new(0xC)); message.set_channel(u4::new(0x8)); message.set_bank(u7::new(0x51)); diff --git a/src/channel_voice2/assignable_per_note_controller.rs b/src/channel_voice2/assignable_per_note_controller.rs index 160d932..e00a90e 100644 --- a/src/channel_voice2/assignable_per_note_controller.rs +++ b/src/channel_voice2/assignable_per_note_controller.rs @@ -33,7 +33,7 @@ mod tests { fn builder() { use crate::traits::{Channeled, Grouped}; - let mut message = AssignablePerNoteController::new_arr(); + let mut message = AssignablePerNoteController::<[u32; 4]>::new(); message.set_group(u4::new(0x2)); message.set_channel(u4::new(0x4)); message.set_note(u7::new(0x6F)); diff --git a/src/channel_voice2/channel_pitch_bend.rs b/src/channel_voice2/channel_pitch_bend.rs index 4f91058..c84be9b 100644 --- a/src/channel_voice2/channel_pitch_bend.rs +++ b/src/channel_voice2/channel_pitch_bend.rs @@ -29,7 +29,7 @@ mod tests { fn builder() { use crate::traits::{Channeled, Grouped}; - let mut message = ChannelPitchBend::new_arr(); + let mut message = ChannelPitchBend::<[u32; 4]>::new(); message.set_group(u4::new(0xB)); message.set_channel(u4::new(0x9)); message.set_pitch_bend_data(0x08306AF8); diff --git a/src/channel_voice2/control_change.rs b/src/channel_voice2/control_change.rs index 84d215e..09460bc 100644 --- a/src/channel_voice2/control_change.rs +++ b/src/channel_voice2/control_change.rs @@ -30,7 +30,7 @@ mod tests { #[test] fn setters() { use crate::traits::{Channeled, Grouped}; - let mut message = ControlChange::new_arr(); + let mut message = ControlChange::<[u32; 4]>::new(); message.set_group(u4::new(0x3)); message.set_channel(u4::new(0x9)); message.set_control(u7::new(0x30)); diff --git a/src/channel_voice2/key_pressure.rs b/src/channel_voice2/key_pressure.rs index f32b65e..7595384 100644 --- a/src/channel_voice2/key_pressure.rs +++ b/src/channel_voice2/key_pressure.rs @@ -31,7 +31,7 @@ mod tests { fn builder() { use crate::traits::{Channeled, Grouped}; - let mut message = KeyPressure::new_arr(); + let mut message = KeyPressure::<[u32; 4]>::new(); message.set_group(u4::new(0xB)); message.set_channel(u4::new(0xC)); message.set_note(u7::new(0x59)); diff --git a/src/channel_voice2/note_off.rs b/src/channel_voice2/note_off.rs index ab4c2c9..ce8a76f 100644 --- a/src/channel_voice2/note_off.rs +++ b/src/channel_voice2/note_off.rs @@ -36,7 +36,7 @@ mod tests { fn builder() { use crate::traits::{Channeled, Grouped}; - let mut message = NoteOff::new_arr(); + let mut message = NoteOff::<[u32; 4]>::new(); message.set_group(u4::new(0x2)); message.set_channel(u4::new(0x4)); message.set_note(u7::new(0x4E)); @@ -50,7 +50,7 @@ mod tests { fn builder_no_attribute() { use crate::traits::{Channeled, Grouped}; - let mut message = NoteOff::new_arr(); + let mut message = NoteOff::<[u32; 4]>::new(); message.set_group(u4::new(0x2)); message.set_channel(u4::new(0x4)); message.set_note(u7::new(0x4E)); diff --git a/src/channel_voice2/note_on.rs b/src/channel_voice2/note_on.rs index 759792e..ff5737a 100644 --- a/src/channel_voice2/note_on.rs +++ b/src/channel_voice2/note_on.rs @@ -17,7 +17,7 @@ pub(crate) const STATUS: u8 = 0b1001; /// use midi2::prelude::*; /// use midi2::prelude::*; /// -/// let mut message = channel_voice2::NoteOn::new_arr(); +/// let mut message = channel_voice2::NoteOn::<[u32; 4]>::new(); /// message.set_group(u4::new(0x8)); /// message.set_channel(u4::new(0x8)); /// message.set_note(u7::new(0x5E)); @@ -57,7 +57,7 @@ mod tests { use crate::traits::{Channeled, Grouped}; use crate::ux::u9; - let mut message = NoteOn::new_arr(); + let mut message = NoteOn::<[u32; 4]>::new(); message.set_group(u4::new(0x8)); message.set_channel(u4::new(0x8)); message.set_note(u7::new(0x5E)); @@ -74,7 +74,7 @@ mod tests { fn builder_no_attribute() { use crate::traits::{Channeled, Grouped}; - let mut message = NoteOn::new_arr(); + let mut message = NoteOn::<[u32; 4]>::new(); message.set_group(u4::new(0x8)); message.set_channel(u4::new(0x8)); message.set_note(u7::new(0x5E)); diff --git a/src/channel_voice2/per_note_management.rs b/src/channel_voice2/per_note_management.rs index 1f688b1..00d11ef 100644 --- a/src/channel_voice2/per_note_management.rs +++ b/src/channel_voice2/per_note_management.rs @@ -33,7 +33,7 @@ mod tests { fn setters() { use crate::traits::{Channeled, Grouped}; - let mut message = PerNoteManagement::new_arr(); + let mut message = PerNoteManagement::<[u32; 4]>::new(); message.set_group(u4::new(0xB)); message.set_channel(u4::new(0x9)); message.set_note(u7::new(0x1C)); diff --git a/src/channel_voice2/per_note_pitch_bend.rs b/src/channel_voice2/per_note_pitch_bend.rs index 1c13811..662c527 100644 --- a/src/channel_voice2/per_note_pitch_bend.rs +++ b/src/channel_voice2/per_note_pitch_bend.rs @@ -31,7 +31,7 @@ mod tests { fn builder() { use crate::traits::{Channeled, Grouped}; - let mut message = PerNotePitchBend::new_arr(); + let mut message = PerNotePitchBend::<[u32; 4]>::new(); message.set_group(u4::new(0x9)); message.set_channel(u4::new(0x2)); message.set_note(u7::new(0x76)); diff --git a/src/channel_voice2/program_change.rs b/src/channel_voice2/program_change.rs index bf1d8c1..b6378d6 100644 --- a/src/channel_voice2/program_change.rs +++ b/src/channel_voice2/program_change.rs @@ -80,7 +80,7 @@ mod tests { fn builder() { use crate::traits::{Channeled, Grouped}; - let mut message = ProgramChange::new_arr(); + let mut message = ProgramChange::<[u32; 4]>::new(); message.set_group(u4::new(0xF)); message.set_channel(u4::new(0xE)); message.set_program(u7::new(0x75)); @@ -93,7 +93,7 @@ mod tests { fn builder_no_bank() { use crate::traits::{Channeled, Grouped}; - let mut message = ProgramChange::new_arr(); + let mut message = ProgramChange::<[u32; 4]>::new(); message.set_group(u4::new(0xF)); message.set_channel(u4::new(0xE)); message.set_program(u7::new(0x75)); diff --git a/src/channel_voice2/registered_controller.rs b/src/channel_voice2/registered_controller.rs index cffc7d3..cda13ef 100644 --- a/src/channel_voice2/registered_controller.rs +++ b/src/channel_voice2/registered_controller.rs @@ -33,7 +33,7 @@ mod tests { fn builder() { use crate::traits::{Channeled, Grouped}; - let mut message = RegisteredController::new_arr(); + let mut message = RegisteredController::<[u32; 4]>::new(); message.set_group(u4::new(0xA)); message.set_channel(u4::new(0xB)); message.set_bank(u7::new(0x7D)); diff --git a/src/channel_voice2/registered_per_note_controller.rs b/src/channel_voice2/registered_per_note_controller.rs index f87a36c..965a767 100644 --- a/src/channel_voice2/registered_per_note_controller.rs +++ b/src/channel_voice2/registered_per_note_controller.rs @@ -31,7 +31,7 @@ mod tests { fn builder() { use crate::traits::{Channeled, Grouped}; - let mut message = RegisteredPerNoteController::new_arr(); + let mut message = RegisteredPerNoteController::<[u32; 4]>::new(); message.set_group(u4::new(0x4)); message.set_channel(u4::new(0x5)); message.set_note(u7::new(0x6C)); diff --git a/src/channel_voice2/relative_assignable_controller.rs b/src/channel_voice2/relative_assignable_controller.rs index 735821f..6c92b90 100644 --- a/src/channel_voice2/relative_assignable_controller.rs +++ b/src/channel_voice2/relative_assignable_controller.rs @@ -33,7 +33,7 @@ mod tests { fn builder() { use crate::traits::{Channeled, Grouped}; - let mut message = RelativeAssignableController::new_arr(); + let mut message = RelativeAssignableController::<[u32; 4]>::new(); message.set_group(u4::new(0x3)); message.set_channel(u4::new(0x1)); message.set_bank(u7::new(0x24)); diff --git a/src/channel_voice2/relative_registered_controller.rs b/src/channel_voice2/relative_registered_controller.rs index f7327d0..6124483 100644 --- a/src/channel_voice2/relative_registered_controller.rs +++ b/src/channel_voice2/relative_registered_controller.rs @@ -33,7 +33,7 @@ mod tests { fn builder() { use crate::traits::{Channeled, Grouped}; - let mut message = RelativeRegisteredController::new_arr(); + let mut message = RelativeRegisteredController::<[u32; 4]>::new(); message.set_group(u4::new(0x1)); message.set_channel(u4::new(0xE)); message.set_bank(u7::new(0x45)); diff --git a/src/flex_data/set_chord_name.rs b/src/flex_data/set_chord_name.rs index 57e0039..5e23ca7 100644 --- a/src/flex_data/set_chord_name.rs +++ b/src/flex_data/set_chord_name.rs @@ -405,7 +405,7 @@ mod tests { #[test] fn setters() { - let mut message = SetChordName::new_arr(); + let mut message = SetChordName::<[u32; 4]>::new(); message.set_group(u4::new(0x7)); message.set_optional_channel(Some(u4::new(0xB))); message.set_tonic_sharps_flats(SharpsFlats::Flat); diff --git a/src/flex_data/set_key_signature.rs b/src/flex_data/set_key_signature.rs index dd56168..44d12ae 100644 --- a/src/flex_data/set_key_signature.rs +++ b/src/flex_data/set_key_signature.rs @@ -94,7 +94,7 @@ mod tests { #[test] fn setters() { - let mut message = SetKeySignature::new_arr(); + let mut message = SetKeySignature::<[u32; 4]>::new(); message.set_group(u4::new(0x4)); message.set_tonic(flex_data::tonic::Tonic::D); message.set_sharps_flats(SharpsFlats::Sharps(u3::new(5))); @@ -106,7 +106,7 @@ mod tests { #[test] fn set_flats() { - let mut message = SetKeySignature::new_arr(); + let mut message = SetKeySignature::<[u32; 4]>::new(); message.set_group(u4::new(0x4)); message.set_tonic(flex_data::tonic::Tonic::D); message.set_sharps_flats(SharpsFlats::Flats(u3::new(5))); @@ -118,7 +118,7 @@ mod tests { #[test] fn builder_non_standard() { - let mut message = SetKeySignature::new_arr(); + let mut message = SetKeySignature::<[u32; 4]>::new(); message.set_group(u4::new(0x4)); message.set_tonic(flex_data::tonic::Tonic::NonStandard); message.set_sharps_flats(SharpsFlats::NonStandard); @@ -130,7 +130,7 @@ mod tests { #[test] fn builder_channel() { - let mut message = SetKeySignature::new_arr(); + let mut message = SetKeySignature::<[u32; 4]>::new(); message.set_group(u4::new(0x4)); message.set_tonic(flex_data::tonic::Tonic::NonStandard); message.set_sharps_flats(SharpsFlats::NonStandard); diff --git a/src/flex_data/set_metronome.rs b/src/flex_data/set_metronome.rs index 1c809b0..196c128 100644 --- a/src/flex_data/set_metronome.rs +++ b/src/flex_data/set_metronome.rs @@ -61,7 +61,7 @@ mod tests { #[test] fn setters() { - let mut message = SetMetronome::new_arr(); + let mut message = SetMetronome::<[u32; 4]>::new(); message.set_group(u4::new(0x1)); message.set_number_of_clocks_per_primary_click(0x9B); message.set_bar_accent1(0x4A); diff --git a/src/flex_data/set_tempo.rs b/src/flex_data/set_tempo.rs index 58af46d..162148f 100644 --- a/src/flex_data/set_tempo.rs +++ b/src/flex_data/set_tempo.rs @@ -36,7 +36,7 @@ mod tests { #[test] fn builder() { - let mut message = SetTempo::new_arr(); + let mut message = SetTempo::<[u32; 4]>::new(); message.set_group(u4::new(0x7)); message.set_number_of_10_nanosecond_units_per_quarter_note(0xF751FE05); assert_eq!(message, SetTempo([0xD710_0000, 0xF751_FE05, 0x0, 0x0,]),); diff --git a/src/flex_data/set_time_signature.rs b/src/flex_data/set_time_signature.rs index 55a0892..f81c232 100644 --- a/src/flex_data/set_time_signature.rs +++ b/src/flex_data/set_time_signature.rs @@ -46,7 +46,7 @@ mod tests { #[test] fn builder() { - let mut message = SetTimeSignature::new_arr(); + let mut message = SetTimeSignature::<[u32; 4]>::new(); message.set_group(u4::new(0xA)); message.set_numerator(0xCD); message.set_denominator(0x90); diff --git a/src/message.rs b/src/message.rs index facd16b..4b2098b 100644 --- a/src/message.rs +++ b/src/message.rs @@ -273,7 +273,7 @@ mod tests { fn from_level2() { use crate::channel_voice1::ChannelPressure; - let level2_message = ChannelPressure::new_arr(); + let level2_message = ChannelPressure::<[u32; 4]>::new(); let _: UmpMessage<[u32; 4]> = level2_message.into(); } @@ -291,7 +291,7 @@ mod tests { fn from_level2_bytes() { use crate::channel_voice1::ChannelPressure; - let level2_message = ChannelPressure::new_arr_bytes(); + let level2_message = ChannelPressure::<[u8; 3]>::new(); let _: BytesMessage<[u8; 3]> = level2_message.into(); } @@ -300,7 +300,7 @@ mod tests { fn from_level2_channel_voice2() { use crate::channel_voice2::ChannelPressure; - let level2_message = ChannelPressure::new_arr(); + let level2_message = ChannelPressure::<[u32; 4]>::new(); let _: UmpMessage<[u32; 4]> = level2_message.into(); } @@ -309,7 +309,7 @@ mod tests { fn from_level2_ump_stream() { use crate::ump_stream::EndOfClip; - let level2_message = EndOfClip::new_arr(); + let level2_message = EndOfClip::<[u32; 4]>::new(); let _: UmpMessage<[u32; 4]> = level2_message.into(); } @@ -318,7 +318,7 @@ mod tests { fn from_level2_utility() { use crate::utility::DeltaClockstampTPQ; - let level2_message = DeltaClockstampTPQ::new_arr(); + let level2_message = DeltaClockstampTPQ::<[u32; 4]>::new(); let _: UmpMessage<[u32; 4]> = level2_message.into(); } @@ -327,7 +327,7 @@ mod tests { fn from_level2_system_common() { use crate::system_common::Stop; - let level2_message = Stop::new_arr(); + let level2_message = Stop::<[u32; 4]>::new(); let _: UmpMessage<[u32; 4]> = level2_message.into(); } } diff --git a/src/system_common/README.md b/src/system_common/README.md index beb81b5..fbe449c 100644 --- a/src/system_common/README.md +++ b/src/system_common/README.md @@ -15,7 +15,7 @@ standards. ```rust use midi2::prelude::*; -let mut message = system_common::SongSelect::new_arr_bytes(); +let mut message = system_common::SongSelect::<[u8; 3]>::new(); message.set_song(u7::new(0x42)); assert_eq!(message.data(), &[0xF3, 0x42]); ``` @@ -26,7 +26,7 @@ encoded into Universal Message Packets. ```rust use midi2::prelude::*; -let mut message = system_common::SongSelect::new_arr(); +let mut message = system_common::SongSelect::<[u32; 4]>::new(); message.set_song(u7::new(0x42)); message.set_group(u4::new(0x3)); assert_eq!(message.data(), &[0x13F3_4200]); diff --git a/src/system_common/song_position_pointer.rs b/src/system_common/song_position_pointer.rs index 3aaa83d..d06ac83 100644 --- a/src/system_common/song_position_pointer.rs +++ b/src/system_common/song_position_pointer.rs @@ -34,14 +34,14 @@ mod tests { #[test] fn setters() { - let mut message = SongPositionPointer::new_arr(); + let mut message = SongPositionPointer::<[u32; 4]>::new(); message.set_group(u4::new(0xA)); message.set_position(u14::new(0x367D)); assert_eq!(message, SongPositionPointer([0x1AF2_7D6C, 0x0, 0x0, 0x0]),); } #[test] fn setters_bytes() { - let mut message = SongPositionPointer::new_arr_bytes(); + let mut message = SongPositionPointer::<[u8; 3]>::new(); message.set_position(u14::new(0x367D)); assert_eq!(message, SongPositionPointer([0xF2, 0x7D, 0x6C]),); } diff --git a/src/system_common/song_select.rs b/src/system_common/song_select.rs index e39cf3e..b5715f4 100644 --- a/src/system_common/song_select.rs +++ b/src/system_common/song_select.rs @@ -34,7 +34,7 @@ mod tests { #[test] fn setter() { - let mut message = SongSelect::new_arr(); + let mut message = SongSelect::<[u32; 4]>::new(); message.set_group(u4::new(0xA)); message.set_song(u7::new(0x4F)); assert_eq!(message, SongSelect([0x1AF3_4F00, 0x0, 0x0, 0x0]),); @@ -42,7 +42,7 @@ mod tests { #[test] fn setters_bytes() { - let mut message = SongSelect::new_arr_bytes(); + let mut message = SongSelect::<[u8; 3]>::new(); message.set_song(u7::new(0x4F)); assert_eq!(message, SongSelect([0xF3, 0x4F, 0x0]),); } diff --git a/src/system_common/time_code.rs b/src/system_common/time_code.rs index 4d68a90..ee7b7f0 100644 --- a/src/system_common/time_code.rs +++ b/src/system_common/time_code.rs @@ -34,7 +34,7 @@ mod tests { #[test] fn setter() { - let mut message = TimeCode::new_arr(); + let mut message = TimeCode::<[u32; 4]>::new(); message.set_group(u4::new(0x5)); message.set_time_code(u7::new(0x5F)); assert_eq!(message, TimeCode([0x15F1_5F00, 0x0, 0x0, 0x0]),); @@ -42,7 +42,7 @@ mod tests { #[test] fn setters_bytes() { - let mut message = TimeCode::new_arr_bytes(); + let mut message = TimeCode::<[u8; 3]>::new(); message.set_time_code(u7::new(0x5F)); assert_eq!(message, TimeCode([0xF1, 0x5F, 0x0,]),); } diff --git a/src/ump_stream/device_identity.rs b/src/ump_stream/device_identity.rs index 8ae85e2..15853be 100644 --- a/src/ump_stream/device_identity.rs +++ b/src/ump_stream/device_identity.rs @@ -68,7 +68,7 @@ mod tests { #[test] fn builder() { - let mut message = DeviceIdentity::new_arr(); + let mut message = DeviceIdentity::<[u32; 4]>::new(); message.set_device_manufacturer([u7::new(0x0F), u7::new(0x33), u7::new(0x28)]); message.set_device_family(u14::new(0xF4A)); message.set_device_family_model_number(u14::new(0x3818)); diff --git a/src/ump_stream/end_of_clip.rs b/src/ump_stream/end_of_clip.rs index a82e4ff..8f1df90 100644 --- a/src/ump_stream/end_of_clip.rs +++ b/src/ump_stream/end_of_clip.rs @@ -20,7 +20,7 @@ mod tests { #[test] fn setters() { assert_eq!( - EndOfClip::new_arr(), + EndOfClip::<[u32; 4]>::new(), EndOfClip([0xF021_0000, 0x0, 0x0, 0x0]) ); } diff --git a/src/ump_stream/endpoint_discovery.rs b/src/ump_stream/endpoint_discovery.rs index ddd47da..66472fa 100644 --- a/src/ump_stream/endpoint_discovery.rs +++ b/src/ump_stream/endpoint_discovery.rs @@ -37,7 +37,7 @@ mod tests { #[test] fn builder() { - let mut message = EndpointDiscovery::new_arr(); + let mut message = EndpointDiscovery::<[u32; 4]>::new(); message.set_ump_version_major(0x1); message.set_ump_version_minor(0x1); message.set_request_endpoint_info(true); diff --git a/src/ump_stream/endpoint_info.rs b/src/ump_stream/endpoint_info.rs index e8b0910..e92752c 100644 --- a/src/ump_stream/endpoint_info.rs +++ b/src/ump_stream/endpoint_info.rs @@ -40,7 +40,7 @@ mod tests { #[test] fn builder() { - let mut message = EndpointInfo::new_arr(); + let mut message = EndpointInfo::<[u32; 4]>::new(); message.set_ump_version_major(0x1); message.set_ump_version_minor(0x1); message.set_static_function_blocks(true); diff --git a/src/ump_stream/function_block_discovery.rs b/src/ump_stream/function_block_discovery.rs index 8439290..78c7595 100644 --- a/src/ump_stream/function_block_discovery.rs +++ b/src/ump_stream/function_block_discovery.rs @@ -30,7 +30,7 @@ mod tests { #[test] fn setters() { - let mut message = FunctionBlockDiscovery::new_arr(); + let mut message = FunctionBlockDiscovery::<[u32; 4]>::new(); message.set_function_block_number(0x09); message.set_requesting_function_block_info(true); message.set_requesting_function_block_name(true); diff --git a/src/ump_stream/function_block_info.rs b/src/ump_stream/function_block_info.rs index 3c95c7d..cfdaefd 100644 --- a/src/ump_stream/function_block_info.rs +++ b/src/ump_stream/function_block_info.rs @@ -242,7 +242,7 @@ mod tests { #[test] fn builder() { - let mut message = FunctionBlockInfo::new_arr(); + let mut message = FunctionBlockInfo::<[u32; 4]>::new(); message.set_active(true); message.set_function_block_number(u7::new(0x11)); message.set_first_group(u4::new(0xD)); diff --git a/src/ump_stream/start_of_clip.rs b/src/ump_stream/start_of_clip.rs index 9faea8a..9bbc730 100644 --- a/src/ump_stream/start_of_clip.rs +++ b/src/ump_stream/start_of_clip.rs @@ -20,7 +20,7 @@ mod tests { #[test] fn builder() { assert_eq!( - StartOfClip::new_arr(), + StartOfClip::<[u32; 4]>::new(), StartOfClip([0xF020_0000, 0x0, 0x0, 0x0]), ); } diff --git a/src/ump_stream/stream_configuration_notification.rs b/src/ump_stream/stream_configuration_notification.rs index 7289a40..4ffd91b 100644 --- a/src/ump_stream/stream_configuration_notification.rs +++ b/src/ump_stream/stream_configuration_notification.rs @@ -29,7 +29,7 @@ mod tests { #[test] fn builder() { - let mut message = StreamConfigurationNotification::new_arr(); + let mut message = StreamConfigurationNotification::<[u32; 4]>::new(); message.set_protocol(0x2); message.set_receive_jr_timestamps(true); message.set_send_jr_timestamps(true); diff --git a/src/ump_stream/stream_configuration_request.rs b/src/ump_stream/stream_configuration_request.rs index 7493cd5..86e04c0 100644 --- a/src/ump_stream/stream_configuration_request.rs +++ b/src/ump_stream/stream_configuration_request.rs @@ -29,7 +29,7 @@ mod tests { #[test] fn builder() { - let mut message = StreamConfigurationRequest::new_arr(); + let mut message = StreamConfigurationRequest::<[u32; 4]>::new(); message.set_protocol(0x2); message.set_receive_jr_timestamps(true); message.set_send_jr_timestamps(true); diff --git a/src/utility/mod.rs b/src/utility/mod.rs index 6224bd6..f302ead 100644 --- a/src/utility/mod.rs +++ b/src/utility/mod.rs @@ -82,13 +82,13 @@ mod timestamp { #[test] fn new_arr() { - let message = Timestamp::new_arr(); + let message = Timestamp::<[u32; 4]>::new(); assert_eq!(message, Timestamp([0x0020_0000, 0x0, 0x0, 0x0])); } #[test] fn rebuffer_into() { - let message = Timestamp::new_arr(); + let message = Timestamp::<[u32; 4]>::new(); let rebuffered: Timestamp> = message.rebuffer_into(); assert_eq!(rebuffered, Timestamp(std::vec![0x0020_0000])); } From cff6e33599e5a243a33f2af602a11be349712f65 Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Sun, 12 May 2024 14:30:12 +0200 Subject: [PATCH 05/25] docs: add docs for arr constructors --- midi2_proc/src/generate_message.rs | 6 ++++++ src/channel_voice1/channel_pressure.rs | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/midi2_proc/src/generate_message.rs b/midi2_proc/src/generate_message.rs index 8db90e4..3c78ed3 100644 --- a/midi2_proc/src/generate_message.rs +++ b/midi2_proc/src/generate_message.rs @@ -469,6 +469,7 @@ fn new_impl( + crate::buffer::BufferResize > #root_ident { + /// Create a new message backed by a resizable buffer. pub fn new() -> #root_ident { let mut buffer = ::default(); @@ -499,6 +500,10 @@ fn new_array_impl( quote! { impl #root_ident<#buffer_type> { + /// Create a new message backed by a simple array type buffer. + /// + /// Note: this constructor will fail to compile for `SIZE` values + /// which are smaller than the minimum representable message size. pub fn new() -> #root_ident<#buffer_type> { let _valid = >::VALID; @@ -524,6 +529,7 @@ fn try_new_impl( + crate::buffer::BufferTryResize > #root_ident { + /// Create a new message backed by a buffer with fallible resize. pub fn try_new() -> core::result::Result<#root_ident, crate::error::BufferOverflow> { let mut buffer = ::default(); diff --git a/src/channel_voice1/channel_pressure.rs b/src/channel_voice1/channel_pressure.rs index 3c8f679..35dd3e2 100644 --- a/src/channel_voice1/channel_pressure.rs +++ b/src/channel_voice1/channel_pressure.rs @@ -39,6 +39,22 @@ mod tests { }; use pretty_assertions::assert_eq; + #[test] + fn new_arr() { + assert_eq!( + ChannelPressure::<[u32; 1]>::new(), + ChannelPressure([0x20D0_0000]) + ); + } + + #[test] + fn new_arr_bytes() { + assert_eq!( + ChannelPressure::<[u8; 2]>::new(), + ChannelPressure([0xD0, 0x00]) + ); + } + #[test] fn setters() { let mut message = ChannelPressure::<[u32; 4]>::new(); From ebeb2bb72ebd196f6b1edf01a6891474ff359d7d Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Sun, 12 May 2024 14:44:38 +0200 Subject: [PATCH 06/25] refactor: replace redundant instances of `try_new` with `new` --- README.md | 3 +-- src/buffer.rs | 3 +-- src/channel_voice1/channel_pressure.rs | 17 +++++++---------- src/flex_data/unknown_metadata_text.rs | 2 +- src/message.rs | 2 +- src/sysex7/README.md | 3 +-- src/sysex7/mod.rs | 10 +++++----- src/sysex8/mod.rs | 6 +++--- 8 files changed, 20 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index a9f1e64..bfdf9ea 100644 --- a/README.md +++ b/README.md @@ -168,8 +168,7 @@ represent messages within a fixed size array. ```rust use midi2::prelude::*; -let mut message = sysex8::Sysex8::<[u32; 16]>::try_new() - .expect("Buffer is large enough for min message size"); +let mut message = sysex8::Sysex8::<[u32; 16]>::new(); // in this mode methods which would require a // buffer resize are fallible diff --git a/src/buffer.rs b/src/buffer.rs index 11e07b4..e1c8520 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -39,8 +39,7 @@ //! ```rust //! use midi2::prelude::*; //! -//! let mut message = sysex8::Sysex8::<[u32; 64]>::try_new() -//! .expect("Buffer is large enough for default size"); +//! let mut message = sysex8::Sysex8::<[u32; 64]>::new(); //! assert_eq!(message.try_set_payload(0..20), Ok(())); //! ``` //! `Vec` implements [BufferMut] and [BufferResize]. diff --git a/src/channel_voice1/channel_pressure.rs b/src/channel_voice1/channel_pressure.rs index 35dd3e2..2a49045 100644 --- a/src/channel_voice1/channel_pressure.rs +++ b/src/channel_voice1/channel_pressure.rs @@ -160,10 +160,7 @@ mod tests { #[test] fn data_with_outsized_buffer() { - assert_eq!( - ChannelPressure::<[u32; 2]>::try_new().unwrap().data(), - &[0x20D0_0000] - ); + assert_eq!(ChannelPressure::<[u32; 2]>::new().data(), &[0x20D0_0000]); } #[test] @@ -223,18 +220,18 @@ mod tests { } #[test] - fn try_new_with_custom_buffer() { + fn new_with_arr() { assert_eq!( - ChannelPressure::<[u32; 2]>::try_new(), - Ok(ChannelPressure([0x20D0_0000, 0x0])) + ChannelPressure::<[u32; 2]>::new(), + ChannelPressure([0x20D0_0000, 0x0]), ) } #[test] - fn try_new_with_custom_buffer_bytes() { + fn new_with_arr_bytes() { assert_eq!( - ChannelPressure::<[u8; 3]>::try_new(), - Ok(ChannelPressure([0xD0, 0x00, 0x0])) + ChannelPressure::<[u8; 3]>::new(), + ChannelPressure([0xD0, 0x00, 0x0]), ) } diff --git a/src/flex_data/unknown_metadata_text.rs b/src/flex_data/unknown_metadata_text.rs index c9d77c7..a251b64 100644 --- a/src/flex_data/unknown_metadata_text.rs +++ b/src/flex_data/unknown_metadata_text.rs @@ -177,7 +177,7 @@ mod tests { #[test] fn try_set_text() { - let mut message = UnknownMetadataText::<[u32; 8]>::try_new().unwrap(); + let mut message = UnknownMetadataText::<[u32; 8]>::new(); message .try_set_text("Gimme some signal!") .expect("Shouldn't fail"); diff --git a/src/message.rs b/src/message.rs index 4b2098b..ccdd07c 100644 --- a/src/message.rs +++ b/src/message.rs @@ -282,7 +282,7 @@ mod tests { fn from_level2_flex_data() { use crate::flex_data::Lyrics; - let level2_message = Lyrics::<[u32; 4]>::try_new().expect("Buffer large enough"); + let level2_message = Lyrics::<[u32; 4]>::new(); let _: UmpMessage<[u32; 4]> = level2_message.into(); } diff --git a/src/sysex7/README.md b/src/sysex7/README.md index e04fa37..1e91725 100644 --- a/src/sysex7/README.md +++ b/src/sysex7/README.md @@ -109,8 +109,7 @@ Use with fixed size, or fallible buffers. ```rust use midi2::prelude::*; -let mut message = sysex7::Sysex7::<[u8; 22]>::try_new() - .expect("Buffer is large enough"); +let mut message = sysex7::Sysex7::<[u8; 22]>::new(); // only fallible methods are available assert_eq!(message.try_set_payload((0u8..20u8).map(u7::new)), Ok(())); diff --git a/src/sysex7/mod.rs b/src/sysex7/mod.rs index 5a261bc..48545e3 100644 --- a/src/sysex7/mod.rs +++ b/src/sysex7/mod.rs @@ -1152,7 +1152,7 @@ mod tests { #[test] fn try_set_payload_bytes() { - let mut message = Sysex7::<[u8; 22]>::try_new().unwrap(); + let mut message = Sysex7::<[u8; 22]>::new(); message.try_set_payload((0u8..20u8).map(u7::new)).unwrap(); assert_eq!( message, @@ -1165,7 +1165,7 @@ mod tests { #[test] fn try_set_payload_bytes_fail() { - let mut message = Sysex7::<[u8; 22]>::try_new().unwrap(); + let mut message = Sysex7::<[u8; 22]>::new(); assert_eq!( message.try_set_payload((0u8..30u8).map(u7::new)), Err(crate::error::BufferOverflow), @@ -1226,7 +1226,7 @@ mod tests { #[test] fn try_set_rubbish_payload_to_fixed_size_buffer_ump() { use crate::detail::test_support::rubbish_payload_iterator::RubbishPayloadIterator; - let mut message = Sysex7::<[u32; 18]>::try_new().unwrap(); + let mut message = Sysex7::<[u32; 18]>::new(); message .try_set_payload(RubbishPayloadIterator::new().map(u7::new)) .expect("Shouldn't fail"); @@ -1302,7 +1302,7 @@ mod tests { #[test] fn try_set_rubbish_payload_to_fixed_size_buffer() { use crate::detail::test_support::rubbish_payload_iterator::RubbishPayloadIterator; - let mut message = Sysex7::<[u8; 52]>::try_new().unwrap(); + let mut message = Sysex7::<[u8; 52]>::new(); message .try_set_payload(RubbishPayloadIterator::new().map(u7::new)) .expect("Shouldn't fail"); @@ -1524,7 +1524,7 @@ mod tests { #[test] fn set_payload_to_fixed_size_buffer_with_overflow() { - let mut message = Sysex7::<[u32; 8]>::try_new().unwrap(); + let mut message = Sysex7::<[u32; 8]>::new(); assert_eq!( message.try_set_payload((0..30).map(u7::new)), Err(crate::error::BufferOverflow) diff --git a/src/sysex8/mod.rs b/src/sysex8/mod.rs index 4806dce..b78ed12 100644 --- a/src/sysex8/mod.rs +++ b/src/sysex8/mod.rs @@ -918,7 +918,7 @@ mod tests { #[test] fn set_rubbish_payload_to_fixed_size_buffer() { use crate::detail::test_support::rubbish_payload_iterator::RubbishPayloadIterator; - let mut message = Sysex8::<[u32; 16]>::try_new().unwrap(); + let mut message = Sysex8::<[u32; 16]>::new(); assert_eq!( message.try_set_payload(RubbishPayloadIterator::new()), Ok(()) @@ -968,7 +968,7 @@ mod tests { #[test] fn set_and_reset_payload_fixed_size_buffer() { - let mut message = Sysex8::<[u32; 13]>::try_new().unwrap(); + let mut message = Sysex8::<[u32; 13]>::new(); assert_eq!(message.try_set_payload(0..30), Ok(())); assert_eq!(message.try_set_payload(0..20), Ok(())); assert_eq!( @@ -988,7 +988,7 @@ mod tests { #[test] fn set_payload_to_fixed_size_buffer_with_overflow() { - let mut message = Sysex8::<[u32; 16]>::try_new().unwrap(); + let mut message = Sysex8::<[u32; 16]>::new(); assert_eq!( message.try_set_payload(0..60), Err(crate::error::BufferOverflow) From 0fbbe6a98b3dd0e9afd508b78f6c1467e675574e Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Mon, 13 May 2024 21:20:05 +0200 Subject: [PATCH 07/25] feat: rebuffer trait infallible for array types greater than min size --- README.md | 2 +- midi2_proc/src/generate_message.rs | 20 +++++++++++++++++++- src/channel_voice1/channel_pressure.rs | 10 ++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bfdf9ea..3e6b3e7 100644 --- a/README.md +++ b/README.md @@ -225,7 +225,7 @@ let mut owned: NoteOn::<[u32; 4]> = { let buffer = [0x4898_5E03_u32, 0x6A14_E98A]; // the borrowed message is immutable and cannot outlive `buffer` let borrowed = NoteOn::try_from(&buffer[..]).expect("Data is valid"); - borrowed.try_rebuffer_into().expect("Buffer is large enough") + borrowed.rebuffer_into() }; // the owned message is mutable and liberated from the buffer lifetime. diff --git a/midi2_proc/src/generate_message.rs b/midi2_proc/src/generate_message.rs index 3c78ed3..35260a0 100644 --- a/midi2_proc/src/generate_message.rs +++ b/midi2_proc/src/generate_message.rs @@ -439,6 +439,23 @@ fn rebuffer_from_impl(root_ident: &syn::Ident, args: &GenerateMessageArgs) -> To } } +fn rebuffer_from_array_impl(root_ident: &syn::Ident, args: &GenerateMessageArgs) -> TokenStream { + let constraint = generic_buffer_constraint(args); + let buffer_type = quote! { [::Unit; SIZE] }; + quote! { + impl crate::traits::RebufferFrom<#root_ident> for #root_ident<#buffer_type> + { + fn rebuffer_from(other: #root_ident) -> Self { + let _valid = >::VALID; + let mut buffer = <#buffer_type as crate::buffer::BufferDefault>::default(); + let message_size = other.data().len(); + buffer[..message_size].copy_from_slice(other.data()); + #root_ident(buffer) + } + } + } +} + fn try_rebuffer_from_impl(root_ident: &syn::Ident, args: &GenerateMessageArgs) -> TokenStream { let generics = crate::common::try_rebuffer_generics(args.representation()); quote! { @@ -759,7 +776,8 @@ pub fn generate_message(attrs: TokenStream1, item: TokenStream1) -> TokenStream1 }); if args.fixed_size { - tokens.extend(size_impl(root_ident, &args)) + tokens.extend(size_impl(root_ident, &args)); + tokens.extend(rebuffer_from_array_impl(root_ident, &args)); } if let Some(property) = properties.iter().find(|p| p.is_group()) { tokens.extend(grouped_impl(root_ident, property)); diff --git a/src/channel_voice1/channel_pressure.rs b/src/channel_voice1/channel_pressure.rs index 2a49045..483cf54 100644 --- a/src/channel_voice1/channel_pressure.rs +++ b/src/channel_voice1/channel_pressure.rs @@ -288,6 +288,16 @@ mod rebuffer_tests { ); } + #[test] + fn rebuffer_from_array() { + let buffer = [0x2FD6_0900_u32]; + let borrowed = ChannelPressure::try_from(&buffer[..]).unwrap(); + assert_eq!( + ChannelPressure::<[u32; 1]>::rebuffer_from(borrowed), + ChannelPressure([0x2FD6_0900_u32]), + ); + } + #[test] fn try_rebuffer_from_fail() { let buffer = [0x2FD6_0900_u32]; From d3dd8a5ec33182785e50e370941ea8a244b58b2b Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Mon, 13 May 2024 21:37:25 +0200 Subject: [PATCH 08/25] feat: ump <-> bytes conversions infallible for array backed messages --- README.md | 3 +- midi2_proc/src/generate_message.rs | 49 ++++++++++++++++++++++---- src/channel_voice1/channel_pressure.rs | 20 +++++++++++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 3e6b3e7..c88e73f 100644 --- a/README.md +++ b/README.md @@ -257,8 +257,7 @@ use midi2::{ }; let message = ChannelPressure::<[u8; 3]>::new(); -let message: ChannelPressure<[u32; 4]> = message.try_into_ump(). - expect("Buffer is large enough"); +let message: ChannelPressure<[u32; 4]> = message.into_ump(); assert_eq!(message.data(), &[0x20D0_0000]); ``` diff --git a/midi2_proc/src/generate_message.rs b/midi2_proc/src/generate_message.rs index 35260a0..b40b446 100644 --- a/midi2_proc/src/generate_message.rs +++ b/midi2_proc/src/generate_message.rs @@ -617,7 +617,7 @@ fn channeled_impl( } fn from_bytes_impl(root_ident: &syn::Ident, properties: &Vec) -> TokenStream { - let convert_properties = convert_properties(properties); + let convert_properties = convert_properties(properties, "e! { B }); quote! { impl< A: crate::buffer::Bytes, @@ -637,8 +637,24 @@ fn from_bytes_impl(root_ident: &syn::Ident, properties: &Vec) -> Token } } +fn from_bytes_array_impl(root_ident: &syn::Ident, properties: &Vec) -> TokenStream { + let array_type = quote! { [u32; SIZE] }; + let convert_properties = convert_properties(properties, &array_type); + quote! { + impl crate::traits::FromBytes<#root_ident> for #root_ident<#array_type> + { + fn from_bytes(other: #root_ident) -> Self { + let _valid = >::VALID; + let mut buffer = <#array_type as crate::buffer::BufferDefault>::default(); + #convert_properties + Self(buffer) + } + } + } +} + fn try_from_bytes_impl(root_ident: &syn::Ident, properties: &Vec) -> TokenStream { - let convert_properties = convert_properties(properties); + let convert_properties = convert_properties(properties, "e! { B }); quote! { impl< A: crate::buffer::Bytes, @@ -658,7 +674,7 @@ fn try_from_bytes_impl(root_ident: &syn::Ident, properties: &Vec) -> T } } -fn convert_properties(properties: &Vec) -> TokenStream { +fn convert_properties(properties: &Vec, target_buffer_type: &TokenStream) -> TokenStream { let mut convert_properties = TokenStream::new(); for property in properties.iter().filter(|p| !p.readonly && !p.writeonly) { let std_only_attribute = std_only_attribute(property); @@ -666,7 +682,7 @@ fn convert_properties(properties: &Vec) -> TokenStream { convert_properties.extend(quote! { #std_only_attribute - <#meta_type as crate::detail::property::WriteProperty>::write( + <#meta_type as crate::detail::property::WriteProperty<#target_buffer_type>>::write( &mut buffer, <#meta_type as crate::detail::property::ReadProperty>::read(&other.0) ); @@ -676,7 +692,7 @@ fn convert_properties(properties: &Vec) -> TokenStream { } fn from_ump_impl(root_ident: &syn::Ident, properties: &Vec) -> TokenStream { - let convert_properties = convert_properties(properties); + let convert_properties = convert_properties(properties, "e! { B }); quote! { impl< A: crate::buffer::Ump, @@ -696,8 +712,24 @@ fn from_ump_impl(root_ident: &syn::Ident, properties: &Vec) -> TokenSt } } +fn from_ump_array_impl(root_ident: &syn::Ident, properties: &Vec) -> TokenStream { + let array_type = quote! { [u8; SIZE] }; + let convert_properties = convert_properties(properties, &array_type); + quote! { + impl crate::traits::FromUmp<#root_ident> for #root_ident<#array_type> + { + fn from_ump(other: #root_ident) -> Self { + let _valid = >::VALID; + let mut buffer = <#array_type as crate::buffer::BufferDefault>::default(); + #convert_properties + Self(buffer) + } + } + } +} + fn try_from_ump_impl(root_ident: &syn::Ident, properties: &Vec) -> TokenStream { - let convert_properties = convert_properties(properties); + let convert_properties = convert_properties(properties, "e! { B }); quote! { impl< A: crate::buffer::Ump, @@ -793,6 +825,11 @@ pub fn generate_message(attrs: TokenStream1, item: TokenStream1) -> TokenStream1 tokens.extend(from_ump_impl(root_ident, &properties)); tokens.extend(try_from_bytes_impl(root_ident, &properties)); tokens.extend(try_from_ump_impl(root_ident, &properties)); + + if args.fixed_size { + tokens.extend(from_ump_array_impl(root_ident, &properties)); + tokens.extend(from_bytes_array_impl(root_ident, &properties)); + } } } if let Some(via_type) = args.via.as_ref() { diff --git a/src/channel_voice1/channel_pressure.rs b/src/channel_voice1/channel_pressure.rs index 483cf54..f0bb612 100644 --- a/src/channel_voice1/channel_pressure.rs +++ b/src/channel_voice1/channel_pressure.rs @@ -193,6 +193,16 @@ mod tests { ); } + #[test] + fn from_bytes_array() { + let buffer = [0xD6_u8, 0x09_u8]; + let borrowed = ChannelPressure::try_from(&buffer[..]).unwrap(); + assert_eq!( + ChannelPressure::<[u32; 1]>::from_bytes(borrowed), + ChannelPressure([0x20D6_0900_u32]), + ); + } + #[test] fn try_from_ump() { let buffer = [0x2FD6_0900_u32]; @@ -203,6 +213,16 @@ mod tests { ); } + #[test] + fn from_ump_array() { + let buffer = [0x2FD6_0900_u32]; + let borrowed = ChannelPressure::try_from(&buffer[..]).unwrap(); + assert_eq!( + ChannelPressure::<[u8; 2]>::from_ump(borrowed), + ChannelPressure([0xD6_u8, 0x09_u8]), + ); + } + #[test] fn new_with_custom_buffer() { assert_eq!( From f24cb000310b2d0e80e471a6aeb2c92e36b82d5f Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Tue, 14 May 2024 06:19:26 +0200 Subject: [PATCH 09/25] chore: cleanup empty files --- :: | 0 ::new | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 :: delete mode 100644 ::new diff --git a/:: b/:: deleted file mode 100644 index e69de29..0000000 diff --git a/::new b/::new deleted file mode 100644 index e69de29..0000000 From 532499f71c3379941f2bab6500657e385d1d3bdf Mon Sep 17 00:00:00 2001 From: "mail@kurtgrassl.de" Date: Tue, 14 May 2024 15:39:12 +0200 Subject: [PATCH 10/25] Switching implementation from mod.rs to file names based on module name --- src/{channel_voice1/mod.rs => channel_voice1.rs} | 0 src/{channel_voice2/mod.rs => channel_voice2.rs} | 0 src/ci.rs | 1 + src/ci/mod.rs | 1 - src/{detail/mod.rs => detail.rs} | 0 src/detail/{test_support/mod.rs => test_support.rs} | 0 src/{flex_data/mod.rs => flex_data.rs} | 0 src/{sysex7/mod.rs => sysex7.rs} | 2 +- src/{sysex8/mod.rs => sysex8.rs} | 0 src/{system_common/mod.rs => system_common.rs} | 2 +- src/{ump_stream/mod.rs => ump_stream.rs} | 0 src/{utility/mod.rs => utility.rs} | 0 12 files changed, 3 insertions(+), 3 deletions(-) rename src/{channel_voice1/mod.rs => channel_voice1.rs} (100%) rename src/{channel_voice2/mod.rs => channel_voice2.rs} (100%) create mode 100644 src/ci.rs delete mode 100644 src/ci/mod.rs rename src/{detail/mod.rs => detail.rs} (100%) rename src/detail/{test_support/mod.rs => test_support.rs} (100%) rename src/{flex_data/mod.rs => flex_data.rs} (100%) rename src/{sysex7/mod.rs => sysex7.rs} (99%) rename src/{sysex8/mod.rs => sysex8.rs} (100%) rename src/{system_common/mod.rs => system_common.rs} (99%) rename src/{ump_stream/mod.rs => ump_stream.rs} (100%) rename src/{utility/mod.rs => utility.rs} (100%) diff --git a/src/channel_voice1/mod.rs b/src/channel_voice1.rs similarity index 100% rename from src/channel_voice1/mod.rs rename to src/channel_voice1.rs diff --git a/src/channel_voice2/mod.rs b/src/channel_voice2.rs similarity index 100% rename from src/channel_voice2/mod.rs rename to src/channel_voice2.rs diff --git a/src/ci.rs b/src/ci.rs new file mode 100644 index 0000000..630b94d --- /dev/null +++ b/src/ci.rs @@ -0,0 +1 @@ +#![doc = include_str!("ci/README.md")] diff --git a/src/ci/mod.rs b/src/ci/mod.rs deleted file mode 100644 index bff99d5..0000000 --- a/src/ci/mod.rs +++ /dev/null @@ -1 +0,0 @@ -#![doc = include_str!("README.md")] diff --git a/src/detail/mod.rs b/src/detail.rs similarity index 100% rename from src/detail/mod.rs rename to src/detail.rs diff --git a/src/detail/test_support/mod.rs b/src/detail/test_support.rs similarity index 100% rename from src/detail/test_support/mod.rs rename to src/detail/test_support.rs diff --git a/src/flex_data/mod.rs b/src/flex_data.rs similarity index 100% rename from src/flex_data/mod.rs rename to src/flex_data.rs diff --git a/src/sysex7/mod.rs b/src/sysex7.rs similarity index 99% rename from src/sysex7/mod.rs rename to src/sysex7.rs index 48545e3..7909273 100644 --- a/src/sysex7/mod.rs +++ b/src/sysex7.rs @@ -1,4 +1,4 @@ -#![doc = include_str!("README.md")] +#![doc = include_str!("sysex7/README.md")] use crate::{ detail::{common_properties, helpers as message_helpers, BitOps}, diff --git a/src/sysex8/mod.rs b/src/sysex8.rs similarity index 100% rename from src/sysex8/mod.rs rename to src/sysex8.rs diff --git a/src/system_common/mod.rs b/src/system_common.rs similarity index 99% rename from src/system_common/mod.rs rename to src/system_common.rs index 08bc399..fc7036e 100644 --- a/src/system_common/mod.rs +++ b/src/system_common.rs @@ -1,4 +1,4 @@ -#![doc = include_str!("README.md")] +#![doc = include_str!("system_common/README.md")] pub(crate) const UMP_MESSAGE_TYPE: u8 = 0x1; diff --git a/src/ump_stream/mod.rs b/src/ump_stream.rs similarity index 100% rename from src/ump_stream/mod.rs rename to src/ump_stream.rs diff --git a/src/utility/mod.rs b/src/utility.rs similarity index 100% rename from src/utility/mod.rs rename to src/utility.rs From a8558f586932319c34739d0efc81fc700de2e5d8 Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Tue, 14 May 2024 15:16:08 +0200 Subject: [PATCH 11/25] feat: new Packets trait implemented by all ump messages --- midi2_proc/src/derives.rs | 23 +++++++++ midi2_proc/src/generate_message.rs | 19 +++++++ midi2_proc/src/lib.rs | 5 ++ src/channel_voice1.rs | 16 ++++-- src/channel_voice1/control_change.rs | 14 ++++-- src/channel_voice2.rs | 11 ++++ src/channel_voice2/assignable_controller.rs | 11 ++++ src/flex_data.rs | 41 +++++++++++++++ src/flex_data/unknown_metadata_text.rs | 37 ++++++++++++++ src/lib.rs | 2 + src/message.rs | 41 +++++++++++++++ src/packets.rs | 33 ++++++++++++ src/sysex7.rs | 38 ++++++++++++++ src/sysex8.rs | 56 +++++++++++++++++++++ src/system_common.rs | 12 +++++ src/system_common/song_position_pointer.rs | 12 +++++ src/ump_stream.rs | 49 +++++++++++++++++- src/ump_stream/device_identity.rs | 16 ++++++ src/ump_stream/endpoint_name.rs | 29 +++++++++++ src/utility.rs | 12 +++++ 20 files changed, 467 insertions(+), 10 deletions(-) create mode 100644 src/packets.rs diff --git a/midi2_proc/src/derives.rs b/midi2_proc/src/derives.rs index 2c42a36..5f0b8de 100644 --- a/midi2_proc/src/derives.rs +++ b/midi2_proc/src/derives.rs @@ -31,6 +31,29 @@ pub fn data(item: TokenStream1) -> TokenStream1 { .into() } +pub fn packets(item: TokenStream1) -> TokenStream1 { + let input = parse_macro_input!(item as ItemEnum); + let ident = &input.ident; + let mut match_arms = TokenStream::new(); + for variant in &input.variants { + let variant_ident = &variant.ident; + match_arms.extend(quote! { + #variant_ident(m) => m.packets(), + }); + } + quote! { + impl crate::Packets for #ident { + fn packets(&self) -> crate::PacketsIterator { + use #ident::*; + match self { + #match_arms + } + } + } + } + .into() +} + pub fn from_bytes(item: TokenStream1) -> TokenStream1 { let input = parse_macro_input!(item as ItemEnum); let ident = &input.ident; diff --git a/midi2_proc/src/generate_message.rs b/midi2_proc/src/generate_message.rs index b40b446..efcd243 100644 --- a/midi2_proc/src/generate_message.rs +++ b/midi2_proc/src/generate_message.rs @@ -385,6 +385,19 @@ fn data_impl(root_ident: &syn::Ident, args: &GenerateMessageArgs) -> TokenStream } } +fn packets_impl(root_ident: &syn::Ident) -> TokenStream { + quote! { + impl crate::Packets for #root_ident { + fn packets(&self) -> crate::PacketsIterator { + crate::PacketsIterator(self + .data() + .chunks_exact(>::MIN_SIZE) + ) + } + } + } +} + fn try_from_slice_impl( root_ident: &syn::Ident, args: &GenerateMessageArgs, @@ -832,6 +845,12 @@ pub fn generate_message(attrs: TokenStream1, item: TokenStream1) -> TokenStream1 } } } + if matches!( + args.representation(), + Representation::Ump | Representation::UmpOrBytes + ) { + tokens.extend(packets_impl(root_ident)); + } if let Some(via_type) = args.via.as_ref() { match args.representation() { Representation::Ump => tokens.extend(ump_message_via(root_ident, &via_type)), diff --git a/midi2_proc/src/lib.rs b/midi2_proc/src/lib.rs index 2504521..ac348d8 100644 --- a/midi2_proc/src/lib.rs +++ b/midi2_proc/src/lib.rs @@ -14,6 +14,11 @@ pub fn derive_data(item: TokenStream1) -> TokenStream1 { derives::data(item) } +#[proc_macro_derive(Packets)] +pub fn derive_packets(item: TokenStream1) -> TokenStream1 { + derives::packets(item) +} + #[proc_macro_derive(Grouped)] pub fn derive_grouped(item: TokenStream1) -> TokenStream1 { derives::grouped(item) diff --git a/src/channel_voice1.rs b/src/channel_voice1.rs index b554204..7096746 100644 --- a/src/channel_voice1.rs +++ b/src/channel_voice1.rs @@ -21,6 +21,7 @@ pub(crate) const UMP_MESSAGE_TYPE: u8 = 0x2; #[derive( derive_more::From, midi2_proc::Data, + midi2_proc::Packets, midi2_proc::Channeled, midi2_proc::Grouped, midi2_proc::FromBytes, @@ -82,11 +83,8 @@ fn status(buffer: &[U]) -> u8 { mod test { use super::*; use crate::{ - traits::{ - Channeled, Data, FromBytes, FromUmp, Grouped, RebufferInto, TryFromBytes, TryFromUmp, - TryRebufferInto, - }, - ux::*, + ux::*, Channeled, Data, FromBytes, FromUmp, Grouped, Packets, RebufferInto, TryFromBytes, + TryFromUmp, TryRebufferInto, }; use pretty_assertions::assert_eq; @@ -177,4 +175,12 @@ mod test { .unwrap(); assert_eq!(message.data(), &[0x2FD6_0900]); } + + #[test] + fn packets() { + let message = ChannelVoice1::try_from(&[0x2FD6_0900_u32][..]).unwrap(); + let mut packets = message.packets(); + assert_eq!(packets.next(), Some(&[0x2FD6_0900_u32][..])); + assert_eq!(packets.next(), None); + } } diff --git a/src/channel_voice1/control_change.rs b/src/channel_voice1/control_change.rs index 892ee6b..5b2cd53 100644 --- a/src/channel_voice1/control_change.rs +++ b/src/channel_voice1/control_change.rs @@ -37,10 +37,7 @@ struct ControlChange { #[cfg(test)] mod tests { use super::*; - use crate::{ - traits::{Channeled, Grouped}, - ux::*, - }; + use crate::{ux::*, Channeled, Grouped, Packets}; use pretty_assertions::assert_eq; #[test] @@ -131,4 +128,13 @@ mod tests { u7::new(0x37), ); } + + #[test] + fn packets() { + let buffer = [0x2AB7_3637_u32]; + let message = ControlChange::try_from(&buffer[..]).unwrap(); + let mut packets = message.packets(); + assert_eq!(packets.next(), Some(&[0x2AB7_3637_u32][..])); + assert_eq!(packets.next(), None); + } } diff --git a/src/channel_voice2.rs b/src/channel_voice2.rs index b89c6fd..e36a23a 100644 --- a/src/channel_voice2.rs +++ b/src/channel_voice2.rs @@ -39,6 +39,7 @@ pub(crate) const UMP_MESSAGE_TYPE: u8 = 0x4; #[derive( derive_more::From, midi2_proc::Data, + midi2_proc::Packets, midi2_proc::Channeled, midi2_proc::Grouped, midi2_proc::RebufferFrom, @@ -137,4 +138,14 @@ mod test { u4::new(0xC), ); } + + #[test] + fn packets() { + use crate::Packets; + + let message = ChannelVoice2::try_from(&[0x4BAC_5900, 0xC0B83064][..]).unwrap(); + let mut packets = message.packets(); + assert_eq!(packets.next(), Some(&[0x4BAC_5900, 0xC0B83064][..])); + assert_eq!(packets.next(), None); + } } diff --git a/src/channel_voice2/assignable_controller.rs b/src/channel_voice2/assignable_controller.rs index 2888fa1..4d26160 100644 --- a/src/channel_voice2/assignable_controller.rs +++ b/src/channel_voice2/assignable_controller.rs @@ -98,4 +98,15 @@ mod tests { 0x3F3ADD42, ); } + + #[test] + fn packets() { + use crate::Packets; + + let buffer = [0x4C38_5138, 0x3F3ADD42]; + let message = AssignableController::try_from(&buffer[..]).unwrap(); + let mut packets = message.packets(); + assert_eq!(packets.next(), Some(&[0x4C38_5138, 0x3F3ADD42][..])); + assert_eq!(packets.next(), None); + } } diff --git a/src/flex_data.rs b/src/flex_data.rs index e81aac3..c532686 100644 --- a/src/flex_data.rs +++ b/src/flex_data.rs @@ -752,6 +752,7 @@ pub(crate) const PERFORMANCE_TEXT_BANK: u8 = 0x2; #[derive( derive_more::From, midi2_proc::Data, + midi2_proc::Packets, midi2_proc::Grouped, midi2_proc::RebufferFrom, midi2_proc::TryRebufferFrom, @@ -1202,4 +1203,44 @@ mod tests { Bank::SetupAndPerformance, ); } + + #[test] + fn packets_small() { + use crate::Packets; + + let message = FlexData::try_from(&[0xD710_0000_u32, 0xF751_FE05][..]).unwrap(); + let mut packets = message.packets(); + assert_eq!(packets.next(), Some(&[0xD710_0000_u32, 0xF751_FE05][..])); + assert_eq!(packets.next(), None); + } + + #[test] + fn packets_big() { + use crate::Packets; + + let message = FlexData::try_from( + &[ + 0xD050_0106, + 0x4769_6D6D, + 0x6520_736F, + 0x6D65_2073, + 0xD0D0_0106, + 0x6967_6E61, + 0x6C21_0000, + 0x0000_0000, + ][..], + ) + .unwrap(); + let mut packets = message.packets(); + + assert_eq!( + packets.next(), + Some(&[0xD050_0106, 0x4769_6D6D, 0x6520_736F, 0x6D65_2073,][..]) + ); + assert_eq!( + packets.next(), + Some(&[0xD0D0_0106, 0x6967_6E61, 0x6C21_0000, 0x0000_0000,][..]) + ); + assert_eq!(packets.next(), None); + } } diff --git a/src/flex_data/unknown_metadata_text.rs b/src/flex_data/unknown_metadata_text.rs index a251b64..1f30d7d 100644 --- a/src/flex_data/unknown_metadata_text.rs +++ b/src/flex_data/unknown_metadata_text.rs @@ -481,4 +481,41 @@ mod tests { ] ); } + + #[test] + fn packets() { + use crate::Packets; + + let message = UnknownMetadataText::try_from( + &[ + 0xD050_0100, + 0x4469_6769, + 0x7461_6C20, + 0x4175_6469, + 0xD090_0100, + 0x6F20_576F, + 0x726B_7374, + 0x6174_696F, + 0xD0D0_0100, + 0x6E20_2D20, + 0x4441_5733, + 0x362D_3136, + ][..], + ) + .unwrap(); + let mut packets = message.packets(); + assert_eq!( + packets.next(), + Some(&[0xD050_0100, 0x4469_6769, 0x7461_6C20, 0x4175_6469,][..]) + ); + assert_eq!( + packets.next(), + Some(&[0xD090_0100, 0x6F20_576F, 0x726B_7374, 0x6174_696F,][..]) + ); + assert_eq!( + packets.next(), + Some(&[0xD0D0_0100, 0x6E20_2D20, 0x4441_5733, 0x362D_3136,][..]) + ); + assert_eq!(packets.next(), None); + } } diff --git a/src/lib.rs b/src/lib.rs index 0cb1122..04e7d68 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,11 +29,13 @@ pub mod result; mod detail; mod message; +mod packets; mod traits; pub use ux; pub use message::*; +pub use packets::*; pub use traits::*; pub mod prelude { diff --git a/src/message.rs b/src/message.rs index ccdd07c..26fbd15 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,6 +1,7 @@ #[derive( derive_more::From, midi2_proc::Data, + midi2_proc::Packets, midi2_proc::RebufferFrom, midi2_proc::TryRebufferFrom, Clone, @@ -244,6 +245,46 @@ mod tests { }; } + #[cfg(feature = "sysex7")] + #[test] + fn packets() { + use crate::Packets; + + let buffer = [ + 0x3E16_0001, + 0x0203_0405, + 0x3E26_0607, + 0x0809_0A0B, + 0x3E26_0C0D, + 0x0E0F_1011, + 0x3E26_1213, + 0x1415_1617, + 0x3E26_1819, + 0x1A1B_1C1D, + 0x3E26_1E1F, + 0x2021_2223, + 0x3E26_2425, + 0x2627_2829, + 0x3E26_2A2B, + 0x2C2D_2E2F, + 0x3E32_3031, + 0x0000_0000, + ]; + let message = UmpMessage::try_from(&buffer[..]).unwrap(); + let mut packets = message.packets(); + + assert_eq!(packets.next(), Some(&[0x3E16_0001, 0x0203_0405,][..])); + assert_eq!(packets.next(), Some(&[0x3E26_0607, 0x0809_0A0B,][..])); + assert_eq!(packets.next(), Some(&[0x3E26_0C0D, 0x0E0F_1011,][..])); + assert_eq!(packets.next(), Some(&[0x3E26_1213, 0x1415_1617,][..])); + assert_eq!(packets.next(), Some(&[0x3E26_1819, 0x1A1B_1C1D,][..])); + assert_eq!(packets.next(), Some(&[0x3E26_1E1F, 0x2021_2223,][..])); + assert_eq!(packets.next(), Some(&[0x3E26_2425, 0x2627_2829,][..])); + assert_eq!(packets.next(), Some(&[0x3E26_2A2B, 0x2C2D_2E2F,][..])); + assert_eq!(packets.next(), Some(&[0x3E32_3031, 0x0000_0000,][..])); + assert_eq!(packets.next(), None); + } + #[cfg(feature = "flex-data")] #[test] fn flex_data() { diff --git a/src/packets.rs b/src/packets.rs new file mode 100644 index 0000000..b1957d2 --- /dev/null +++ b/src/packets.rs @@ -0,0 +1,33 @@ +#[derive(Debug, Clone)] +pub struct PacketsIterator<'a>(pub(crate) core::slice::ChunksExact<'a, u32>); + +impl<'a> core::iter::Iterator for PacketsIterator<'a> { + type Item = &'a [u32]; + fn next(&mut self) -> Option { + self.0.next() + } + fn nth(&mut self, n: usize) -> Option { + self.0.nth(n) + } + fn count(self) -> usize + where + Self: Sized, + { + self.0.count() + } + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } +} + +impl<'a> core::iter::FusedIterator for PacketsIterator<'a> {} + +impl<'a> core::iter::ExactSizeIterator for PacketsIterator<'a> { + fn len(&self) -> usize { + self.0.len() + } +} + +pub trait Packets { + fn packets(&self) -> PacketsIterator; +} diff --git a/src/sysex7.rs b/src/sysex7.rs index 7909273..11432ee 100644 --- a/src/sysex7.rs +++ b/src/sysex7.rs @@ -1540,4 +1540,42 @@ mod tests { std::vec![] ); } + + #[test] + fn packets() { + use crate::Packets; + + let buffer = [ + 0x3016_0001_u32, + 0x0203_0405, + 0x3026_0607, + 0x0809_0A0B, + 0x3026_0C0D, + 0x0E0F_1011, + 0x3026_1213, + 0x1415_1617, + 0x3036_1819, + 0x1A1B_1C1D, + ]; + let message = Sysex7::try_from(&buffer[..]).unwrap(); + let mut packets = message.packets(); + + assert_eq!(packets.next(), Some(&[0x3016_0001, 0x0203_0405,][..])); + assert_eq!(packets.next(), Some(&[0x3026_0607, 0x0809_0A0B,][..])); + assert_eq!(packets.next(), Some(&[0x3026_0C0D, 0x0E0F_1011,][..])); + assert_eq!(packets.next(), Some(&[0x3026_1213, 0x1415_1617,][..])); + assert_eq!(packets.next(), Some(&[0x3036_1819, 0x1A1B_1C1D,][..])); + assert_eq!(packets.next(), None); + } + + #[test] + fn packets_empty() { + use crate::Packets; + + let message = Sysex7::<[u32; 2]>::new(); + let mut packets = message.packets(); + + assert_eq!(packets.next(), Some(&[0x3000_0000, 0x0][..])); + assert_eq!(packets.next(), None); + } } diff --git a/src/sysex8.rs b/src/sysex8.rs index b78ed12..2e34fa7 100644 --- a/src/sysex8.rs +++ b/src/sysex8.rs @@ -1009,4 +1009,60 @@ mod tests { let payload = message.payload().collect::>(); assert_eq!(payload, std::vec![]); } + + #[test] + fn packets() { + use crate::Packets; + + let message = Sysex8::try_from( + &[ + 0x501E_0000, + 0x0102_0304, + 0x0506_0708, + 0x090A_0B0C, + 0x502E_000D, + 0x0E0F_1011, + 0x1213_1415, + 0x1617_1819, + 0x502E_001A, + 0x1B1C_1D1E, + 0x1F20_2122, + 0x2324_2526, + 0x503C_0027, + 0x2829_2A2B, + 0x2C2D_2E2F, + 0x3031_0000, + ][..], + ) + .unwrap(); + + let mut packets = message.packets(); + assert_eq!( + packets.next(), + Some(&[0x501E_0000, 0x0102_0304, 0x0506_0708, 0x090A_0B0C,][..]) + ); + assert_eq!( + packets.next(), + Some(&[0x502E_000D, 0x0E0F_1011, 0x1213_1415, 0x1617_1819,][..]) + ); + assert_eq!( + packets.next(), + Some(&[0x502E_001A, 0x1B1C_1D1E, 0x1F20_2122, 0x2324_2526,][..]) + ); + assert_eq!( + packets.next(), + Some(&[0x503C_0027, 0x2829_2A2B, 0x2C2D_2E2F, 0x3031_0000,][..]) + ); + assert_eq!(packets.next(), None); + } + + #[test] + fn packets_empty() { + use crate::Packets; + + let message = Sysex8::<[u32; 4]>::new(); + let mut packets = message.packets(); + assert_eq!(packets.next(), Some(&[0x5001_0000, 0x0, 0x0, 0x0][..])); + assert_eq!(packets.next(), None); + } } diff --git a/src/system_common.rs b/src/system_common.rs index fc7036e..573256d 100644 --- a/src/system_common.rs +++ b/src/system_common.rs @@ -168,6 +168,7 @@ pub use tune_request::*; #[derive( derive_more::From, midi2_proc::Data, + midi2_proc::Packets, midi2_proc::Grouped, midi2_proc::FromBytes, midi2_proc::FromUmp, @@ -302,4 +303,15 @@ mod tests { time_code::TimeCode::try_from(&[0x15F1_5F00_u32][..]).map(|m| m.into()) ); } + + #[test] + fn packets() { + use crate::Packets; + + let message = SystemCommon::try_from(&[0x15F1_5F00_u32][..]).unwrap(); + let mut packets = message.packets(); + + assert_eq!(packets.next(), Some(&[0x15F1_5F00_u32][..])); + assert_eq!(packets.next(), None); + } } diff --git a/src/system_common/song_position_pointer.rs b/src/system_common/song_position_pointer.rs index d06ac83..6de13db 100644 --- a/src/system_common/song_position_pointer.rs +++ b/src/system_common/song_position_pointer.rs @@ -39,6 +39,7 @@ mod tests { message.set_position(u14::new(0x367D)); assert_eq!(message, SongPositionPointer([0x1AF2_7D6C, 0x0, 0x0, 0x0]),); } + #[test] fn setters_bytes() { let mut message = SongPositionPointer::<[u8; 3]>::new(); @@ -75,4 +76,15 @@ mod tests { u14::new(0x367D), ); } + + #[test] + fn packets() { + use crate::Packets; + + let message = SongPositionPointer::try_from(&[0x1AF2_7D6C][..]).unwrap(); + + let mut packets = message.packets(); + assert_eq!(packets.next(), Some(&[0x1AF2_7D6C][..])); + assert_eq!(packets.next(), None); + } } diff --git a/src/ump_stream.rs b/src/ump_stream.rs index c73bd0e..4d35f0f 100644 --- a/src/ump_stream.rs +++ b/src/ump_stream.rs @@ -38,6 +38,7 @@ const END_FORMAT: u8 = 0x3; #[derive( derive_more::From, midi2_proc::Data, + midi2_proc::Packets, midi2_proc::RebufferFrom, midi2_proc::TryRebufferFrom, Clone, @@ -449,7 +450,7 @@ mod tests { use pretty_assertions::assert_eq; #[test] - fn builder() { + fn try_from_data() { assert_eq!( UmpStream::try_from( &[ @@ -496,4 +497,50 @@ mod tests { )) ); } + + #[test] + fn packets() { + use crate::Packets; + + let message = UmpStream::try_from( + &[ + 0xF403_5268, + 0x7974_686D, + 0x5265_7665, + 0x6C61_7469, + 0xF803_6F6E, + 0x3A20_4265, + 0x6174_7320, + 0x4265_796F, + 0xF803_6E64, + 0x2042_6F75, + 0x6E64_6172, + 0x6965_73F0, + 0xFC03_9F8C, + 0x8DF0_9FA5, + 0x81F0_9F9A, + 0x8000_0000, + ][..], + ) + .unwrap(); + + let mut packets = message.packets(); + assert_eq!( + packets.next(), + Some(&[0xF403_5268, 0x7974_686D, 0x5265_7665, 0x6C61_7469,][..]) + ); + assert_eq!( + packets.next(), + Some(&[0xF803_6F6E, 0x3A20_4265, 0x6174_7320, 0x4265_796F,][..]) + ); + assert_eq!( + packets.next(), + Some(&[0xF803_6E64, 0x2042_6F75, 0x6E64_6172, 0x6965_73F0,][..]) + ); + assert_eq!( + packets.next(), + Some(&[0xFC03_9F8C, 0x8DF0_9FA5, 0x81F0_9F9A, 0x8000_0000,][..]) + ); + assert_eq!(packets.next(), None,); + } } diff --git a/src/ump_stream/device_identity.rs b/src/ump_stream/device_identity.rs index 15853be..6774bce 100644 --- a/src/ump_stream/device_identity.rs +++ b/src/ump_stream/device_identity.rs @@ -118,4 +118,20 @@ mod tests { [u7::new(0x43), u7::new(0x54), u7::new(0x32), u7::new(0x1)], ); } + + #[test] + fn packets() { + use crate::Packets; + + let message = + DeviceIdentity::try_from(&[0xF002_0000, 0x000F_3328, 0x4A1E_1870, 0x4354_3201][..]) + .unwrap(); + let mut packets = message.packets(); + + assert_eq!( + packets.next(), + Some(&[0xF002_0000, 0x000F_3328, 0x4A1E_1870, 0x4354_3201][..]) + ); + assert_eq!(packets.next(), None); + } } diff --git a/src/ump_stream/endpoint_name.rs b/src/ump_stream/endpoint_name.rs index 86143ac..35f863c 100644 --- a/src/ump_stream/endpoint_name.rs +++ b/src/ump_stream/endpoint_name.rs @@ -107,4 +107,33 @@ mod tests { std::vec![] ); } + + #[test] + fn packets() { + use crate::Packets; + let message = EndpointName::try_from( + &[ + 0xF403_4769, + 0x6D6D_6520, + 0x736F_6D65, + 0x2073_6967, + 0xFC03_6E61, + 0x6C20_F09F, + 0x948A_20F0, + 0x9F99_8C00, + ][..], + ) + .unwrap(); + let mut packets = message.packets(); + + assert_eq!( + packets.next(), + Some(&[0xF403_4769, 0x6D6D_6520, 0x736F_6D65, 0x2073_6967,][..]) + ); + assert_eq!( + packets.next(), + Some(&[0xFC03_6E61, 0x6C20_F09F, 0x948A_20F0, 0x9F99_8C00,][..]) + ); + assert_eq!(packets.next(), None); + } } diff --git a/src/utility.rs b/src/utility.rs index f302ead..4987bf4 100644 --- a/src/utility.rs +++ b/src/utility.rs @@ -165,6 +165,7 @@ impl crate::detail::property:: #[derive( derive_more::From, midi2_proc::Data, + midi2_proc::Packets, midi2_proc::RebufferFrom, midi2_proc::TryRebufferFrom, Clone, @@ -230,4 +231,15 @@ mod tests { )) ); } + + #[test] + fn packets() { + use crate::Packets; + + let message = Utility::try_from(&[0x0010_1234][..]).unwrap(); + + let mut packets = message.packets(); + assert_eq!(packets.next(), Some(&[0x0010_1234][..])); + assert_eq!(packets.next(), None); + } } From 8631397fb96f800a1e738242c8ec2507389e07c8 Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Tue, 14 May 2024 16:46:52 +0200 Subject: [PATCH 12/25] docs: adds docs for new packets trait --- src/packets.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/packets.rs b/src/packets.rs index b1957d2..195748c 100644 --- a/src/packets.rs +++ b/src/packets.rs @@ -28,6 +28,41 @@ impl<'a> core::iter::ExactSizeIterator for PacketsIterator<'a> { } } +/// Read the individual packets of a message represented with UMP packets. +/// +/// ## Basic Usage +/// +/// ```rust +/// use midi2::prelude::*; +/// +/// let mut message = flex_data::ProjectName::>::new(); +/// message.set_text("Shadows of the Forgotten Cathedral"); +/// +/// let mut packets = message.packets(); +/// +/// assert_eq!(packets.next(), Some(&[0xD0500101, 0x53686164, 0x6F777320, 0x6F662074][..])); +/// assert_eq!(packets.next(), Some(&[0xD0900101, 0x68652046, 0x6F72676F, 0x7474656E][..])); +/// assert_eq!(packets.next(), Some(&[0xD0D00101, 0x20436174, 0x68656472, 0x616C0000][..])); +/// assert_eq!(packets.next(), None); +/// ``` +/// +/// Packets may be shorter than 128 bytes for certain messages which are represented by shorter +/// packets. +/// +/// ```rust +/// use midi2::prelude::*; +/// +/// let mut message = sysex7::Sysex7::>::new(); +/// message.set_payload((0..20).map(u7::new)); +/// +/// let mut packets = message.packets(); +/// +/// assert_eq!(packets.next(), Some(&[0x30160001, 0x2030405][..])); +/// assert_eq!(packets.next(), Some(&[0x30260607, 0x8090A0B][..])); +/// assert_eq!(packets.next(), Some(&[0x30260C0D, 0xE0F1011][..])); +/// assert_eq!(packets.next(), Some(&[0x30321213, 0x0][..])); +/// assert_eq!(packets.next(), None); +/// ``` pub trait Packets { fn packets(&self) -> PacketsIterator; } From f996b0fb751a653164558c8200ea9da8d62aa4f0 Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Tue, 14 May 2024 22:20:42 +0200 Subject: [PATCH 13/25] docs: indicate which functions require std feature enabled --- Cargo.toml | 1 + README.md | 4 ++-- midi2_proc/src/generate_message.rs | 1 + src/lib.rs | 1 + src/sysex7/README.md | 2 +- 5 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 54eed3f..a9ea69f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,3 +43,4 @@ pretty_assertions = "1.4.0" [package.metadata.docs.rs] all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/README.md b/README.md index c88e73f..6d20ec3 100644 --- a/README.md +++ b/README.md @@ -181,7 +181,7 @@ assert_eq!(message.try_set_payload(0..60), Err(midi2::error::BufferOverflow)); A more advanced use case might be to make a custom buffer which uses an arena allocater to back your messages. -See the [buffer](crate::buffer) docs for more info. +See the [buffer] docs for more info. ### Borrowed Messages @@ -270,7 +270,7 @@ its functionality according to your needs. Here's a list of available features: - `default`: - - **std** - Include [buffer](crate::buffer) integration for `std::vec::Vec` and enable allocating getters for values which return `std::string::String` values. + - **std** - Include [buffer] integration for `std::vec::Vec` and enable allocating getters for values which return `std::string::String` values. - **channel-voice2** — Include message wrappers for the MIDI 2.0 channel voice message type. - **sysex7** — Include message wrappers for the MIDI 7bit system exclusive message type. - **ci** — 🚧 WIP 🚧 diff --git a/midi2_proc/src/generate_message.rs b/midi2_proc/src/generate_message.rs index efcd243..ed8b7b1 100644 --- a/midi2_proc/src/generate_message.rs +++ b/midi2_proc/src/generate_message.rs @@ -319,6 +319,7 @@ fn std_only_attribute(property: &Property) -> TokenStream { if property.std { quote! { #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] } } else { TokenStream::new() diff --git a/src/lib.rs b/src/lib.rs index 04e7d68..59feb3b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![cfg_attr(docsrs, feature(doc_cfg))] #![doc = include_str!("../README.md")] #[cfg(any(feature = "std", test))] diff --git a/src/sysex7/README.md b/src/sysex7/README.md index 1e91725..beac32d 100644 --- a/src/sysex7/README.md +++ b/src/sysex7/README.md @@ -50,7 +50,7 @@ assert_eq!( ## Borrowed workflow -You can create a [Sysex7](crate::sysex7::Sysex7) from +You can create a [Sysex7] from borrowed data and avoid copying or allocating if you have the data already existing in a buffer. From 2b60154e1f551e719b71f9f3a57cb06c742f17c9 Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Tue, 14 May 2024 22:25:51 +0200 Subject: [PATCH 14/25] refactor!: rename DeltaClockstampTPQ -> DeltaClockstampTpq --- src/message.rs | 4 ++-- src/utility.rs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/message.rs b/src/message.rs index 26fbd15..e7dc0c8 100644 --- a/src/message.rs +++ b/src/message.rs @@ -357,9 +357,9 @@ mod tests { #[cfg(feature = "utility")] #[test] fn from_level2_utility() { - use crate::utility::DeltaClockstampTPQ; + use crate::utility::DeltaClockstampTpq; - let level2_message = DeltaClockstampTPQ::<[u32; 4]>::new(); + let level2_message = DeltaClockstampTpq::<[u32; 4]>::new(); let _: UmpMessage<[u32; 4]> = level2_message.into(); } diff --git a/src/utility.rs b/src/utility.rs index 4987bf4..91d400c 100644 --- a/src/utility.rs +++ b/src/utility.rs @@ -113,7 +113,7 @@ mod delta_clockstamp_tpq { use crate::utility; pub const STATUS: u8 = 0b0011; #[midi2_proc::generate_message(Via(crate::utility::Utility), FixedSize, MinSizeUmp(1))] - struct DeltaClockstampTPQ { + struct DeltaClockstampTpq { #[property(common_properties::UmpMessageTypeProperty<{utility::UMP_MESSAGE_TYPE}>)] ump_type: (), #[property(common_properties::ChannelVoiceStatusProperty)] @@ -127,7 +127,7 @@ 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 delta_clockstamp_tpq::DeltaClockstampTpq; pub use no_op::NoOp; pub use timestamp::Timestamp; @@ -179,7 +179,7 @@ pub enum Utility { Clock(clock::Clock), Timestamp(timestamp::Timestamp), DeltaClockstamp(delta_clockstamp::DeltaClockstamp), - DeltaClockstampTpq(delta_clockstamp_tpq::DeltaClockstampTPQ), + DeltaClockstampTpq(delta_clockstamp_tpq::DeltaClockstampTpq), } impl<'a> core::convert::TryFrom<&'a [u32]> for Utility<&'a [u32]> { @@ -194,7 +194,7 @@ impl<'a> core::convert::TryFrom<&'a [u32]> for Utility<&'a [u32]> { 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() + delta_clockstamp_tpq::DeltaClockstampTpq::try_from(buffer)?.into() } _ => Err(crate::error::Error::InvalidData( "Unknown utility message status", From c70d85946ea7c4143149ec2fd3289a2fd372f1e0 Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Tue, 14 May 2024 23:15:56 +0200 Subject: [PATCH 15/25] docs: add documentation to some central traits --- src/traits.rs | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/src/traits.rs b/src/traits.rs index 2f435a8..4804751 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1,9 +1,42 @@ use crate::buffer::{Buffer, BufferMut, Ump}; +/// View the wrapped data of the MIDI message as a slice of units. +/// +/// A slice of [u32] for [Ump] backed messages. +/// +/// ```rust +/// use midi2::{Data, channel_voice1::NoteOn}; +/// +/// let message = NoteOn::<[u32; 4]>::new(); +/// +/// assert_eq!(message.data(), &[0x2090_0000]); +/// ``` +/// +/// A slice of [u8] for [Bytes](crate::buffer::Bytes) backed messages. +/// +/// ```rust +/// use midi2::{Data, channel_voice1::NoteOn}; +/// +/// let message = NoteOn::<[u8; 3]>::new(); +/// +/// assert_eq!(message.data(), &[0x90, 0x00, 0x00]); +/// ``` pub trait Data { fn data(&self) -> &[B::Unit]; } +/// Read and mutate the MIDI 2.0 group field of a wrapped MIDI message. +/// +/// ```rust +/// use midi2::{ux::u4, Grouped, Data, channel_voice2::NoteOn}; +/// +/// let mut message = NoteOn::<[u32; 4]>::new(); +/// +/// message.set_group(u4::new(0xA)); +/// +/// assert_eq!(message.group(), u4::new(0xA)); +/// assert_eq!(message.data(), &[0x4A90_0000, 0x0000_0000]); +/// ``` pub trait Grouped { fn group(&self) -> crate::ux::u4; fn set_group(&mut self, group: crate::ux::u4) @@ -11,6 +44,18 @@ pub trait Grouped { B: BufferMut; } +/// Read and mutate the channel field of a wrapped MIDI message. +/// +/// ```rust +/// use midi2::{ux::u4, Channeled, Data, channel_voice2::NoteOn}; +/// +/// let mut message = NoteOn::<[u32; 4]>::new(); +/// +/// message.set_channel(u4::new(0x5)); +/// +/// assert_eq!(message.channel(), u4::new(0x5)); +/// assert_eq!(message.data(), &[0x4095_0000, 0x0000_0000]); +/// ``` pub trait Channeled { fn channel(&self) -> crate::ux::u4; fn set_channel(&mut self, channel: crate::ux::u4) @@ -18,10 +63,33 @@ pub trait Channeled { B: BufferMut; } +/// Convert a generic message from one [buffer](crate::buffer) specialisation to another. +/// +/// ```rust +/// use midi2::{RebufferFrom, Data, channel_voice1::NoteOn}; +/// +/// let borrowed: NoteOn<&[u32]> = NoteOn::try_from(&[0x2D9E_753D_u32][..]).expect("Valid data"); +/// let owned = NoteOn::<[u32; 4]>::rebuffer_from(borrowed); +/// +/// assert_eq!(owned.data(), &[0x2D9E_753D]); +/// ``` pub trait RebufferFrom: Sized { fn rebuffer_from(value: T) -> Self; } +/// Convert a generic message into a different [buffer](crate::buffer) specialisation. +/// +/// ```rust +/// use midi2::{RebufferInto, Data, channel_voice1::NoteOn}; +/// +/// let borrowed: NoteOn<&[u32]> = NoteOn::try_from(&[0x2D9E_753D_u32][..]).expect("Valid data"); +/// let owned: NoteOn<[u32; 4]> = borrowed.rebuffer_into(); +/// +/// assert_eq!(owned.data(), &[0x2D9E_753D]); +/// ``` +/// +/// Note that this trait has a blanket implementation for all messages which implement +/// [RebufferFrom] (similar to the standard [core::convert::Into] trait) pub trait RebufferInto: Sized { fn rebuffer_into(self) -> T; } @@ -35,10 +103,55 @@ where } } +/// Attempt to convert a generic message from one [buffer](crate::buffer) specialisation to another. +/// +/// The conversion may fail with a [BufferOverflow](crate::error::BufferOverflow) error if the +/// target message representation does not fit all of the message data. +/// +/// ```rust +/// use midi2::{TryRebufferFrom, sysex7::Sysex7}; +/// +/// let borrowed: Sysex7<&[u32]> = Sysex7::try_from(&[ +/// 0x3016_0001, +/// 0x0203_0405, +/// 0x3035_0607, +/// 0x0809_0A00, +/// ][..]).expect("Valid data"); +/// +/// assert!(Sysex7::<[u32; 4]>::try_rebuffer_from(borrowed.clone()).is_ok()); +/// assert!(Sysex7::<[u32; 2]>::try_rebuffer_from(borrowed.clone()).is_err()); +/// ``` pub trait TryRebufferFrom: Sized { fn try_rebuffer_from(value: T) -> core::result::Result; } +/// Attempt to convert a generic message into a different [buffer](crate::buffer) specialisation. +/// +/// The conversion may fail with a [BufferOverflow](crate::error::BufferOverflow) error if the +/// target message representation does not fit all of the message data. +/// +/// ```rust +/// use midi2::{TryRebufferInto, sysex7::Sysex7, error::BufferOverflow}; +/// +/// let borrowed: Sysex7<&[u32]> = Sysex7::try_from(&[ +/// 0x3016_0001, +/// 0x0203_0405, +/// 0x3035_0607, +/// 0x0809_0A00, +/// ][..]).expect("Valid data"); +/// +/// let arr4: Result, BufferOverflow> = borrowed +/// .clone() +/// .try_rebuffer_into(); +/// arr4.expect("Buffer is large enough"); +/// +/// let arr2: Result, BufferOverflow> = borrowed +/// .clone() +/// .try_rebuffer_into(); +/// arr2.expect_err("Buffer is too small"); +/// ``` +/// Note that this trait has a blanket implementation for all messages which implement +/// [TryRebufferFrom] (similar to the standard [core::convert::TryInto] trait) pub trait TryRebufferInto: Sized { fn try_rebuffer_into(self) -> core::result::Result; } From 4aa4d85088ccd95d6d89a5297da14cd69755c1d1 Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Wed, 15 May 2024 07:13:39 +0200 Subject: [PATCH 16/25] docs: further documentation for midi2 core traits --- src/channel_voice1/note_on.rs | 11 ++ src/traits.rs | 247 +++++++++++++++++++++++++++++++++- 2 files changed, 256 insertions(+), 2 deletions(-) diff --git a/src/channel_voice1/note_on.rs b/src/channel_voice1/note_on.rs index 8dfbca1..e7398d0 100644 --- a/src/channel_voice1/note_on.rs +++ b/src/channel_voice1/note_on.rs @@ -53,6 +53,17 @@ mod tests { assert_eq!(message, NoteOn([0x2D9E_753D, 0x0, 0x0, 0x0])); } + #[test] + fn setters_bytes() { + let mut message = NoteOn::<[u8; 3]>::new(); + + message.set_channel(u4::new(0xE)); + message.set_note(u7::new(0x75)); + message.set_velocity(u7::new(0x3D)); + + assert_eq!(message, NoteOn([0x9E, 0x75, 0x3D])); + } + #[test] fn group() { assert_eq!( diff --git a/src/traits.rs b/src/traits.rs index 4804751..781e68b 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -25,7 +25,7 @@ pub trait Data { fn data(&self) -> &[B::Unit]; } -/// Read and mutate the MIDI 2.0 group field of a wrapped MIDI message. +/// Read and write the MIDI 2.0 group field of a wrapped MIDI message. /// /// ```rust /// use midi2::{ux::u4, Grouped, Data, channel_voice2::NoteOn}; @@ -44,7 +44,7 @@ pub trait Grouped { B: BufferMut; } -/// Read and mutate the channel field of a wrapped MIDI message. +/// Read and write the channel field of a wrapped MIDI message. /// /// ```rust /// use midi2::{ux::u4, Channeled, Data, channel_voice2::NoteOn}; @@ -165,10 +165,35 @@ where } } +/// Convert a message from a [Bytes](crate::buffer::Bytes) backing buffer +/// to a [Ump] backing buffer. +/// +/// ```rust +/// use midi2::{FromBytes, Data, channel_voice1::NoteOn}; +/// +/// let bytes_message = NoteOn::try_from(&[0x9E_u8, 0x75, 0x3D][..]).expect("Valid data"); +/// let ump_message = NoteOn::<[u32; 4]>::from_bytes(bytes_message); +/// +/// assert_eq!(ump_message.data(), &[0x209E_753D]); +/// ``` pub trait FromBytes: Sized { fn from_bytes(other: T) -> Self; } +/// Convert a [Bytes](crate::buffer::Bytes) backed message into a [Ump] backed message. +/// +/// ```rust +/// use midi2::{IntoUmp, Data, channel_voice1::NoteOn}; +/// +/// let bytes_message = NoteOn::try_from(&[0x9E_u8, 0x75, 0x3D][..]).expect("Valid data"); +/// let ump_message: NoteOn<[u32; 4]> = bytes_message.into_ump(); +/// +/// assert_eq!(ump_message.data(), &[0x209E_753D]); +/// ``` +/// +/// Note that this is the reciprocal trait to [FromBytes]. +/// Any implementor of [FromBytes] automatically implements [IntoUmp], +/// similar to the [core::convert::Into] trait. pub trait IntoUmp { fn into_ump(self) -> T; } @@ -182,10 +207,42 @@ where } } +/// Convert a message from a [Ump] backing buffer +/// to a [Bytes](crate::buffer::Bytes) backing buffer. +/// +/// Note that in most cases this is a "lossy" conversion. Some +/// fields in a [Ump] message are not represented in a [Bytes](crate::buffer::Bytes) +/// message like `group`, for example. +/// +/// ```rust +/// use midi2::{FromUmp, Data, channel_voice1::NoteOn}; +/// +/// let ump_message = NoteOn::try_from(&[0x279E_753D_u32][..]).expect("Valid data"); +/// let bytes_message = NoteOn::<[u8; 3]>::from_ump(ump_message); +/// +/// assert_eq!(bytes_message.data(), &[0x9E, 0x75, 0x3D]); +/// ``` pub trait FromUmp: Sized { fn from_ump(other: T) -> Self; } +/// Convert a [Ump] backed message into a [Bytes](crate::buffer::Bytes) backed message. +/// +/// Note that in most cases this is a "lossy" conversion. Some +/// fields in a [Ump] message are not represented in a [Bytes](crate::buffer::Bytes) +/// message like `group`, for example. +/// +/// ```rust +/// use midi2::{IntoBytes, Data, channel_voice1::NoteOn}; +/// +/// let ump_message = NoteOn::try_from(&[0x279E_753D_u32][..]).expect("Valid data"); +/// let bytes_message: NoteOn<[u8; 3]> = ump_message.into_bytes(); +/// +/// assert_eq!(bytes_message.data(), &[0x9E, 0x75, 0x3D]); +/// ``` +/// This is the reciprocal trait to [FromUmp]. +/// Any implementor of [FromUmp] automatically implements [IntoBytes], +/// similar to the [core::convert::Into] trait. pub trait IntoBytes { fn into_bytes(self) -> T; } @@ -199,10 +256,67 @@ where } } +/// Attempt to convert a message from a [Bytes](crate::buffer::Bytes) backing buffer +/// to a [Ump] backing buffer. +/// +/// The conversion may fail with a [BufferOverflow](crate::error::BufferOverflow) error +/// if the target buffer is not large enough to contain the data. +/// +/// ```rust +/// use midi2::{TryFromBytes, Data, sysex7::Sysex7}; +/// +/// let bytes_message = Sysex7::try_from(&[ +/// 0xF0_u8, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xF7, +/// ][..]).expect("Valid data"); +/// +/// let ump_message = Sysex7::<[u32; 4]>::try_from_bytes(bytes_message.clone()); +/// +/// assert_eq!(ump_message.expect("Buffer is large enough").data(), &[ +/// 0x3016_0001, +/// 0x0203_0405, +/// 0x3034_0607, +/// 0x0809_0000, +/// ]); +/// +/// let small_ump_message = Sysex7::<[u32; 2]>::try_from_bytes(bytes_message.clone()); +/// small_ump_message.expect_err("Buffer is too small"); +/// ``` pub trait TryFromBytes: Sized { fn try_from_bytes(other: T) -> Result; } +/// Attempt to convert a [Bytes](crate::buffer::Bytes) backed message into a [Ump] backed message. +/// +/// The conversion may fail with a [BufferOverflow](crate::error::BufferOverflow) error +/// if the target buffer is not large enough to contain the data. +/// +/// ```rust +/// use midi2::{TryIntoUmp, Data, sysex7::Sysex7, error::BufferOverflow}; +/// +/// let bytes_message = Sysex7::try_from(&[ +/// 0xF0_u8, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xF7, +/// ][..]).expect("Valid data"); +/// +/// let ump_message: Result, BufferOverflow> = bytes_message +/// .clone() +/// .try_into_ump(); +/// +/// assert_eq!(ump_message.expect("Buffer is large enough").data(), &[ +/// 0x3016_0001, +/// 0x0203_0405, +/// 0x3034_0607, +/// 0x0809_0000, +/// ]); +/// +/// let small_ump_message: Result, BufferOverflow> = bytes_message +/// .clone() +/// .try_into_ump(); +/// small_ump_message.expect_err("Buffer is too small"); +/// ``` +/// +/// Note that this is the reciprocal trait to [TryFromBytes]. +/// Any implementor of [TryFromBytes] automatically implements [IntoUmp], +/// similar to the [core::convert::TryInto] trait. pub trait TryIntoUmp { fn try_into_ump(self) -> Result; } @@ -216,10 +330,75 @@ where } } +/// Attempt to convert a message from a [Ump] backing buffer +/// to a [Bytes](crate::buffer::Bytes) backing buffer. +/// +/// The conversion may fail with a [BufferOverflow](crate::error::BufferOverflow) error +/// if the target buffer is not large enough to contain the data. +/// +/// Note that in most cases this is a "lossy" conversion. Some +/// fields in a [Ump] message are not represented in a [Bytes](crate::buffer::Bytes) +/// message like `group`, for example. +/// +/// ```rust +/// use midi2::{TryFromUmp, Data, sysex7::Sysex7}; +/// +/// let ump_message = Sysex7::try_from(&[ +/// 0x3016_0001_u32, +/// 0x0203_0405, +/// 0x3034_0607, +/// 0x0809_0000, +/// ][..]).expect("Valid data"); +/// +/// let bytes_message = Sysex7::<[u8; 12]>::try_from_ump(ump_message.clone()); +/// +/// assert_eq!(bytes_message.expect("Buffer is large enough").data(), &[ +/// 0xF0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xF7, +/// ]); +/// +/// let small_bytes_message = Sysex7::<[u8; 10]>::try_from_ump(ump_message.clone()); +/// small_bytes_message.expect_err("Buffer is too small"); +/// ``` pub trait TryFromUmp: Sized { fn try_from_ump(other: T) -> Result; } +/// Attempt to convert a [Ump] backed message into a [Bytes](crate::buffer::Bytes) backed message. +/// +/// The conversion may fail with a [BufferOverflow](crate::error::BufferOverflow) error +/// if the target buffer is not large enough to contain the data. +/// +/// Note that in most cases this is a "lossy" conversion. Some +/// fields in a [Ump] message are not represented in a [Bytes](crate::buffer::Bytes) +/// message like `group`, for example. +/// +/// ```rust +/// use midi2::{TryIntoBytes, Data, sysex7::Sysex7, error::BufferOverflow}; +/// +/// let ump_message = Sysex7::try_from(&[ +/// 0x3016_0001_u32, +/// 0x0203_0405, +/// 0x3034_0607, +/// 0x0809_0000, +/// ][..]).expect("Valid data"); +/// +/// let bytes_message: Result, BufferOverflow> = ump_message +/// .clone() +/// .try_into_bytes(); +/// +/// assert_eq!(bytes_message.expect("Buffer is large enough").data(), &[ +/// 0xF0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xF7, +/// ]); +/// +/// let small_bytes_message: Result, BufferOverflow> = ump_message +/// .try_into_bytes() +/// .clone(); +/// small_bytes_message.expect_err("Buffer is too small"); +/// ``` +/// +/// This is the reciprocal trait to [TryFromUmp]. +/// Any implementor of [TryFromUmp] automatically implements [TryIntoBytes], +/// similar to the [core::convert::TryInto] trait. pub trait TryIntoBytes { fn try_into_bytes(self) -> Result; } @@ -233,6 +412,70 @@ where } } +/// Read and write the payload data on a MIDI sysex message. +/// +/// Payload data can be read as an iterator over the [Sysex::Byte] type. +/// +/// ```rust +/// use midi2::{sysex8::Sysex8, Sysex}; +/// +/// let message = Sysex8::try_from(&[ +/// 0x501E_0000, +/// 0x0102_0304, +/// 0x0506_0708, +/// 0x090A_0B0C, +/// 0x5038_000D, +/// 0x0E0F_1011, +/// 0x1213_0000, +/// 0x0000_0000, +/// ][..]).expect("Valid data"); +/// +/// assert_eq!(message.payload().collect::>(), (0..20).collect::>()); +/// ``` +/// +/// When the backing buffer implements [BufferResize](crate::buffer::BufferResize) +/// payload data can be set using [set_payload](Sysex::set_payload). +/// +/// ```rust +/// use midi2::{sysex8::Sysex8, Sysex, Data}; +/// +/// let mut message = Sysex8::>::new(); +/// message.set_payload(0..20); +/// +/// assert_eq!(message.data(), &[ +/// 0x501E_0000, +/// 0x0102_0304, +/// 0x0506_0708, +/// 0x090A_0B0C, +/// 0x5038_000D, +/// 0x0E0F_1011, +/// 0x1213_0000, +/// 0x0000_0000, +/// ]); +/// ``` +/// +/// When the backing buffer implements [BufferTryResize](crate::buffer::BufferTryResize) +/// payload data can be set using [try_set_payload](Sysex::try_set_payload). +/// +/// ```rust +/// use midi2::{sysex8::Sysex8, Sysex, Data}; +/// +/// let mut message = Sysex8::<[u32; 8]>::new(); +/// +/// assert!(message.try_set_payload(0..20).is_ok()); +/// assert_eq!(message.data(), &[ +/// 0x501E_0000, +/// 0x0102_0304, +/// 0x0506_0708, +/// 0x090A_0B0C, +/// 0x5038_000D, +/// 0x0E0F_1011, +/// 0x1213_0000, +/// 0x0000_0000, +/// ]); +/// +/// assert!(message.try_set_payload(0..30).is_err()); +/// ``` pub trait Sysex { type Byte; type PayloadIterator<'a>: core::iter::Iterator From 92696d7ac80a613ded754fc248cfc2918b667f72 Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Wed, 15 May 2024 09:52:27 +0200 Subject: [PATCH 17/25] fix: flex data text bytes iterator is public --- src/flex_data.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/flex_data.rs b/src/flex_data.rs index c532686..899e6bc 100644 --- a/src/flex_data.rs +++ b/src/flex_data.rs @@ -736,6 +736,7 @@ pub use set_key_signature::{SetKeySignature, SharpsFlats as SetKeySignatureSharp pub use set_metronome::*; pub use set_tempo::*; pub use set_time_signature::*; +pub use text::TextBytesIterator; pub use tonic::Tonic; pub use unknown_metadata_text::*; pub use unknown_performance_text::*; From b7923e7264ecefc06af44ef17d70e9720df85933 Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Wed, 15 May 2024 13:52:47 +0200 Subject: [PATCH 18/25] docs: documentation for buffer traits --- src/buffer.rs | 68 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/src/buffer.rs b/src/buffer.rs index e1c8520..a77da2b 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -2,6 +2,43 @@ //! //! All messages in midi2 are backed by a generic buffer type. //! +//! ```rust +//! use midi2::prelude::*; +//! +//! let buffer = [ +//! 0x3E16_0001, +//! 0x0203_0405, +//! 0x3E26_0607, +//! 0x0809_0A0B, +//! 0x3E26_0C0D, +//! 0x0E0F_1011, +//! 0x3E26_1213, +//! 0x1415_1617, +//! 0x3E26_1819, +//! 0x1A1B_1C1D, +//! 0x3E26_1E1F, +//! 0x2021_2223, +//! 0x3E26_2425, +//! 0x2627_2829, +//! 0x3E26_2A2B, +//! 0x2C2D_2E2F, +//! 0x3E32_3031, +//! 0x0000_0000, +//! ]; +//! +//! // A message can be backed with a borrowed slice of data. +//! let message: UmpMessage<&[u32]> = UmpMessage::try_from(&buffer[..]).expect("Valid data"); +//! +//! // Or a vector +//! let vector_backed: UmpMessage> = message.rebuffer_into(); +//! +//! // Or a fixed size array +//! let arr_backed: UmpMessage<[u32; 18]> = vector_backed +//! .try_rebuffer_into() +//! .expect("Buffer large enough"); +//! +//! // (Or indeed a custom buffer, if you implement the right traits!) +//! ``` //! A buffer can be any data type which returns a slice of `u32` or `u8`. //! //! The buffer traits are already implemented for some typical standard rust types: @@ -62,6 +99,14 @@ use crate::error::BufferOverflow; +/// The generic unit type contained within [Buffer] slices. +/// +/// This is a sealed trait. +/// It's only implemented for [u8] and [u32]. +/// +/// A [Buffer] with `U = u8` is a [Bytes] buffer. +/// +/// A [Buffer] with `U = u32` is a [Ump] buffer. #[allow(private_bounds)] pub trait Unit: Copy + UnitPrivate { fn zero() -> Self; @@ -79,40 +124,57 @@ impl Unit for u32 { } } +/// Generic data representation for MIDI message wrapper types. +/// +/// For more info see the [buffer module docs](crate::buffer). pub trait Buffer { type Unit: Unit; fn buffer(&self) -> &[Self::Unit]; } +/// Buffer types which own mutable data. pub trait BufferMut: Buffer { fn buffer_mut(&mut self) -> &mut [::Unit]; } +/// Buffer types which are default constructible. +/// +/// For more info see the [buffer module docs](crate::buffer). // N.B. This is needed because core::default::Default // is not implemented for arrays which are generic over size pub trait BufferDefault { fn default() -> Self; } +/// Buffer types which can support arbitrary resizing. +/// +/// For more info see the [buffer module docs](crate::buffer). pub trait BufferResize { fn resize(&mut self, size: usize); } -/// This trait can be implemented by buffers with -/// fallible memory allocation. +/// Buffer types which can resize, but with a chance of failure. /// -/// It can also be implemented by buffers of a fixed size. +/// Note: This trait is also implemented by buffers of a fixed size. /// In this case `try_resize` should return Ok whenever /// the requested size is less than or equal to the fixed /// size of the buffer and an Err otherwise. +/// +/// For more info see the [buffer module docs](crate::buffer). pub trait BufferTryResize { fn try_resize(&mut self, size: usize) -> Result<(), BufferOverflow>; } +/// Buffers with `Self::Unit = u32`. +/// +/// For more info see the [buffer module docs](crate::buffer). pub trait Ump: Buffer {} impl> Ump for B {} +/// Buffers with `Self::Unit = u8`. +/// +/// For more info see the [buffer module docs](crate::buffer). pub trait Bytes: Buffer {} impl> Bytes for B {} From b14a3683adc2a966381982fc0914492ad32e6a6b Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Wed, 15 May 2024 17:00:58 +0200 Subject: [PATCH 19/25] refactor!: remove aggregate error type and result In practice only one of the two errors are ever returned in any given context, so aggregating them was misleading. --- midi2_proc/src/generate_message.rs | 4 +-- src/channel_voice1.rs | 6 ++-- src/channel_voice1/channel_pressure.rs | 2 +- src/channel_voice2.rs | 6 ++-- src/channel_voice2/attribute.rs | 17 +++++------ src/channel_voice2/controller.rs | 11 +++---- src/channel_voice2/program_change.rs | 4 +-- src/detail/common_properties.rs | 26 ++++++++-------- src/detail/helpers.rs | 18 +++++------ src/detail/property.rs | 4 +-- src/error.rs | 30 +----------------- src/flex_data.rs | 42 +++++++++++++------------- src/flex_data/set_chord_name.rs | 36 +++++++++++----------- src/flex_data/set_key_signature.rs | 4 +-- src/flex_data/text.rs | 8 ++--- src/flex_data/tonic.rs | 14 ++++----- src/flex_data/unknown_metadata_text.rs | 14 ++++----- src/lib.rs | 1 - src/message.rs | 14 ++++----- src/result.rs | 2 -- src/sysex7.rs | 42 +++++++++++++------------- src/sysex8.rs | 32 ++++++++++---------- src/system_common.rs | 12 ++++---- src/ump_stream.rs | 24 +++++++-------- src/ump_stream/function_block_info.rs | 16 +++++----- src/ump_stream/function_block_name.rs | 12 ++++---- src/utility.rs | 12 +++----- 27 files changed, 185 insertions(+), 228 deletions(-) delete mode 100644 src/result.rs diff --git a/midi2_proc/src/generate_message.rs b/midi2_proc/src/generate_message.rs index ed8b7b1..bed86cb 100644 --- a/midi2_proc/src/generate_message.rs +++ b/midi2_proc/src/generate_message.rs @@ -425,10 +425,10 @@ fn try_from_slice_impl( } quote! { impl<'a, #generic_unit> core::convert::TryFrom<&'a [#unit_type]> for #root_ident<&'a [#unit_type]> { - type Error = crate::error::Error; + type Error = crate::error::InvalidData; fn try_from(buffer: &'a [#unit_type]) -> core::result::Result { if buffer.len() < >::MIN_SIZE { - return Err(crate::error::Error::InvalidData("Slice is too short")); + return Err(crate::error::InvalidData("Slice is too short")); } #validation_steps Ok(#root_ident(buffer)) diff --git a/src/channel_voice1.rs b/src/channel_voice1.rs index 7096746..a51e784 100644 --- a/src/channel_voice1.rs +++ b/src/channel_voice1.rs @@ -46,10 +46,10 @@ pub enum ChannelVoice1 { } impl<'a, U: crate::buffer::Unit> core::convert::TryFrom<&'a [U]> for ChannelVoice1<&'a [U]> { - type Error = crate::error::Error; + type Error = crate::error::InvalidData; fn try_from(buffer: &'a [U]) -> Result { if buffer.len() < 1 { - return Err(crate::error::Error::InvalidData("Slice is too short")); + return Err(crate::error::InvalidData("Slice is too short")); }; Ok(match status(buffer) { channel_pressure::STATUS => ChannelPressure::try_from(buffer)?.into(), @@ -59,7 +59,7 @@ impl<'a, U: crate::buffer::Unit> core::convert::TryFrom<&'a [U]> for ChannelVoic note_on::STATUS => NoteOn::try_from(buffer)?.into(), pitch_bend::STATUS => PitchBend::try_from(buffer)?.into(), program_change::STATUS => ProgramChange::try_from(buffer)?.into(), - _ => Err(crate::error::Error::InvalidData( + _ => Err(crate::error::InvalidData( "Unknown midi1 channel voice status", ))?, }) diff --git a/src/channel_voice1/channel_pressure.rs b/src/channel_voice1/channel_pressure.rs index f0bb612..6e6b0a6 100644 --- a/src/channel_voice1/channel_pressure.rs +++ b/src/channel_voice1/channel_pressure.rs @@ -94,7 +94,7 @@ mod tests { fn from_empty_data() { assert_eq!( ChannelPressure::try_from(&<[u32; 0] as Default>::default()[..]), - Err(crate::error::Error::InvalidData("Slice is too short")), + Err(crate::error::InvalidData("Slice is too short")), ); } diff --git a/src/channel_voice2.rs b/src/channel_voice2.rs index e36a23a..85a218d 100644 --- a/src/channel_voice2.rs +++ b/src/channel_voice2.rs @@ -68,10 +68,10 @@ pub enum ChannelVoice2 { } impl<'a> TryFrom<&'a [u32]> for ChannelVoice2<&'a [u32]> { - type Error = crate::error::Error; + type Error = crate::error::InvalidData; fn try_from(buffer: &'a [u32]) -> Result { if buffer.len() < 1 { - return Err(crate::error::Error::InvalidData("Slice is too short")); + return Err(crate::error::InvalidData("Slice is too short")); }; use crate::detail::BitOps; @@ -114,7 +114,7 @@ impl<'a> TryFrom<&'a [u32]> for ChannelVoice2<&'a [u32]> { relative_registered_controller::RelativeRegisteredController::try_from(buffer)? .into() } - _ => Err(crate::error::Error::InvalidData( + _ => Err(crate::error::InvalidData( "Unknown midi2 channel voice status", ))?, }) diff --git a/src/channel_voice2/attribute.rs b/src/channel_voice2/attribute.rs index a37a10c..c88c635 100644 --- a/src/channel_voice2/attribute.rs +++ b/src/channel_voice2/attribute.rs @@ -1,7 +1,4 @@ -use crate::{ - detail::{property, BitOps, Truncate}, - result::Result, -}; +use crate::detail::{property, BitOps, Truncate}; use ux::{u7, u9}; #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -14,13 +11,13 @@ pub enum Attribute { const ERR_INVALID_NOTE_ATTRIBUTE: &str = "Couldn't interpret note attribute"; -pub fn validate_ump(bytes: &[u32]) -> Result<()> { +pub fn validate_ump(bytes: &[u32]) -> Result<(), crate::error::InvalidData> { match bytes[0].octet(3) { 0x0 => Ok(()), 0x1 => Ok(()), 0x2 => Ok(()), 0x3 => Ok(()), - _ => Err(crate::error::Error::InvalidData(ERR_INVALID_NOTE_ATTRIBUTE)), + _ => Err(crate::error::InvalidData(ERR_INVALID_NOTE_ATTRIBUTE)), } } @@ -71,7 +68,7 @@ impl<'a, B: crate::buffer::Ump> property::ReadProperty<'a, B> for AttributePrope fn read(buffer: &'a B) -> Self::Type { from_ump(buffer.buffer()) } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { validate_ump(buffer.buffer()) } } @@ -79,7 +76,7 @@ impl<'a, B: crate::buffer::Ump> property::ReadProperty<'a, B> for AttributePrope impl property::WriteProperty for AttributeProperty { - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn write(buffer: &mut B, v: Self::Type) { @@ -103,7 +100,7 @@ impl property::WriteProperty crate::result::Result> { + fn try_from_ump(bytes: &[u32]) -> Result, crate::error::InvalidData> { validate_ump(bytes)?; Ok(from_ump(bytes)) } @@ -112,7 +109,7 @@ mod tests { fn from_packet_invalid() { assert_eq!( try_from_ump(&[0x0000_0004]), - Err(crate::error::Error::InvalidData(ERR_INVALID_NOTE_ATTRIBUTE)), + Err(crate::error::InvalidData(ERR_INVALID_NOTE_ATTRIBUTE)), ); } diff --git a/src/channel_voice2/controller.rs b/src/channel_voice2/controller.rs index 71c21f3..94c9530 100644 --- a/src/channel_voice2/controller.rs +++ b/src/channel_voice2/controller.rs @@ -1,7 +1,6 @@ use crate::{ detail::{property, BitOps, Truncate}, - error::Error, - result::Result, + error::InvalidData, }; use ux::{u25, u7}; @@ -31,7 +30,7 @@ pub enum Controller { EffectDepth { index: u8, data: u32 }, } -pub fn validate_index(index: u8) -> Result<()> { +pub fn validate_index(index: u8) -> Result<(), crate::error::InvalidData> { match index { 1 => Ok(()), 2 => Ok(()), @@ -55,7 +54,7 @@ pub fn validate_index(index: u8) -> Result<()> { 93 => Ok(()), 94 => Ok(()), 95 => Ok(()), - _ => Err(Error::InvalidData("Couldn't interpret controller index")), + _ => Err(InvalidData("Couldn't interpret controller index")), } } @@ -138,7 +137,7 @@ impl property::Property for ControllerProperty { } impl<'a, B: crate::buffer::Ump> property::ReadProperty<'a, B> for ControllerProperty { - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { let buffer = buffer.buffer(); validate_index(buffer[0].octet(3)) } @@ -151,7 +150,7 @@ impl<'a, B: crate::buffer::Ump> property::ReadProperty<'a, B> for ControllerProp impl property::WriteProperty for ControllerProperty { - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { diff --git a/src/channel_voice2/program_change.rs b/src/channel_voice2/program_change.rs index b6378d6..9ab3382 100644 --- a/src/channel_voice2/program_change.rs +++ b/src/channel_voice2/program_change.rs @@ -39,13 +39,13 @@ impl<'a, B: crate::buffer::Ump> property::ReadProperty<'a, B> for BankProperty { None } } - fn validate(_buffer: &B) -> crate::result::Result<()> { + fn validate(_buffer: &B) -> Result<(), crate::error::InvalidData> { Ok(()) } } impl property::WriteProperty for BankProperty { - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn write(buffer: &mut B, v: Self::Type) { diff --git a/src/detail/common_properties.rs b/src/detail/common_properties.rs index 80d926f..9643b3a 100644 --- a/src/detail/common_properties.rs +++ b/src/detail/common_properties.rs @@ -19,13 +19,11 @@ impl<'a, const TYPE: u8, B: Buffer> ReadProperty<'a, B> for UmpMessageTypeProper fn read(_buffer: &'a B) -> Self::Type { () } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { if ::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::Error::InvalidData( - "Incorrect ump message type", - )); + return Err(crate::error::InvalidData("Incorrect ump message type")); } } Ok(()) @@ -40,7 +38,7 @@ impl WriteProperty buffer.buffer_mut().specialise_u32_mut()[0].set_nibble(0, crate::ux::u4::new(TYPE)); } } - fn validate(_value: &Self::Type) -> crate::result::Result<()> { + fn validate(_value: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -58,7 +56,7 @@ impl<'a, const STATUS: u8, B: Buffer> ReadProperty<'a, B> for ChannelVoiceStatus fn read(_buffer: &'a B) -> Self::Type { () } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { let status = match ::UNIT_ID { UNIT_ID_U32 => { let b = buffer.buffer().specialise_u32()[0]; @@ -73,7 +71,7 @@ impl<'a, const STATUS: u8, B: Buffer> ReadProperty<'a, B> for ChannelVoiceStatus if status == u4::new(STATUS) { Ok(()) } else { - Err(crate::error::Error::InvalidData("Incorrect message status")) + Err(crate::error::InvalidData("Incorrect message status")) } } } @@ -94,7 +92,7 @@ impl WriteProperty _ => unreachable!(), } } - fn validate(_value: &Self::Type) -> crate::result::Result<()> { + fn validate(_value: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -142,7 +140,7 @@ impl< _ => unreachable!(), } } - fn validate(_buffer: &B) -> crate::result::Result<()> { + fn validate(_buffer: &B) -> Result<(), crate::error::InvalidData> { Ok(()) } } @@ -154,7 +152,7 @@ impl< T: Default + schema::UmpSchemaRepr + schema::BytesSchemaRepr, > WriteProperty for HybridSchemaProperty { - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn write(buffer: &mut B, v: Self::Type) { @@ -202,7 +200,7 @@ impl< _ => unreachable!(), } } - fn validate(_buffer: &B) -> crate::result::Result<()> { + fn validate(_buffer: &B) -> Result<(), crate::error::InvalidData> { Ok(()) } } @@ -221,7 +219,7 @@ impl< ) } } - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -253,7 +251,7 @@ impl< _ => unreachable!(), } } - fn validate(_buffer: &B) -> crate::result::Result<()> { + fn validate(_buffer: &B) -> Result<(), crate::error::InvalidData> { Ok(()) } } @@ -272,7 +270,7 @@ impl< ) } } - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { diff --git a/src/detail/helpers.rs b/src/detail/helpers.rs index 95856ef..0f763a8 100644 --- a/src/detail/helpers.rs +++ b/src/detail/helpers.rs @@ -13,7 +13,7 @@ pub fn sysex_group_consistent_groups( buffer: &[u32], stride: usize, ump_type: crate::ux::u4, -) -> crate::result::Result<()> { +) -> Result<(), crate::error::InvalidData> { use crate::detail::BitOps; use group_from_packet as gfp; if buffer @@ -23,7 +23,7 @@ pub fn sysex_group_consistent_groups( { Ok(()) } else { - Err(crate::error::Error::InvalidData(ERR_INCONSISTENT_GROUPS)) + Err(crate::error::InvalidData(ERR_INCONSISTENT_GROUPS)) } } @@ -53,8 +53,8 @@ pub fn validate_sysex_group_statuses< is_end: IsEnd, stride: usize, ump_type: crate::ux::u4, -) -> crate::result::Result<()> { - use crate::{detail::BitOps, error::Error}; +) -> Result<(), crate::error::InvalidData> { + use crate::{detail::BitOps, error::InvalidData}; let mut iter = buffer .chunks(stride) @@ -62,27 +62,27 @@ pub fn validate_sysex_group_statuses< .peekable(); let Some(first_packet) = iter.next() else { - return Err(Error::InvalidData(ERR_EMPTY_MESSAGE)); + return Err(InvalidData(ERR_EMPTY_MESSAGE)); }; if iter.peek().is_none() { if is_complete(first_packet) { return Ok(()); } else { - return Err(Error::InvalidData(ERR_SYSEX_EXPECTED_COMPLETE)); + return Err(InvalidData(ERR_SYSEX_EXPECTED_COMPLETE)); } } if !is_begin(first_packet) { - return Err(Error::InvalidData(ERR_SYSEX_EXPECTED_BEGIN)); + return Err(InvalidData(ERR_SYSEX_EXPECTED_BEGIN)); } while let Some(chunk) = iter.next() { if iter.peek().is_some() && !is_continue(chunk) { - return Err(Error::InvalidData(ERR_SYSEX_EXPECTED_CONTINUE)); + return Err(InvalidData(ERR_SYSEX_EXPECTED_CONTINUE)); } if iter.peek().is_none() && !is_end(chunk) { - return Err(Error::InvalidData(ERR_SYSEX_EXPECTED_END)); + return Err(InvalidData(ERR_SYSEX_EXPECTED_END)); } } diff --git a/src/detail/property.rs b/src/detail/property.rs index a99807a..990c826 100644 --- a/src/detail/property.rs +++ b/src/detail/property.rs @@ -5,7 +5,7 @@ pub trait Property { pub trait ReadProperty<'a, B: crate::buffer::Buffer>: Property { fn read(buffer: &'a B) -> Self::Type; // validate that the data in the buffer represents a valid instance of the property - fn validate(buffer: &B) -> crate::result::Result<()>; + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData>; } pub trait WriteProperty: Property { @@ -17,7 +17,7 @@ pub trait WriteProperty: Pr // This function is currently unused, but we'll keep it hangingin around // in case we need it sometime down the line. #[allow(dead_code)] - fn validate(v: &Self::Type) -> crate::result::Result<()>; + fn validate(v: &Self::Type) -> Result<(), crate::error::InvalidData>; fn default() -> Self::Type; } diff --git a/src/error.rs b/src/error.rs index 38a1b92..14bbb09 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,25 +2,7 @@ pub struct BufferOverflow; #[derive(Clone, Debug, PartialEq, Eq)] -pub struct InvalidData(&'static str); - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum Error { - BufferOverflow, - InvalidData(&'static str), -} - -impl core::convert::From for Error { - fn from(_: BufferOverflow) -> Self { - Error::BufferOverflow - } -} - -impl core::convert::From for Error { - fn from(value: InvalidData) -> Self { - Error::InvalidData(value.0) - } -} +pub struct InvalidData(pub &'static str); #[cfg(feature = "std")] impl std::error::Error for BufferOverflow {} @@ -41,13 +23,3 @@ impl std::fmt::Display for InvalidData { ::fmt(self, f) } } - -#[cfg(feature = "std")] -impl std::error::Error for Error {} - -#[cfg(feature = "std")] -impl std::fmt::Display for Error { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - ::fmt(self, f) - } -} diff --git a/src/flex_data.rs b/src/flex_data.rs index 899e6bc..4748105 100644 --- a/src/flex_data.rs +++ b/src/flex_data.rs @@ -790,11 +790,11 @@ pub enum FlexData { } impl<'a> TryFrom<&'a [u32]> for FlexData<&'a [u32]> { - type Error = crate::error::Error; + type Error = crate::error::InvalidData; fn try_from(value: &'a [u32]) -> Result { use FlexData::*; if value.len() < 1 { - return Err(crate::error::Error::InvalidData("Slice is too short")); + return Err(crate::error::InvalidData("Slice is too short")); }; Ok(match value[0].word(1) { 0x00_00 => SetTempo(set_tempo::SetTempo::try_from(value)?.into()), @@ -832,7 +832,7 @@ impl<'a> TryFrom<&'a [u32]> for FlexData<&'a [u32]> { 0x02_02 => LyricsLanguage(lyrics_language::LyricsLanguage::try_from(value)?.into()), 0x02_03 => Ruby(ruby::Ruby::try_from(value)?.into()), 0x02_04 => RubyLanguage(ruby_language::RubyLanguage::try_from(value)?.into()), - _ => Err(crate::error::Error::InvalidData( + _ => Err(crate::error::InvalidData( "Couldn't interpret flex data status / bank fields", ))?, }) @@ -873,7 +873,7 @@ impl<'a, const STATUS: u8, B: Ump> ReadProperty<'a, B> for StatusProperty Self::Type { () } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { if buffer .buffer() .chunks_exact(4) @@ -881,7 +881,7 @@ impl<'a, const STATUS: u8, B: Ump> ReadProperty<'a, B> for StatusProperty WriteProperty for StatusProperty crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -908,7 +908,7 @@ impl<'a, const BANK: u8, B: Ump> ReadProperty<'a, B> for BankProperty { fn read(_buffer: &'a B) -> Self::Type { () } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { if buffer .buffer() .chunks_exact(4) @@ -916,7 +916,7 @@ impl<'a, const BANK: u8, B: Ump> ReadProperty<'a, B> for BankProperty { { Ok(()) } else { - Err(crate::error::Error::InvalidData("Incorrect message bank")) + Err(crate::error::InvalidData("Incorrect message bank")) } } } @@ -925,7 +925,7 @@ impl WriteProperty for BankProperty fn write(buffer: &mut B, _v: Self::Type) { buffer.buffer_mut()[0].set_octet(2, BANK); } - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -943,11 +943,11 @@ impl<'a, const FORMAT: u8, B: Ump> ReadProperty<'a, B> for FormatProperty Self::Type { () } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { if FORMAT == buffer.buffer()[0].crumb(4).into() { Ok(()) } else { - Err(crate::error::Error::InvalidData("Incorrect message format")) + Err(crate::error::InvalidData("Incorrect message format")) } } } @@ -956,7 +956,7 @@ impl WriteProperty for FormatProperty crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -974,7 +974,7 @@ impl<'a, B: Ump> ReadProperty<'a, B> for OptionalChannelProperty { fn read(buffer: &'a B) -> Self::Type { optional_channel_from_slice(buffer.buffer()) } - fn validate(_buffer: &B) -> crate::result::Result<()> { + fn validate(_buffer: &B) -> Result<(), crate::error::InvalidData> { Ok(()) } } @@ -985,7 +985,7 @@ impl WriteProperty for OptionalChannelProperty { let data = buffer_slice; optional_channel_to_slice(data, v); } - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -1025,12 +1025,12 @@ impl<'a, B: Ump> ReadProperty<'a, B> for NoChannelProperty { fn read(_buffer: &'a B) -> Self::Type { () } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { use crate::ux::u2; if buffer.buffer()[0].crumb(5) != u2::new(0x0) { Ok(()) } else { - Err(crate::error::Error::InvalidData( + Err(crate::error::InvalidData( "Address field should be non zero.", )) } @@ -1046,7 +1046,7 @@ impl WriteProperty for NoChannelProperty { data[0].set_crumb(5, u2::new(0x1)); data[0].set_nibble(3, u4::new(0x0)); } - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -1065,7 +1065,7 @@ impl<'a, B: Ump> ReadProperty<'a, B> for ConsistentFormatsProperty { () } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { use crate::detail::helpers::validate_sysex_group_statuses; validate_sysex_group_statuses( @@ -1090,7 +1090,7 @@ impl<'a, B: Ump> ReadProperty<'a, B> for GroupProperty { fn read(buffer: &'a B) -> Self::Type { buffer.buffer()[0].nibble(1) } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { use crate::detail::helpers::sysex_group_consistent_groups; sysex_group_consistent_groups(buffer.buffer(), 4, crate::ux::u4::new(UMP_MESSAGE_TYPE)) } @@ -1106,7 +1106,7 @@ impl WriteProperty for GroupProperty { packet[0].set_nibble(1, group); } } - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -1160,7 +1160,7 @@ mod tests { let buffer = []; assert_eq!( FlexData::try_from(&buffer[..]), - Err(crate::error::Error::InvalidData("Slice is too short")), + Err(crate::error::InvalidData("Slice is too short")), ); } diff --git a/src/flex_data/set_chord_name.rs b/src/flex_data/set_chord_name.rs index 5e23ca7..a89cfcc 100644 --- a/src/flex_data/set_chord_name.rs +++ b/src/flex_data/set_chord_name.rs @@ -1,8 +1,6 @@ use crate::{ detail::{common_properties, schema, BitOps}, - error::Error, flex_data::{self, UMP_MESSAGE_TYPE}, - result::Result, ux::u4, }; @@ -73,7 +71,7 @@ impl<'a, B: crate::buffer::Ump> crate::detail::property::ReadProperty<'a, B> fn read(buffer: &'a B) -> Self::Type { SharpsFlats::from_nibble(buffer.buffer()[3].nibble(0)).unwrap() } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { SharpsFlats::from_nibble(buffer.buffer()[3].nibble(0))?; Ok(()) } @@ -85,7 +83,7 @@ impl crate::detail::property:: fn write(buffer: &mut B, v: Self::Type) { buffer.buffer_mut()[3].set_nibble(0, v.into_nibble()); } - fn validate(_: &Self::Type) -> crate::result::Result<()> { + fn validate(_: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -99,7 +97,7 @@ impl<'a, B: crate::buffer::Ump> crate::detail::property::ReadProperty<'a, B> fn read(buffer: &'a B) -> Self::Type { SharpsFlats::from_nibble(buffer.buffer()[1].nibble(0)).unwrap() } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { SharpsFlats::from_nibble(buffer.buffer()[1].nibble(0))?; Ok(()) } @@ -111,7 +109,7 @@ impl crate::detail::property:: fn write(buffer: &mut B, v: Self::Type) { buffer.buffer_mut()[1].set_nibble(0, v.into_nibble()); } - fn validate(_: &Self::Type) -> crate::result::Result<()> { + fn validate(_: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -120,7 +118,7 @@ impl crate::detail::property:: } impl SharpsFlats { - fn from_nibble(nibble: u4) -> Result { + fn from_nibble(nibble: u4) -> Result { use SharpsFlats::*; match u8::from(nibble) { 0x2 => Ok(DoubleSharp), @@ -128,7 +126,7 @@ impl SharpsFlats { 0x0 => Ok(Natural), 0xF => Ok(Flat), 0xE => Ok(DoubleFlat), - _ => Err(Error::InvalidData( + _ => Err(crate::error::InvalidData( "Couldn't interpret Sharps / Flats field", )), } @@ -194,7 +192,7 @@ impl crate::detail::property::Prope impl<'a, B: crate::buffer::Ump> crate::detail::property::ReadProperty<'a, B> for ChordTypeProperty> { - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { ChordType::from_octet(buffer.buffer()[1].octet(1))?; Ok(()) } @@ -206,7 +204,7 @@ impl<'a, B: crate::buffer::Ump> crate::detail::property::ReadProperty<'a, B> impl crate::detail::property::WriteProperty for ChordTypeProperty> { - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn write(buffer: &mut B, v: Self::Type) { @@ -220,7 +218,7 @@ impl crate::detail::property:: impl<'a, B: crate::buffer::Ump> crate::detail::property::ReadProperty<'a, B> for ChordTypeProperty> { - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { ChordType::from_octet(buffer.buffer()[3].octet(1))?; Ok(()) } @@ -232,7 +230,7 @@ impl<'a, B: crate::buffer::Ump> crate::detail::property::ReadProperty<'a, B> impl crate::detail::property::WriteProperty for ChordTypeProperty> { - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn write(buffer: &mut B, v: Self::Type) { @@ -244,7 +242,7 @@ impl crate::detail::property:: } impl ChordType { - fn from_octet(octet: u8) -> Result { + fn from_octet(octet: u8) -> Result { use ChordType::*; match octet { 0x00 => Ok(ClearChord), @@ -274,7 +272,7 @@ impl ChordType { 0x18 => Ok(Power), 0x19 => Ok(Suspended2nd), 0x1A => Ok(Suspended4th), - _ => Err(Error::InvalidData("Couldn't interpret Chord field")), + _ => Err(crate::error::InvalidData("Couldn't interpret Chord field")), } } @@ -340,7 +338,7 @@ macro_rules! alteration_property_impl { impl<'a, B: crate::buffer::Ump> crate::detail::property::ReadProperty<'a, B> for AlterationProperty> { - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { alteration_from_octet(buffer.buffer()[$buffer_index].octet($octet_index))?; Ok(()) } @@ -353,7 +351,7 @@ macro_rules! alteration_property_impl { crate::detail::property::WriteProperty for AlterationProperty> { - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn write(buffer: &mut B, v: Self::Type) { @@ -374,7 +372,7 @@ alteration_property_impl!(0x0, 0x0, 0x00FF_0000, 0x0, 2, 1); alteration_property_impl!(0x0, 0x0, 0x0, 0x0000_FF00, 3, 2); alteration_property_impl!(0x0, 0x0, 0x0, 0x0000_00FF, 3, 3); -fn alteration_from_octet(octet: u8) -> Result> { +fn alteration_from_octet(octet: u8) -> Result, crate::error::InvalidData> { use Alteration::*; match u8::from(octet.nibble(0)) { 0x0 => Ok(None), @@ -382,7 +380,9 @@ fn alteration_from_octet(octet: u8) -> Result> { 0x2 => Ok(Some(Subtract(octet.nibble(1)))), 0x3 => Ok(Some(Raise(octet.nibble(1)))), 0x4 => Ok(Some(Lower(octet.nibble(1)))), - _ => Err(Error::InvalidData("Couldn't interpret alteration field")), + _ => Err(crate::error::InvalidData( + "Couldn't interpret alteration field", + )), } } diff --git a/src/flex_data/set_key_signature.rs b/src/flex_data/set_key_signature.rs index 44d12ae..a3d26a3 100644 --- a/src/flex_data/set_key_signature.rs +++ b/src/flex_data/set_key_signature.rs @@ -60,7 +60,7 @@ impl<'a, B: crate::buffer::Ump> crate::detail::property::ReadProperty<'a, B> _ => unreachable!(), } } - fn validate(_buffer: &B) -> crate::result::Result<()> { + fn validate(_buffer: &B) -> Result<(), crate::error::InvalidData> { Ok(()) } } @@ -78,7 +78,7 @@ impl crate::detail::property:: }, ); } - fn validate(_: &Self::Type) -> crate::result::Result<()> { + fn validate(_: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { diff --git a/src/flex_data/text.rs b/src/flex_data/text.rs index de2625c..ac07d34 100644 --- a/src/flex_data/text.rs +++ b/src/flex_data/text.rs @@ -33,7 +33,7 @@ impl<'a, B: Ump + BufferMut> WriteProperty for TextWriteStrProperty<'a> { fn default() -> Self::Type { "" } - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } } @@ -175,7 +175,7 @@ impl<'a, B: 'a + Ump> ReadProperty<'a, B> for TextReadBytesProperty<'a> { byte_index: 0, } } - fn validate(_buffer: &B) -> crate::result::Result<()> { + fn validate(_buffer: &B) -> Result<(), crate::error::InvalidData> { Ok(()) } } @@ -194,10 +194,10 @@ impl<'a, B: Ump> ReadProperty<'a, B> for TextReadStringProperty { let bytes = TextReadBytesProperty::read(buffer).collect(); std::string::String::from_utf8(bytes).unwrap() } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { let bytes = TextReadBytesProperty::read(buffer).collect(); std::string::String::from_utf8(bytes).map_err(|_| { - crate::error::Error::InvalidData("Payload bytes do not represent a valid utf string") + crate::error::InvalidData("Payload bytes do not represent a valid utf string") })?; Ok(()) } diff --git a/src/flex_data/tonic.rs b/src/flex_data/tonic.rs index 16c0039..4945fe8 100644 --- a/src/flex_data/tonic.rs +++ b/src/flex_data/tonic.rs @@ -1,7 +1,5 @@ use crate::{ detail::{schema, BitOps}, - error::Error, - result::Result, ux::*, }; @@ -28,7 +26,7 @@ impl crate::detail::property::Prope impl<'a, B: crate::buffer::Ump> crate::detail::property::ReadProperty<'a, B> for TonicProperty> { - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { Tonic::from_nibble(buffer.buffer()[1].nibble(1))?; Ok(()) } @@ -40,7 +38,7 @@ impl<'a, B: crate::buffer::Ump> crate::detail::property::ReadProperty<'a, B> impl crate::detail::property::WriteProperty for TonicProperty> { - fn validate(_: &Tonic) -> crate::result::Result<()> { + fn validate(_: &Tonic) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -54,7 +52,7 @@ impl crate::detail::property:: impl<'a, B: crate::buffer::Ump> crate::detail::property::ReadProperty<'a, B> for TonicProperty> { - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { Tonic::from_nibble(buffer.buffer()[3].nibble(1))?; Ok(()) } @@ -66,7 +64,7 @@ impl<'a, B: crate::buffer::Ump> crate::detail::property::ReadProperty<'a, B> impl crate::detail::property::WriteProperty for TonicProperty> { - fn validate(_: &Tonic) -> crate::result::Result<()> { + fn validate(_: &Tonic) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -85,7 +83,7 @@ impl core::default::Default for Tonic { } impl Tonic { - fn from_nibble(nibble: u4) -> Result { + fn from_nibble(nibble: u4) -> Result { use Tonic::*; match u8::from(nibble) { 0x0 => Ok(NonStandard), @@ -96,7 +94,7 @@ impl Tonic { 0x5 => Ok(E), 0x6 => Ok(F), 0x7 => Ok(G), - _ => Err(Error::InvalidData("Couldn't interpret Tonic field")), + _ => Err(crate::error::InvalidData("Couldn't interpret Tonic field")), } } diff --git a/src/flex_data/unknown_metadata_text.rs b/src/flex_data/unknown_metadata_text.rs index 1f30d7d..87c2b55 100644 --- a/src/flex_data/unknown_metadata_text.rs +++ b/src/flex_data/unknown_metadata_text.rs @@ -241,7 +241,7 @@ mod tests { 0x0000_0000, ][..] ), - Err(crate::error::Error::InvalidData("Incorrect message status")), + Err(crate::error::InvalidData("Incorrect message status")), ) } @@ -260,7 +260,7 @@ mod tests { 0x0000_0000, ][..] ), - Err(crate::error::Error::InvalidData("Incorrect message bank")), + Err(crate::error::InvalidData("Incorrect message bank")), ) } @@ -279,7 +279,7 @@ mod tests { 0x0000_0000, ][..] ), - Err(crate::error::Error::InvalidData( + Err(crate::error::InvalidData( crate::detail::helpers::ERR_INCONSISTENT_GROUPS )), ) @@ -300,7 +300,7 @@ mod tests { 0x0000_0000, ][..] ), - Err(crate::error::Error::InvalidData( + Err(crate::error::InvalidData( crate::detail::helpers::ERR_SYSEX_EXPECTED_BEGIN )), ) @@ -321,7 +321,7 @@ mod tests { 0x0000_0000, ][..] ), - Err(crate::error::Error::InvalidData( + Err(crate::error::InvalidData( crate::detail::helpers::ERR_SYSEX_EXPECTED_END )), ) @@ -333,7 +333,7 @@ mod tests { UnknownMetadataText::try_from( &[0xD050_0100, 0x4769_6D6D, 0x6520_736F, 0x6D65_2073,][..] ), - Err(crate::error::Error::InvalidData( + Err(crate::error::InvalidData( crate::detail::helpers::ERR_SYSEX_EXPECTED_COMPLETE )), ) @@ -358,7 +358,7 @@ mod tests { 0x6D65_2073, ][..] ), - Err(crate::error::Error::InvalidData( + Err(crate::error::InvalidData( crate::detail::helpers::ERR_SYSEX_EXPECTED_CONTINUE )), ) diff --git a/src/lib.rs b/src/lib.rs index 59feb3b..3e93c08 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,7 +26,6 @@ pub mod utility; pub mod buffer; pub mod error; -pub mod result; mod detail; mod message; diff --git a/src/message.rs b/src/message.rs index e7dc0c8..e145a26 100644 --- a/src/message.rs +++ b/src/message.rs @@ -30,15 +30,13 @@ pub enum UmpMessage { } impl<'a> core::convert::TryFrom<&'a [u32]> for UmpMessage<&'a [u32]> { - type Error = crate::error::Error; + type Error = crate::error::InvalidData; fn try_from(buffer: &'a [u32]) -> Result { use crate::detail::BitOps; use UmpMessage::*; if buffer.len() < 1 { - return Err(crate::error::Error::InvalidData( - "Ump message slice is empty", - )); + return Err(crate::error::InvalidData("Ump message slice is empty")); } Ok(match u8::from(buffer[0].nibble(0)) { @@ -74,7 +72,7 @@ impl<'a> core::convert::TryFrom<&'a [u32]> for UmpMessage<&'a [u32]> { crate::utility::UMP_MESSAGE_TYPE => { Utility(crate::utility::Utility::try_from(buffer)?.into()) } - _ => Err(crate::error::Error::InvalidData( + _ => Err(crate::error::InvalidData( "Couldn't interpret ump message type", ))?, }) @@ -112,10 +110,10 @@ pub enum BytesMessage { feature = "system-common" ))] impl<'a> core::convert::TryFrom<&'a [u8]> for BytesMessage<&'a [u8]> { - type Error = crate::error::Error; + type Error = crate::error::InvalidData; fn try_from(buffer: &'a [u8]) -> Result { if buffer.len() < 1 { - return Err(crate::error::Error::InvalidData("Bytes slice is empty")); + return Err(crate::error::InvalidData("Bytes slice is empty")); } use BytesMessage::*; @@ -130,7 +128,7 @@ impl<'a> core::convert::TryFrom<&'a [u8]> for BytesMessage<&'a [u8]> { 0xF1..=0xF6 | 0xF8..=0xFF => { SystemCommon(crate::system_common::SystemCommon::try_from(buffer)?.into()) } - _ => Err(crate::error::Error::InvalidData( + _ => Err(crate::error::InvalidData( "Couldn't interpret bytes message type", ))?, }) diff --git a/src/result.rs b/src/result.rs deleted file mode 100644 index d5dc169..0000000 --- a/src/result.rs +++ /dev/null @@ -1,2 +0,0 @@ -use crate::error::Error; -pub type Result = core::result::Result; diff --git a/src/sysex7.rs b/src/sysex7.rs index 11432ee..4a75e12 100644 --- a/src/sysex7.rs +++ b/src/sysex7.rs @@ -49,11 +49,11 @@ impl crate::detail::property::Property for Sysex7By impl<'a, B: crate::buffer::Buffer> crate::detail::property::ReadProperty<'a, B> for Sysex7BytesBeginByte { - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { match ::UNIT_ID { crate::buffer::UNIT_ID_U8 => { if buffer.specialise_u8()[0] != START_BYTE { - Err(crate::error::Error::InvalidData(ERR_NO_BEGIN_BYTE)) + Err(crate::error::InvalidData(ERR_NO_BEGIN_BYTE)) } else { Ok(()) } @@ -75,7 +75,7 @@ impl crate::detail::propert buffer.specialise_u8_mut()[0] = START_BYTE; } } - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -95,14 +95,14 @@ impl<'a, B: crate::buffer::Buffer> crate::detail::property::ReadProperty<'a, B> fn read(_buffer: &'a B) -> Self::Type { () } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { match ::UNIT_ID { crate::buffer::UNIT_ID_U8 => buffer .specialise_u8() .iter() .position(|b| *b == 0xF7) .map(|_| ()) - .ok_or(crate::error::Error::InvalidData(ERR_NO_END_BYTE)), + .ok_or(crate::error::InvalidData(ERR_NO_END_BYTE)), crate::buffer::UNIT_ID_U32 => Ok(()), _ => unreachable!(), } @@ -118,7 +118,7 @@ impl crate::detail::propert buffer.specialise_u8_mut()[last] = END_BYTE; } } - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -137,7 +137,7 @@ impl<'a, B: crate::buffer::Buffer> crate::detail::property::ReadProperty<'a, B> fn read(_buffer: &'a B) -> Self::Type { () } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { if ::UNIT_ID == crate::buffer::UNIT_ID_U32 { message_helpers::validate_sysex_group_statuses( buffer.specialise_u32(), @@ -157,7 +157,7 @@ impl crate::detail::propert for ConsistentStatuses { fn write(_: &mut B, _: Self::Type) {} - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -177,14 +177,14 @@ impl<'a, B: crate::buffer::Buffer> crate::detail::property::ReadProperty<'a, B> fn read(_buffer: &'a B) -> Self::Type { () } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { if ::UNIT_ID == crate::buffer::UNIT_ID_U32 { if buffer .specialise_u32() .chunks_exact(2) .any(|p| u8::from(p[0].nibble(3)) > 6) { - Err(crate::error::Error::InvalidData(ERR_INVALID_PACKET_SIZE)) + Err(crate::error::InvalidData(ERR_INVALID_PACKET_SIZE)) } else { Ok(()) } @@ -198,7 +198,7 @@ impl crate::detail::propert for ValidPacketSizes { fn write(_buffer: &mut B, _v: Self::Type) {} - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -220,7 +220,7 @@ impl<'a, B: crate::buffer::Buffer> crate::detail::property::ReadProperty<'a, B> Default::default() } } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { if ::UNIT_ID == crate::buffer::UNIT_ID_U32 { message_helpers::sysex_group_consistent_groups( buffer.specialise_u32(), @@ -248,7 +248,7 @@ impl crate::detail::propert } } } - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -871,7 +871,7 @@ mod tests { fn try_from_bytes_with_no_end_byte() { assert_eq!( Sysex7::try_from(&[0xF0_u8, 0x0_u8, 0x1_u8, 0x2_u8][..]), - Err(crate::error::Error::InvalidData(ERR_NO_END_BYTE)) + Err(crate::error::InvalidData(ERR_NO_END_BYTE)) ) } @@ -879,7 +879,7 @@ mod tests { fn try_from_bytes_with_no_begin_byte() { assert_eq!( Sysex7::try_from(&[0x0_u8, 0x1_u8, 0x2_u8, 0xF7_u8][..]), - Err(crate::error::Error::InvalidData(ERR_NO_BEGIN_BYTE)) + Err(crate::error::InvalidData(ERR_NO_BEGIN_BYTE)) ) } @@ -1047,7 +1047,7 @@ mod tests { 0x0E00_0000_u32, ][..] ), - Err(crate::error::Error::InvalidData( + Err(crate::error::InvalidData( message_helpers::ERR_INCONSISTENT_GROUPS )), ); @@ -1066,7 +1066,7 @@ mod tests { 0x0E00_0000_u32, ][..] ), - Err(crate::error::Error::InvalidData( + Err(crate::error::InvalidData( message_helpers::ERR_SYSEX_EXPECTED_END )), ); @@ -1076,7 +1076,7 @@ mod tests { fn try_from_ump_incorrect_complete_status() { assert_eq!( Sysex7::try_from(&[0x3416_0001_u32, 0x0203_0405_u32,][..]), - Err(crate::error::Error::InvalidData( + Err(crate::error::InvalidData( message_helpers::ERR_SYSEX_EXPECTED_COMPLETE )), ); @@ -1095,7 +1095,7 @@ mod tests { 0x0E00_0000_u32, ][..] ), - Err(crate::error::Error::InvalidData( + Err(crate::error::InvalidData( message_helpers::ERR_SYSEX_EXPECTED_BEGIN )), ); @@ -1114,7 +1114,7 @@ mod tests { 0x0E00_0000_u32, ][..] ), - Err(crate::error::Error::InvalidData( + Err(crate::error::InvalidData( message_helpers::ERR_SYSEX_EXPECTED_CONTINUE )), ); @@ -1133,7 +1133,7 @@ mod tests { 0x0E00_0000_u32, ][..] ), - Err(crate::error::Error::InvalidData(ERR_INVALID_PACKET_SIZE)), + Err(crate::error::InvalidData(ERR_INVALID_PACKET_SIZE)), ); } diff --git a/src/sysex8.rs b/src/sysex8.rs index 2e34fa7..1841657 100644 --- a/src/sysex8.rs +++ b/src/sysex8.rs @@ -42,7 +42,7 @@ impl<'a, B: crate::buffer::Ump> crate::detail::property::ReadProperty<'a, B> fn read(_buffer: &'a B) -> Self::Type { () } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { message_helpers::validate_sysex_group_statuses( buffer.buffer(), |p| u8::from(p[0].nibble(2)) == 0x0, @@ -63,12 +63,12 @@ impl crate::detail::property::Property for ValidPacket impl<'a, B: crate::buffer::Ump> crate::detail::property::ReadProperty<'a, B> for ValidPacketSizes { fn read(_buffer: &'a B) -> Self::Type {} - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { if buffer.buffer().chunks_exact(4).any(|p| { let number_bytes = u8::from(p[0].nibble(3)); number_bytes < 1 || number_bytes > 14 }) { - Err(crate::error::Error::InvalidData( + Err(crate::error::InvalidData( ERR_INVALID_NUMBER_OF_PAYLOAD_BYTES, )) } else { @@ -90,7 +90,7 @@ impl crate::detail::property:: packet[0].set_nibble(3, sz.max(ux::u4::new(1))); } } - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -108,7 +108,7 @@ impl<'a, B: crate::buffer::Ump> crate::detail::property::ReadProperty<'a, B> for fn read(buffer: &'a B) -> Self::Type { buffer.buffer()[0].nibble(1) } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { message_helpers::sysex_group_consistent_groups( buffer.buffer(), 4, @@ -129,7 +129,7 @@ impl crate::detail::property:: packet[0].set_nibble(1, group); } } - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -147,7 +147,7 @@ impl<'a, B: crate::buffer::Ump> crate::detail::property::ReadProperty<'a, B> for fn read(buffer: &'a B) -> Self::Type { stream_id_from_packet(buffer.buffer()) } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { let sid = stream_id_from_packet; let buffer = buffer.buffer(); if buffer @@ -157,7 +157,7 @@ impl<'a, B: crate::buffer::Ump> crate::detail::property::ReadProperty<'a, B> for { Ok(()) } else { - Err(crate::error::Error::InvalidData(ERR_INCONSISTENT_STREAM_ID)) + Err(crate::error::InvalidData(ERR_INCONSISTENT_STREAM_ID)) } } } @@ -178,7 +178,7 @@ impl crate::detail::property:: packet[0].set_octet(3, id); } } - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -574,7 +574,7 @@ mod tests { 0x3031_0000, ][..] ), - Err(crate::error::Error::InvalidData( + Err(crate::error::InvalidData( ERR_INVALID_NUMBER_OF_PAYLOAD_BYTES )), ); @@ -603,7 +603,7 @@ mod tests { 0x3031_0000, ][..] ), - Err(crate::error::Error::InvalidData( + Err(crate::error::InvalidData( crate::detail::helpers::ERR_INCONSISTENT_GROUPS )), ); @@ -632,7 +632,7 @@ mod tests { 0x3031_0000, ][..] ), - Err(crate::error::Error::InvalidData(ERR_INCONSISTENT_STREAM_ID,)), + Err(crate::error::InvalidData(ERR_INCONSISTENT_STREAM_ID,)), ); } @@ -659,7 +659,7 @@ mod tests { 0x3031_0000, ][..] ), - Err(crate::error::Error::InvalidData( + Err(crate::error::InvalidData( crate::detail::helpers::ERR_SYSEX_EXPECTED_BEGIN )), ); @@ -688,7 +688,7 @@ mod tests { 0x3031_0000, ][..] ), - Err(crate::error::Error::InvalidData( + Err(crate::error::InvalidData( crate::detail::helpers::ERR_SYSEX_EXPECTED_CONTINUE )), ); @@ -717,7 +717,7 @@ mod tests { 0x3031_0000, ][..] ), - Err(crate::error::Error::InvalidData( + Err(crate::error::InvalidData( crate::detail::helpers::ERR_SYSEX_EXPECTED_END )), ); @@ -727,7 +727,7 @@ mod tests { fn try_from_slice_expected_complete() { assert_eq!( Sysex8::try_from(&[0x541C_BB00, 0x0102_0304, 0x0506_0708, 0x090A_0B00,][..]), - Err(crate::error::Error::InvalidData( + Err(crate::error::InvalidData( crate::detail::helpers::ERR_SYSEX_EXPECTED_COMPLETE )), ); diff --git a/src/system_common.rs b/src/system_common.rs index 573256d..29d8ca6 100644 --- a/src/system_common.rs +++ b/src/system_common.rs @@ -196,10 +196,10 @@ pub enum SystemCommon { } impl<'a, U: crate::buffer::Unit> core::convert::TryFrom<&'a [U]> for SystemCommon<&'a [U]> { - type Error = crate::error::Error; + type Error = crate::error::InvalidData; fn try_from(buffer: &'a [U]) -> Result { if buffer.len() < 1 { - return Err(crate::error::Error::InvalidData("Slice is too short")); + return Err(crate::error::InvalidData("Slice is too short")); }; Ok(match status(&buffer) { @@ -215,7 +215,7 @@ impl<'a, U: crate::buffer::Unit> core::convert::TryFrom<&'a [U]> for SystemCommo time_code::STATUS => time_code::TimeCode::try_from(buffer)?.into(), timing_clock::STATUS => timing_clock::TimingClock::try_from(buffer)?.into(), tune_request::STATUS => tune_request::TuneRequest::try_from(buffer)?.into(), - _ => Err(crate::error::Error::InvalidData( + _ => Err(crate::error::InvalidData( "Unknown midi1 channel voice status", ))?, }) @@ -236,9 +236,9 @@ impl<'a, const STATUS: u8, B: crate::buffer::Buffer> crate::detail::property::Re fn read(_buffer: &'a B) -> Self::Type { () } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { if status(buffer.buffer()) != STATUS { - Err(crate::error::Error::InvalidData("Incorrect status field")) + Err(crate::error::InvalidData("Incorrect status field")) } else { Ok(()) } @@ -262,7 +262,7 @@ impl _ => unreachable!(), } } - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { diff --git a/src/ump_stream.rs b/src/ump_stream.rs index 4d35f0f..1da2933 100644 --- a/src/ump_stream.rs +++ b/src/ump_stream.rs @@ -65,11 +65,11 @@ pub enum UmpStream { } impl<'a> TryFrom<&'a [u32]> for UmpStream<&'a [u32]> { - type Error = crate::error::Error; + type Error = crate::error::InvalidData; fn try_from(value: &'a [u32]) -> Result { use UmpStream::*; if value.len() < 1 { - return Err(crate::error::Error::InvalidData("Slice is too short")); + return Err(crate::error::InvalidData("Slice is too short")); }; Ok(match status_from_buffer(value) { device_identity::STATUS => { @@ -109,7 +109,7 @@ impl<'a> TryFrom<&'a [u32]> for UmpStream<&'a [u32]> { stream_configuration_request::STATUS => StreamConfigurationRequest( stream_configuration_request::StreamConfigurationRequest::try_from(value)?.into(), ), - _ => Err(crate::error::Error::InvalidData( + _ => Err(crate::error::InvalidData( "Couldn't interpret flex data status / bank fields", ))?, }) @@ -126,7 +126,7 @@ impl<'a, const STATUS: u16, B: Ump> property::ReadProperty<'a, B> for StatusProp fn read(_buffer: &'a B) -> Self::Type { () } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { if buffer .buffer() .chunks_exact(4) @@ -134,13 +134,13 @@ impl<'a, const STATUS: u16, B: Ump> property::ReadProperty<'a, B> for StatusProp { Ok(()) } else { - Err(crate::error::Error::InvalidData("Incorrect message status")) + Err(crate::error::InvalidData("Incorrect message status")) } } } impl property::WriteProperty for StatusProperty { - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn write(buffer: &mut B, _v: Self::Type) { @@ -165,7 +165,7 @@ impl<'a, B: Ump> property::ReadProperty<'a, B> for ConsistentFormatsProperty { () } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { use crate::detail::helpers::validate_sysex_group_statuses; use crate::detail::BitOps; @@ -188,7 +188,7 @@ impl property::WriteProperty for ConsistentFormatsPropert fn write(buffer: &mut B, _v: Self::Type) { set_format_fields(buffer.buffer_mut()) } - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } } @@ -224,7 +224,7 @@ impl<'a, const OFFSET: usize, B: Ump + BufferMut> property::WriteProperty fn default() -> Self::Type { "" } - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } } @@ -322,7 +322,7 @@ impl<'a, B: 'a + Ump> property::ReadProperty<'a, B> for TextReadBytesProperty<'a offset: 0, } } - fn validate(_buffer: &B) -> crate::result::Result<()> { + fn validate(_buffer: &B) -> Result<(), crate::error::InvalidData> { Ok(()) } } @@ -341,10 +341,10 @@ impl<'a, B: Ump> property::ReadProperty<'a, B> for TextReadStringProperty { let bytes = TextReadBytesProperty::read(buffer).collect(); std::string::String::from_utf8(bytes).unwrap() } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { let bytes = TextReadBytesProperty::read(buffer).collect(); std::string::String::from_utf8(bytes).map_err(|_| { - crate::error::Error::InvalidData("Payload bytes do not represent a valid utf string") + crate::error::InvalidData("Payload bytes do not represent a valid utf string") })?; Ok(()) } diff --git a/src/ump_stream/function_block_info.rs b/src/ump_stream/function_block_info.rs index cfdaefd..fdb5768 100644 --- a/src/ump_stream/function_block_info.rs +++ b/src/ump_stream/function_block_info.rs @@ -62,7 +62,7 @@ impl<'a, B: crate::buffer::Ump> property::ReadProperty<'a, B> for UiHintProperty _ => unreachable!(), } } - fn validate(_buffer: &B) -> crate::result::Result<()> { + fn validate(_buffer: &B) -> Result<(), crate::error::InvalidData> { Ok(()) } } @@ -70,7 +70,7 @@ impl<'a, B: crate::buffer::Ump> property::ReadProperty<'a, B> for UiHintProperty impl property::WriteProperty for UiHintProperty { - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn write(buffer: &mut B, v: Self::Type) { @@ -124,14 +124,14 @@ impl<'a, B: crate::buffer::Ump> property::ReadProperty<'a, B> for Midi1PortPrope _ => panic!(), } } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { use crate::detail::BitOps; match u8::from(buffer.buffer()[0].crumb(14)) { 0b00 => Ok(()), 0b01 => Ok(()), 0b10 => Ok(()), - _ => Err(crate::error::Error::InvalidData( + _ => Err(crate::error::InvalidData( "Couldn't interpret midi1 port field", )), } @@ -141,7 +141,7 @@ impl<'a, B: crate::buffer::Ump> property::ReadProperty<'a, B> for Midi1PortPrope impl property::WriteProperty for Midi1PortProperty { - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn write(buffer: &mut B, v: Self::Type) { @@ -188,11 +188,11 @@ impl<'a, B: crate::buffer::Ump> property::ReadProperty<'a, B> for DirectionPrope _ => panic!(), } } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { use crate::detail::BitOps; match u8::from(buffer.buffer()[0].crumb(15)) { - 0b00 => Err(crate::error::Error::InvalidData( + 0b00 => Err(crate::error::InvalidData( "Couldn't interpret direction field", )), 0b01 => Ok(()), @@ -206,7 +206,7 @@ impl<'a, B: crate::buffer::Ump> property::ReadProperty<'a, B> for DirectionPrope impl property::WriteProperty for DirectionProperty { - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn write(buffer: &mut B, v: Self::Type) { diff --git a/src/ump_stream/function_block_name.rs b/src/ump_stream/function_block_name.rs index 3f6d263..8d84aa1 100644 --- a/src/ump_stream/function_block_name.rs +++ b/src/ump_stream/function_block_name.rs @@ -43,7 +43,7 @@ impl property::Property for FunctionBlockProperty { } impl<'a, B: Ump> property::ReadProperty<'a, B> for FunctionBlockProperty { - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { use crate::detail::BitOps; let function_block = buffer.buffer()[0].octet(2); @@ -52,7 +52,7 @@ impl<'a, B: Ump> property::ReadProperty<'a, B> for FunctionBlockProperty { .chunks_exact(4) .all(|packet| packet[0].octet(2) == function_block) { - Err(crate::error::Error::InvalidData( + Err(crate::error::InvalidData( "Inconsistent function block fields", )) } else { @@ -66,7 +66,7 @@ impl<'a, B: Ump> property::ReadProperty<'a, B> for FunctionBlockProperty { } impl property::WriteProperty for FunctionBlockProperty { - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -95,7 +95,7 @@ impl<'a, B: 'a + Ump> property::ReadProperty<'a, B> for TextReadBytesProperty<'a offset: 1, } } - fn validate(_buffer: &B) -> crate::result::Result<()> { + fn validate(_buffer: &B) -> Result<(), crate::error::InvalidData> { Ok(()) } } @@ -114,10 +114,10 @@ impl<'a, B: Ump> property::ReadProperty<'a, B> for TextReadStringProperty { let bytes = TextReadBytesProperty::read(buffer).collect(); std::string::String::from_utf8(bytes).unwrap() } - fn validate(buffer: &B) -> crate::result::Result<()> { + fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> { let bytes = TextReadBytesProperty::read(buffer).collect(); std::string::String::from_utf8(bytes).map_err(|_| { - crate::error::Error::InvalidData("Payload bytes do not represent a valid utf string") + crate::error::InvalidData("Payload bytes do not represent a valid utf string") })?; Ok(()) } diff --git a/src/utility.rs b/src/utility.rs index 91d400c..fe28086 100644 --- a/src/utility.rs +++ b/src/utility.rs @@ -142,7 +142,7 @@ impl<'a, B: crate::buffer::Ump> crate::detail::property::ReadProperty<'a, B> for use crate::detail::BitOps; buffer.buffer()[0].word(1) } - fn validate(_buffer: &B) -> crate::result::Result<()> { + fn validate(_buffer: &B) -> Result<(), crate::error::InvalidData> { Ok(()) } } @@ -154,7 +154,7 @@ impl crate::detail::property:: use crate::detail::BitOps; buffer.buffer_mut()[0].set_word(1, value); } - fn validate(_v: &Self::Type) -> crate::result::Result<()> { + fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> { Ok(()) } fn default() -> Self::Type { @@ -183,10 +183,10 @@ pub enum Utility { } impl<'a> core::convert::TryFrom<&'a [u32]> for Utility<&'a [u32]> { - type Error = crate::error::Error; + type Error = crate::error::InvalidData; fn try_from(buffer: &'a [u32]) -> Result { if buffer.len() < 1 { - return Err(crate::error::Error::InvalidData("Slice is too short")); + return Err(crate::error::InvalidData("Slice is too short")); }; Ok(match status(buffer) { no_op::STATUS => no_op::NoOp::try_from(buffer)?.into(), @@ -196,9 +196,7 @@ impl<'a> core::convert::TryFrom<&'a [u32]> for Utility<&'a [u32]> { delta_clockstamp_tpq::STATUS => { delta_clockstamp_tpq::DeltaClockstampTpq::try_from(buffer)?.into() } - _ => Err(crate::error::Error::InvalidData( - "Unknown utility message status", - ))?, + _ => Err(crate::error::InvalidData("Unknown utility message status"))?, }) } } From 9d8de72e63fcae568abd24df32b18cae3236206d Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Wed, 15 May 2024 17:09:11 +0200 Subject: [PATCH 20/25] docs: fix wording in README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6d20ec3..8edb478 100644 --- a/README.md +++ b/README.md @@ -235,7 +235,7 @@ assert_eq!(owned.data(), &[0x4899_5E03, 0x6A14_E98A]) ## Support For Classical MIDI Byte Stream Messages -Messages which can be represented in classical midi byte stream format are also supported. +Messages which can be represented in classical MIDI byte stream format are also supported. To do this simply use a backing buffer over `u8` instead of `u32`! ✨🎩 ```rust @@ -264,8 +264,8 @@ assert_eq!(message.data(), &[0x20D0_0000]); ## Cargo Features -midi2 provides several compile-time features that you can enable or disable to customize -its functionality according to your needs. +Several compile-time features are provided that you can enable or disable to customize +functionality according to your needs. Here's a list of available features: From dd301f079c3be8d61b7fb7c51a54a55cdd653040 Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Wed, 15 May 2024 23:00:25 +0200 Subject: [PATCH 21/25] feat: infallible rebuffer to array buffer for fixed size aggregates --- midi2_proc/src/common.rs | 7 +++++++ midi2_proc/src/derives.rs | 27 +++++++++++++++++++++++++++ midi2_proc/src/lib.rs | 5 +++++ src/channel_voice1.rs | 19 +++++++++++++++++++ src/channel_voice2.rs | 9 +++++++++ src/system_common.rs | 17 +++++++++++++++++ src/utility.rs | 9 +++++++++ 7 files changed, 93 insertions(+) diff --git a/midi2_proc/src/common.rs b/midi2_proc/src/common.rs index 6810bb1..0869e0a 100644 --- a/midi2_proc/src/common.rs +++ b/midi2_proc/src/common.rs @@ -22,6 +22,13 @@ impl BufferGeneric { Self::Bytes(param) => param.ident.clone(), } } + pub fn type_param(&self) -> syn::TypeParam { + match self { + Self::UmpOrBytes(param) => param.clone(), + Self::Ump(param) => param.clone(), + Self::Bytes(param) => param.clone(), + } + } } pub fn buffer_generic(generics: &syn::Generics) -> Option { diff --git a/midi2_proc/src/derives.rs b/midi2_proc/src/derives.rs index 5f0b8de..a234edb 100644 --- a/midi2_proc/src/derives.rs +++ b/midi2_proc/src/derives.rs @@ -205,6 +205,33 @@ pub fn rebuffer_from(item: TokenStream1) -> TokenStream1 { .into() } +pub fn rebuffer_from_array(item: TokenStream1) -> TokenStream1 { + let input = parse_macro_input!(item as ItemEnum); + let ident = &input.ident; + let mut match_arms = TokenStream::new(); + for variant in &input.variants { + let variant_ident = &variant.ident; + match_arms.extend(quote! { + #ident::#variant_ident(m) => #ident::#variant_ident(m.rebuffer_into()), + }); + } + let buffer_generic = common::buffer_generic(&input.generics).expect("Expected buffer generic"); + let buffer_generic_id = buffer_generic.ident(); + let buffer_generic_type_param = buffer_generic.type_param(); + let arr_type = quote! { [<#buffer_generic_id as crate::buffer::Buffer>::Unit; SIZE] }; + quote! { + impl crate::RebufferFrom<#ident<#buffer_generic_id>> for #ident<#arr_type> { + fn rebuffer_from(other: #ident<#buffer_generic_id>) -> Self { + use crate::RebufferInto; + match other { + #match_arms + } + } + } + } + .into() +} + pub fn try_rebuffer_from(item: TokenStream1) -> TokenStream1 { let input = parse_macro_input!(item as ItemEnum); let ident = &input.ident; diff --git a/midi2_proc/src/lib.rs b/midi2_proc/src/lib.rs index ac348d8..5cd22be 100644 --- a/midi2_proc/src/lib.rs +++ b/midi2_proc/src/lib.rs @@ -59,6 +59,11 @@ pub fn derive_rebuffer_from(item: TokenStream1) -> TokenStream1 { derives::rebuffer_from(item) } +#[proc_macro_derive(RebufferFromArray)] +pub fn derive_rebuffer_from_array(item: TokenStream1) -> TokenStream1 { + derives::rebuffer_from_array(item) +} + #[proc_macro_derive(TryRebufferFrom)] pub fn derive_try_rebuffer_from(item: TokenStream1) -> TokenStream1 { derives::try_rebuffer_from(item) diff --git a/src/channel_voice1.rs b/src/channel_voice1.rs index a51e784..41c62c6 100644 --- a/src/channel_voice1.rs +++ b/src/channel_voice1.rs @@ -29,6 +29,7 @@ pub(crate) const UMP_MESSAGE_TYPE: u8 = 0x2; midi2_proc::TryFromBytes, midi2_proc::TryFromUmp, midi2_proc::RebufferFrom, + midi2_proc::RebufferFromArray, midi2_proc::TryRebufferFrom, Clone, Debug, @@ -183,4 +184,22 @@ mod test { assert_eq!(packets.next(), Some(&[0x2FD6_0900_u32][..])); assert_eq!(packets.next(), None); } + + #[test] + fn rebuffer_from_array() { + let borrowed = ChannelVoice1::try_from(&[0x2FD6_0900_u32][..]).unwrap(); + let _owned: ChannelVoice1<[u32; 4]> = borrowed.rebuffer_into(); + } + + #[test] + fn rebuffer_from_array_small() { + let borrowed = ChannelVoice1::try_from(&[0x2FD6_0900_u32][..]).unwrap(); + let _owned: ChannelVoice1<[u32; 1]> = borrowed.rebuffer_into(); + } + + #[test] + fn rebuffer_from_array_bytes() { + let borrowed = ChannelVoice1::try_from(&[0xD6_u8, 0x09_u8][..]).unwrap(); + let _owned: ChannelVoice1<[u8; 3]> = borrowed.rebuffer_into(); + } } diff --git a/src/channel_voice2.rs b/src/channel_voice2.rs index 85a218d..208c77b 100644 --- a/src/channel_voice2.rs +++ b/src/channel_voice2.rs @@ -43,6 +43,7 @@ pub(crate) const UMP_MESSAGE_TYPE: u8 = 0x4; midi2_proc::Channeled, midi2_proc::Grouped, midi2_proc::RebufferFrom, + midi2_proc::RebufferFromArray, midi2_proc::TryRebufferFrom, Clone, Debug, @@ -148,4 +149,12 @@ mod test { assert_eq!(packets.next(), Some(&[0x4BAC_5900, 0xC0B83064][..])); assert_eq!(packets.next(), None); } + + #[test] + fn rebuffer_from_array() { + use crate::RebufferFrom; + + let message = ChannelVoice2::try_from(&[0x4BAC_5900, 0xC0B83064][..]).unwrap(); + let _ = ChannelVoice2::<[u32; 2]>::rebuffer_from(message); + } } diff --git a/src/system_common.rs b/src/system_common.rs index 29d8ca6..4256d61 100644 --- a/src/system_common.rs +++ b/src/system_common.rs @@ -175,6 +175,7 @@ pub use tune_request::*; midi2_proc::TryFromBytes, midi2_proc::TryFromUmp, midi2_proc::RebufferFrom, + midi2_proc::RebufferFromArray, midi2_proc::TryRebufferFrom, Clone, Debug, @@ -314,4 +315,20 @@ mod tests { assert_eq!(packets.next(), Some(&[0x15F1_5F00_u32][..])); assert_eq!(packets.next(), None); } + + #[test] + fn rebuffer_from_array() { + use crate::RebufferFrom; + + let message = SystemCommon::try_from(&[0x15F1_5F00_u32][..]).unwrap(); + let _ = SystemCommon::<[u32; 1]>::rebuffer_from(message); + } + + #[test] + fn rebuffer_from_array_bytes() { + use crate::RebufferFrom; + + let message = SystemCommon::try_from(&[0xF3_u8, 0x4D][..]).unwrap(); + let _ = SystemCommon::<[u8; 3]>::rebuffer_from(message); + } } diff --git a/src/utility.rs b/src/utility.rs index fe28086..b51aa2d 100644 --- a/src/utility.rs +++ b/src/utility.rs @@ -167,6 +167,7 @@ impl crate::detail::property:: midi2_proc::Data, midi2_proc::Packets, midi2_proc::RebufferFrom, + midi2_proc::RebufferFromArray, midi2_proc::TryRebufferFrom, Clone, Debug, @@ -240,4 +241,12 @@ mod tests { assert_eq!(packets.next(), Some(&[0x0010_1234][..])); assert_eq!(packets.next(), None); } + + #[test] + fn rebuffer_from() { + use crate::RebufferFrom; + + let message = Utility::try_from(&[0x0010_1234][..]).unwrap(); + let _ = Utility::<[u32; 1]>::rebuffer_from(message); + } } From 01541e49613dfdf6004f6a6dc3ecdd6211f3bf93 Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Wed, 15 May 2024 23:35:52 +0200 Subject: [PATCH 22/25] docs: MIDI 1.0 channel voice docs --- src/channel_voice1.rs | 2 + src/channel_voice1/README.md | 85 ++++++++++++++++++++++++++ src/channel_voice1/channel_pressure.rs | 3 + src/channel_voice1/control_change.rs | 3 + src/channel_voice1/key_pressure.rs | 3 + src/channel_voice1/note_off.rs | 3 + src/channel_voice1/note_on.rs | 3 + src/channel_voice1/pitch_bend.rs | 3 + src/channel_voice1/program_change.rs | 3 + src/packets.rs | 4 ++ 10 files changed, 112 insertions(+) create mode 100644 src/channel_voice1/README.md diff --git a/src/channel_voice1.rs b/src/channel_voice1.rs index 41c62c6..9b44e59 100644 --- a/src/channel_voice1.rs +++ b/src/channel_voice1.rs @@ -1,3 +1,5 @@ +#![doc = include_str!("channel_voice1/README.md")] + use crate::detail::BitOps; mod channel_pressure; diff --git a/src/channel_voice1/README.md b/src/channel_voice1/README.md new file mode 100644 index 0000000..ad423bc --- /dev/null +++ b/src/channel_voice1/README.md @@ -0,0 +1,85 @@ +MIDI 1.0 Channel Voice Messages + +## Basic Usage + +```rust +use midi2::{ + prelude::*, + channel_voice1::ControlChange, +}; + +let mut message = ControlChange::<[u32; 4]>::new(); +message.set_channel(u4::new(0xA)); +message.set_group(u4::new(0xC)); +message.set_control(u7::new(0x36)); +message.set_control_data(u7::new(0x37)); + +assert_eq!(message.data(), &[0x2CBA_3637]); +``` + +## Channeled + +`channel_voice1` messages are [Channeled](crate::Channeled). + +## Grouped + +`channel_voice1` messages are [Grouped](crate::Grouped) +when backed with [Ump](crate::buffer::Ump) buffers. + +## Aggregate Message + +There is a single aggregate [ChannelVoice1] enum type which +can represent an arbitrary `channel_voice1` message. + +```rust +use midi2::{ + prelude::*, + channel_voice1::ChannelVoice1, +}; + +let mut message = ChannelVoice1::try_from(&[0x2CBA_3637_u32][..]).expect("Valid data"); + +match message { + ChannelVoice1::ChannelPressure(m) => println!("channel_pressure {:?}", m.data()), + ChannelVoice1::ControlChange(m) => println!("control_change {:?}", m.data()), + ChannelVoice1::KeyPressure(m) => println!("key_pressure {:?}", m.data()), + ChannelVoice1::NoteOff(m) => println!("note_off {:?}", m.data()), + ChannelVoice1::NoteOn(m) => println!("note_on {:?}", m.data()), + ChannelVoice1::PitchBend(m) => println!("pitch_bend {:?}", m.data()), + ChannelVoice1::ProgramChange(m) => println!("program_change {:?}", m.data()), +} +``` + +## Generic Over [Unit](crate::buffer::Unit) + +`channel_voice1` messages can also be represented with [Bytes](crate::buffer::Bytes) buffers + as well as [Ump](crate::buffer::Ump) buffers. + +```rust +use midi2::{ + prelude::*, + channel_voice1::ControlChange, +}; + +let mut message = ControlChange::<[u8; 3]>::new(); +message.set_channel(u4::new(0xA)); +message.set_control(u7::new(0x36)); +message.set_control_data(u7::new(0x37)); + +assert_eq!(message.data(), &[0xBA, 0x36, 0x37]); +``` + +## Fixed Size + +All `channel_voice1` messages are Fixed size. + +```rust +use midi2::channel_voice1::KeyPressure; + + +// All channel_voice1 bytes-backed messages fit into a `[u8; 3]` +let _ = KeyPressure::<[u8; 3]>::new(); + +// All channel_voice1 ump-backed messages fit into a `[u32; 1]` +let _ = KeyPressure::<[u32; 1]>::new(); +``` diff --git a/src/channel_voice1/channel_pressure.rs b/src/channel_voice1/channel_pressure.rs index 6e6b0a6..bdec04a 100644 --- a/src/channel_voice1/channel_pressure.rs +++ b/src/channel_voice1/channel_pressure.rs @@ -5,6 +5,9 @@ use crate::{ pub(crate) const STATUS: u8 = 0b1101; +/// MIDI 1.0 Channel Voice Channel Pressure Message +/// +/// See the [module docs](crate::channel_voice1) for more info. #[midi2_proc::generate_message( Via(crate::channel_voice1::ChannelVoice1), FixedSize, diff --git a/src/channel_voice1/control_change.rs b/src/channel_voice1/control_change.rs index 5b2cd53..3edd7e3 100644 --- a/src/channel_voice1/control_change.rs +++ b/src/channel_voice1/control_change.rs @@ -5,6 +5,9 @@ use crate::{ pub(crate) const STATUS: u8 = 0b1011; +/// MIDI 1.0 Channel Voice Control Change Message +/// +/// See the [module docs](crate::channel_voice1) for more info. #[midi2_proc::generate_message( Via(crate::channel_voice1::ChannelVoice1), FixedSize, diff --git a/src/channel_voice1/key_pressure.rs b/src/channel_voice1/key_pressure.rs index bf85b01..76c363b 100644 --- a/src/channel_voice1/key_pressure.rs +++ b/src/channel_voice1/key_pressure.rs @@ -5,6 +5,9 @@ use crate::{ pub(crate) const STATUS: u8 = 0b1010; +/// MIDI 1.0 Channel Voice Key Pressure Message +/// +/// See the [module docs](crate::channel_voice1) for more info. #[midi2_proc::generate_message( Via(crate::channel_voice1::ChannelVoice1), FixedSize, diff --git a/src/channel_voice1/note_off.rs b/src/channel_voice1/note_off.rs index f7566e7..1927796 100644 --- a/src/channel_voice1/note_off.rs +++ b/src/channel_voice1/note_off.rs @@ -5,6 +5,9 @@ use crate::{ pub(crate) const STATUS: u8 = 0b1000; +/// MIDI 1.0 Channel Voice Note Off Message +/// +/// See the [module docs](crate::channel_voice1) for more info. #[midi2_proc::generate_message( Via(crate::channel_voice1::ChannelVoice1), FixedSize, diff --git a/src/channel_voice1/note_on.rs b/src/channel_voice1/note_on.rs index e7398d0..1ff0643 100644 --- a/src/channel_voice1/note_on.rs +++ b/src/channel_voice1/note_on.rs @@ -5,6 +5,9 @@ use crate::{ pub(crate) const STATUS: u8 = 0b1001; +/// MIDI 1.0 Channel Voice Note On Message +/// +/// See the [module docs](crate::channel_voice1) for more info. #[midi2_proc::generate_message( Via(crate::channel_voice1::ChannelVoice1), FixedSize, diff --git a/src/channel_voice1/pitch_bend.rs b/src/channel_voice1/pitch_bend.rs index e858e16..c2bcde0 100644 --- a/src/channel_voice1/pitch_bend.rs +++ b/src/channel_voice1/pitch_bend.rs @@ -5,6 +5,9 @@ use crate::{ pub(crate) const STATUS: u8 = 0b1110; +/// MIDI 1.0 Channel Voice Pitch Bend Message +/// +/// See the [module docs](crate::channel_voice1) for more info. #[midi2_proc::generate_message( Via(crate::channel_voice1::ChannelVoice1), FixedSize, diff --git a/src/channel_voice1/program_change.rs b/src/channel_voice1/program_change.rs index db8bbea..1f18acb 100644 --- a/src/channel_voice1/program_change.rs +++ b/src/channel_voice1/program_change.rs @@ -5,6 +5,9 @@ use crate::{ pub(crate) const STATUS: u8 = 0b1100; +/// MIDI 1.0 Channel Voice Program Change Message +/// +/// See the [module docs](crate::channel_voice1) for more info. #[midi2_proc::generate_message( Via(crate::channel_voice1::ChannelVoice1), FixedSize, diff --git a/src/packets.rs b/src/packets.rs index 195748c..f8e2354 100644 --- a/src/packets.rs +++ b/src/packets.rs @@ -1,3 +1,7 @@ +/// Iterator type for reading the individual packets of a +/// [Ump](crate::buffer::Ump) backed message. +/// +/// Returned from [Packets::packets]. #[derive(Debug, Clone)] pub struct PacketsIterator<'a>(pub(crate) core::slice::ChunksExact<'a, u32>); From 695e70703efc5eb74d5e247201ea9b42aad3cf07 Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Thu, 16 May 2024 09:12:47 +0200 Subject: [PATCH 23/25] docs: change working in root README --- README.md | 4 +- src/channel_voice1/README.md | 4 ++ src/channel_voice2/README.md | 85 ++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 src/channel_voice2/README.md diff --git a/README.md b/README.md index 8edb478..fa268c1 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ Ergonomic, versatile, strong types wrapping MIDI 2.0 message data. This implementation of MIDI 2.0 is based on the 1.1 revision of the specifications. -For detailed midi2 specification see [the documentation](https://midi.org/) -on which this crate is based. +See [the official MIDI 2.0 specification](https://midi.org/) +for more details on the data protocol standard. ## ⚠️ **Note!** ⚠️ diff --git a/src/channel_voice1/README.md b/src/channel_voice1/README.md index ad423bc..d772948 100644 --- a/src/channel_voice1/README.md +++ b/src/channel_voice1/README.md @@ -15,6 +15,10 @@ message.set_control(u7::new(0x36)); message.set_control_data(u7::new(0x37)); assert_eq!(message.data(), &[0x2CBA_3637]); +assert_eq!(message.channel(), u4::new(0xA)); +assert_eq!(message.group(), u4::new(0xC)); +assert_eq!(message.control(), u7::new(0x36)); +assert_eq!(message.control_data(), u7::new(0x37)); ``` ## Channeled diff --git a/src/channel_voice2/README.md b/src/channel_voice2/README.md new file mode 100644 index 0000000..42ba57b --- /dev/null +++ b/src/channel_voice2/README.md @@ -0,0 +1,85 @@ +MIDI 2.0 Channel Voice Messages + +## Basic Usage + +```rust +use midi2::{ + prelude::*, + channel_voice2::NoteOn, +}; + +let mut message = ControlChange::<[u32; 4]>::new(); +message.set_channel(u4::new(0xA)); +message.set_group(u4::new(0xC)); +message.set_control(u7::new(0x36)); +message.set_control_data(u7::new(0x37)); + +assert_eq!(message.data(), &[0x2CBA_3637]); +``` + +## Channeled + +`channel_voice1` messages are [Channeled](crate::Channeled). + +## Grouped + +`channel_voice1` messages are [Grouped](crate::Grouped) +when backed with [Ump](crate::buffer::Ump) buffers. + +## Aggregate Message + +There is a single aggregate [ChannelVoice1] enum type which +can represent an arbitrary `channel_voice1` message. + +```rust +use midi2::{ + prelude::*, + channel_voice1::ChannelVoice1, +}; + +let mut message = ChannelVoice1::try_from(&[0x2CBA_3637_u32][..]).expect("Valid data"); + +match message { + ChannelVoice1::ChannelPressure(m) => println!("channel_pressure {:?}", m.data()), + ChannelVoice1::ControlChange(m) => println!("control_change {:?}", m.data()), + ChannelVoice1::KeyPressure(m) => println!("key_pressure {:?}", m.data()), + ChannelVoice1::NoteOff(m) => println!("note_off {:?}", m.data()), + ChannelVoice1::NoteOn(m) => println!("note_on {:?}", m.data()), + ChannelVoice1::PitchBend(m) => println!("pitch_bend {:?}", m.data()), + ChannelVoice1::ProgramChange(m) => println!("program_change {:?}", m.data()), +} +``` + +## Generic Over [Unit](crate::buffer::Unit) + +`channel_voice1` messages can also be represented with [Bytes](crate::buffer::Bytes) buffers + as well as [Ump](crate::buffer::Ump) buffers. + +```rust +use midi2::{ + prelude::*, + channel_voice1::ControlChange, +}; + +let mut message = ControlChange::<[u8; 3]>::new(); +message.set_channel(u4::new(0xA)); +message.set_control(u7::new(0x36)); +message.set_control_data(u7::new(0x37)); + +assert_eq!(message.data(), &[0xBA, 0x36, 0x37]); +``` + +## Fixed Size + +All `channel_voice1` messages are Fixed size. + +```rust +use midi2::channel_voice1::KeyPressure; + + +// All channel_voice1 bytes-backed messages fit into a `[u8; 3]` +let _ = KeyPressure::<[u8; 3]>::new(); + +// All channel_voice1 ump-backed messages fit into a `[u32; 1]` +let _ = KeyPressure::<[u32; 1]>::new(); +``` From c23fe24891564b517336ee13c4bb84d80292002b Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Thu, 16 May 2024 09:29:02 +0200 Subject: [PATCH 24/25] chore: bump cargo version to 0.5.0 --- Cargo.toml | 4 ++-- README.md | 2 +- midi2_proc/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a9ea69f..f6fa3b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "midi2" -version = "0.4.0" +version = "0.5.0" description = "Ergonomic, versatile, strong types wrapping MIDI 2.0 message data." edition = "2021" readme = "README.md" @@ -35,7 +35,7 @@ utility = [] [dependencies] derive_more = { version = "0.99.17", features = ["from"], default-features = false } -midi2_proc = { version = "0.4.0", path = "midi2_proc" } +midi2_proc = { version = "0.5.0", path = "midi2_proc" } ux = "0.1.6" [dev-dependencies] diff --git a/README.md b/README.md index fa268c1..8d2163c 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ You'll want to setup midi2 without default features to compile without the `std` feature. ```toml -midi2 = { version = "0.4.0", default-features = false, features = ["channel-voice2", "sysex7"], } +midi2 = { version = "0.5.0", default-features = false, features = ["channel-voice2", "sysex7"], } ``` ### Generic Representation diff --git a/midi2_proc/Cargo.toml b/midi2_proc/Cargo.toml index 7062b25..16c4773 100644 --- a/midi2_proc/Cargo.toml +++ b/midi2_proc/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "midi2_proc" description = "Internal procedural macro crate. Only intended for use with midi2" -version = "0.4.0" +version = "0.5.0" edition = "2021" readme = "README.md" license = "MIT OR Apache-2.0" From 9ad26bec2077260356360e085501ad36528c86fa Mon Sep 17 00:00:00 2001 From: Ben Leadbetter Date: Thu, 16 May 2024 09:29:19 +0200 Subject: [PATCH 25/25] docs: update changelog --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79ea471..bdc4b4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +# 0.5.0 +docs: generally improve documentation of public modules and traits +feat: infallible constructors and converters for array backed messages +feat: new `Packets` trait implemented by all ump messages +fix: flex data text bytes iterator is public +refactor!: ⚠️ remove dedicated array constructors in favour of unified generic constructors +refactor!: ⚠️ remove redundant aggregate error type and result +refactor!: ⚠️ rename DeltaClockstampTPQ -> DeltaClockstampTpq +refactor: switching implementation from mod.rs to file names based on module name + # 0.4.0 feat: top level messages implement From for all messages fix: ⚠️ utility messages should be excluded when feature is not enabled