use crate::traits::{SysexInternal, SysexTryResizeError};
#[cfg(any(feature = "sysex7", feature = "sysex8", feature = "flex-data"))]
pub fn group_from_packet(p: &[u32]) -> crate::ux::u4 {
use crate::detail::BitOps;
p[0].nibble(1)
}
pub const ERR_INCONSISTENT_GROUPS: &str = "Inconsistent groups across packets";
#[cfg(any(feature = "sysex7", feature = "sysex8", feature = "flex-data"))]
pub fn sysex_group_consistent_groups(
buffer: &[u32],
stride: usize,
ump_type: crate::ux::u4,
) -> Result<(), crate::error::InvalidData> {
use crate::detail::BitOps;
use group_from_packet as gfp;
if buffer
.chunks_exact(stride)
.take_while(|chunk| chunk[0].nibble(0) == ump_type)
.all(|chunk| gfp(chunk) == gfp(buffer))
{
Ok(())
} else {
Err(crate::error::InvalidData(ERR_INCONSISTENT_GROUPS))
}
}
pub const ERR_SYSEX_EXPECTED_COMPLETE: &str = "Expected Complete packet";
pub const ERR_SYSEX_EXPECTED_BEGIN: &str = "Expected Begin packet";
pub const ERR_SYSEX_EXPECTED_CONTINUE: &str = "Expected Continue packet";
pub const ERR_SYSEX_EXPECTED_END: &str = "Expected End packet";
pub const ERR_EMPTY_MESSAGE: &str = "The message buffer is empty";
#[cfg(any(
feature = "sysex7",
feature = "sysex8",
feature = "flex-data",
feature = "ump-stream"
))]
pub fn validate_sysex_group_statuses<
IsComplete: Fn(&[u32]) -> bool,
IsBegin: Fn(&[u32]) -> bool,
IsContinue: Fn(&[u32]) -> bool,
IsEnd: Fn(&[u32]) -> bool,
>(
buffer: &[u32],
is_complete: IsComplete,
is_begin: IsBegin,
is_continue: IsContinue,
is_end: IsEnd,
stride: usize,
ump_type: crate::ux::u4,
) -> Result<(), crate::error::InvalidData> {
use crate::{detail::BitOps, error::InvalidData};
let mut iter = buffer
.chunks(stride)
.take_while(|chunk| chunk[0].nibble(0) == ump_type)
.peekable();
let Some(first_packet) = iter.next() else {
return Err(InvalidData(ERR_EMPTY_MESSAGE));
};
if iter.peek().is_none() {
if is_complete(first_packet) {
return Ok(());
} else {
return Err(InvalidData(ERR_SYSEX_EXPECTED_COMPLETE));
}
}
if !is_begin(first_packet) {
return Err(InvalidData(ERR_SYSEX_EXPECTED_BEGIN));
}
while let Some(chunk) = iter.next() {
if iter.peek().is_some() && !is_continue(chunk) {
return Err(InvalidData(ERR_SYSEX_EXPECTED_CONTINUE));
}
if iter.peek().is_none() && !is_end(chunk) {
return Err(InvalidData(ERR_SYSEX_EXPECTED_END));
}
}
Ok(())
}
pub fn try_splice_sysex_data<
B: crate::buffer::Buffer + crate::buffer::BufferMut + crate::buffer::BufferTryResize,
S: SysexInternal<B>,
D: core::iter::Iterator<Item = <S as crate::traits::Sysex<B>>::Byte>,
R: core::ops::RangeBounds<usize>,
>(
sysex: &mut S,
data: D,
range: R,
) -> core::result::Result<(), crate::error::BufferOverflow> {
match detail::try_splice_sysex_data(sysex, data, |s, sz| s.try_resize(sz), range) {
Err(e) => {
sysex
.try_resize(0)
.map_err(|_| crate::error::BufferOverflow)?;
Err(e)
}
Ok(()) => Ok(()),
}
}
pub fn splice_sysex_data<
B: crate::buffer::Buffer + crate::buffer::BufferMut + crate::buffer::BufferResize,
S: SysexInternal<B>,
D: core::iter::Iterator<Item = <S as crate::traits::Sysex<B>>::Byte>,
R: core::ops::RangeBounds<usize>,
>(
sysex: &mut S,
data: D,
range: R,
) {
detail::try_splice_sysex_data(
sysex,
data,
|s, sz| {
s.resize(sz);
Ok(())
},
range,
)
.expect("Resizable buffers should not fail here")
}
mod detail {
use crate::error::BufferOverflow;
use super::*;
pub fn try_splice_sysex_data<
B: crate::buffer::Buffer + crate::buffer::BufferMut,
S: crate::traits::SysexInternal<B>,
D: core::iter::Iterator<Item = <S as crate::traits::Sysex<B>>::Byte>,
R: Fn(&mut S, usize) -> core::result::Result<(), SysexTryResizeError>,
Rg: core::ops::RangeBounds<usize>,
>(
sysex: &mut S,
data: D,
resize: R,
range: Rg,
) -> core::result::Result<(), crate::error::BufferOverflow> {
sysex.compact();
let initial_size = sysex.payload_size();
let splice_begin = match range.start_bound() {
core::ops::Bound::Included(&v) => v,
core::ops::Bound::Excluded(&v) => v + 1,
core::ops::Bound::Unbounded => 0,
};
let splice_end = match range.end_bound() {
core::ops::Bound::Included(&v) => v + 1,
core::ops::Bound::Excluded(&v) => v,
core::ops::Bound::Unbounded => initial_size,
};
let splice_size = splice_end - splice_begin;
let mut running_data_size_estimate = match data.size_hint() {
(_, Some(upper)) => upper,
(lower, None) => lower,
};
let mut written = 0;
let mut additional_size_for_overflow = 1;
let mut data = data.peekable();
if splice_end < splice_end + running_data_size_estimate - splice_size {
if let Err(SysexTryResizeError(sz)) = resize(
sysex,
running_data_size_estimate + initial_size - splice_size,
) {
running_data_size_estimate = sz.saturating_sub(initial_size - splice_size);
};
}
let mut tail = splice_end + running_data_size_estimate - splice_size;
sysex.move_payload_tail(splice_end, tail);
'main: loop {
while written < running_data_size_estimate {
match data.next() {
Some(v) => {
sysex.write_datum(v, splice_begin + written);
written += 1;
}
None => {
break 'main;
}
}
}
debug_assert_eq!(written, running_data_size_estimate);
if data.peek().is_none() {
break;
}
running_data_size_estimate += additional_size_for_overflow;
{
let mut to = splice_begin + running_data_size_estimate;
if tail < to {
if let Err(SysexTryResizeError(sz)) = resize(
sysex,
running_data_size_estimate + initial_size - splice_size,
) {
running_data_size_estimate = sz.saturating_sub(initial_size - splice_size);
to = splice_begin + running_data_size_estimate - splice_size;
};
}
sysex.move_payload_tail(tail, to);
tail = splice_begin + running_data_size_estimate;
}
additional_size_for_overflow *= 2;
if written >= running_data_size_estimate {
return Err(BufferOverflow);
}
}
sysex.move_payload_tail(tail, splice_begin + written);
resize(sysex, written + initial_size - splice_size)
.map_err(|_| crate::error::BufferOverflow)?;
Ok(())
}
}