Skip to content

Commit 909c6e1

Browse files
committed
feat: extend sysex api
Add methods to the Sysex trait to allow fine grained manipulation of the payload data. For example, allow setting bytes and inserting data
1 parent f196aac commit 909c6e1

File tree

4 files changed

+1652
-31
lines changed

4 files changed

+1652
-31
lines changed

midi2/src/detail/helpers.rs

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -89,15 +89,16 @@ pub fn validate_sysex_group_statuses<
8989
Ok(())
9090
}
9191

92-
pub fn try_set_sysex_data<
92+
pub fn try_insert_sysex_data<
9393
B: crate::buffer::Buffer + crate::buffer::BufferMut + crate::buffer::BufferTryResize,
9494
S: SysexInternal<B>,
9595
D: core::iter::Iterator<Item = <S as crate::traits::Sysex<B>>::Byte>,
9696
>(
9797
sysex: &mut S,
9898
data: D,
99+
before: usize,
99100
) -> core::result::Result<(), crate::error::BufferOverflow> {
100-
match detail::try_set_sysex_data(sysex, data, |s, sz| s.try_resize(sz)) {
101+
match detail::try_insert_sysex_data(sysex, data, |s, sz| s.try_resize(sz), before) {
101102
Err(e) => {
102103
// if the write failed we reset the message
103104
// back to zero data
@@ -110,25 +111,33 @@ pub fn try_set_sysex_data<
110111
}
111112
}
112113

113-
pub fn set_sysex_data<
114+
pub fn insert_sysex_data<
114115
B: crate::buffer::Buffer + crate::buffer::BufferMut + crate::buffer::BufferResize,
115116
S: SysexInternal<B>,
116117
D: core::iter::Iterator<Item = <S as crate::traits::Sysex<B>>::Byte>,
117118
>(
118119
sysex: &mut S,
119120
data: D,
121+
before: usize,
120122
) {
121-
detail::try_set_sysex_data(sysex, data, |s, sz| {
122-
s.resize(sz);
123-
Ok(())
124-
})
123+
detail::try_insert_sysex_data(
124+
sysex,
125+
data,
126+
|s, sz| {
127+
s.resize(sz);
128+
Ok(())
129+
},
130+
before,
131+
)
125132
.expect("Resizable buffers should not fail here")
126133
}
127134

128135
mod detail {
136+
use crate::error::BufferOverflow;
137+
129138
use super::*;
130139

131-
pub fn try_set_sysex_data<
140+
pub fn try_insert_sysex_data<
132141
B: crate::buffer::Buffer + crate::buffer::BufferMut,
133142
S: crate::traits::SysexInternal<B>,
134143
D: core::iter::Iterator<Item = <S as crate::traits::Sysex<B>>::Byte>,
@@ -137,8 +146,14 @@ mod detail {
137146
sysex: &mut S,
138147
data: D,
139148
resize: R,
149+
before: usize,
140150
) -> core::result::Result<(), crate::error::BufferOverflow> {
151+
// reformat first to ensure data is optimally filling the
152+
// underlying buffer
153+
sysex.compact();
154+
141155
// get an initial estimate for the size of the data
156+
let initial_size = sysex.payload_size();
142157
let mut running_data_size_estimate = match data.size_hint() {
143158
(_, Some(upper)) => upper,
144159
// not the optimal case - could lead to additional copying
@@ -149,45 +164,62 @@ mod detail {
149164
let mut data = data.peekable();
150165

151166
// initial buffer resize
152-
if let Err(SysexTryResizeError(sz)) = resize(sysex, running_data_size_estimate) {
167+
if let Err(SysexTryResizeError(sz)) =
168+
resize(sysex, running_data_size_estimate + initial_size)
169+
{
153170
// failed. we'll work with what we've got
154-
running_data_size_estimate = sz;
171+
running_data_size_estimate = sz.saturating_sub(initial_size);
155172
};
156173

174+
debug_assert_eq!(
175+
sysex.payload_size(),
176+
running_data_size_estimate + initial_size
177+
);
178+
179+
let mut tail = before + running_data_size_estimate;
180+
sysex.move_payload_tail(before, tail);
181+
157182
'main: loop {
158183
while written < running_data_size_estimate {
159184
match data.next() {
160185
Some(v) => {
161-
sysex.write_datum(v, written);
186+
sysex.write_datum(v, before + written);
162187
written += 1;
163188
}
164189
None => {
165190
break 'main;
166191
}
167192
}
168193
}
169-
assert_eq!(written, running_data_size_estimate);
194+
debug_assert_eq!(written, running_data_size_estimate);
195+
196+
if data.peek().is_none() {
197+
// done
198+
break;
199+
}
170200

171201
// we underestimated.
172202
// resize to make more space
173203
running_data_size_estimate += additional_size_for_overflow;
204+
if let Err(SysexTryResizeError(sz)) =
205+
resize(sysex, running_data_size_estimate + initial_size)
206+
{
207+
// failed. we'll work with what we've got
208+
running_data_size_estimate = sz.saturating_sub(initial_size);
209+
};
210+
sysex.move_payload_tail(tail, before + running_data_size_estimate);
211+
tail = before + running_data_size_estimate;
174212
additional_size_for_overflow *= 2;
175213

176-
if data.peek().is_some() {
177-
if let Err(SysexTryResizeError(sz)) = resize(sysex, running_data_size_estimate) {
178-
// failed. we'll work with what we've got
179-
running_data_size_estimate = sz;
180-
};
181-
}
182-
183214
if written >= running_data_size_estimate {
184-
return Err(Default::default());
215+
return Err(BufferOverflow);
185216
}
186217
}
187218

188219
if written < running_data_size_estimate {
189220
// we shrink the buffer back down to the correct size
190-
resize(sysex, written).map_err(|_| crate::error::BufferOverflow)?;
221+
sysex.move_payload_tail(tail, before + written);
222+
resize(sysex, written + initial_size).map_err(|_| crate::error::BufferOverflow)?;
191223
}
192224

193225
Ok(())

0 commit comments

Comments
 (0)