Skip to content

Commit

Permalink
Merge branch 'release/0.5.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
Ben Leadbetter committed May 16, 2024
2 parents 7381b6f + 9ad26be commit bc08348
Show file tree
Hide file tree
Showing 81 changed files with 1,822 additions and 451 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -35,11 +35,12 @@ 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]
pretty_assertions = "1.4.0"

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
30 changes: 14 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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!** ⚠️

Expand All @@ -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));
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -182,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

Expand Down Expand Up @@ -226,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.
Expand All @@ -236,13 +235,13 @@ 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
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));

Expand All @@ -257,22 +256,21 @@ use midi2::{
channel_voice1::ChannelPressure,
};

let message = ChannelPressure::new_arr_bytes();
let message: ChannelPressure<[u32; 4]> = message.try_into_ump().
expect("Buffer is large enough");
let message = ChannelPressure::<[u8; 3]>::new();
let message: ChannelPressure<[u32; 4]> = message.into_ump();

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:

- `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 🚧
Expand Down
2 changes: 1 addition & 1 deletion midi2_proc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
7 changes: 7 additions & 0 deletions midi2_proc/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<BufferGeneric> {
Expand Down
50 changes: 50 additions & 0 deletions midi2_proc/src/derives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<B: crate::buffer::Ump> crate::Packets for #ident<B> {
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;
Expand Down Expand Up @@ -182,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<const SIZE: usize, #buffer_generic_type_param> 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;
Expand Down
Loading

0 comments on commit bc08348

Please sign in to comment.