| @@ -4,4 +4,11 @@ version = "0.1.0" | |||
| authors = ["Bergmann89 <info@bergmann89.de>"] | |||
| edition = "2018" | |||
| [features] | |||
| default = [ "tokio-executor" ] | |||
| tokio-executor = [ "futures", "num_cpus", "tokio" ] | |||
| [dependencies] | |||
| futures = { version = "0.3", optional = true } | |||
| num_cpus = { version = "1.13", optional = true } | |||
| tokio = { version = "0.3", features = [ "macros", "rt-multi-thread" ], optional = true } | |||
| @@ -1,11 +1,11 @@ | |||
| use crate::{Executor, DefaultExecutor}; | |||
| pub trait Driver<D>: Sized | |||
| pub trait Driver<'a, D>: Sized | |||
| where D: Send, | |||
| { | |||
| fn exec_with<E>(self, executor: E) -> E::Result | |||
| where E: Executor<D>; | |||
| where E: Executor<'a, D>; | |||
| fn exec(self) -> <DefaultExecutor as Executor<D>>::Result | |||
| fn exec(self) -> <DefaultExecutor as Executor<'a, D>>::Result | |||
| { self.exec_with(DefaultExecutor::default()) } | |||
| } | |||
| @@ -2,22 +2,22 @@ use super::{ | |||
| Consumer, IndexedConsumer, Producer, IndexedProducer, Reducer, ProducerCallback, IndexedProducerCallback, | |||
| }; | |||
| pub trait Executor<D> | |||
| pub trait Executor<'a, D> | |||
| where D: Send, | |||
| { | |||
| type Result: Send; | |||
| fn exec<P, C, R>(self, producer: P, consumer: C) -> Self::Result | |||
| where | |||
| P: Producer, | |||
| C: Consumer<P::Item, Result = D, Reducer = R>, | |||
| R: Reducer<D>; | |||
| P: Producer + 'a, | |||
| C: Consumer<P::Item, Result = D, Reducer = R> + 'a, | |||
| R: Reducer<D> + Send; | |||
| fn exec_indexed<P, C, R>(self, producer: P, consumer: C) -> Self::Result | |||
| where | |||
| P: IndexedProducer, | |||
| C: IndexedConsumer<P::Item, Result = D, Reducer = R>, | |||
| R: Reducer<D>; | |||
| P: IndexedProducer + 'a, | |||
| C: IndexedConsumer<P::Item, Result = D, Reducer = R> + 'a, | |||
| R: Reducer<D> + Send; | |||
| } | |||
| pub struct ExecutorCallback<E, C> { | |||
| @@ -34,35 +34,35 @@ impl<E, C> ExecutorCallback<E, C> { | |||
| } | |||
| } | |||
| impl<E, D, C, I, R> ProducerCallback<I> for ExecutorCallback<E, C> | |||
| impl<'a, E, D, C, I, R> ProducerCallback<'a, I> for ExecutorCallback<E, C> | |||
| where | |||
| E: Executor<D>, | |||
| E: Executor<'a, D>, | |||
| D: Send, | |||
| C: Consumer<I, Result = D, Reducer = R>, | |||
| R: Reducer<D>, | |||
| C: Consumer<I, Result = D, Reducer = R> + 'a, | |||
| R: Reducer<D> + Send, | |||
| { | |||
| type Output = E::Result; | |||
| fn callback<P>(self, producer: P) -> Self::Output | |||
| where | |||
| P: Producer<Item = I> | |||
| P: Producer<Item = I> + 'a | |||
| { | |||
| self.executor.exec(producer, self.consumer) | |||
| } | |||
| } | |||
| impl<E, D, C, I, R> IndexedProducerCallback<I> for ExecutorCallback<E, C> | |||
| impl<'a, E, D, C, I, R> IndexedProducerCallback<'a, I> for ExecutorCallback<E, C> | |||
| where | |||
| E: Executor<D>, | |||
| E: Executor<'a, D>, | |||
| D: Send, | |||
| C: IndexedConsumer<I, Result = D, Reducer = R>, | |||
| R: Reducer<D>, | |||
| C: IndexedConsumer<I, Result = D, Reducer = R> + 'a, | |||
| R: Reducer<D> + Send, | |||
| { | |||
| type Output = E::Result; | |||
| fn callback<P>(self, producer: P) -> Self::Output | |||
| where | |||
| P: IndexedProducer<Item = I> | |||
| P: IndexedProducer<Item = I> + 'a | |||
| { | |||
| self.executor.exec_indexed(producer, self.consumer) | |||
| } | |||
| @@ -8,9 +8,9 @@ use super::ParallelIterator; | |||
| /// | |||
| /// [`ParallelIterator`]: trait.ParallelIterator.html | |||
| /// [`std::iter::IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html | |||
| pub trait IntoParallelIterator { | |||
| pub trait IntoParallelIterator<'a> { | |||
| /// The parallel iterator type that will be created. | |||
| type Iter: ParallelIterator<Item = Self::Item>; | |||
| type Iter: ParallelIterator<'a, Item = Self::Item>; | |||
| /// The type of item that the parallel iterator will produce. | |||
| type Item: Send; | |||
| @@ -53,13 +53,13 @@ pub trait IntoParallelIterator { | |||
| /// | |||
| /// [`ParallelIterator`]: trait.ParallelIterator.html | |||
| /// [`IntoParallelIterator`]: trait.IntoParallelIterator.html | |||
| pub trait IntoParallelRefIterator<'data> { | |||
| pub trait IntoParallelRefIterator<'a> { | |||
| /// The type of the parallel iterator that will be returned. | |||
| type Iter: ParallelIterator<Item = Self::Item>; | |||
| type Iter: ParallelIterator<'a, Item = Self::Item>; | |||
| /// The type of item that the parallel iterator will produce. | |||
| /// This will typically be an `&'data T` reference type. | |||
| type Item: Send + 'data; | |||
| /// This will typically be an `&'a T` reference type. | |||
| type Item: Send + 'a; | |||
| /// Converts `self` into a parallel iterator. | |||
| /// | |||
| @@ -76,7 +76,7 @@ pub trait IntoParallelRefIterator<'data> { | |||
| /// assert!(v.par_iter().zip(&v) | |||
| /// .all(|(a, b)| std::ptr::eq(a, b))); | |||
| /// ``` | |||
| fn par_iter(&'data self) -> Self::Iter; | |||
| fn par_iter(&'a self) -> Self::Iter; | |||
| } | |||
| /// `IntoParallelRefMutIterator` implements the conversion to a | |||
| @@ -92,13 +92,13 @@ pub trait IntoParallelRefIterator<'data> { | |||
| /// | |||
| /// [`ParallelIterator`]: trait.ParallelIterator.html | |||
| /// [`IntoParallelIterator`]: trait.IntoParallelIterator.html | |||
| pub trait IntoParallelRefMutIterator<'data> { | |||
| pub trait IntoParallelRefMutIterator<'a> { | |||
| /// The type of iterator that will be created. | |||
| type Iter: ParallelIterator<Item = Self::Item>; | |||
| type Iter: ParallelIterator<'a, Item = Self::Item>; | |||
| /// The type of item that will be produced; this is typically an | |||
| /// `&'data mut T` reference. | |||
| type Item: Send + 'data; | |||
| /// `&'a mut T` reference. | |||
| type Item: Send + 'a; | |||
| /// Creates the parallel iterator from `self`. | |||
| /// | |||
| @@ -111,10 +111,12 @@ pub trait IntoParallelRefMutIterator<'data> { | |||
| /// v.par_iter_mut().enumerate().for_each(|(i, x)| *x = i); | |||
| /// assert_eq!(v, [0, 1, 2, 3, 4]); | |||
| /// ``` | |||
| fn par_iter_mut(&'data mut self) -> Self::Iter; | |||
| fn par_iter_mut(&'a mut self) -> Self::Iter; | |||
| } | |||
| impl<T: ParallelIterator> IntoParallelIterator for T { | |||
| impl<'a, T> IntoParallelIterator<'a> for T | |||
| where T: ParallelIterator<'a> | |||
| { | |||
| type Iter = T; | |||
| type Item = T::Item; | |||
| @@ -123,26 +125,28 @@ impl<T: ParallelIterator> IntoParallelIterator for T { | |||
| } | |||
| } | |||
| impl<'data, I: 'data + ?Sized> IntoParallelRefIterator<'data> for I | |||
| impl<'a, I> IntoParallelRefIterator<'a> for I | |||
| where | |||
| &'data I: IntoParallelIterator, | |||
| I: 'a + ?Sized, | |||
| &'a I: IntoParallelIterator<'a>, | |||
| { | |||
| type Iter = <&'data I as IntoParallelIterator>::Iter; | |||
| type Item = <&'data I as IntoParallelIterator>::Item; | |||
| type Iter = <&'a I as IntoParallelIterator<'a>>::Iter; | |||
| type Item = <&'a I as IntoParallelIterator<'a>>::Item; | |||
| fn par_iter(&'data self) -> Self::Iter { | |||
| fn par_iter(&'a self) -> Self::Iter { | |||
| self.into_par_iter() | |||
| } | |||
| } | |||
| impl<'data, I: 'data + ?Sized> IntoParallelRefMutIterator<'data> for I | |||
| impl<'a, I> IntoParallelRefMutIterator<'a> for I | |||
| where | |||
| &'data mut I: IntoParallelIterator, | |||
| I: 'a + ?Sized, | |||
| &'a mut I: IntoParallelIterator<'a>, | |||
| { | |||
| type Iter = <&'data mut I as IntoParallelIterator>::Iter; | |||
| type Item = <&'data mut I as IntoParallelIterator>::Item; | |||
| type Iter = <&'a mut I as IntoParallelIterator<'a>>::Iter; | |||
| type Item = <&'a mut I as IntoParallelIterator<'a>>::Item; | |||
| fn par_iter_mut(&'data mut self) -> Self::Iter { | |||
| fn par_iter_mut(&'a mut self) -> Self::Iter { | |||
| self.into_par_iter() | |||
| } | |||
| } | |||
| @@ -16,7 +16,7 @@ use crate::inner::{for_each::ForEach, map::Map}; | |||
| /// | |||
| /// [iter]: index.html | |||
| /// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html | |||
| pub trait ParallelIterator: Sized + Send { | |||
| pub trait ParallelIterator<'a>: Sized + Send { | |||
| /// The type of item that this parallel iterator produces. | |||
| /// For example, if you use the [`for_each`] method, this is the type of | |||
| /// item that your closure will be invoked with. | |||
| @@ -38,10 +38,10 @@ pub trait ParallelIterator: Sized + Send { | |||
| /// [README]: README.md | |||
| fn drive<E, C, D, R>(self, executor: E, consumer: C) -> E::Result | |||
| where | |||
| E: Executor<D>, | |||
| C: Consumer<Self::Item, Result = D, Reducer = R>, | |||
| E: Executor<'a, D>, | |||
| C: Consumer<Self::Item, Result = D, Reducer = R> + 'a, | |||
| D: Send, | |||
| R: Reducer<D>; | |||
| R: Reducer<D> + Send; | |||
| /// Internal method used to define the behavior of this parallel | |||
| /// iterator. You should not need to call this directly. | |||
| @@ -60,7 +60,7 @@ pub trait ParallelIterator: Sized + Send { | |||
| /// [README]: README.md | |||
| fn with_producer<CB>(self, callback: CB) -> CB::Output | |||
| where | |||
| CB: ProducerCallback<Self::Item>; | |||
| CB: ProducerCallback<'a, Self::Item>; | |||
| /// Internal method used to define the behavior of this parallel | |||
| /// iterator. You should not need to call this directly. | |||
| @@ -124,7 +124,7 @@ pub trait ParallelIterator: Sized + Send { | |||
| /// those points. | |||
| /// | |||
| /// **Note:** Not implemented for `u64`, `i64`, `u128`, or `i128` ranges | |||
| pub trait IndexedParallelIterator: ParallelIterator { | |||
| pub trait IndexedParallelIterator<'a>: ParallelIterator<'a> { | |||
| /// Internal method used to define the behavior of this parallel | |||
| /// iterator. You should not need to call this directly. | |||
| /// | |||
| @@ -141,7 +141,7 @@ pub trait IndexedParallelIterator: ParallelIterator { | |||
| /// [README]: README.md | |||
| fn drive_indexed<E, C, D, R>(self, executor: E, consumer: C) -> E::Result | |||
| where | |||
| E: Executor<D>, | |||
| E: Executor<'a, D>, | |||
| C: IndexedConsumer<Self::Item, Result = D, Reducer = R>, | |||
| D: Send, | |||
| R: Reducer<D>; | |||
| @@ -163,7 +163,7 @@ pub trait IndexedParallelIterator: ParallelIterator { | |||
| /// [README]: README.md | |||
| fn with_producer_indexed<CB>(self, callback: CB) -> CB::Output | |||
| where | |||
| CB: IndexedProducerCallback<Self::Item>; | |||
| CB: IndexedProducerCallback<'a, Self::Item>; | |||
| /// Produces an exact count of how many items this iterator will | |||
| /// produce, presuming no panic occurs. | |||
| @@ -19,6 +19,11 @@ pub trait Producer: Send + Sized { | |||
| /// are possible. | |||
| fn into_iter(self) -> Self::IntoIter; | |||
| /// Number of splits/threads this iterator will use to proceed. | |||
| fn splits(&self) -> Option<usize> { | |||
| None | |||
| } | |||
| /// Split midway into a new producer if possible, otherwise return `None`. | |||
| fn split(self) -> (Self, Option<Self>); | |||
| @@ -58,6 +63,7 @@ pub trait Producer: Send + Sized { | |||
| /// | |||
| /// [r]: https://github.com/rayon-rs/rayon/blob/master/src/iter/plumbing/README.md | |||
| /// [20671]: https://github.com/rust-lang/rust/issues/20671 | |||
| #[allow(clippy::len_without_is_empty)] | |||
| pub trait IndexedProducer: Send + Sized { | |||
| /// The type of item that will be produced by this producer once | |||
| /// it is converted into an iterator. | |||
| @@ -70,6 +76,15 @@ pub trait IndexedProducer: Send + Sized { | |||
| /// are possible. | |||
| fn into_iter(self) -> Self::IntoIter; | |||
| /// Number of splits/threads this iterator will use to proceed. | |||
| fn splits(&self) -> Option<usize> { | |||
| None | |||
| } | |||
| /// Produces an exact count of how many items this producer will | |||
| /// emit, presuming no panic occurs. | |||
| fn len(&self) -> usize; | |||
| /// The minimum number of items that we will process | |||
| /// sequentially. Defaults to 1, which means that we will split | |||
| /// all the way down to a single item. This can be raised higher | |||
| @@ -80,8 +95,8 @@ pub trait IndexedProducer: Send + Sized { | |||
| /// needed. | |||
| /// | |||
| /// [`with_min_len`]: ../trait.IndexedParallelIterator.html#method.with_min_len | |||
| fn min_len(&self) -> usize { | |||
| 1 | |||
| fn min_len(&self) -> Option<usize> { | |||
| None | |||
| } | |||
| /// The maximum number of items that we will process | |||
| @@ -93,8 +108,8 @@ pub trait IndexedProducer: Send + Sized { | |||
| /// overhead, so this should not be needed. | |||
| /// | |||
| /// [`with_max_len`]: ../trait.IndexedParallelIterator.html#method.with_max_len | |||
| fn max_len(&self) -> usize { | |||
| usize::MAX | |||
| fn max_len(&self) -> Option<usize> { | |||
| None | |||
| } | |||
| /// Split into two producers; one produces items `0..index`, the | |||
| @@ -119,7 +134,7 @@ pub trait IndexedProducer: Send + Sized { | |||
| /// | |||
| /// [r]: https://github.com/rayon-rs/rayon/blob/master/src/iter/plumbing/README.md#producer-callback | |||
| /// [FnOnce]: https://doc.rust-lang.org/std/ops/trait.FnOnce.html | |||
| pub trait ProducerCallback<I> { | |||
| pub trait ProducerCallback<'p, I> { | |||
| /// The type of value returned by this callback. Analogous to | |||
| /// [`Output` from the `FnOnce` trait][Output]. | |||
| /// | |||
| @@ -131,7 +146,7 @@ pub trait ProducerCallback<I> { | |||
| /// `P`, and hence implementors must be defined for any producer. | |||
| fn callback<P>(self, producer: P) -> Self::Output | |||
| where | |||
| P: Producer<Item = I>; | |||
| P: Producer<Item = I> + 'p; | |||
| } | |||
| /// The `IndexedProducerCallback` trait is a kind of generic closure, | |||
| @@ -140,7 +155,7 @@ pub trait ProducerCallback<I> { | |||
| /// | |||
| /// [r]: https://github.com/rayon-rs/rayon/blob/master/src/iter/plumbing/README.md#producer-callback | |||
| /// [FnOnce]: https://doc.rust-lang.org/std/ops/trait.FnOnce.html | |||
| pub trait IndexedProducerCallback<I> { | |||
| pub trait IndexedProducerCallback<'p, I> { | |||
| /// The type of value returned by this callback. Analogous to | |||
| /// [`Output` from the `FnOnce` trait][Output]. | |||
| /// | |||
| @@ -152,5 +167,5 @@ pub trait IndexedProducerCallback<I> { | |||
| /// `P`, and hence implementors must be defined for any producer. | |||
| fn callback<P>(self, producer: P) -> Self::Output | |||
| where | |||
| P: IndexedProducer<Item = I>; | |||
| P: IndexedProducer<Item = I> + 'p; | |||
| } | |||
| @@ -1,5 +1,13 @@ | |||
| mod sequential; | |||
| #[cfg(feature = "tokio-executor")] | |||
| mod tokio; | |||
| pub use sequential::Sequential as SequentialExecutor; | |||
| #[cfg(feature = "tokio-executor")] | |||
| pub use self::tokio::Tokio as TokioExecutor; | |||
| #[cfg(feature = "tokio-executor")] | |||
| pub type DefaultExecutor = TokioExecutor; | |||
| #[cfg(not(feature = "tokio-executor"))] | |||
| pub type DefaultExecutor = SequentialExecutor; | |||
| @@ -6,15 +6,15 @@ use crate::core::{ | |||
| #[derive(Default)] | |||
| pub struct Sequential; | |||
| impl<D> Executor<D> for Sequential | |||
| impl<'a, D> Executor<'a, D> for Sequential | |||
| where D: Send, | |||
| { | |||
| type Result = D; | |||
| fn exec<P, C, R>(self, producer: P, consumer: C) -> Self::Result | |||
| where | |||
| P: Producer, | |||
| C: Consumer<P::Item, Result = D, Reducer = R>, | |||
| P: Producer + 'a, | |||
| C: Consumer<P::Item, Result = D, Reducer = R> + 'a, | |||
| R: Reducer<D>, | |||
| { | |||
| if consumer.is_full() { | |||
| @@ -0,0 +1,201 @@ | |||
| use std::mem::transmute; | |||
| use std::cmp; | |||
| use futures::{future::{Future, BoxFuture, FutureExt}, join}; | |||
| use tokio::task::{spawn}; | |||
| use crate::core::{ | |||
| Consumer, Executor, Folder, IndexedConsumer, IndexedProducer, Producer, Reducer, | |||
| }; | |||
| pub struct Tokio { | |||
| splits: usize, | |||
| } | |||
| impl Tokio { | |||
| pub fn new(splits: usize) -> Self { | |||
| Self { splits } | |||
| } | |||
| } | |||
| impl Default for Tokio { | |||
| fn default() -> Self { | |||
| Self { | |||
| splits: 2 * num_cpus::get() | |||
| } | |||
| } | |||
| } | |||
| impl<'a, D> Executor<'a, D> for Tokio | |||
| where D: Send, | |||
| { | |||
| type Result = BoxFuture<'a, D>; | |||
| fn exec<P, C, R>(self, producer: P, consumer: C) -> Self::Result | |||
| where | |||
| P: Producer + 'a, | |||
| C: Consumer<P::Item, Result = D, Reducer = R> + 'a, | |||
| R: Reducer<D> + Send, | |||
| { | |||
| let splits = producer.splits().unwrap_or(self.splits); | |||
| let splitter = Splitter::new(splits); | |||
| exec(splitter, producer, consumer) | |||
| } | |||
| fn exec_indexed<P, C, R>(self, producer: P, consumer: C) -> Self::Result | |||
| where | |||
| P: IndexedProducer + 'a, | |||
| C: IndexedConsumer<P::Item, Result = D, Reducer = R> + 'a, | |||
| R: Reducer<D> + Send, | |||
| { | |||
| let splits = producer.splits().unwrap_or(self.splits); | |||
| let splitter = IndexedSplitter::new(splits, producer.len(), producer.min_len(), producer.max_len()); | |||
| exec_indexed(splitter, producer, consumer) | |||
| } | |||
| } | |||
| fn exec<'a, P, C>(mut splitter: Splitter, producer: P, consumer: C) -> BoxFuture<'a, C::Result> | |||
| where | |||
| P: Producer + 'a, | |||
| C: Consumer<P::Item> + 'a, | |||
| C::Reducer: Send, | |||
| { | |||
| async move { | |||
| if consumer.is_full() { | |||
| consumer.into_folder().complete() | |||
| } else if splitter.try_split() { | |||
| match producer.split() { | |||
| (left_producer, Some(right_producer)) => { | |||
| let ((left_consumer, reducer), right_consumer) = | |||
| (consumer.split_off_left(), consumer); | |||
| let left = run_as_task(exec(splitter, left_producer, left_consumer)); | |||
| let right = run_as_task(exec(splitter, right_producer, right_consumer)); | |||
| let (left_result, right_result) = join!(left, right); | |||
| reducer.reduce(left_result, right_result) | |||
| } | |||
| (producer, None) => producer.fold_with(consumer.into_folder()).complete(), | |||
| } | |||
| } else { | |||
| producer.fold_with(consumer.into_folder()).complete() | |||
| } | |||
| } | |||
| .boxed() | |||
| } | |||
| fn exec_indexed<'a, P, C>(mut splitter: IndexedSplitter, producer: P, consumer: C) -> BoxFuture<'a, C::Result> | |||
| where | |||
| P: IndexedProducer + 'a, | |||
| C: IndexedConsumer<P::Item> + 'a, | |||
| C::Reducer: Send, | |||
| { | |||
| async move { | |||
| if consumer.is_full() { | |||
| consumer.into_folder().complete() | |||
| } else { | |||
| let len = producer.len(); | |||
| if splitter.try_split(len) { | |||
| let mid = len / 2; | |||
| let (left_producer, right_producer) = producer.split_at(mid); | |||
| let (left_consumer, right_consumer, reducer) = consumer.split_at(mid); | |||
| let left = run_as_task(exec_indexed(splitter, left_producer, left_consumer)); | |||
| let right = run_as_task(exec_indexed(splitter, right_producer, right_consumer)); | |||
| let (left_result, right_result) = join!(left, right); | |||
| reducer.reduce(left_result, right_result) | |||
| } else { | |||
| producer.fold_with(consumer.into_folder()).complete() | |||
| } | |||
| } | |||
| } | |||
| .boxed() | |||
| } | |||
| async fn run_as_task<'a, T, F>(f: F) -> T | |||
| where | |||
| T: Send + 'a, | |||
| F: Future<Output = T> + Send + 'a, | |||
| { | |||
| struct Pointer<T>(*mut T); | |||
| unsafe impl<T> Send for Pointer<T> {} | |||
| let mut result = None; | |||
| let r = Pointer(&mut result as *mut _); | |||
| let task: BoxFuture<'a, ()> = async move { | |||
| unsafe { | |||
| *r.0 = Some(f.await); | |||
| } | |||
| } | |||
| .boxed(); | |||
| let task: BoxFuture<'static, ()> = unsafe { transmute(task) }; | |||
| spawn(task).await.expect("Error in tokio executor"); | |||
| result.unwrap() | |||
| } | |||
| #[derive(Clone, Copy)] | |||
| struct Splitter { | |||
| splits: usize, | |||
| } | |||
| impl Splitter { | |||
| #[inline] | |||
| fn new(splits: usize) -> Self { | |||
| Self { | |||
| splits, | |||
| } | |||
| } | |||
| #[inline] | |||
| fn try_split(&mut self) -> bool { | |||
| if self.splits > 0 { | |||
| self.splits /= 2; | |||
| true | |||
| } else { | |||
| false | |||
| } | |||
| } | |||
| } | |||
| #[derive(Clone, Copy)] | |||
| struct IndexedSplitter { | |||
| inner: Splitter, | |||
| min: usize, | |||
| } | |||
| impl IndexedSplitter { | |||
| #[inline] | |||
| fn new(splits: usize, len: usize, min: Option<usize>, max: Option<usize>) -> Self { | |||
| let min = min.unwrap_or_default(); | |||
| let mut ret = Self { | |||
| inner: Splitter::new(splits), | |||
| min: cmp::max(min, 1), | |||
| }; | |||
| if let Some(max) = max { | |||
| let min_splits = len / cmp::max(max, 1); | |||
| if min_splits > ret.inner.splits { | |||
| ret.inner.splits = min_splits; | |||
| } | |||
| } | |||
| ret | |||
| } | |||
| #[inline] | |||
| fn try_split(&mut self, len: usize) -> bool { | |||
| len / 2 >= self.min && self.inner.try_split() | |||
| } | |||
| } | |||
| @@ -17,13 +17,13 @@ impl<X, O> ForEach<X, O> | |||
| } | |||
| } | |||
| impl<X, O> Driver<()> for ForEach<X, O> | |||
| impl<'a, X, O> Driver<'a, ()> for ForEach<X, O> | |||
| where | |||
| X: ParallelIterator, | |||
| O: Fn(X::Item) + Clone + Send, | |||
| X: ParallelIterator<'a>, | |||
| O: Fn(X::Item) + Clone + Send + 'a, | |||
| { | |||
| fn exec_with<E>(self, executor: E) -> E::Result | |||
| where E: Executor<()> | |||
| where E: Executor<'a, ()> | |||
| { | |||
| let iterator = self.iterator; | |||
| let operation = self.operation; | |||
| @@ -89,15 +89,15 @@ mod tests { | |||
| use super::*; | |||
| use crate::*; | |||
| #[test] | |||
| fn test_for_each() { | |||
| #[tokio::test] | |||
| async fn test_for_each() { | |||
| let x = (0..10usize) | |||
| .into_par_iter() | |||
| .map(Some) | |||
| .for_each(|j| { | |||
| println!("{:?}", j); | |||
| }) | |||
| .exec(); | |||
| .exec().await; | |||
| dbg!(x); | |||
| } | |||
| @@ -16,20 +16,20 @@ impl<X, O> Map<X, O> { | |||
| } | |||
| } | |||
| impl<X, O, T> ParallelIterator for Map<X, O> | |||
| impl<'a, X, O, T> ParallelIterator<'a> for Map<X, O> | |||
| where | |||
| X: ParallelIterator, | |||
| O: Fn(X::Item) -> T + Sync + Send + Copy, | |||
| X: ParallelIterator<'a>, | |||
| O: Fn(X::Item) -> T + Sync + Send + Copy + 'a, | |||
| T: Send, | |||
| { | |||
| type Item = O::Output; | |||
| fn drive<E, C, D, R>(self, executor: E, consumer: C) -> E::Result | |||
| where | |||
| E: Executor<D>, | |||
| C: Consumer<Self::Item, Result = D, Reducer = R>, | |||
| E: Executor<'a, D>, | |||
| C: Consumer<Self::Item, Result = D, Reducer = R> + 'a, | |||
| D: Send, | |||
| R: Reducer<D> | |||
| R: Reducer<D> + Send, | |||
| { | |||
| let consumer = MapConsumer::new(consumer, self.operation); | |||
| @@ -38,7 +38,7 @@ where | |||
| fn with_producer<CB>(self, callback: CB) -> CB::Output | |||
| where | |||
| CB: ProducerCallback<Self::Item>, | |||
| CB: ProducerCallback<'a, Self::Item>, | |||
| { | |||
| self.base.with_producer(MapCallback { | |||
| callback, | |||
| @@ -51,15 +51,15 @@ where | |||
| } | |||
| } | |||
| impl<X, O, T> IndexedParallelIterator for Map<X, O> | |||
| impl<'a, X, O, T> IndexedParallelIterator<'a> for Map<X, O> | |||
| where | |||
| X: IndexedParallelIterator, | |||
| O: Fn(X::Item) -> T + Sync + Send + Copy, | |||
| X: IndexedParallelIterator<'a>, | |||
| O: Fn(X::Item) -> T + Sync + Send + Copy + 'a, | |||
| T: Send, | |||
| { | |||
| fn drive_indexed<E, C, D, R>(self, executor: E, consumer: C) -> E::Result | |||
| where | |||
| E: Executor<D>, | |||
| E: Executor<'a, D>, | |||
| C: IndexedConsumer<Self::Item, Result = D, Reducer = R>, | |||
| D: Send, | |||
| R: Reducer<D> | |||
| @@ -71,7 +71,7 @@ where | |||
| fn with_producer_indexed<CB>(self, callback: CB) -> CB::Output | |||
| where | |||
| CB: IndexedProducerCallback<Self::Item>, | |||
| CB: IndexedProducerCallback<'a, Self::Item>, | |||
| { | |||
| self.base.with_producer_indexed(MapCallback { | |||
| callback, | |||
| @@ -91,17 +91,17 @@ struct MapCallback<CB, O> { | |||
| operation: O, | |||
| } | |||
| impl<I, O, T, CB> ProducerCallback<I> for MapCallback<CB, O> | |||
| impl<'a, I, O, T, CB> ProducerCallback<'a, I> for MapCallback<CB, O> | |||
| where | |||
| CB: ProducerCallback<T>, | |||
| O: Fn(I) -> T + Sync + Send + Copy, | |||
| CB: ProducerCallback<'a, T>, | |||
| O: Fn(I) -> T + Sync + Send + Copy + 'a, | |||
| T: Send, | |||
| { | |||
| type Output = CB::Output; | |||
| fn callback<P>(self, base: P) -> CB::Output | |||
| where | |||
| P: Producer<Item = I>, | |||
| P: Producer<Item = I> + 'a, | |||
| { | |||
| let producer = MapProducer { | |||
| base, | |||
| @@ -112,17 +112,17 @@ where | |||
| } | |||
| } | |||
| impl<I, O, T, CB> IndexedProducerCallback<I> for MapCallback<CB, O> | |||
| impl<'a, I, O, T, CB> IndexedProducerCallback<'a, I> for MapCallback<CB, O> | |||
| where | |||
| CB: IndexedProducerCallback<T>, | |||
| O: Fn(I) -> T + Sync + Send + Copy, | |||
| CB: IndexedProducerCallback<'a, T>, | |||
| O: Fn(I) -> T + Sync + Send + Copy + 'a, | |||
| T: Send, | |||
| { | |||
| type Output = CB::Output; | |||
| fn callback<P>(self, base: P) -> CB::Output | |||
| where | |||
| P: IndexedProducer<Item = I>, | |||
| P: IndexedProducer<Item = I> + 'a, | |||
| { | |||
| let producer = MapProducer { | |||
| base, | |||
| @@ -196,11 +196,19 @@ where | |||
| self.base.into_iter().map(self.operation) | |||
| } | |||
| fn min_len(&self) -> usize { | |||
| fn splits(&self) -> Option<usize> { | |||
| self.base.splits() | |||
| } | |||
| fn len(&self) -> usize { | |||
| self.base.len() | |||
| } | |||
| fn min_len(&self) -> Option<usize> { | |||
| self.base.min_len() | |||
| } | |||
| fn max_len(&self) -> usize { | |||
| fn max_len(&self) -> Option<usize> { | |||
| self.base.max_len() | |||
| } | |||
| @@ -10,7 +10,7 @@ struct IterProducer { | |||
| range: Range<usize>, | |||
| } | |||
| impl IntoParallelIterator for Range<usize> { | |||
| impl<'a> IntoParallelIterator<'a> for Range<usize> { | |||
| type Iter = Iter; | |||
| type Item = usize; | |||
| @@ -19,15 +19,15 @@ impl IntoParallelIterator for Range<usize> { | |||
| } | |||
| } | |||
| impl ParallelIterator for Iter { | |||
| impl<'a> ParallelIterator<'a> for Iter { | |||
| type Item = usize; | |||
| fn drive<E, C, D, R>(self, executor: E, consumer: C) -> E::Result | |||
| where | |||
| E: Executor<D>, | |||
| C: Consumer<Self::Item, Result = D, Reducer = R>, | |||
| E: Executor<'a, D>, | |||
| C: Consumer<Self::Item, Result = D, Reducer = R> + 'a, | |||
| D: Send, | |||
| R: Reducer<D> | |||
| R: Reducer<D> + Send, | |||
| { | |||
| self.with_producer(ExecutorCallback::new(executor, consumer)) | |||
| } | |||
| @@ -38,7 +38,7 @@ impl ParallelIterator for Iter { | |||
| fn with_producer<CB>(self, callback: CB) -> CB::Output | |||
| where | |||
| CB: ProducerCallback<Self::Item>, | |||
| CB: ProducerCallback<'a, Self::Item>, | |||
| { | |||
| callback.callback(IterProducer { range: self.range }) | |||
| } | |||