Skip to content

Commit 180e121

Browse files
author
Ben Leadbetter
committed
chore: merge branch 'release/0.7.0'
2 parents be7871d + 30ea119 commit 180e121

40 files changed

+1755
-97
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
# 0.7.0
2+
* feat!: packet types
3+
* Packet types for each ump message type.
4+
* Messages are formed of packets.
5+
* The Packets trait has Item = Packet. (breaking change)
6+
* feat: allow messages to be created with external backing buffers
7+
* docs: improve warning formatting in top level readme
8+
* docs: improve readme example
9+
110
# 0.6.5
211
* docs: improve readme example
312

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "midi2"
3-
version = "0.6.5"
3+
version = "0.7.0"
44
description = "Ergonomic, versatile, strong types wrapping MIDI 2.0 message data."
55
edition = "2021"
66
readme = "README.md"
@@ -37,7 +37,7 @@ utility = []
3737
[dependencies]
3838
derive_more = { version = "0.99.17", features = ["from"], default-features = false }
3939
fixed = "1.27.0"
40-
midi2_proc = { version = "0.6.5", path = "midi2_proc" }
40+
midi2_proc = { version = "0.7.0", path = "midi2_proc" }
4141
ux = "0.1.6"
4242

4343
[dev-dependencies]

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ This implementation of MIDI 2.0 is based on the 1.1 revision of the specificatio
66
See [the official MIDI 2.0 specification](https://midi.org/)
77
for more details on the data protocol standard.
88

9-
## ⚠️ **Note!** ⚠️
10-
11-
This crate is still in its alpha phase and is not
12-
recommended for production.
9+
> [!CAUTION]
10+
>
11+
> This project is still in early development.
12+
> Expect breaking changes and bugs, and please report any issues you encounter.
1313
1414
We would welcome contributions!
1515
Please refer to the [CONTRIBUTOR.md](CONTRIBUTOR.md)
@@ -157,7 +157,7 @@ You'll want to setup midi2 without default features to compile
157157
without the `std` feature.
158158

159159
```toml
160-
midi2 = { version = "0.6.5", default-features = false, features = ["channel-voice2", "sysex7"], }
160+
midi2 = { version = "0.7.0", default-features = false, features = ["channel-voice2", "sysex7"], }
161161
```
162162

163163
### Generic Representation

examples/handling_messages.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use midi2::prelude::*;
22

33
fn handle_message(buffer: &[u32]) {
44
match UmpMessage::try_from(buffer) {
5+
#[cfg(feature = "channel-voice2")]
56
Ok(UmpMessage::ChannelVoice2(m)) => {
67
println!("Channel Voice2: channel: {}", m.channel());
78
match m {

midi2_proc/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "midi2_proc"
33
description = "Internal procedural macro crate. Only intended for use with midi2"
4-
version = "0.6.5"
4+
version = "0.7.0"
55
edition = "2021"
66
readme = "README.md"
77
license = "MIT OR Apache-2.0"

midi2_proc/src/derives.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -375,16 +375,25 @@ pub fn debug(item: TokenStream1) -> TokenStream1 {
375375
_ => panic!("Only enums and structs supported"),
376376
};
377377
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
378-
let buffer_id = common::buffer_generic(generics)
379-
.expect("Expected buffer generic")
380-
.ident();
378+
379+
let buffer_id = if ident == "Packet" {
380+
// special handling
381+
// always a u32 slice
382+
quote! {crate::buffer::UNIT_ID_U32}
383+
} else {
384+
let buffer_ident = common::buffer_generic(generics)
385+
.expect("Expected buffer generic")
386+
.ident();
387+
quote! {<<#buffer_ident as crate::buffer::Buffer>::Unit as crate::buffer::UnitPrivate>::UNIT_ID}
388+
};
389+
381390
quote! {
382391
impl #impl_generics core::fmt::Debug for #ident #ty_generics #where_clause {
383392
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
384393
use crate::BufferAccess as BufferAccessDeriveDebug;
385394

386395
fmt.write_fmt(format_args!("{}([", stringify!(#ident)))?;
387-
match <<#buffer_id as crate::buffer::Buffer>::Unit as crate::buffer::UnitPrivate>::UNIT_ID {
396+
match #buffer_id {
388397
crate::buffer::UNIT_ID_U8 => {
389398
use crate::buffer::SpecialiseU8 as SpecialiseU8DeriveDebug;
390399

midi2_proc/src/generate_ci.rs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,33 @@ fn new_impl(root_ident: &syn::Ident, properties: &[Property]) -> TokenStream {
328328
}
329329
}
330330

331+
fn new_with_buffer_impl(root_ident: &syn::Ident, properties: &[Property]) -> TokenStream {
332+
let initialise_properties = initialise_property_statements(properties, quote! {B});
333+
quote! {
334+
impl<const VERSION: u8,
335+
B: crate::buffer::Bytes
336+
+ crate::buffer::BufferMut
337+
+ crate::buffer::BufferResize
338+
> #root_ident<VERSION, B>
339+
{
340+
/// Create a new message backed by a resizable buffer.
341+
pub fn new_with_buffer(buffer: B) -> Self where Self: crate::ci::version::CiVersion<VERSION>
342+
{
343+
let mut sysex7 = crate::sysex7::Sysex7::<B>::new_with_buffer(buffer);
344+
let payload_size = <Self as crate::traits::MinSize<B>>::MIN_SIZE - 2;
345+
<crate::sysex7::Sysex7<B> as crate::SysexInternal<B>>::resize(&mut sysex7, payload_size);
346+
let buffer_ref_mut = <crate::sysex7::Sysex7<B> as crate::BufferAccess<B>>::buffer_access_mut(&mut sysex7);
347+
if buffer_ref_mut.buffer().len() > 5 {
348+
// write the version
349+
buffer_ref_mut.buffer_mut()[5] = VERSION;
350+
}
351+
#initialise_properties
352+
#root_ident::<VERSION, B>(sysex7)
353+
}
354+
}
355+
}
356+
}
357+
331358
fn try_new_impl(root_ident: &syn::Ident, properties: &[Property]) -> TokenStream {
332359
let initialise_properties = initialise_property_statements(properties, quote! {B});
333360
quote! {
@@ -354,6 +381,31 @@ fn try_new_impl(root_ident: &syn::Ident, properties: &[Property]) -> TokenStream
354381
}
355382
}
356383

384+
fn try_new_with_buffer_impl(root_ident: &syn::Ident, properties: &[Property]) -> TokenStream {
385+
let initialise_properties = initialise_property_statements(properties, quote! {B});
386+
quote! {
387+
impl<const VERSION: u8,
388+
B: crate::buffer::Bytes
389+
+ crate::buffer::BufferMut
390+
+ crate::buffer::BufferTryResize
391+
> #root_ident<VERSION, B>
392+
{
393+
/// Create a new message backed by a buffer with fallible resize.
394+
pub fn try_new_with_buffer(buffer: B) -> Result<Self, crate::error::BufferOverflow> where Self: crate::ci::version::CiVersion<VERSION>
395+
{
396+
let mut sysex7 = crate::sysex7::Sysex7::<B>::try_new_with_buffer(buffer)?;
397+
let payload_size = <Self as crate::traits::MinSize<B>>::MIN_SIZE - 2;
398+
<crate::sysex7::Sysex7<B> as crate::SysexInternal<B>>::try_resize(&mut sysex7, payload_size)?;
399+
let buffer_ref_mut = <crate::sysex7::Sysex7<B> as crate::BufferAccess<B>>::buffer_access_mut(&mut sysex7);
400+
// write the version
401+
buffer_ref_mut.buffer_mut()[5] = VERSION;
402+
#initialise_properties
403+
Ok(#root_ident::<VERSION, B>(sysex7))
404+
}
405+
}
406+
}
407+
}
408+
357409
fn ci_version_impls(root_ident: &syn::Ident, args: &GenerateCiArgs) -> TokenStream {
358410
let mut ret = TokenStream::new();
359411

@@ -490,7 +542,7 @@ fn try_from_slice_impl(root_ident: &syn::Ident, properties: &[Property]) -> Toke
490542
type Error = crate::error::InvalidData;
491543
fn try_from(buffer: &'a [u8]) -> core::result::Result<Self, Self::Error> {
492544
if buffer.len() < <Self as crate::traits::MinSize<&[u8]>>::MIN_SIZE {
493-
return Err(crate::error::InvalidData("Slice is too short"));
545+
return Err(crate::error::InvalidData(crate::detail::common_err_strings::ERR_SLICE_TOO_SHORT));
494546
}
495547
if buffer[5] != VERSION {
496548
return Err(crate::error::InvalidData("Incorrect CI version"));
@@ -550,6 +602,8 @@ pub fn generate_ci(attrs: TokenStream1, item: TokenStream1) -> TokenStream1 {
550602
let min_size_impl = min_size_impl(root_ident, &args);
551603
let new_impl = new_impl(root_ident, &properties);
552604
let try_new_impl = try_new_impl(root_ident, &properties);
605+
let new_with_buffer = new_with_buffer_impl(root_ident, &properties);
606+
let try_new_with_buffer = try_new_with_buffer_impl(root_ident, &properties);
553607
let ci_version_impls = ci_version_impls(root_ident, &args);
554608
let deref_sysex7_impl = deref_sysex7_impl(root_ident);
555609
let message_impl = message_impl(root_ident, &properties);
@@ -574,6 +628,8 @@ pub fn generate_ci(attrs: TokenStream1, item: TokenStream1) -> TokenStream1 {
574628
#ci_version_impls
575629
#rebuffer_from_impl
576630
#try_rebuffer_from_impl
631+
#new_with_buffer
632+
#try_new_with_buffer
577633
});
578634

579635
tokens.into()

midi2_proc/src/generate_message.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,66 @@ fn new_impl(
463463
}
464464
}
465465

466+
fn new_with_buffer_impl(
467+
root_ident: &syn::Ident,
468+
args: &GenerateMessageArgs,
469+
properties: &[Property],
470+
) -> TokenStream {
471+
let constraint = generic_buffer_constraint(args);
472+
let initialise_properties = initialise_property_statements(properties, quote! {B});
473+
quote! {
474+
impl<B: #constraint
475+
+ crate::buffer::BufferMut
476+
+ crate::buffer::BufferResize
477+
> #root_ident<B>
478+
{
479+
/// Create a new message backed by the provided resizable buffer.
480+
/// The provided buffer will be zeroed at initialization.
481+
pub fn new_with_buffer(mut buffer: B) -> #root_ident<B>
482+
{
483+
let buffer_ref_mut = &mut buffer;
484+
let sz = <Self as crate::traits::MinSize<B>>::MIN_SIZE;
485+
buffer_ref_mut.resize(sz);
486+
for b in &mut buffer_ref_mut.buffer_mut()[..sz] {
487+
*b = <<B as crate::buffer::Buffer>::Unit as crate::buffer::Unit>::zero();
488+
}
489+
#initialise_properties
490+
#root_ident::<B>(buffer)
491+
}
492+
}
493+
}
494+
}
495+
496+
fn try_new_with_buffer_impl(
497+
root_ident: &syn::Ident,
498+
args: &GenerateMessageArgs,
499+
properties: &[Property],
500+
) -> TokenStream {
501+
let constraint = generic_buffer_constraint(args);
502+
let initialise_properties = initialise_property_statements(properties, quote! {B});
503+
quote! {
504+
impl<B: #constraint
505+
+ crate::buffer::BufferMut
506+
+ crate::buffer::BufferTryResize
507+
> #root_ident<B>
508+
{
509+
/// Create a new message backed by the provided buffer.
510+
/// The provided buffer will be zeroed at initialization.
511+
pub fn try_new_with_buffer(mut buffer: B) -> Result<#root_ident<B>, crate::error::BufferOverflow>
512+
{
513+
let buffer_ref_mut = &mut buffer;
514+
let sz = <Self as crate::traits::MinSize<B>>::MIN_SIZE;
515+
buffer_ref_mut.try_resize(sz)?;
516+
for b in &mut buffer_ref_mut.buffer_mut()[..sz] {
517+
*b = <<B as crate::buffer::Buffer>::Unit as crate::buffer::Unit>::zero();
518+
}
519+
#initialise_properties
520+
Ok(#root_ident::<B>(buffer))
521+
}
522+
}
523+
}
524+
}
525+
466526
fn new_array_impl(
467527
root_ident: &syn::Ident,
468528
args: &GenerateMessageArgs,
@@ -732,6 +792,8 @@ pub fn generate_message(attrs: TokenStream1, item: TokenStream1) -> TokenStream1
732792
let rebuffer_from_impl = rebuffer_from_impl(root_ident, &args);
733793
let try_rebuffer_from_impl = try_rebuffer_from_impl(root_ident, &args);
734794
let new_impl = new_impl(root_ident, &args, &properties);
795+
let new_with_buffer_impl = new_with_buffer_impl(root_ident, &args, &properties);
796+
let try_new_with_buffer_impl = try_new_with_buffer_impl(root_ident, &args, &properties);
735797
let new_array_impl = new_array_impl(root_ident, &args, &properties);
736798
let try_new_impl = try_new_impl(root_ident, &args, &properties);
737799
let clone_impl = clone_impl(root_ident, &args);
@@ -749,6 +811,8 @@ pub fn generate_message(attrs: TokenStream1, item: TokenStream1) -> TokenStream1
749811
#rebuffer_from_impl
750812
#try_rebuffer_from_impl
751813
#new_impl
814+
#new_with_buffer_impl
815+
#try_new_with_buffer_impl
752816
#new_array_impl
753817
#try_new_impl
754818
#clone_impl

src/buffer.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,16 @@ impl<const SIZE: usize, U: Unit> BufferTryResize for [U; SIZE] {
228228
}
229229
}
230230

231+
impl<U: Unit> BufferTryResize for &mut [U] {
232+
fn try_resize(&mut self, size: usize) -> Result<(), BufferOverflow> {
233+
if size > self.len() {
234+
Err(BufferOverflow)
235+
} else {
236+
Ok(())
237+
}
238+
}
239+
}
240+
231241
#[cfg(any(feature = "std", test))]
232242
impl<U: Unit> Buffer for std::vec::Vec<U> {
233243
type Unit = U;
@@ -257,6 +267,28 @@ impl<U: Unit> BufferDefault for std::vec::Vec<U> {
257267
}
258268
}
259269

270+
#[cfg(any(feature = "std", test))]
271+
impl<U: Unit> Buffer for &mut std::vec::Vec<U> {
272+
type Unit = U;
273+
fn buffer(&self) -> &[Self::Unit] {
274+
self
275+
}
276+
}
277+
278+
#[cfg(any(feature = "std", test))]
279+
impl<U: Unit> BufferMut for &mut std::vec::Vec<U> {
280+
fn buffer_mut(&mut self) -> &mut [<Self as Buffer>::Unit] {
281+
self
282+
}
283+
}
284+
285+
#[cfg(any(feature = "std", test))]
286+
impl<U: Unit> BufferResize for &mut std::vec::Vec<U> {
287+
fn resize(&mut self, size: usize) {
288+
std::vec::Vec::resize(*self, size, U::zero());
289+
}
290+
}
291+
260292
pub(crate) const UNIT_ID_U8: u8 = 0;
261293
pub(crate) const UNIT_ID_U32: u8 = 1;
262294

src/channel_voice1.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ mod control_change;
77
mod key_pressure;
88
mod note_off;
99
mod note_on;
10+
mod packet;
1011
mod pitch_bend;
1112
mod program_change;
1213

@@ -15,6 +16,7 @@ pub use control_change::*;
1516
pub use key_pressure::*;
1617
pub use note_off::*;
1718
pub use note_on::*;
19+
pub use packet::Packet;
1820
pub use pitch_bend::*;
1921
pub use program_change::*;
2022

@@ -52,7 +54,9 @@ impl<'a, U: crate::buffer::Unit> core::convert::TryFrom<&'a [U]> for ChannelVoic
5254
type Error = crate::error::InvalidData;
5355
fn try_from(buffer: &'a [U]) -> Result<Self, Self::Error> {
5456
if buffer.is_empty() {
55-
return Err(crate::error::InvalidData("Slice is too short"));
57+
return Err(crate::error::InvalidData(
58+
crate::detail::common_err_strings::ERR_SLICE_TOO_SHORT,
59+
));
5660
};
5761
Ok(match status(buffer) {
5862
channel_pressure::STATUS => ChannelPressure::try_from(buffer)?.into(),
@@ -183,7 +187,7 @@ mod test {
183187
fn packets() {
184188
let message = ChannelVoice1::try_from(&[0x2FD6_0900_u32][..]).unwrap();
185189
let mut packets = message.packets();
186-
assert_eq!(packets.next(), Some(&[0x2FD6_0900_u32][..]));
190+
assert_eq!(&*packets.next().unwrap(), &[0x2FD6_0900_u32][..]);
187191
assert_eq!(packets.next(), None);
188192
}
189193

0 commit comments

Comments
 (0)