pub struct UsingQueue<T> {
pending: Option<T>,
in_use: Vec<T>,
max_size: usize,
}
pub enum GetAction {
Take,
Clone,
}
impl<T> UsingQueue<T> {
pub fn new(max_size: usize) -> UsingQueue<T> {
UsingQueue {
pending: None,
in_use: vec![],
max_size,
}
}
pub fn peek_last_ref(&self) -> Option<&T> {
self.pending.as_ref().or(self.in_use.last())
}
pub fn use_last_ref(&mut self) -> Option<&T> {
if let Some(x) = self.pending.take() {
self.in_use.push(x);
if self.in_use.len() > self.max_size {
self.in_use.remove(0);
}
}
self.in_use.last()
}
pub fn set_pending(&mut self, b: T) {
self.pending = Some(b);
}
pub fn is_in_use(&self) -> bool { self.in_use.len() > 0 }
pub fn reset(&mut self) {
self.pending = None;
self.in_use.clear();
}
fn take_used_if<P>(&mut self, predicate: P) -> Option<T> where P: Fn(&T) -> bool {
self.in_use.iter().position(|r| predicate(r)).map(|i| self.in_use.remove(i))
}
fn clone_used_if<P>(&mut self, predicate: P) -> Option<T> where P: Fn(&T) -> bool, T: Clone {
self.in_use.iter().find(|r| predicate(r)).cloned()
}
pub fn get_used_if<P>(&mut self, action: GetAction, predicate: P) -> Option<T> where P: Fn(&T) -> bool, T: Clone {
match action {
GetAction::Take => self.take_used_if(predicate),
GetAction::Clone => self.clone_used_if(predicate),
}
}
pub fn get_pending_if<P>(&mut self, predicate: P) -> Option<T> where P: Fn(&T) -> bool, T: Clone {
if let Some(ref x) = self.pending {
if predicate(x) {
Some(x.clone())
} else {
None
}
} else {
self.in_use.last().into_iter().filter(|x| predicate(x)).next().cloned()
}
}
}
#[test]
fn should_not_find_when_pushed() {
let mut q = UsingQueue::new(2);
q.set_pending(1);
assert!(q.take_used_if(|i| i == &1).is_none());
}
#[test]
fn should_not_find_when_pushed_with_clone() {
let mut q = UsingQueue::new(2);
q.set_pending(1);
assert!(q.clone_used_if(|i| i == &1).is_none());
}
#[test]
fn should_find_when_pushed_and_used() {
let mut q = UsingQueue::new(2);
q.set_pending(1);
q.use_last_ref();
assert!(q.take_used_if(|i| i == &1).unwrap() == 1);
}
#[test]
fn should_have_same_semantics_for_get_take_clone() {
let mut q = UsingQueue::new(2);
q.set_pending(1);
assert!(q.get_used_if(GetAction::Clone, |i| i == &1).is_none());
assert!(q.get_used_if(GetAction::Take, |i| i == &1).is_none());
q.use_last_ref();
assert!(q.get_used_if(GetAction::Clone, |i| i == &1).unwrap() == 1);
assert!(q.get_used_if(GetAction::Clone, |i| i == &1).unwrap() == 1);
assert!(q.get_used_if(GetAction::Take, |i| i == &1).unwrap() == 1);
assert!(q.get_used_if(GetAction::Clone, |i| i == &1).is_none());
assert!(q.get_used_if(GetAction::Take, |i| i == &1).is_none());
}
#[test]
fn should_find_when_pushed_and_used_with_clone() {
let mut q = UsingQueue::new(2);
q.set_pending(1);
q.use_last_ref();
assert!(q.clone_used_if(|i| i == &1).unwrap() == 1);
}
#[test]
fn should_not_find_again_when_pushed_and_taken() {
let mut q = UsingQueue::new(2);
q.set_pending(1);
q.use_last_ref();
assert!(q.take_used_if(|i| i == &1).unwrap() == 1);
assert!(q.clone_used_if(|i| i == &1).is_none());
}
#[test]
fn should_find_again_when_pushed_and_cloned() {
let mut q = UsingQueue::new(2);
q.set_pending(1);
q.use_last_ref();
assert!(q.clone_used_if(|i| i == &1).unwrap() == 1);
assert!(q.clone_used_if(|i| i == &1).unwrap() == 1);
assert!(q.take_used_if(|i| i == &1).unwrap() == 1);
}
#[test]
fn should_find_when_others_used() {
let mut q = UsingQueue::new(2);
q.set_pending(1);
q.use_last_ref();
q.set_pending(2);
q.use_last_ref();
assert!(q.take_used_if(|i| i == &1).is_some());
}
#[test]
fn should_not_find_when_too_many_used() {
let mut q = UsingQueue::new(1);
q.set_pending(1);
q.use_last_ref();
q.set_pending(2);
q.use_last_ref();
assert!(q.take_used_if(|i| i == &1).is_none());
}
#[test]
fn should_not_find_when_not_used_and_then_pushed() {
let mut q = UsingQueue::new(3);
q.set_pending(1);
q.set_pending(2);
q.use_last_ref();
assert!(q.take_used_if(|i| i == &1).is_none());
}
#[test]
fn should_peek_correctly_after_push() {
let mut q = UsingQueue::new(3);
q.set_pending(1);
assert_eq!(q.peek_last_ref(), Some(&1));
q.set_pending(2);
assert_eq!(q.peek_last_ref(), Some(&2));
}
#[test]
fn should_inspect_correctly() {
let mut q = UsingQueue::new(3);
q.set_pending(1);
assert_eq!(q.use_last_ref(), Some(&1));
assert_eq!(q.peek_last_ref(), Some(&1));
q.set_pending(2);
assert_eq!(q.use_last_ref(), Some(&2));
assert_eq!(q.peek_last_ref(), Some(&2));
}
#[test]
fn should_not_find_when_not_used_peeked_and_then_pushed() {
let mut q = UsingQueue::new(3);
q.set_pending(1);
q.peek_last_ref();
q.set_pending(2);
q.use_last_ref();
assert!(q.take_used_if(|i| i == &1).is_none());
}
#[test]
fn should_pop_used() {
let mut q = UsingQueue::new(3);
q.set_pending(1);
q.use_last_ref();
let popped = q.get_pending_if(|i| i == &1);
assert_eq!(popped, Some(1));
}
#[test]
fn should_not_pop_last_pending() {
let mut q = UsingQueue::new(3);
q.set_pending(1);
assert_eq!(q.get_pending_if(|i| i == &1), Some(1));
assert_eq!(q.get_pending_if(|i| i == &1), Some(1));
}
#[test]
fn should_not_pop_unused_before_used() {
let mut q = UsingQueue::new(3);
q.set_pending(1);
q.set_pending(2);
let popped = q.get_pending_if(|i| i == &1);
assert_eq!(popped, None);
}
#[test]
fn should_not_remove_used_popped() {
let mut q = UsingQueue::new(3);
q.set_pending(1);
q.use_last_ref();
assert_eq!(q.get_pending_if(|i| i == &1), Some(1));
assert_eq!(q.get_pending_if(|i| i == &1), Some(1));
}