beamer_core/
sysex_pool.rs1pub struct SysExOutputPool {
11 buffers: Vec<Vec<u8>>,
13 lengths: Vec<usize>,
15 max_slots: usize,
17 max_buffer_size: usize,
19 next_slot: usize,
21 overflowed: bool,
23 #[cfg(feature = "sysex-heap-fallback")]
25 fallback: Vec<Vec<u8>>,
26}
27
28impl SysExOutputPool {
29 pub const DEFAULT_SLOTS: usize = 16;
31 pub const DEFAULT_BUFFER_SIZE: usize = 512;
33
34 pub fn new() -> Self {
36 Self::with_capacity(Self::DEFAULT_SLOTS, Self::DEFAULT_BUFFER_SIZE)
37 }
38
39 pub fn with_capacity(slots: usize, buffer_size: usize) -> Self {
43 let mut buffers = Vec::with_capacity(slots);
44 for _ in 0..slots {
45 buffers.push(vec![0u8; buffer_size]);
46 }
47 let lengths = vec![0usize; slots];
48
49 Self {
50 buffers,
51 lengths,
52 max_slots: slots,
53 max_buffer_size: buffer_size,
54 next_slot: 0,
55 overflowed: false,
56 #[cfg(feature = "sysex-heap-fallback")]
57 fallback: Vec::new(),
58 }
59 }
60
61 #[inline]
66 pub fn clear(&mut self) {
67 self.next_slot = 0;
68 self.overflowed = false;
69 }
70
71 pub fn allocate(&mut self, data: &[u8]) -> Option<(*const u8, usize)> {
80 if self.next_slot >= self.max_slots {
81 self.overflowed = true;
82
83 #[cfg(feature = "sysex-heap-fallback")]
84 {
85 let copy_len = data.len().min(self.max_buffer_size);
86 self.fallback.push(data[..copy_len].to_vec());
87 }
88
89 return None;
90 }
91
92 let slot = self.next_slot;
93 self.next_slot += 1;
94
95 let copy_len = data.len().min(self.max_buffer_size);
96 self.buffers[slot][..copy_len].copy_from_slice(&data[..copy_len]);
97 self.lengths[slot] = copy_len;
98
99 Some((self.buffers[slot].as_ptr(), copy_len))
100 }
101
102 pub fn allocate_slice(&mut self, data: &[u8]) -> Option<&[u8]> {
106 if self.next_slot >= self.max_slots {
107 self.overflowed = true;
108
109 #[cfg(feature = "sysex-heap-fallback")]
110 {
111 let copy_len = data.len().min(self.max_buffer_size);
112 self.fallback.push(data[..copy_len].to_vec());
113 }
114
115 return None;
116 }
117
118 let slot = self.next_slot;
119 self.next_slot += 1;
120
121 let copy_len = data.len().min(self.max_buffer_size);
122 self.buffers[slot][..copy_len].copy_from_slice(&data[..copy_len]);
123 self.lengths[slot] = copy_len;
124
125 Some(&self.buffers[slot][..copy_len])
126 }
127
128 #[inline]
130 pub fn has_overflowed(&self) -> bool {
131 self.overflowed
132 }
133
134 #[inline]
136 pub fn capacity(&self) -> usize {
137 self.max_slots
138 }
139
140 #[inline]
142 pub fn used(&self) -> usize {
143 self.next_slot
144 }
145
146 #[cfg(feature = "sysex-heap-fallback")]
148 #[inline]
149 pub fn has_fallback(&self) -> bool {
150 !self.fallback.is_empty()
151 }
152
153 #[cfg(feature = "sysex-heap-fallback")]
157 #[inline]
158 pub fn take_fallback(&mut self) -> Vec<Vec<u8>> {
159 std::mem::take(&mut self.fallback)
160 }
161}
162
163impl Default for SysExOutputPool {
164 fn default() -> Self {
165 Self::new()
166 }
167}
168
169#[cfg(test)]
170mod tests {
171 use super::*;
172
173 #[test]
174 fn test_new_pool() {
175 let pool = SysExOutputPool::new();
176 assert_eq!(pool.capacity(), SysExOutputPool::DEFAULT_SLOTS);
177 assert_eq!(pool.used(), 0);
178 assert!(!pool.has_overflowed());
179 }
180
181 #[test]
182 fn test_allocate() {
183 let mut pool = SysExOutputPool::with_capacity(2, 64);
184 let data = [0xF0, 0x41, 0x10, 0xF7];
185
186 let result = pool.allocate(&data);
187 assert!(result.is_some());
188 assert_eq!(pool.used(), 1);
189
190 let (ptr, len) = result.unwrap();
191 assert_eq!(len, 4);
192 let slice = unsafe { std::slice::from_raw_parts(ptr, len) };
193 assert_eq!(slice, &data);
194 }
195
196 #[test]
197 fn test_allocate_slice() {
198 let mut pool = SysExOutputPool::with_capacity(2, 64);
199 let data = [0xF0, 0x41, 0x10, 0xF7];
200
201 let result = pool.allocate_slice(&data);
202 assert!(result.is_some());
203 assert_eq!(result.unwrap(), &data);
204 assert_eq!(pool.used(), 1);
205 }
206
207 #[test]
208 fn test_overflow() {
209 let mut pool = SysExOutputPool::with_capacity(1, 64);
210 let data = [0xF0, 0xF7];
211
212 assert!(pool.allocate(&data).is_some());
213 assert!(!pool.has_overflowed());
214
215 assert!(pool.allocate(&data).is_none());
216 assert!(pool.has_overflowed());
217 }
218
219 #[test]
220 fn test_clear() {
221 let mut pool = SysExOutputPool::with_capacity(1, 64);
222 let data = [0xF0, 0xF7];
223
224 pool.allocate(&data);
225 pool.allocate(&data); assert!(pool.has_overflowed());
227 assert_eq!(pool.used(), 1);
228
229 pool.clear();
230 assert!(!pool.has_overflowed());
231 assert_eq!(pool.used(), 0);
232 }
233
234 #[test]
235 fn test_truncation() {
236 let mut pool = SysExOutputPool::with_capacity(1, 4);
237 let data = [0xF0, 0x41, 0x10, 0x42, 0x00, 0xF7]; let result = pool.allocate_slice(&data);
240 assert!(result.is_some());
241 assert_eq!(result.unwrap().len(), 4); }
243}