From cf82462c27ebb7cb5ae8b5e8e0be6b25ccb2c22f Mon Sep 17 00:00:00 2001 From: james7132 Date: Fri, 31 Dec 2021 19:41:04 -0500 Subject: [PATCH 1/9] Document bevy_tasks and enable #![warn(missing_docs)] --- crates/bevy_tasks/src/iter/mod.rs | 1 + crates/bevy_tasks/src/lib.rs | 65 ++++++++++++++++ crates/bevy_tasks/src/slice.rs | 118 +++++++++++++++++++++++++++++ crates/bevy_tasks/src/task_pool.rs | 19 +++++ 4 files changed, 203 insertions(+) diff --git a/crates/bevy_tasks/src/iter/mod.rs b/crates/bevy_tasks/src/iter/mod.rs index bebc1c0792e2c..480936d68226e 100644 --- a/crates/bevy_tasks/src/iter/mod.rs +++ b/crates/bevy_tasks/src/iter/mod.rs @@ -16,6 +16,7 @@ where B: Iterator + Send, Self: Sized + Send, { + /// The type of item that is being iterated over. type Item; /// Returns the next batch of items for processing. diff --git a/crates/bevy_tasks/src/lib.rs b/crates/bevy_tasks/src/lib.rs index db95dc28db447..4b8b05c52264e 100644 --- a/crates/bevy_tasks/src/lib.rs +++ b/crates/bevy_tasks/src/lib.rs @@ -1,3 +1,4 @@ +#![warn(missing_docs)] #![doc = include_str!("../README.md")] mod slice; @@ -25,6 +26,7 @@ pub use countdown_event::CountdownEvent; mod iter; pub use iter::ParallelIterator; +#[allow(missing_docs)] pub mod prelude { #[doc(hidden)] pub use crate::{ @@ -34,10 +36,73 @@ pub mod prelude { }; } +// The following docs are copied from `num_cpus`'s docs for the wrapped functions. +// Attributed under MIT or Apache: https://github.com/seanmonstar/num_cpus + +/// Returns the number of available CPUs of the current system. +/// +/// This function will get the number of logical cores. Sometimes this is different from the number +/// of physical cores (See [Simultaneous multithreading on Wikipedia][smt]). +/// +/// This will always return at least `1`. +/// +/// # Examples +/// +/// ```rust +/// let cpus = bevy_tasks::logical_core_count(); +/// if cpus > 1 { +/// println!("We are on a multicore system with {} CPUs", cpus); +/// } else { +/// println!("We are on a single core system"); +/// } +/// ``` +/// +/// # Note +/// +/// This will check [sched affinity] on Linux, showing a lower number of CPUs if the current +/// thread does not have access to all the computer's CPUs. +/// +/// This will also check [cgroups], frequently used in containers to constrain CPU usage. +/// +/// [smt]: https://en.wikipedia.org/wiki/Simultaneous_multithreading +/// [sched affinity]: http://www.gnu.org/software/libc/manual/html_node/CPU-Affinity.html +/// [cgroups]: https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt +#[inline(always)] pub fn logical_core_count() -> usize { num_cpus::get() } +/// Returns the number of physical cores of the current system. +/// +/// This will always return at least `1`. +/// +/// # Note +/// +/// Physical count is supported only on Linux, mac OS and Windows platforms. +/// On other platforms, or if the physical count fails on supported platforms, +/// this function returns the same as [`get()`], which is the number of logical +/// CPUS. +/// +/// # Examples +/// +/// ```rust +/// let logical_cpus = bevy_tasks::logical_core_count(); +/// let physical_cpus = bevy_tasks::physical_core_count(); +/// if logical_cpus > physical_cpus { +/// println!("We have simultaneous multithreading with about {:.2} \ +/// logical cores to 1 physical core.", +/// (logical_cpus as f64) / (physical_cpus as f64)); +/// } else if logical_cpus == physical_cpus { +/// println!("Either we don't have simultaneous multithreading, or our \ +/// system doesn't support getting the number of physical CPUs."); +/// } else { +/// println!("We have less logical CPUs than physical CPUs, maybe we only have access to \ +/// some of the CPUs on our system."); +/// } +/// ``` +/// +/// [`logical_core_count()`]: fn.logical_core_count.html +#[inline(always)] pub fn physical_core_count() -> usize { num_cpus::get_physical() } diff --git a/crates/bevy_tasks/src/slice.rs b/crates/bevy_tasks/src/slice.rs index a04c9af10a28f..e0d4af33a55e5 100644 --- a/crates/bevy_tasks/src/slice.rs +++ b/crates/bevy_tasks/src/slice.rs @@ -1,6 +1,33 @@ use super::TaskPool; +/// Provides functions for mapping read-only slices across a provided `TaskPool`. pub trait ParallelSlice: AsRef<[T]> { + /// Splits the slice into chunks of size `chunks_size` or less and queues up one task + /// per chunk on the provided `task_pool` and returns a mapped `Vec` of the collected + /// results. + /// + /// # Example + /// + /// ```rust + /// # use bevy_tasks::prelude::*; + /// # use bevy_tasks::TaskPool; + /// let task_pool = TaskPool::new(); + /// let counts = (0..10000).collect::>(); + /// let incremented = counts.par_chunk_map(&task_pool, 100, |chunk| { + /// let mut results = Vec::new(); + /// for count in chunk { + /// results.push(*count + 2); + /// } + /// results + /// }); + /// # let flattened: Vec<_> = incremented.into_iter().flatten().collect(); + /// # assert_eq!(flattened, (2..10002).collect::>()); + /// ``` + /// + /// # See Also + /// + /// `ParallelSliceMut::par_chunk_map_mut` for mapping mutable slices. + /// `ParallelSlice::par_splat_map` for mapping when a specific chunk size is unknown. fn par_chunk_map(&self, task_pool: &TaskPool, chunk_size: usize, f: F) -> Vec where F: Fn(&[T]) -> R + Send + Sync, @@ -15,6 +42,35 @@ pub trait ParallelSlice: AsRef<[T]> { }) } + /// Splits the slice into a maximum of `self.len() / max_tasks` chunks of approximately + /// equal size and queues one task per chunk on the provided `task_pool` and returns a + /// mapped `Vec` of the collected results. + /// + /// If `max_tasks` is `None`, this function will attempt to use one chunk per thread in + /// `task_pool`. + /// + /// # Example + /// + /// ```rust + /// # use bevy_tasks::prelude::*; + /// # use bevy_tasks::TaskPool; + /// let task_pool = TaskPool::new(); + /// let counts = (0..10000).collect::>(); + /// let incremented = counts.par_splat_map(&task_pool, None, |chunk| { + /// let mut results = Vec::new(); + /// for count in chunk { + /// results.push(*count + 2); + /// } + /// results + /// }); + /// # let flattened: Vec<_> = incremented.into_iter().flatten().collect(); + /// # assert_eq!(flattened, (2..10002).collect::>()); + /// ``` + /// + /// # See Also + /// + /// `ParallelSliceMut::par_splat_map` for mapping mutable slices. + /// `ParallelSlice::par_chunk_map` for mapping when a specific chunk size is desirable. fn par_splat_map(&self, task_pool: &TaskPool, max_tasks: Option, f: F) -> Vec where F: Fn(&[T]) -> R + Send + Sync, @@ -35,7 +91,37 @@ pub trait ParallelSlice: AsRef<[T]> { impl ParallelSlice for S where S: AsRef<[T]> {} +/// Provides functions for mapping mutable slices across a provided `TaskPool`. pub trait ParallelSliceMut: AsMut<[T]> { + /// Splits the slice into chunks of size `chunks_size` or less and queues up one task + /// per chunk on the provided `task_pool` and returns a mapped `Vec` of the collected + /// results. + /// + /// # Example + /// + /// ```rust + /// # use bevy_tasks::prelude::*; + /// # use bevy_tasks::TaskPool; + /// let task_pool = TaskPool::new(); + /// let mut counts = (0..10000).collect::>(); + /// let incremented = counts.par_chunk_map_mut(&task_pool, 100, |chunk| { + /// let mut results = Vec::new(); + /// for count in chunk { + /// *count += 5; + /// results.push(*count - 2); + /// } + /// results + /// }); + /// + /// assert_eq!(counts, (5..10005).collect::>()); + /// # let flattened: Vec<_> = incremented.into_iter().flatten().collect(); + /// # assert_eq!(flattened, (3..10003).collect::>()); + /// ``` + /// + /// # See Also + /// + /// `ParallelSlice::par_chunk_map` for mapping immutable slices. + /// `ParallelSliceMut::par_splat_map` for mapping when a specific chunk size is unknown. fn par_chunk_map_mut(&mut self, task_pool: &TaskPool, chunk_size: usize, f: F) -> Vec where F: Fn(&mut [T]) -> R + Send + Sync, @@ -50,6 +136,38 @@ pub trait ParallelSliceMut: AsMut<[T]> { }) } + /// Splits the slice into a maximum of `self.len() / max_tasks` chunks of approximately + /// equal size and queues one task per chunk on the provided `task_pool` and returns a + /// mapped `Vec` of the collected results. + /// + /// If `max_tasks` is `None`, this function will attempt to use one chunk per thread in + /// `task_pool`. + /// + /// # Example + /// + /// ```rust + /// # use bevy_tasks::prelude::*; + /// # use bevy_tasks::TaskPool; + /// let task_pool = TaskPool::new(); + /// let mut counts = (0..10000).collect::>(); + /// let incremented = counts.par_splat_map_mut(&task_pool, None, |chunk| { + /// let mut results = Vec::new(); + /// for count in chunk { + /// *count += 5; + /// results.push(*count - 2); + /// } + /// results + /// }); + /// + /// assert_eq!(counts, (5..10005).collect::>()); + /// # let flattened: Vec<_> = incremented.into_iter().flatten().collect::>(); + /// # assert_eq!(flattened, (3..10003).collect::>()); + /// ``` + /// + /// # See Also + /// + /// `ParallelSlice::par_splat_map` for mapping immutable slices. + /// `ParallelSliceMut::par_chunk_map` for mapping when a specific chunk size is desirable. fn par_splat_map_mut( &mut self, task_pool: &TaskPool, diff --git a/crates/bevy_tasks/src/task_pool.rs b/crates/bevy_tasks/src/task_pool.rs index bf23ef1a586c9..420af0d18491f 100644 --- a/crates/bevy_tasks/src/task_pool.rs +++ b/crates/bevy_tasks/src/task_pool.rs @@ -236,6 +236,11 @@ impl TaskPool { Task::new(self.executor.spawn(future)) } + /// Spawns a static future on the thread-local async executor for the current thread. The task + /// will run entirely on the thread the task was spawned on. The returned Task is a future. + /// It can also be cancelled and "detached" allowing it to continue running without having + /// to be polled by the end-user. Users should generally prefer to use `spawn` instead, unless + /// the provided future is not `Send`. pub fn spawn_local(&self, future: impl Future + 'static) -> Task where T: 'static, @@ -250,6 +255,9 @@ impl Default for TaskPool { } } +/// A `TaskPool` scope for running one or more non-`'static` futures. +/// +/// For more information, see `TaskPool::scope` for usage. #[derive(Debug)] pub struct Scope<'scope, T> { executor: &'scope async_executor::Executor<'scope>, @@ -258,11 +266,22 @@ pub struct Scope<'scope, T> { } impl<'scope, T: Send + 'scope> Scope<'scope, T> { + /// Spawns a scoped future onto the thread pool. The scope *must* outlive + /// the provided future. The results of the future will be returned as a part of + /// `TaskPool::scope`'s return value. + /// + /// For more information, see `TaskPool::scope` for usage. pub fn spawn + 'scope + Send>(&mut self, f: Fut) { let task = self.executor.spawn(f); self.spawned.push(task); } + /// Spawns a scoped future onto the thread-local executor. The scope *must* outlive + /// the provided future. The results of the future will be returned as a part of + /// `TaskPool::scope`'s return value. Users should generally prefer to use `spawn` instead, unless + /// the provided future is not `Send`. + /// + /// For more information, see `TaskPool::scope` for usage. pub fn spawn_local + 'scope>(&mut self, f: Fut) { let task = self.local_executor.spawn(f); self.spawned.push(task); From c6236a3824dc04845c0ce4aef50aff895a18d4b8 Mon Sep 17 00:00:00 2001 From: James Liu Date: Fri, 31 Dec 2021 19:55:04 -0500 Subject: [PATCH 2/9] Fix doc links --- crates/bevy_tasks/src/lib.rs | 2 +- crates/bevy_tasks/src/slice.rs | 16 +++++++-------- crates/bevy_tasks/src/task_pool.rs | 31 +++++++++++++++++------------- 3 files changed, 27 insertions(+), 22 deletions(-) diff --git a/crates/bevy_tasks/src/lib.rs b/crates/bevy_tasks/src/lib.rs index 4b8b05c52264e..0fc7564e4d207 100644 --- a/crates/bevy_tasks/src/lib.rs +++ b/crates/bevy_tasks/src/lib.rs @@ -80,7 +80,7 @@ pub fn logical_core_count() -> usize { /// /// Physical count is supported only on Linux, mac OS and Windows platforms. /// On other platforms, or if the physical count fails on supported platforms, -/// this function returns the same as [`get()`], which is the number of logical +/// this function returns the same as [`logical_core_count()`], which is the number of logical /// CPUS. /// /// # Examples diff --git a/crates/bevy_tasks/src/slice.rs b/crates/bevy_tasks/src/slice.rs index e0d4af33a55e5..c4be07e6aad07 100644 --- a/crates/bevy_tasks/src/slice.rs +++ b/crates/bevy_tasks/src/slice.rs @@ -26,8 +26,8 @@ pub trait ParallelSlice: AsRef<[T]> { /// /// # See Also /// - /// `ParallelSliceMut::par_chunk_map_mut` for mapping mutable slices. - /// `ParallelSlice::par_splat_map` for mapping when a specific chunk size is unknown. + /// [`ParallelSliceMut::par_chunk_map_mut`] for mapping mutable slices. + /// [`ParallelSlice::par_splat_map`] for mapping when a specific chunk size is unknown. fn par_chunk_map(&self, task_pool: &TaskPool, chunk_size: usize, f: F) -> Vec where F: Fn(&[T]) -> R + Send + Sync, @@ -69,8 +69,8 @@ pub trait ParallelSlice: AsRef<[T]> { /// /// # See Also /// - /// `ParallelSliceMut::par_splat_map` for mapping mutable slices. - /// `ParallelSlice::par_chunk_map` for mapping when a specific chunk size is desirable. + /// [`ParallelSliceMut::par_splat_map_mut`] for mapping mutable slices. + /// [`ParallelSlice::par_chunk_map`] for mapping when a specific chunk size is desirable. fn par_splat_map(&self, task_pool: &TaskPool, max_tasks: Option, f: F) -> Vec where F: Fn(&[T]) -> R + Send + Sync, @@ -120,8 +120,8 @@ pub trait ParallelSliceMut: AsMut<[T]> { /// /// # See Also /// - /// `ParallelSlice::par_chunk_map` for mapping immutable slices. - /// `ParallelSliceMut::par_splat_map` for mapping when a specific chunk size is unknown. + /// [`ParallelSlice::par_chunk_map`] for mapping immutable slices. + /// [`ParallelSliceMut::par_splat_map_mut`] for mapping when a specific chunk size is unknown. fn par_chunk_map_mut(&mut self, task_pool: &TaskPool, chunk_size: usize, f: F) -> Vec where F: Fn(&mut [T]) -> R + Send + Sync, @@ -166,8 +166,8 @@ pub trait ParallelSliceMut: AsMut<[T]> { /// /// # See Also /// - /// `ParallelSlice::par_splat_map` for mapping immutable slices. - /// `ParallelSliceMut::par_chunk_map` for mapping when a specific chunk size is desirable. + /// [`ParallelSlice::par_splat_map`] for mapping immutable slices. + /// [`ParallelSliceMut::par_chunk_map_mut`] for mapping when a specific chunk size is desirable. fn par_splat_map_mut( &mut self, task_pool: &TaskPool, diff --git a/crates/bevy_tasks/src/task_pool.rs b/crates/bevy_tasks/src/task_pool.rs index 420af0d18491f..568f4364e36ca 100644 --- a/crates/bevy_tasks/src/task_pool.rs +++ b/crates/bevy_tasks/src/task_pool.rs @@ -228,7 +228,9 @@ impl TaskPool { /// Spawns a static future onto the thread pool. The returned Task is a future. It can also be /// cancelled and "detached" allowing it to continue running without having to be polled by the - /// end-user. + /// end-user. + /// + /// If the provided future is non-`Send`, [`TaskPool::spawn_local`] should be used instead. pub fn spawn(&self, future: impl Future + Send + 'static) -> Task where T: Send + 'static, @@ -237,10 +239,10 @@ impl TaskPool { } /// Spawns a static future on the thread-local async executor for the current thread. The task - /// will run entirely on the thread the task was spawned on. The returned Task is a future. - /// It can also be cancelled and "detached" allowing it to continue running without having - /// to be polled by the end-user. Users should generally prefer to use `spawn` instead, unless - /// the provided future is not `Send`. + /// will run entirely on the thread the task was spawned on. The returned Task is a future. + /// It can also be cancelled and "detached" allowing it to continue running without having + /// to be polled by the end-user. Users should generally prefer to use [`TaskPool::spawn`] + /// instead, unless the provided future is not `Send`. pub fn spawn_local(&self, future: impl Future + 'static) -> Task where T: 'static, @@ -256,7 +258,7 @@ impl Default for TaskPool { } /// A `TaskPool` scope for running one or more non-`'static` futures. -/// +/// /// For more information, see `TaskPool::scope` for usage. #[derive(Debug)] pub struct Scope<'scope, T> { @@ -268,9 +270,12 @@ pub struct Scope<'scope, T> { impl<'scope, T: Send + 'scope> Scope<'scope, T> { /// Spawns a scoped future onto the thread pool. The scope *must* outlive /// the provided future. The results of the future will be returned as a part of - /// `TaskPool::scope`'s return value. - /// - /// For more information, see `TaskPool::scope` for usage. + /// [`TaskPool::scope`]'s return value. + /// + /// If the provided future is non-`Send`, [`Scope::spawn_local`] should be used + /// instead. + /// + /// For more information, see [`TaskPool::scope`] for usage. pub fn spawn + 'scope + Send>(&mut self, f: Fut) { let task = self.executor.spawn(f); self.spawned.push(task); @@ -278,10 +283,10 @@ impl<'scope, T: Send + 'scope> Scope<'scope, T> { /// Spawns a scoped future onto the thread-local executor. The scope *must* outlive /// the provided future. The results of the future will be returned as a part of - /// `TaskPool::scope`'s return value. Users should generally prefer to use `spawn` instead, unless - /// the provided future is not `Send`. - /// - /// For more information, see `TaskPool::scope` for usage. + /// [`TaskPool::scope`]'s return value. Users should generally prefer to use + /// [`Scope::spawn`] instead, unless the provided future is not `Send`. + /// + /// For more information, see [`TaskPool::scope`] for usage. pub fn spawn_local + 'scope>(&mut self, f: Fut) { let task = self.local_executor.spawn(f); self.spawned.push(task); From e52fec632016124b9fd4ee37b76c42654855f3cb Mon Sep 17 00:00:00 2001 From: James Liu Date: Fri, 31 Dec 2021 20:00:56 -0500 Subject: [PATCH 3/9] Fix formatting --- crates/bevy_tasks/src/task_pool.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/crates/bevy_tasks/src/task_pool.rs b/crates/bevy_tasks/src/task_pool.rs index 568f4364e36ca..f119ff51cb699 100644 --- a/crates/bevy_tasks/src/task_pool.rs +++ b/crates/bevy_tasks/src/task_pool.rs @@ -228,8 +228,8 @@ impl TaskPool { /// Spawns a static future onto the thread pool. The returned Task is a future. It can also be /// cancelled and "detached" allowing it to continue running without having to be polled by the - /// end-user. - /// + /// end-user. + /// /// If the provided future is non-`Send`, [`TaskPool::spawn_local`] should be used instead. pub fn spawn(&self, future: impl Future + Send + 'static) -> Task where @@ -239,9 +239,9 @@ impl TaskPool { } /// Spawns a static future on the thread-local async executor for the current thread. The task - /// will run entirely on the thread the task was spawned on. The returned Task is a future. - /// It can also be cancelled and "detached" allowing it to continue running without having - /// to be polled by the end-user. Users should generally prefer to use [`TaskPool::spawn`] + /// will run entirely on the thread the task was spawned on. The returned Task is a future. + /// It can also be cancelled and "detached" allowing it to continue running without having + /// to be polled by the end-user. Users should generally prefer to use [`TaskPool::spawn`] /// instead, unless the provided future is not `Send`. pub fn spawn_local(&self, future: impl Future + 'static) -> Task where @@ -258,7 +258,7 @@ impl Default for TaskPool { } /// A `TaskPool` scope for running one or more non-`'static` futures. -/// +/// /// For more information, see `TaskPool::scope` for usage. #[derive(Debug)] pub struct Scope<'scope, T> { @@ -271,10 +271,10 @@ impl<'scope, T: Send + 'scope> Scope<'scope, T> { /// Spawns a scoped future onto the thread pool. The scope *must* outlive /// the provided future. The results of the future will be returned as a part of /// [`TaskPool::scope`]'s return value. - /// - /// If the provided future is non-`Send`, [`Scope::spawn_local`] should be used + /// + /// If the provided future is non-`Send`, [`Scope::spawn_local`] should be used /// instead. - /// + /// /// For more information, see [`TaskPool::scope`] for usage. pub fn spawn + 'scope + Send>(&mut self, f: Fut) { let task = self.executor.spawn(f); @@ -283,9 +283,9 @@ impl<'scope, T: Send + 'scope> Scope<'scope, T> { /// Spawns a scoped future onto the thread-local executor. The scope *must* outlive /// the provided future. The results of the future will be returned as a part of - /// [`TaskPool::scope`]'s return value. Users should generally prefer to use + /// [`TaskPool::scope`]'s return value. Users should generally prefer to use /// [`Scope::spawn`] instead, unless the provided future is not `Send`. - /// + /// /// For more information, see [`TaskPool::scope`] for usage. pub fn spawn_local + 'scope>(&mut self, f: Fut) { let task = self.local_executor.spawn(f); From 21927b1363eeac55f5057a6f255b356a2ec9c952 Mon Sep 17 00:00:00 2001 From: james7132 Date: Fri, 31 Dec 2021 20:53:21 -0500 Subject: [PATCH 4/9] Address review comments --- crates/bevy_tasks/src/iter/adapters.rs | 56 ++++++----------- crates/bevy_tasks/src/iter/mod.rs | 83 +++++++++++++------------- crates/bevy_tasks/src/lib.rs | 72 +--------------------- crates/bevy_tasks/src/slice.rs | 30 ++++++---- 4 files changed, 77 insertions(+), 164 deletions(-) diff --git a/crates/bevy_tasks/src/iter/adapters.rs b/crates/bevy_tasks/src/iter/adapters.rs index 047f6fb8ad5f0..d05da201ad25d 100644 --- a/crates/bevy_tasks/src/iter/adapters.rs +++ b/crates/bevy_tasks/src/iter/adapters.rs @@ -10,11 +10,9 @@ pub struct Chain { impl ParallelIterator for Chain where B: Iterator + Send, - T: ParallelIterator, - U: ParallelIterator, + T: ParallelIterator, + U: ParallelIterator, { - type Item = T::Item; - fn next_batch(&mut self) -> Option { if self.left_in_progress { match self.left.next_batch() { @@ -35,11 +33,9 @@ pub struct Map { impl ParallelIterator> for Map where B: Iterator + Send, - U: ParallelIterator, - F: FnMut(U::Item) -> T + Send + Clone, + U: ParallelIterator, + F: FnMut(B::Item) -> T + Send + Clone, { - type Item = T; - fn next_batch(&mut self) -> Option> { self.iter.next_batch().map(|b| b.map(self.f.clone())) } @@ -54,11 +50,9 @@ pub struct Filter { impl ParallelIterator> for Filter where B: Iterator + Send, - P: ParallelIterator, - F: FnMut(&P::Item) -> bool + Send + Clone, + P: ParallelIterator, + F: FnMut(&B::Item) -> bool + Send + Clone, { - type Item = P::Item; - fn next_batch(&mut self) -> Option> { self.iter .next_batch() @@ -75,11 +69,9 @@ pub struct FilterMap { impl ParallelIterator> for FilterMap where B: Iterator + Send, - P: ParallelIterator, - F: FnMut(P::Item) -> Option + Send + Clone, + P: ParallelIterator, + F: FnMut(B::Item) -> Option + Send + Clone, { - type Item = R; - fn next_batch(&mut self) -> Option> { self.iter.next_batch().map(|b| b.filter_map(self.f.clone())) } @@ -94,13 +86,11 @@ pub struct FlatMap { impl ParallelIterator> for FlatMap where B: Iterator + Send, - P: ParallelIterator, - F: FnMut(P::Item) -> U + Send + Clone, + P: ParallelIterator, + F: FnMut(B::Item) -> U + Send + Clone, U: IntoIterator, U::IntoIter: Send, { - type Item = U::Item; - // This extends each batch using the flat map. The other option is // to turn each IntoIter into its own batch. fn next_batch(&mut self) -> Option> { @@ -116,12 +106,10 @@ pub struct Flatten

{ impl ParallelIterator> for Flatten

where B: Iterator + Send, - P: ParallelIterator, + P: ParallelIterator, B::Item: IntoIterator, ::IntoIter: Send, { - type Item = ::Item; - // This extends each batch using the flatten. The other option is to // turn each IntoIter into its own batch. fn next_batch(&mut self) -> Option> { @@ -137,10 +125,8 @@ pub struct Fuse

{ impl ParallelIterator for Fuse

where B: Iterator + Send, - P: ParallelIterator, + P: ParallelIterator, { - type Item = P::Item; - fn next_batch(&mut self) -> Option { match &mut self.iter { Some(iter) => match iter.next_batch() { @@ -164,11 +150,9 @@ pub struct Inspect { impl ParallelIterator> for Inspect where B: Iterator + Send, - P: ParallelIterator, - F: FnMut(&P::Item) + Send + Clone, + P: ParallelIterator, + F: FnMut(&B::Item) + Send + Clone, { - type Item = P::Item; - fn next_batch(&mut self) -> Option> { self.iter.next_batch().map(|b| b.inspect(self.f.clone())) } @@ -182,11 +166,9 @@ pub struct Copied

{ impl<'a, B, P, T> ParallelIterator> for Copied

where B: Iterator + Send, - P: ParallelIterator, + P: ParallelIterator, T: 'a + Copy, { - type Item = T; - fn next_batch(&mut self) -> Option> { self.iter.next_batch().map(|b| b.copied()) } @@ -200,11 +182,9 @@ pub struct Cloned

{ impl<'a, B, P, T> ParallelIterator> for Cloned

where B: Iterator + Send, - P: ParallelIterator, + P: ParallelIterator, T: 'a + Copy, { - type Item = T; - fn next_batch(&mut self) -> Option> { self.iter.next_batch().map(|b| b.cloned()) } @@ -219,10 +199,8 @@ pub struct Cycle

{ impl ParallelIterator for Cycle

where B: Iterator + Send, - P: ParallelIterator + Clone, + P: ParallelIterator + Clone, { - type Item = P::Item; - fn next_batch(&mut self) -> Option { match self.curr.as_mut().and_then(|c| c.next_batch()) { batch @ Some(_) => batch, diff --git a/crates/bevy_tasks/src/iter/mod.rs b/crates/bevy_tasks/src/iter/mod.rs index 480936d68226e..990782d5923c3 100644 --- a/crates/bevy_tasks/src/iter/mod.rs +++ b/crates/bevy_tasks/src/iter/mod.rs @@ -13,12 +13,9 @@ pub use adapters::*; /// using [`ParallelIterator`]. pub trait ParallelIterator where - B: Iterator + Send, + B: Iterator + Send, Self: Sized + Send, { - /// The type of item that is being iterated over. - type Item; - /// Returns the next batch of items for processing. /// /// Each batch is an iterator with items of the same type as the @@ -49,7 +46,7 @@ where /// Consumes the parallel iterator and returns the last item. /// /// See [`Iterator::last()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.last) - fn last(mut self, _pool: &TaskPool) -> Option { + fn last(mut self, _pool: &TaskPool) -> Option { let mut last_item = None; while let Some(batch) = self.next_batch() { last_item = batch.last(); @@ -61,7 +58,7 @@ where /// /// See [`Iterator::nth()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.nth) // TODO: Optimize with size_hint on each batch - fn nth(mut self, _pool: &TaskPool, n: usize) -> Option { + fn nth(mut self, _pool: &TaskPool, n: usize) -> Option { let mut i = 0; while let Some(batch) = self.next_batch() { for item in batch { @@ -81,7 +78,7 @@ where // TODO: Use IntoParallelIterator for U fn chain(self, other: U) -> Chain where - U: ParallelIterator, + U: ParallelIterator, { Chain { left: self, @@ -96,7 +93,7 @@ where /// See [`Iterator::map()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map) fn map(self, f: F) -> Map where - F: FnMut(Self::Item) -> T + Send + Clone, + F: FnMut(B::Item) -> T + Send + Clone, { Map { iter: self, f } } @@ -106,7 +103,7 @@ where /// See [`Iterator::for_each()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.for_each) fn for_each(mut self, pool: &TaskPool, f: F) where - F: FnMut(Self::Item) + Send + Clone + Sync, + F: FnMut(B::Item) + Send + Clone + Sync, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -124,7 +121,7 @@ where /// See [`Iterator::filter()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter) fn filter(self, predicate: F) -> Filter where - F: FnMut(&Self::Item) -> bool, + F: FnMut(&B::Item) -> bool, { Filter { iter: self, @@ -137,7 +134,7 @@ where /// See [`Iterator::filter_map()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter_map) fn filter_map(self, f: F) -> FilterMap where - F: FnMut(Self::Item) -> Option, + F: FnMut(B::Item) -> Option, { FilterMap { iter: self, f } } @@ -148,7 +145,7 @@ where /// See [`Iterator::flat_map()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.flat_map) fn flat_map(self, f: F) -> FlatMap where - F: FnMut(Self::Item) -> U, + F: FnMut(B::Item) -> U, U: IntoIterator, { FlatMap { iter: self, f } @@ -159,7 +156,7 @@ where /// See [`Iterator::flatten()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.flatten) fn flatten(self) -> Flatten where - Self::Item: IntoIterator, + B::Item: IntoIterator, { Flatten { iter: self } } @@ -177,7 +174,7 @@ where /// See [`Iterator::inspect()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.inspect) fn inspect(self, f: F) -> Inspect where - F: FnMut(&Self::Item), + F: FnMut(&B::Item), { Inspect { iter: self, f } } @@ -195,8 +192,8 @@ where // TODO: Investigate optimizations for less copying fn collect(mut self, pool: &TaskPool) -> C where - C: std::iter::FromIterator, - Self::Item: Send + 'static, + C: std::iter::FromIterator, + B::Item: Send + 'static, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -214,9 +211,9 @@ where // TODO: Investigate optimizations for less copying fn partition(mut self, pool: &TaskPool, f: F) -> (C, C) where - C: Default + Extend + Send, - F: FnMut(&Self::Item) -> bool + Send + Sync + Clone, - Self::Item: Send + 'static, + C: Default + Extend + Send, + F: FnMut(&B::Item) -> bool + Send + Sync + Clone, + B::Item: Send + 'static, { let (mut a, mut b) = <(C, C)>::default(); pool.scope(|s| { @@ -242,7 +239,7 @@ where /// See [`Iterator::fold()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.fold) fn fold(mut self, pool: &TaskPool, init: C, f: F) -> Vec where - F: FnMut(C, Self::Item) -> C + Send + Sync + Clone, + F: FnMut(C, B::Item) -> C + Send + Sync + Clone, C: Clone + Send + Sync + 'static, { pool.scope(|s| { @@ -261,7 +258,7 @@ where /// See [`Iterator::all()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.all) fn all(mut self, pool: &TaskPool, f: F) -> bool where - F: FnMut(Self::Item) -> bool + Send + Sync + Clone, + F: FnMut(B::Item) -> bool + Send + Sync + Clone, { pool.scope(|s| { while let Some(mut batch) = self.next_batch() { @@ -280,7 +277,7 @@ where /// See [`Iterator::any()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.any) fn any(mut self, pool: &TaskPool, f: F) -> bool where - F: FnMut(Self::Item) -> bool + Send + Sync + Clone, + F: FnMut(B::Item) -> bool + Send + Sync + Clone, { pool.scope(|s| { while let Some(mut batch) = self.next_batch() { @@ -300,7 +297,7 @@ where // TODO: Investigate optimizations for less copying fn position(mut self, pool: &TaskPool, f: F) -> Option where - F: FnMut(Self::Item) -> bool + Send + Sync + Clone, + F: FnMut(B::Item) -> bool + Send + Sync + Clone, { let poses = pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -331,9 +328,9 @@ where /// Returns the maximum item of a parallel iterator. /// /// See [`Iterator::max()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.max) - fn max(mut self, pool: &TaskPool) -> Option + fn max(mut self, pool: &TaskPool) -> Option where - Self::Item: Ord + Send + 'static, + B::Item: Ord + Send + 'static, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -348,9 +345,9 @@ where /// Returns the minimum item of a parallel iterator. /// /// See [`Iterator::min()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.min) - fn min(mut self, pool: &TaskPool) -> Option + fn min(mut self, pool: &TaskPool) -> Option where - Self::Item: Ord + Send + 'static, + B::Item: Ord + Send + 'static, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -365,11 +362,11 @@ where /// Returns the item that gives the maximum value from the specified function. /// /// See [`Iterator::max_by_key()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.max_by_key) - fn max_by_key(mut self, pool: &TaskPool, f: F) -> Option + fn max_by_key(mut self, pool: &TaskPool, f: F) -> Option where R: Ord, - F: FnMut(&Self::Item) -> R + Send + Sync + Clone, - Self::Item: Send + 'static, + F: FnMut(&B::Item) -> R + Send + Sync + Clone, + B::Item: Send + 'static, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -386,10 +383,10 @@ where /// function. /// /// See [`Iterator::max_by()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.max_by) - fn max_by(mut self, pool: &TaskPool, f: F) -> Option + fn max_by(mut self, pool: &TaskPool, f: F) -> Option where - F: FnMut(&Self::Item, &Self::Item) -> std::cmp::Ordering + Send + Sync + Clone, - Self::Item: Send + 'static, + F: FnMut(&B::Item, &B::Item) -> std::cmp::Ordering + Send + Sync + Clone, + B::Item: Send + 'static, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -405,11 +402,11 @@ where /// Returns the item that gives the minimum value from the specified function. /// /// See [`Iterator::min_by_key()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.min_by_key) - fn min_by_key(mut self, pool: &TaskPool, f: F) -> Option + fn min_by_key(mut self, pool: &TaskPool, f: F) -> Option where R: Ord, - F: FnMut(&Self::Item) -> R + Send + Sync + Clone, - Self::Item: Send + 'static, + F: FnMut(&B::Item) -> R + Send + Sync + Clone, + B::Item: Send + 'static, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -426,10 +423,10 @@ where /// function. /// /// See [`Iterator::min_by()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.min_by) - fn min_by(mut self, pool: &TaskPool, f: F) -> Option + fn min_by(mut self, pool: &TaskPool, f: F) -> Option where - F: FnMut(&Self::Item, &Self::Item) -> std::cmp::Ordering + Send + Sync + Clone, - Self::Item: Send + 'static, + F: FnMut(&B::Item, &B::Item) -> std::cmp::Ordering + Send + Sync + Clone, + B::Item: Send + 'static, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -447,7 +444,7 @@ where /// See [`Iterator::copied()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.copied) fn copied<'a, T>(self) -> Copied where - Self: ParallelIterator, + Self: ParallelIterator, T: 'a + Copy, { Copied { iter: self } @@ -458,7 +455,7 @@ where /// See [`Iterator::cloned()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.cloned) fn cloned<'a, T>(self) -> Cloned where - Self: ParallelIterator, + Self: ParallelIterator, T: 'a + Copy, { Cloned { iter: self } @@ -482,7 +479,7 @@ where /// See [`Iterator::sum()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.sum) fn sum(mut self, pool: &TaskPool) -> R where - S: std::iter::Sum + Send + 'static, + S: std::iter::Sum + Send + 'static, R: std::iter::Sum, { pool.scope(|s| { @@ -499,7 +496,7 @@ where /// See [`Iterator::product()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.product) fn product(mut self, pool: &TaskPool) -> R where - S: std::iter::Product + Send + 'static, + S: std::iter::Product + Send + 'static, R: std::iter::Product, { pool.scope(|s| { diff --git a/crates/bevy_tasks/src/lib.rs b/crates/bevy_tasks/src/lib.rs index 0fc7564e4d207..d4e8d9dfe1367 100644 --- a/crates/bevy_tasks/src/lib.rs +++ b/crates/bevy_tasks/src/lib.rs @@ -36,73 +36,5 @@ pub mod prelude { }; } -// The following docs are copied from `num_cpus`'s docs for the wrapped functions. -// Attributed under MIT or Apache: https://github.com/seanmonstar/num_cpus - -/// Returns the number of available CPUs of the current system. -/// -/// This function will get the number of logical cores. Sometimes this is different from the number -/// of physical cores (See [Simultaneous multithreading on Wikipedia][smt]). -/// -/// This will always return at least `1`. -/// -/// # Examples -/// -/// ```rust -/// let cpus = bevy_tasks::logical_core_count(); -/// if cpus > 1 { -/// println!("We are on a multicore system with {} CPUs", cpus); -/// } else { -/// println!("We are on a single core system"); -/// } -/// ``` -/// -/// # Note -/// -/// This will check [sched affinity] on Linux, showing a lower number of CPUs if the current -/// thread does not have access to all the computer's CPUs. -/// -/// This will also check [cgroups], frequently used in containers to constrain CPU usage. -/// -/// [smt]: https://en.wikipedia.org/wiki/Simultaneous_multithreading -/// [sched affinity]: http://www.gnu.org/software/libc/manual/html_node/CPU-Affinity.html -/// [cgroups]: https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt -#[inline(always)] -pub fn logical_core_count() -> usize { - num_cpus::get() -} - -/// Returns the number of physical cores of the current system. -/// -/// This will always return at least `1`. -/// -/// # Note -/// -/// Physical count is supported only on Linux, mac OS and Windows platforms. -/// On other platforms, or if the physical count fails on supported platforms, -/// this function returns the same as [`logical_core_count()`], which is the number of logical -/// CPUS. -/// -/// # Examples -/// -/// ```rust -/// let logical_cpus = bevy_tasks::logical_core_count(); -/// let physical_cpus = bevy_tasks::physical_core_count(); -/// if logical_cpus > physical_cpus { -/// println!("We have simultaneous multithreading with about {:.2} \ -/// logical cores to 1 physical core.", -/// (logical_cpus as f64) / (physical_cpus as f64)); -/// } else if logical_cpus == physical_cpus { -/// println!("Either we don't have simultaneous multithreading, or our \ -/// system doesn't support getting the number of physical CPUs."); -/// } else { -/// println!("We have less logical CPUs than physical CPUs, maybe we only have access to \ -/// some of the CPUs on our system."); -/// } -/// ``` -/// -/// [`logical_core_count()`]: fn.logical_core_count.html -#[inline(always)] -pub fn physical_core_count() -> usize { - num_cpus::get_physical() -} +pub use num_cpus::get as logical_core_count; +pub use num_cpus::get_physical as physical_core_count; diff --git a/crates/bevy_tasks/src/slice.rs b/crates/bevy_tasks/src/slice.rs index c4be07e6aad07..15ab477a844ff 100644 --- a/crates/bevy_tasks/src/slice.rs +++ b/crates/bevy_tasks/src/slice.rs @@ -2,9 +2,11 @@ use super::TaskPool; /// Provides functions for mapping read-only slices across a provided `TaskPool`. pub trait ParallelSlice: AsRef<[T]> { - /// Splits the slice into chunks of size `chunks_size` or less and queues up one task - /// per chunk on the provided `task_pool` and returns a mapped `Vec` of the collected - /// results. + /// Splits the slice in chunks of size `chunks_size` or less and maps the chunks + /// in parallel across the provided `task_pool`. One task is spawned in the task pool + /// for every chunk. + /// + /// Returns a `Vec` of the mapped results. /// /// # Example /// @@ -42,13 +44,14 @@ pub trait ParallelSlice: AsRef<[T]> { }) } - /// Splits the slice into a maximum of `self.len() / max_tasks` chunks of approximately - /// equal size and queues one task per chunk on the provided `task_pool` and returns a - /// mapped `Vec` of the collected results. + /// Splits the slice into a maximum of `max_tasks` chunks, and maps the chunks in parallel + /// across the provided `task_pool`. One task is spawned in the task pool for every chunk. /// /// If `max_tasks` is `None`, this function will attempt to use one chunk per thread in /// `task_pool`. /// + /// Returns a `Vec` of the mapped results. + /// /// # Example /// /// ```rust @@ -93,9 +96,11 @@ impl ParallelSlice for S where S: AsRef<[T]> {} /// Provides functions for mapping mutable slices across a provided `TaskPool`. pub trait ParallelSliceMut: AsMut<[T]> { - /// Splits the slice into chunks of size `chunks_size` or less and queues up one task - /// per chunk on the provided `task_pool` and returns a mapped `Vec` of the collected - /// results. + /// Splits the slice in chunks of size `chunks_size` or less and maps the chunks + /// in parallel across the provided `task_pool`. One task is spawned in the task pool + /// for every chunk. + /// + /// Returns a `Vec` of the mapped results. /// /// # Example /// @@ -136,13 +141,14 @@ pub trait ParallelSliceMut: AsMut<[T]> { }) } - /// Splits the slice into a maximum of `self.len() / max_tasks` chunks of approximately - /// equal size and queues one task per chunk on the provided `task_pool` and returns a - /// mapped `Vec` of the collected results. + /// Splits the slice into a maximum of `max_tasks` chunks, and maps the chunks in parallel + /// across the provided `task_pool`. One task is spawned in the task pool for every chunk. /// /// If `max_tasks` is `None`, this function will attempt to use one chunk per thread in /// `task_pool`. /// + /// Returns a `Vec` of the mapped results. + /// /// # Example /// /// ```rust From b8d17af76402c60ec3a8cc8727ac1482193c1c9e Mon Sep 17 00:00:00 2001 From: James Liu Date: Fri, 31 Dec 2021 20:57:36 -0500 Subject: [PATCH 5/9] More intra-doc link fixes --- crates/bevy_tasks/src/slice.rs | 4 ++-- crates/bevy_tasks/src/task_pool.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/bevy_tasks/src/slice.rs b/crates/bevy_tasks/src/slice.rs index 15ab477a844ff..269effb389218 100644 --- a/crates/bevy_tasks/src/slice.rs +++ b/crates/bevy_tasks/src/slice.rs @@ -1,6 +1,6 @@ use super::TaskPool; -/// Provides functions for mapping read-only slices across a provided `TaskPool`. +/// Provides functions for mapping read-only slices across a provided [`TaskPool`]. pub trait ParallelSlice: AsRef<[T]> { /// Splits the slice in chunks of size `chunks_size` or less and maps the chunks /// in parallel across the provided `task_pool`. One task is spawned in the task pool @@ -94,7 +94,7 @@ pub trait ParallelSlice: AsRef<[T]> { impl ParallelSlice for S where S: AsRef<[T]> {} -/// Provides functions for mapping mutable slices across a provided `TaskPool`. +/// Provides functions for mapping mutable slices across a provided [`TaskPool`]. pub trait ParallelSliceMut: AsMut<[T]> { /// Splits the slice in chunks of size `chunks_size` or less and maps the chunks /// in parallel across the provided `task_pool`. One task is spawned in the task pool diff --git a/crates/bevy_tasks/src/task_pool.rs b/crates/bevy_tasks/src/task_pool.rs index f119ff51cb699..4d50555f92f37 100644 --- a/crates/bevy_tasks/src/task_pool.rs +++ b/crates/bevy_tasks/src/task_pool.rs @@ -259,7 +259,7 @@ impl Default for TaskPool { /// A `TaskPool` scope for running one or more non-`'static` futures. /// -/// For more information, see `TaskPool::scope` for usage. +/// For more information, see [`TaskPool::scope`]. #[derive(Debug)] pub struct Scope<'scope, T> { executor: &'scope async_executor::Executor<'scope>, @@ -275,7 +275,7 @@ impl<'scope, T: Send + 'scope> Scope<'scope, T> { /// If the provided future is non-`Send`, [`Scope::spawn_local`] should be used /// instead. /// - /// For more information, see [`TaskPool::scope`] for usage. + /// For more information, see [`TaskPool::scope`]. pub fn spawn + 'scope + Send>(&mut self, f: Fut) { let task = self.executor.spawn(f); self.spawned.push(task); @@ -286,7 +286,7 @@ impl<'scope, T: Send + 'scope> Scope<'scope, T> { /// [`TaskPool::scope`]'s return value. Users should generally prefer to use /// [`Scope::spawn`] instead, unless the provided future is not `Send`. /// - /// For more information, see [`TaskPool::scope`] for usage. + /// For more information, see [`TaskPool::scope`]. pub fn spawn_local + 'scope>(&mut self, f: Fut) { let task = self.local_executor.spawn(f); self.spawned.push(task); From 0b5987f0e66719389438fc0a9a317e59251d3de3 Mon Sep 17 00:00:00 2001 From: james7132 Date: Fri, 31 Dec 2021 21:48:42 -0500 Subject: [PATCH 6/9] Fix broken benchmarks --- benches/benches/bevy_tasks/iter.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/benches/benches/bevy_tasks/iter.rs b/benches/benches/bevy_tasks/iter.rs index aafa4b6f5b3db..5f267dbc4b4e0 100644 --- a/benches/benches/bevy_tasks/iter.rs +++ b/benches/benches/bevy_tasks/iter.rs @@ -6,8 +6,6 @@ impl<'a, T> ParallelIterator> for ParChunks<'a, T> where T: 'a + Send + Sync, { - type Item = &'a T; - fn next_batch(&mut self) -> Option> { self.0.next().map(|s| s.iter()) } @@ -18,8 +16,6 @@ impl<'a, T> ParallelIterator> for ParChunksMut<'a, T> where T: 'a + Send + Sync, { - type Item = &'a mut T; - fn next_batch(&mut self) -> Option> { self.0.next().map(|s| s.iter_mut()) } From edd26d8cbf57bb999dd655ad89d568ac6225354c Mon Sep 17 00:00:00 2001 From: James Liu Date: Sat, 1 Jan 2022 14:41:18 -0500 Subject: [PATCH 7/9] Rename B -> BatchIter --- crates/bevy_tasks/src/iter/mod.rs | 84 +++++++++++++++---------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/crates/bevy_tasks/src/iter/mod.rs b/crates/bevy_tasks/src/iter/mod.rs index 990782d5923c3..02f6cd8528195 100644 --- a/crates/bevy_tasks/src/iter/mod.rs +++ b/crates/bevy_tasks/src/iter/mod.rs @@ -11,16 +11,16 @@ pub use adapters::*; /// run in parallel is inexpensive, *a [`ParallelIterator`] could take longer /// than a normal [`Iterator`]*. Therefore, you should profile your code before /// using [`ParallelIterator`]. -pub trait ParallelIterator +pub trait ParallelIterator where - B: Iterator + Send, + BatchIter: Iterator + Send, Self: Sized + Send, { /// Returns the next batch of items for processing. /// /// Each batch is an iterator with items of the same type as the /// [`ParallelIterator`]. Returns `None` when there are no batches left. - fn next_batch(&mut self) -> Option; + fn next_batch(&mut self) -> Option; /// Returns the bounds on the remaining number of items in the /// parallel iterator. @@ -46,7 +46,7 @@ where /// Consumes the parallel iterator and returns the last item. /// /// See [`Iterator::last()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.last) - fn last(mut self, _pool: &TaskPool) -> Option { + fn last(mut self, _pool: &TaskPool) -> Option { let mut last_item = None; while let Some(batch) = self.next_batch() { last_item = batch.last(); @@ -58,7 +58,7 @@ where /// /// See [`Iterator::nth()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.nth) // TODO: Optimize with size_hint on each batch - fn nth(mut self, _pool: &TaskPool, n: usize) -> Option { + fn nth(mut self, _pool: &TaskPool, n: usize) -> Option { let mut i = 0; while let Some(batch) = self.next_batch() { for item in batch { @@ -78,7 +78,7 @@ where // TODO: Use IntoParallelIterator for U fn chain(self, other: U) -> Chain where - U: ParallelIterator, + U: ParallelIterator, { Chain { left: self, @@ -93,7 +93,7 @@ where /// See [`Iterator::map()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map) fn map(self, f: F) -> Map where - F: FnMut(B::Item) -> T + Send + Clone, + F: FnMut(BatchIter::Item) -> T + Send + Clone, { Map { iter: self, f } } @@ -103,7 +103,7 @@ where /// See [`Iterator::for_each()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.for_each) fn for_each(mut self, pool: &TaskPool, f: F) where - F: FnMut(B::Item) + Send + Clone + Sync, + F: FnMut(BatchIter::Item) + Send + Clone + Sync, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -121,7 +121,7 @@ where /// See [`Iterator::filter()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter) fn filter(self, predicate: F) -> Filter where - F: FnMut(&B::Item) -> bool, + F: FnMut(&BatchIter::Item) -> bool, { Filter { iter: self, @@ -134,7 +134,7 @@ where /// See [`Iterator::filter_map()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter_map) fn filter_map(self, f: F) -> FilterMap where - F: FnMut(B::Item) -> Option, + F: FnMut(BatchIter::Item) -> Option, { FilterMap { iter: self, f } } @@ -145,7 +145,7 @@ where /// See [`Iterator::flat_map()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.flat_map) fn flat_map(self, f: F) -> FlatMap where - F: FnMut(B::Item) -> U, + F: FnMut(BatchIter::Item) -> U, U: IntoIterator, { FlatMap { iter: self, f } @@ -156,7 +156,7 @@ where /// See [`Iterator::flatten()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.flatten) fn flatten(self) -> Flatten where - B::Item: IntoIterator, + BatchIter::Item: IntoIterator, { Flatten { iter: self } } @@ -174,7 +174,7 @@ where /// See [`Iterator::inspect()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.inspect) fn inspect(self, f: F) -> Inspect where - F: FnMut(&B::Item), + F: FnMut(&BatchIter::Item), { Inspect { iter: self, f } } @@ -192,8 +192,8 @@ where // TODO: Investigate optimizations for less copying fn collect(mut self, pool: &TaskPool) -> C where - C: std::iter::FromIterator, - B::Item: Send + 'static, + C: std::iter::FromIterator, + BatchIter::Item: Send + 'static, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -211,9 +211,9 @@ where // TODO: Investigate optimizations for less copying fn partition(mut self, pool: &TaskPool, f: F) -> (C, C) where - C: Default + Extend + Send, - F: FnMut(&B::Item) -> bool + Send + Sync + Clone, - B::Item: Send + 'static, + C: Default + Extend + Send, + F: FnMut(&BatchIter::Item) -> bool + Send + Sync + Clone, + BatchIter::Item: Send + 'static, { let (mut a, mut b) = <(C, C)>::default(); pool.scope(|s| { @@ -239,7 +239,7 @@ where /// See [`Iterator::fold()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.fold) fn fold(mut self, pool: &TaskPool, init: C, f: F) -> Vec where - F: FnMut(C, B::Item) -> C + Send + Sync + Clone, + F: FnMut(C, BatchIter::Item) -> C + Send + Sync + Clone, C: Clone + Send + Sync + 'static, { pool.scope(|s| { @@ -258,7 +258,7 @@ where /// See [`Iterator::all()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.all) fn all(mut self, pool: &TaskPool, f: F) -> bool where - F: FnMut(B::Item) -> bool + Send + Sync + Clone, + F: FnMut(BatchIter::Item) -> bool + Send + Sync + Clone, { pool.scope(|s| { while let Some(mut batch) = self.next_batch() { @@ -277,7 +277,7 @@ where /// See [`Iterator::any()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.any) fn any(mut self, pool: &TaskPool, f: F) -> bool where - F: FnMut(B::Item) -> bool + Send + Sync + Clone, + F: FnMut(BatchIter::Item) -> bool + Send + Sync + Clone, { pool.scope(|s| { while let Some(mut batch) = self.next_batch() { @@ -297,7 +297,7 @@ where // TODO: Investigate optimizations for less copying fn position(mut self, pool: &TaskPool, f: F) -> Option where - F: FnMut(B::Item) -> bool + Send + Sync + Clone, + F: FnMut(BatchIter::Item) -> bool + Send + Sync + Clone, { let poses = pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -328,9 +328,9 @@ where /// Returns the maximum item of a parallel iterator. /// /// See [`Iterator::max()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.max) - fn max(mut self, pool: &TaskPool) -> Option + fn max(mut self, pool: &TaskPool) -> Option where - B::Item: Ord + Send + 'static, + BatchIter::Item: Ord + Send + 'static, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -345,9 +345,9 @@ where /// Returns the minimum item of a parallel iterator. /// /// See [`Iterator::min()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.min) - fn min(mut self, pool: &TaskPool) -> Option + fn min(mut self, pool: &TaskPool) -> Option where - B::Item: Ord + Send + 'static, + BatchIter::Item: Ord + Send + 'static, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -362,11 +362,11 @@ where /// Returns the item that gives the maximum value from the specified function. /// /// See [`Iterator::max_by_key()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.max_by_key) - fn max_by_key(mut self, pool: &TaskPool, f: F) -> Option + fn max_by_key(mut self, pool: &TaskPool, f: F) -> Option where R: Ord, - F: FnMut(&B::Item) -> R + Send + Sync + Clone, - B::Item: Send + 'static, + F: FnMut(&BatchIter::Item) -> R + Send + Sync + Clone, + BatchIter::Item: Send + 'static, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -383,10 +383,10 @@ where /// function. /// /// See [`Iterator::max_by()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.max_by) - fn max_by(mut self, pool: &TaskPool, f: F) -> Option + fn max_by(mut self, pool: &TaskPool, f: F) -> Option where - F: FnMut(&B::Item, &B::Item) -> std::cmp::Ordering + Send + Sync + Clone, - B::Item: Send + 'static, + F: FnMut(&BatchIter::Item, &BatchIter::Item) -> std::cmp::Ordering + Send + Sync + Clone, + BatchIter::Item: Send + 'static, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -402,11 +402,11 @@ where /// Returns the item that gives the minimum value from the specified function. /// /// See [`Iterator::min_by_key()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.min_by_key) - fn min_by_key(mut self, pool: &TaskPool, f: F) -> Option + fn min_by_key(mut self, pool: &TaskPool, f: F) -> Option where R: Ord, - F: FnMut(&B::Item) -> R + Send + Sync + Clone, - B::Item: Send + 'static, + F: FnMut(&BatchIter::Item) -> R + Send + Sync + Clone, + BatchIter::Item: Send + 'static, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -423,10 +423,10 @@ where /// function. /// /// See [`Iterator::min_by()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.min_by) - fn min_by(mut self, pool: &TaskPool, f: F) -> Option + fn min_by(mut self, pool: &TaskPool, f: F) -> Option where - F: FnMut(&B::Item, &B::Item) -> std::cmp::Ordering + Send + Sync + Clone, - B::Item: Send + 'static, + F: FnMut(&BatchIter::Item, &BatchIter::Item) -> std::cmp::Ordering + Send + Sync + Clone, + BatchIter::Item: Send + 'static, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -444,7 +444,7 @@ where /// See [`Iterator::copied()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.copied) fn copied<'a, T>(self) -> Copied where - Self: ParallelIterator, + Self: ParallelIterator, T: 'a + Copy, { Copied { iter: self } @@ -455,7 +455,7 @@ where /// See [`Iterator::cloned()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.cloned) fn cloned<'a, T>(self) -> Cloned where - Self: ParallelIterator, + Self: ParallelIterator, T: 'a + Copy, { Cloned { iter: self } @@ -479,7 +479,7 @@ where /// See [`Iterator::sum()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.sum) fn sum(mut self, pool: &TaskPool) -> R where - S: std::iter::Sum + Send + 'static, + S: std::iter::Sum + Send + 'static, R: std::iter::Sum, { pool.scope(|s| { @@ -496,7 +496,7 @@ where /// See [`Iterator::product()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.product) fn product(mut self, pool: &TaskPool) -> R where - S: std::iter::Product + Send + 'static, + S: std::iter::Product + Send + 'static, R: std::iter::Product, { pool.scope(|s| { From 050ad6e36de501d59d1f5488852cf1b680fc8ae6 Mon Sep 17 00:00:00 2001 From: James Liu Date: Sat, 15 Jan 2022 02:45:42 -0800 Subject: [PATCH 8/9] Add missing markdown bullet point list. Co-authored-by: Pascal Hertleif --- crates/bevy_tasks/src/slice.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_tasks/src/slice.rs b/crates/bevy_tasks/src/slice.rs index 269effb389218..73fb553648e8a 100644 --- a/crates/bevy_tasks/src/slice.rs +++ b/crates/bevy_tasks/src/slice.rs @@ -28,8 +28,8 @@ pub trait ParallelSlice: AsRef<[T]> { /// /// # See Also /// - /// [`ParallelSliceMut::par_chunk_map_mut`] for mapping mutable slices. - /// [`ParallelSlice::par_splat_map`] for mapping when a specific chunk size is unknown. + /// - [`ParallelSliceMut::par_chunk_map_mut`] for mapping mutable slices. + /// - [`ParallelSlice::par_splat_map`] for mapping when a specific chunk size is unknown. fn par_chunk_map(&self, task_pool: &TaskPool, chunk_size: usize, f: F) -> Vec where F: Fn(&[T]) -> R + Send + Sync, From 232527f4994cb8746602f2530405d7caa78bb5da Mon Sep 17 00:00:00 2001 From: james7132 Date: Sat, 15 Jan 2022 19:52:14 -0800 Subject: [PATCH 9/9] Mention the ordering of results returned by slice functions --- crates/bevy_tasks/src/slice.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_tasks/src/slice.rs b/crates/bevy_tasks/src/slice.rs index 73fb553648e8a..4b5d875ea989b 100644 --- a/crates/bevy_tasks/src/slice.rs +++ b/crates/bevy_tasks/src/slice.rs @@ -6,7 +6,7 @@ pub trait ParallelSlice: AsRef<[T]> { /// in parallel across the provided `task_pool`. One task is spawned in the task pool /// for every chunk. /// - /// Returns a `Vec` of the mapped results. + /// Returns a `Vec` of the mapped results in the same order as the input. /// /// # Example /// @@ -50,7 +50,7 @@ pub trait ParallelSlice: AsRef<[T]> { /// If `max_tasks` is `None`, this function will attempt to use one chunk per thread in /// `task_pool`. /// - /// Returns a `Vec` of the mapped results. + /// Returns a `Vec` of the mapped results in the same order as the input. /// /// # Example /// @@ -100,7 +100,7 @@ pub trait ParallelSliceMut: AsMut<[T]> { /// in parallel across the provided `task_pool`. One task is spawned in the task pool /// for every chunk. /// - /// Returns a `Vec` of the mapped results. + /// Returns a `Vec` of the mapped results in the same order as the input. /// /// # Example /// @@ -147,7 +147,7 @@ pub trait ParallelSliceMut: AsMut<[T]> { /// If `max_tasks` is `None`, this function will attempt to use one chunk per thread in /// `task_pool`. /// - /// Returns a `Vec` of the mapped results. + /// Returns a `Vec` of the mapped results in the same order as the input. /// /// # Example ///