use std::sync::Arc;
use std::iter::FromIterator;
use std::fmt;
use conslist::ConsList;
use shared::Shared;
pub struct Queue<A>(ConsList<A>, ConsList<A>);
impl<A> Queue<A> {
pub fn new() -> Self {
Queue(conslist![], conslist![])
}
pub fn from<R, I>(it: I) -> Queue<A>
where
I: IntoIterator<Item = R>,
R: Shared<A>,
{
it.into_iter().map(|a| a.shared()).collect()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty() && self.1.is_empty()
}
pub fn len(&self) -> usize {
self.0.len() + self.1.len()
}
pub fn push<R>(&self, v: R) -> Self
where
R: Shared<A>,
{
Queue(self.0.clone(), self.1.cons(v))
}
pub fn pop(&self) -> Option<(Arc<A>, Queue<A>)> {
match self {
&Queue(ref l, ref r) if l.is_empty() && r.is_empty() => None,
&Queue(ref l, ref r) => match l.uncons() {
None => Queue(r.reverse(), conslist![]).pop(),
Some((a, d)) => Some((a, Queue(d, r.clone()))),
},
}
}
pub fn iter(&self) -> Iter<A> {
Iter {
current: self.clone(),
}
}
}
impl<A> Clone for Queue<A> {
fn clone(&self) -> Self {
Queue(self.0.clone(), self.1.clone())
}
}
impl<A> fmt::Debug for Queue<A>
where
A: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
ConsList::<A>::from(self).fmt(f)
}
}
impl<A: PartialEq> PartialEq for Queue<A> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0 && self.1 == other.1
}
}
impl<A: Eq> Eq for Queue<A> {}
pub struct Iter<A> {
current: Queue<A>,
}
impl<A> Iterator for Iter<A> {
type Item = Arc<A>;
fn next(&mut self) -> Option<Self::Item> {
match self.current.pop() {
None => None,
Some((a, q)) => {
self.current = q;
Some(a)
}
}
}
}
impl<A> IntoIterator for Queue<A> {
type Item = Arc<A>;
type IntoIter = Iter<A>;
fn into_iter(self) -> Self::IntoIter {
Iter { current: self }
}
}
impl<'a, A> IntoIterator for &'a Queue<A> {
type Item = Arc<A>;
type IntoIter = Iter<A>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<A, T> FromIterator<T> for Queue<A>
where
T: Shared<A>,
{
fn from_iter<I>(source: I) -> Self
where
I: IntoIterator<Item = T>,
{
source.into_iter().fold(Queue::new(), |q, v| q.push(v))
}
}
impl<'a, A, T> From<&'a [T]> for Queue<A>
where
&'a T: Shared<A>,
{
fn from(slice: &'a [T]) -> Queue<A> {
slice.into_iter().collect()
}
}
impl<A, T> From<Vec<T>> for Queue<A>
where
T: Shared<A>,
{
fn from(vec: Vec<T>) -> Queue<A> {
vec.into_iter().collect()
}
}
impl<'a, A, T> From<&'a Vec<T>> for Queue<A>
where
&'a T: Shared<A>,
{
fn from(vec: &'a Vec<T>) -> Queue<A> {
vec.into_iter().collect()
}
}
#[cfg(any(test, feature = "quickcheck"))]
use quickcheck::{Arbitrary, Gen};
#[cfg(any(test, feature = "quickcheck"))]
impl<A: Arbitrary + Sync> Arbitrary for Queue<A> {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
Queue::from_iter(Vec::<A>::arbitrary(g))
}
}
#[cfg(any(test, feature = "proptest"))]
pub mod proptest {
use super::*;
use proptest::strategy::{BoxedStrategy, Strategy, ValueTree};
use std::ops::Range;
pub fn queue<T: Strategy + 'static>(
element: T,
size: Range<usize>,
) -> BoxedStrategy<Queue<<T::Value as ValueTree>::Value>> {
::proptest::collection::vec(element, size)
.prop_map(|v| Queue::from(v))
.boxed()
}
}
#[cfg(test)]
mod test {
use super::*;
use std::iter::FromIterator;
#[test]
fn general_consistency() {
let q = Queue::new().push(1).push(2).push(3).push(4).push(5).push(6);
assert_eq!(6, q.len());
let vec: Vec<i32> = vec![1, 2, 3, 4, 5, 6];
assert_eq!(vec, Vec::from_iter(q.iter().map(|a| *a)))
}
quickcheck! {
fn length(v: Vec<i32>) -> bool {
let q = Queue::from_iter(v.clone());
v.len() == q.len()
}
fn order(v: Vec<i32>) -> bool {
let q = Queue::from_iter(v.clone());
v == Vec::from_iter(q.iter().map(|a| *a))
}
}
}