use super::midi::Event;
use alloc::boxed::Box;
const MIDI_QUEUE_SIZE: usize = 4096;
const MIDI_QUEUE_MASK: usize = 0xfff;
#[derive(Debug)]
pub struct MidiQueue {
items: Box<[Option<Event>; MIDI_QUEUE_SIZE]>,
given: usize,
taken: usize,
}
impl MidiQueue {
pub fn new() -> MidiQueue {
const INIT: Option<Event> = None;
MidiQueue {
items: Box::new([INIT; MIDI_QUEUE_SIZE]),
given: 0,
taken: 0,
}
}
pub fn push(&mut self, value: Event) -> bool {
let (given, taken) = (self.given, self.taken);
if given.wrapping_sub(taken) >= MIDI_QUEUE_SIZE {
return false;
}
let slot = given & MIDI_QUEUE_MASK;
self.items[slot] = Some(value);
self.given = given.wrapping_add(1);
true
}
pub fn peek(&self) -> Option<&Event> {
let (given, taken) = (self.given, self.taken);
if given == taken {
return None;
}
let slot = taken & MIDI_QUEUE_MASK;
self.items[slot].as_ref()
}
pub fn pop(&mut self) -> Option<Event> {
let (given, taken) = (self.given, self.taken);
if given == taken {
return None;
}
let slot = taken & MIDI_QUEUE_MASK;
let value = self.items[slot].take();
self.taken = taken.wrapping_add(1);
value
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::midi::Message;
fn example_event() -> Event {
Event {
msg: Message::note_on(0x3c, 0x7f, 0x6).unwrap(),
time: 10000,
}
}
#[test]
fn test_empty() {
let mut queue = MidiQueue::new();
assert!(queue.peek().is_none());
assert!(queue.pop().is_none());
}
#[test]
fn test_single() {
let mut queue = MidiQueue::new();
let event = example_event();
assert_eq!(queue.push(event.clone()), true);
assert_eq!(queue.peek().unwrap(), &event);
assert_eq!(&queue.pop().unwrap(), &event);
assert!(queue.peek().is_none());
assert!(queue.pop().is_none());
}
#[test]
fn test_mostly_empty() {
let mut queue = MidiQueue::new();
let event = example_event();
assert_eq!(queue.push(event.clone()), true);
assert_eq!(queue.push(event.clone()), true);
assert_eq!(queue.push(event.clone()), true);
assert_eq!(queue.peek().unwrap(), &event);
assert_eq!(&queue.pop().unwrap(), &event);
assert_eq!(queue.peek().unwrap(), &event);
assert_eq!(&queue.pop().unwrap(), &event);
assert_eq!(queue.peek().unwrap(), &event);
assert_eq!(&queue.pop().unwrap(), &event);
assert!(queue.peek().is_none());
assert!(queue.pop().is_none());
assert_eq!(queue.push(event.clone()), true);
assert_eq!(queue.peek().unwrap(), &event);
assert_eq!(&queue.pop().unwrap(), &event);
assert!(queue.peek().is_none());
assert!(queue.pop().is_none());
}
#[test]
fn test_mostly_full() {
let mut queue = MidiQueue::new();
let event = example_event();
for _ in 0..MIDI_QUEUE_SIZE - 3 {
assert_eq!(queue.push(event.clone()), true);
}
assert_eq!(queue.push(event.clone()), true);
assert_eq!(queue.push(event.clone()), true);
assert_eq!(queue.push(event.clone()), true);
assert_eq!(queue.push(event.clone()), false);
assert_eq!(queue.peek().unwrap(), &event);
assert_eq!(&queue.pop().unwrap(), &event);
assert_eq!(queue.push(event.clone()), true);
assert_eq!(queue.push(event.clone()), false);
for _ in 0..MIDI_QUEUE_SIZE {
assert_eq!(queue.peek().unwrap(), &event);
assert_eq!(&queue.pop().unwrap(), &event);
}
assert!(queue.peek().is_none());
assert!(queue.pop().is_none());
}
#[test]
fn test_usize_overflow() {
let mut queue = MidiQueue::new();
let event = example_event();
queue.given = usize::MAX - MIDI_QUEUE_SIZE;
queue.taken = usize::MAX - MIDI_QUEUE_SIZE;
const CHUNK: usize = 1000;
assert!(CHUNK < MIDI_QUEUE_SIZE);
for _ in 0..5 {
for _ in 0..CHUNK {
assert_eq!(queue.push(event.clone()), true);
}
for _ in 0..CHUNK {
assert_eq!(queue.peek().unwrap(), &event);
assert_eq!(&queue.pop().unwrap(), &event);
}
}
assert!(queue.peek().is_none());
assert!(queue.pop().is_none());
}
}