use super::{Bar, BarExt};
use std::iter::FusedIterator;
#[cfg(feature = "rayon")]
use rayon::iter::{
IndexedParallelIterator, ParallelIterator,
plumbing::{Consumer, Folder, Producer, ProducerCallback, UnindexedConsumer},
};
#[cfg(feature = "rayon")]
use std::sync::{Arc, Mutex};
#[derive(Debug)]
pub struct BarIter<T> {
inner: T,
#[cfg(feature = "rayon")]
pb: Arc<Mutex<Bar>>,
#[cfg(not(feature = "rayon"))]
pb: Bar,
}
impl<T> BarIter<T> {
pub fn into_inner(self) -> T {
self.inner
}
}
impl<S, T: Iterator<Item = S>> Iterator for BarIter<T> {
type Item = S;
fn next(&mut self) -> Option<Self::Item> {
let item = self.inner.next();
if item.is_some() {
#[cfg(feature = "rayon")]
self.pb.lock().unwrap().update(1).unwrap();
#[cfg(not(feature = "rayon"))]
self.pb.update(1).unwrap();
} else {
#[cfg(feature = "rayon")]
self.pb.lock().unwrap().refresh().unwrap();
#[cfg(not(feature = "rayon"))]
self.pb.refresh().unwrap();
}
item
}
}
impl<T: DoubleEndedIterator> DoubleEndedIterator for BarIter<T> {
fn next_back(&mut self) -> Option<Self::Item> {
let item = self.inner.next();
if item.is_some() {
#[cfg(feature = "rayon")]
self.pb.lock().unwrap().update(1).unwrap();
#[cfg(not(feature = "rayon"))]
self.pb.update(1).unwrap();
} else {
#[cfg(feature = "rayon")]
self.pb.lock().unwrap().refresh().unwrap();
#[cfg(not(feature = "rayon"))]
self.pb.refresh().unwrap();
}
item
}
}
impl<T: FusedIterator> FusedIterator for BarIter<T> {}
impl<T: ExactSizeIterator> ExactSizeIterator for BarIter<T> {
fn len(&self) -> usize {
self.inner.len()
}
}
#[cfg(feature = "rayon")]
struct BarFolder<C> {
inner: C,
pb: Arc<Mutex<Bar>>,
}
#[cfg(feature = "rayon")]
impl<T, C: Folder<T>> Folder<T> for BarFolder<C> {
type Result = C::Result;
fn complete(self) -> Self::Result {
self.inner.complete()
}
fn consume(self, item: T) -> Self {
self.pb.lock().unwrap().update(1).unwrap();
Self {
inner: self.inner.consume(item),
pb: self.pb,
}
}
fn full(&self) -> bool {
self.inner.full()
}
}
#[cfg(feature = "rayon")]
struct BarConsumer<C> {
inner: C,
pb: Arc<Mutex<Bar>>,
}
#[cfg(feature = "rayon")]
impl<T, C: Consumer<T>> Consumer<T> for BarConsumer<C> {
type Folder = BarFolder<C::Folder>;
type Reducer = C::Reducer;
type Result = C::Result;
fn full(&self) -> bool {
self.inner.full()
}
fn into_folder(self) -> Self::Folder {
BarFolder {
inner: self.inner.into_folder(),
pb: self.pb,
}
}
fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
let (left, right, reducer) = self.inner.split_at(index);
(
Self {
inner: left,
pb: self.pb.clone(),
},
Self {
inner: right,
pb: self.pb,
},
reducer,
)
}
}
#[cfg(feature = "rayon")]
impl<T, C: UnindexedConsumer<T>> UnindexedConsumer<T> for BarConsumer<C> {
fn split_off_left(&self) -> Self {
Self {
inner: self.inner.split_off_left(),
pb: self.pb.clone(),
}
}
fn to_reducer(&self) -> Self::Reducer {
self.inner.to_reducer()
}
}
#[cfg(feature = "rayon")]
#[cfg_attr(docsrs, doc(cfg(feature = "rayon")))]
impl<S: Send, T: ParallelIterator<Item = S>> ParallelIterator for BarIter<T> {
type Item = S;
fn drive_unindexed<C>(self, consumer: C) -> C::Result
where
C: UnindexedConsumer<Self::Item>,
{
self.inner.drive_unindexed(BarConsumer {
inner: consumer,
pb: self.pb,
})
}
}
#[cfg(feature = "rayon")]
struct BarProducer<T> {
inner: T,
pb: Arc<Mutex<Bar>>,
}
#[cfg(feature = "rayon")]
impl<T, P: Producer<Item = T>> Producer for BarProducer<P> {
type IntoIter = BarIter<P::IntoIter>;
type Item = T;
fn into_iter(self) -> Self::IntoIter {
BarIter {
inner: self.inner.into_iter(),
pb: self.pb,
}
}
fn max_len(&self) -> usize {
self.inner.max_len()
}
fn min_len(&self) -> usize {
self.inner.min_len()
}
fn split_at(self, index: usize) -> (Self, Self) {
let (left, right) = self.inner.split_at(index);
(
Self {
inner: left,
pb: self.pb.clone(),
},
Self {
inner: right,
pb: self.pb,
},
)
}
}
#[cfg(feature = "rayon")]
#[cfg_attr(docsrs, doc(cfg(feature = "rayon")))]
impl<S: Send, T: IndexedParallelIterator<Item = S>> IndexedParallelIterator for BarIter<T> {
fn drive<C: Consumer<Self::Item>>(self, consumer: C) -> C::Result {
let consumer = BarConsumer {
inner: consumer,
pb: self.pb,
};
self.inner.drive(consumer)
}
fn len(&self) -> usize {
self.inner.len()
}
fn with_producer<CB: ProducerCallback<Self::Item>>(self, callback: CB) -> CB::Output {
return self.inner.with_producer(Callback {
inner: callback,
pb: self.pb,
});
struct Callback<CB> {
inner: CB,
pb: Arc<Mutex<Bar>>,
}
impl<T, CB: ProducerCallback<T>> ProducerCallback<T> for Callback<CB> {
type Output = CB::Output;
fn callback<P>(self, inner: P) -> CB::Output
where
P: Producer<Item = T>,
{
self.inner.callback(BarProducer { inner, pb: self.pb })
}
}
}
}
pub trait TqdmIterator
where
Self: Iterator + Sized,
{
fn tqdm(self) -> BarIter<Self> {
Self::tqdm_with_bar(self, Bar::default())
}
fn tqdm_with_bar(self, pb: Bar) -> BarIter<Self>;
}
impl<S, T: Iterator<Item = S>> TqdmIterator for T {
fn tqdm_with_bar(self, mut pb: Bar) -> BarIter<Self> {
if pb.indefinite() {
pb.total = self.size_hint().0;
}
BarIter {
inner: self,
#[cfg(feature = "rayon")]
pb: Arc::new(Mutex::new(pb)),
#[cfg(not(feature = "rayon"))]
pb,
}
}
}
#[cfg(feature = "rayon")]
pub trait TqdmParallelIterator
where
Self: ParallelIterator + Sized,
{
fn tqdm(self) -> BarIter<Self>
where
Self: IndexedParallelIterator,
{
Self::tqdm_with_bar(self, Bar::default())
}
fn tqdm_with_bar(self, pb: Bar) -> BarIter<Self>
where
Self: IndexedParallelIterator;
}
#[cfg(feature = "rayon")]
impl<S, T: ParallelIterator<Item = S>> TqdmParallelIterator for T {
fn tqdm_with_bar(self, mut pb: Bar) -> BarIter<Self>
where
Self: IndexedParallelIterator,
{
if pb.indefinite() {
pb.total = self.len();
}
BarIter {
inner: self,
#[cfg(feature = "rayon")]
pb: Arc::new(Mutex::new(pb)),
#[cfg(not(feature = "rayon"))]
pb,
}
}
}