//! Parallelism stream combinator extensions to futures::Stream use futures::{stream::TryStream, TryFutureExt}; use tokio::{runtime, task::JoinError}; use super::TryBroadbandExt; use crate::{utils::sys::available_parallelism, Error, Result}; /// Parallelism extensions to augment futures::StreamExt. These combinators are /// for computation-oriented workloads, unlike -band combinators for I/O /// workloads; these default to the available compute parallelism for the /// system. Threads are currently drawn from the tokio-spawn pool. Results are /// unordered. pub trait TryParallelExt where Self: TryStream> + Send + Sized, E: From + From + Send + 'static, T: Send + 'static, { fn paralleln_and_then( self, h: H, n: N, f: F, ) -> impl TryStream> + Send where N: Into>, H: Into>, F: Fn(Self::Ok) -> Result + Clone + Send + 'static, U: Send + 'static; fn parallel_and_then( self, h: H, f: F, ) -> impl TryStream> + Send where H: Into>, F: Fn(Self::Ok) -> Result + Clone + Send + 'static, U: Send + 'static, { self.paralleln_and_then(h, None, f) } } impl TryParallelExt for S where S: TryStream> + Send + Sized, E: From + From + Send + 'static, T: Send + 'static, { fn paralleln_and_then( self, h: H, n: N, f: F, ) -> impl TryStream> + Send where N: Into>, H: Into>, F: Fn(Self::Ok) -> Result + Clone + Send + 'static, U: Send + 'static, { let n = n.into().unwrap_or_else(available_parallelism); let h = h.into().unwrap_or_else(runtime::Handle::current); self.broadn_and_then(n, move |val| { let (h, f) = (h.clone(), f.clone()); async move { h.spawn_blocking(move || f(val)).map_err(E::from).await? } }) } }