use core::ops::{Sub, SubAssign};
use avr_oxide::alloc::vec::Vec;
use avr_oxide::alloc::boxed::Box;
pub trait Floored {
fn floor() -> Self;
}
#[derive(Copy,Clone,PartialEq,Eq)]
pub struct DelayQueueHandle(usize);
pub trait DelayQueue<C,T>
where
C: Sub + SubAssign + Eq + Ord + Copy + Floored
{
fn insert_at(&mut self, position: C, item: T) -> DelayQueueHandle;
fn remove(&mut self, cancel_handle: DelayQueueHandle) -> bool;
fn decrement(&mut self, by: C);
fn consume_next_ready(&mut self) -> Option<T>;
}
pub struct SimpleDelayQueue<C,T>
where
C: Sub + SubAssign + Eq + Ord + Copy + Floored
{
first: Option<Box<SimpleDelayQueueElement<C,T>>>,
ready: Vec<T>
}
pub struct SimpleDelayQueueElement<C,T> {
counter: C,
contains: T,
next: Option<Box<Self>>
}
impl Floored for u8 {
fn floor() -> Self {
0u8
}
}
impl Floored for u16 {
fn floor() -> Self {
0u16
}
}
impl Floored for u32 {
fn floor() -> Self {
0u32
}
}
impl<C,T> SimpleDelayQueue<C,T>
where
C: Sub + SubAssign + Eq + Ord + Copy + Floored
{
pub fn new() -> Self {
SimpleDelayQueue {
first: Option::None,
ready: Vec::new()
}
}
fn move_ready(&mut self) {
loop {
match &self.first {
None => break,
Some(element) => {
if element.counter != C::floor() {
break;
}
}
};
let content = match self.first.take() {
None => avr_oxide::oserror::halt(avr_oxide::oserror::OsError::InternalError),
Some(node) => {
self.first = node.next;
node.contains
}
};
self.ready.push(content);
}
}
}
impl<C,T> DelayQueue<C,T> for SimpleDelayQueue<C,T>
where
C: Sub + SubAssign + Eq + Ord + Copy + Floored
{
fn insert_at(&mut self, mut position: C, item: T) -> DelayQueueHandle {
let mut insert_at = &mut self.first as *mut Option<Box<SimpleDelayQueueElement<C,T>>>;
loop {
unsafe {
match &mut *insert_at {
None => {
break;
},
Some(some_element) => {
if position < some_element.counter {
some_element.counter -= position;
break;
} else {
position -= some_element.counter;
}
insert_at = &mut some_element.next as *mut Option<Box<SimpleDelayQueueElement<C,T>>>;
}
}
};
}
unsafe {
let new_element = Box::new(SimpleDelayQueueElement {
counter: position,
contains: item,
next: core::mem::replace(&mut *insert_at, Option::None)
});
let dqhandle = DelayQueueHandle(&*new_element as *const SimpleDelayQueueElement<C,T> as usize);
(&mut *insert_at).replace(new_element);
dqhandle
}
}
fn remove(&mut self, cancel_handle: DelayQueueHandle) -> bool {
let mut candidate = &mut self.first as *mut Option<Box<SimpleDelayQueueElement<C,T>>>;
loop {
unsafe {
match &mut *candidate {
None => {
return false;
},
Some(some_element) => {
let candidate_handle = DelayQueueHandle(&**some_element as *const SimpleDelayQueueElement<C,T> as usize);
if candidate_handle == cancel_handle {
break;
} else {
candidate = &mut some_element.next as *mut Option<Box<SimpleDelayQueueElement<C,T>>>;
}
}
}
}
}
unsafe {
match (&mut *candidate).take() {
None => {
avr_oxide::oserror::halt(avr_oxide::oserror::OsError::InternalError);
},
Some(instance) => {
let _none = core::mem::replace(&mut *candidate, instance.next);
}
}
}
true
}
#[optimize(speed)]
fn decrement(&mut self, mut by: C) {
while by > C::floor() {
match &mut self.first {
None => break,
Some(element) => {
if element.counter > by {
element.counter -= by;
by = C::floor(); } else {
by -= element.counter;
element.counter = C::floor();
}
}
}
self.move_ready();
}
}
#[optimize(speed)]
fn consume_next_ready(&mut self) -> Option<T> {
self.ready.pop()
}
}
#[cfg(test)]
mod tests {
use std::string::String;
#[allow(unused_imports)]
use super::*;
#[test]
fn delay_queue_ordered() {
let mut queue = SimpleDelayQueue::<u16,&str>::new();
queue.insert_at(1, "First");
queue.insert_at(16, "Second");
queue.insert_at(17, "Third");
queue.insert_at(24, "Fourth");
queue.insert_at(39, "Fifth");
queue.insert_at(42, "Sixth");
assert_eq!(queue.consume_next_ready(), Option::None);
assert_eq!(queue.consume_next_ready(), Option::None);
queue.decrement(1);
assert_eq!(queue.consume_next_ready(), Option::Some("First"));
assert_eq!(queue.consume_next_ready(), Option::None);
for _i in 0..14 {
queue.decrement(1);
assert_eq!(queue.consume_next_ready(), Option::None);
}
queue.decrement(1);
assert_eq!(queue.consume_next_ready(), Option::Some("Second"));
assert_eq!(queue.consume_next_ready(), Option::None);
queue.decrement(1);
assert_eq!(queue.consume_next_ready(), Option::Some("Third"));
assert_eq!(queue.consume_next_ready(), Option::None);
for _i in 0..50 {
queue.decrement(1);
}
assert_eq!(queue.consume_next_ready(), Option::Some("Sixth"));
assert_eq!(queue.consume_next_ready(), Option::Some("Fifth"));
assert_eq!(queue.consume_next_ready(), Option::Some("Fourth"));
assert_eq!(queue.consume_next_ready(), Option::None);
}
#[test]
fn delay_queue_out_of_order() {
let mut queue = SimpleDelayQueue::<u16,&str>::new();
queue.insert_at(24, "Fourth");
queue.insert_at(42, "Sixth");
queue.insert_at(17, "Third");
queue.insert_at(1, "First");
queue.insert_at(16, "Second");
queue.insert_at(39, "Fifth");
assert_eq!(queue.consume_next_ready(), Option::None);
assert_eq!(queue.consume_next_ready(), Option::None);
queue.decrement(1);
assert_eq!(queue.consume_next_ready(), Option::Some("First"));
assert_eq!(queue.consume_next_ready(), Option::None);
for _i in 0..14 {
queue.decrement(1);
assert_eq!(queue.consume_next_ready(), Option::None);
}
queue.decrement(1);
assert_eq!(queue.consume_next_ready(), Option::Some("Second"));
assert_eq!(queue.consume_next_ready(), Option::None);
queue.decrement(1);
assert_eq!(queue.consume_next_ready(), Option::Some("Third"));
assert_eq!(queue.consume_next_ready(), Option::None);
for _i in 0..50 {
queue.decrement(1);
}
assert_eq!(queue.consume_next_ready(), Option::Some("Sixth"));
assert_eq!(queue.consume_next_ready(), Option::Some("Fifth"));
assert_eq!(queue.consume_next_ready(), Option::Some("Fourth"));
assert_eq!(queue.consume_next_ready(), Option::None);
}
#[test]
fn delay_queue_large_decrement() {
let mut queue = SimpleDelayQueue::<u16,&str>::new();
queue.insert_at(24, "Fourth");
queue.insert_at(42, "Sixth");
queue.insert_at(17, "Third");
queue.insert_at(1, "First");
queue.insert_at(16, "Second");
queue.insert_at(39, "Fifth");
queue.decrement(17);
assert_eq!(queue.consume_next_ready(), Option::Some("Third"));
assert_eq!(queue.consume_next_ready(), Option::Some("Second"));
assert_eq!(queue.consume_next_ready(), Option::Some("First"));
assert_eq!(queue.consume_next_ready(), Option::None);
queue.decrement(17);
assert_eq!(queue.consume_next_ready(), Option::Some("Fourth"));
assert_eq!(queue.consume_next_ready(), Option::None);
queue.decrement(17);
assert_eq!(queue.consume_next_ready(), Option::Some("Sixth"));
assert_eq!(queue.consume_next_ready(), Option::Some("Fifth"));
assert_eq!(queue.consume_next_ready(), Option::None);
queue.decrement(17);
assert_eq!(queue.consume_next_ready(), Option::None);
}
#[test]
fn delay_queue_remove() {
let mut queue = SimpleDelayQueue::<u16,&str>::new();
queue.insert_at(24, "Fourth");
let sixth = queue.insert_at(42, "Sixth");
let third = queue.insert_at(17, "Third");
let first = queue.insert_at(1, "First");
queue.insert_at(16, "Second");
queue.insert_at(39, "Fifth");
assert_eq!(queue.remove(first), true);
assert_eq!(queue.remove(sixth), true);
assert_eq!(queue.remove(sixth), false);
queue.decrement(17);
assert_eq!(queue.consume_next_ready(), Option::Some("Third"));
assert_eq!(queue.consume_next_ready(), Option::Some("Second"));
assert_eq!(queue.consume_next_ready(), Option::None);
assert_eq!(queue.remove(third), false);
queue.decrement(17);
assert_eq!(queue.consume_next_ready(), Option::Some("Fourth"));
assert_eq!(queue.consume_next_ready(), Option::None);
queue.decrement(17);
assert_eq!(queue.consume_next_ready(), Option::Some("Fifth"));
assert_eq!(queue.consume_next_ready(), Option::None);
queue.decrement(17);
assert_eq!(queue.consume_next_ready(), Option::None);
}
}