use avr_oxide::concurrency::{interrupt, Isolated};
use avr_oxide::OxideResult;
use avr_oxide::sync::EventWait;
use avr_oxide::private::ringq;
use avr_oxide::OxideResult::{Ok,Err};
pub struct BinaryRingQ
{
length: u8,
items: u8,
blocked_consumers: EventWait
}
impl BinaryRingQ {
pub fn new() -> Self {
BinaryRingQ {
length: 0,
items: 0,
blocked_consumers: EventWait::new()
}
}
pub fn consume_blocking(&mut self) -> bool {
loop {
let value = interrupt::isolated(|_isotoken|{
if self.length == 0 {
None
} else {
let bit = (self.items & 0b1) as u8;
self.items >>= 1;
self.length -= 1;
Some(bit != 0)
}
});
match value {
None => {
self.blocked_consumers.wait();
},
Some(value) => {
return value;
}
}
}
}
pub fn append(&mut self, _isotoken: Isolated, element: bool) -> OxideResult<(),ringq::QueueError> {
if self.length >= 8 {
Err(ringq::QueueError::QueueFull)
} else {
if element {
let bit = 0b1u8 << self.length;
self.items |= bit;
}
self.length += 1;
self.blocked_consumers.release_one();
Ok(())
}
}
}
#[cfg(test)]
mod tests {
use avr_oxide::private::binaryringq::BinaryRingQ;
#[test]
fn test_binaryringq() {
let mut testq = BinaryRingQ::new();
avr_oxide::concurrency::interrupt::isolated(|isotoken|{
assert!(testq.append(isotoken, true).is_ok());
assert!(testq.append(isotoken, false).is_ok());
assert!(testq.append(isotoken, false).is_ok());
assert!(testq.append(isotoken, true).is_ok());
assert!(testq.append(isotoken, true).is_ok());
assert!(testq.append(isotoken, true).is_ok());
assert!(testq.append(isotoken, false).is_ok());
assert!(testq.append(isotoken, true).is_ok());
assert!(testq.append(isotoken, true).is_err());
assert_eq!(testq.consume_blocking(), true);
assert_eq!(testq.consume_blocking(), false);
assert_eq!(testq.consume_blocking(), false);
assert_eq!(testq.consume_blocking(), true);
assert_eq!(testq.consume_blocking(), true);
assert_eq!(testq.consume_blocking(), true);
assert_eq!(testq.consume_blocking(), false);
assert_eq!(testq.consume_blocking(), true);
});
}
}