use std::iter::FromIterator;
#[derive(Clone, Debug)]
pub struct TransIter<F: FnMut(&T) -> I, I: IntoIterator<Item = T>, T> {
get_next: F,
queue: std::collections::VecDeque<T>,
mode: Mode,
}
impl<F: FnMut(&T) -> I, I: IntoIterator<Item = T>, T> TransIter<F, I, T> {
pub fn new(initial: T, recursion: F) -> Self {
Self {get_next: recursion, queue: std::iter::once(initial).collect(), mode: Default::default()}
}
pub fn new_multi(initial: impl IntoIterator<Item = T>, recursion: F) -> Self {
Self {get_next: recursion, queue: FromIterator::from_iter(initial), mode: Default::default()}
}
pub fn breadth_first(self) -> Self {
Self {mode: Mode::BreadthFirst, ..self}
}
pub fn depth_first(self) -> Self {
Self {mode: Mode::DepthFirst, ..self}
}
pub fn depth_first_unordered(self) -> Self {
Self {mode: Mode::DepthFirstUnordered, ..self}
}
pub fn into_trans_prio_queue(self) -> TransPrioQueue<F, I, T> where T: Ord {
TransPrioQueue::new_multi(self.queue, self.get_next)
}
}
impl<F: FnMut(&T) -> I, I: IntoIterator<Item = T>, T> Iterator for TransIter<F, I, T> {
type Item = T;
fn next(&mut self) -> Option<T> {
let res = self.queue.pop_front();
res.as_ref().map(&mut self.get_next).map(|items| match self.mode {
Mode::BreadthFirst => self.queue.extend(items),
Mode::DepthFirst => {
let mut items = Vec::from_iter(items);
self.queue.reserve(items.len());
while let Some(i) = items.pop() {
self.queue.push_front(i);
}
},
Mode::DepthFirstUnordered => {
let items = items.into_iter();
self.queue.reserve(items.size_hint().0);
items.for_each(|i| self.queue.push_front(i))
},
});
res
}
}
#[derive(Copy, Clone, Debug)]
enum Mode {
BreadthFirst,
DepthFirst,
DepthFirstUnordered,
}
impl Default for Mode {
fn default() -> Self {
Self::BreadthFirst
}
}
#[derive(Clone, Debug)]
pub struct TransPrioQueue<F: FnMut(&T) -> I, I: IntoIterator<Item = T>, T: Ord> {
get_next: F,
data: std::collections::BinaryHeap<T>,
}
impl<F: FnMut(&T) -> I, I: IntoIterator<Item = T>, T: Ord> TransPrioQueue<F, I, T> {
pub fn new(initial: T, recursion: F) -> Self {
Self {get_next: recursion, data: std::iter::once(initial).collect()}
}
pub fn new_multi(initial: impl IntoIterator<Item = T>, recursion: F) -> Self {
Self {get_next: recursion, data: FromIterator::from_iter(initial)}
}
}
impl<F: FnMut(&T) -> I, I: IntoIterator<Item = T>, T: Ord> Iterator for TransPrioQueue<F, I, T> {
type Item = T;
fn next(&mut self) -> Option<T> {
let res = self.data.pop();
res.as_ref().map(&mut self.get_next).map(|items| self.data.extend(items));
res
}
}
pub trait IntoTransIter<T> {
fn trans_iter_with<F: FnMut(&T) -> I, I: IntoIterator<Item = T>>(
self,
recursion: F
) -> TransIter<F, I, T>;
fn trans_prio_queue_with<F: FnMut(&T) -> I, I: IntoIterator<Item = T>>(
self,
recursion: F
) -> TransPrioQueue<F, I, T>
where Self: Sized,
T: Ord,
{
self.trans_iter_with(recursion).into_trans_prio_queue()
}
}
impl<T> IntoTransIter<T> for T {
fn trans_iter_with<F: FnMut(&T) -> I, I: IntoIterator<Item = T>>(
self,
recursion: F
) -> TransIter<F, I, T> {
TransIter::new(self, recursion)
}
}
pub trait AutoTransIter<T>: IntoTransIter<T> + Sized {
type RecIter: IntoIterator<Item = T>;
fn recurse(item: &T) -> Self::RecIter;
fn trans_iter(self) -> TransIter<fn(&T) -> Self::RecIter, Self::RecIter, T> {
self.trans_iter_with(Self::recurse)
}
fn trans_prio_queue(self) -> TransPrioQueue<fn(&T) -> Self::RecIter, Self::RecIter, T> where T: Ord {
self.trans_prio_queue_with(Self::recurse)
}
}
#[cfg(test)]
#[macro_use(quickcheck)]
extern crate quickcheck_macros;
#[cfg(test)]
mod tests;