use crate::scoped_start::{Started, start_or_run_with};
use std::thread::Scope;
pub trait ScopeBody<'env> {
type Output;
fn run<'scope>(self, scope: &'scope Scope<'scope, 'env>) -> Self::Output;
}
pub fn in_thread_scope<'env, B: ScopeBody<'env>>(body: B) -> B::Output {
#[cfg_attr(
dylint_lib = "monochromatic_lint_closure",
expect(
avoidable_closure,
reason = "`std::thread::scope` accepts only a callable, and it must carry the body; see package/git-policy/cli/doc/closure-lint-suppressions.md"
)
)]
let value: B::Output = std::thread::scope(move |scope| { return body.run(scope); });
return value;
}
struct AllJobs<S, T> {
states: Vec<S>,
job: fn(S) -> T,
}
impl<'env, S: Send + 'env, T: Send + 'env> ScopeBody<'env> for AllJobs<S, T> {
type Output = Vec<std::thread::Result<T>>;
fn run<'scope>(self, scope: &'scope Scope<'scope, 'env>) -> Self::Output {
let mut started: Vec<Started<'scope, T>> = Vec::new();
for state in self.states {
started.push(start_or_run_with(scope, state, self.job));
}
let mut results: Vec<std::thread::Result<T>> = Vec::new();
for each in started {
results.push(each.join());
}
return results;
}
}
pub fn run_all_side_by_side<S: Send, T: Send>(states: Vec<S>, job: fn(S) -> T) -> Vec<std::thread::Result<T>> {
return in_thread_scope(AllJobs { states, job });
}
struct BesideCaller<S, T, C, U> {
thread_state: S,
thread_job: fn(S) -> T,
caller_state: C,
caller_job: fn(C) -> U,
}
impl<'env, S: Send + 'env, T: Send + 'env, C, U> ScopeBody<'env> for BesideCaller<S, T, C, U> {
type Output = (std::thread::Result<T>, U);
fn run<'scope>(self, scope: &'scope Scope<'scope, 'env>) -> Self::Output {
let started: Started<'scope, T> = start_or_run_with(scope, self.thread_state, self.thread_job);
let here: U = (self.caller_job)(self.caller_state);
return (started.join(), here);
}
}
pub fn run_beside_caller<S: Send, T: Send, C, U>(
(thread_state, thread_job): (S, fn(S) -> T),
(caller_state, caller_job): (C, fn(C) -> U),
) -> (std::thread::Result<T>, U) {
return in_thread_scope(BesideCaller { thread_state, thread_job, caller_state, caller_job });
}
#[cfg(test)]
#[path = "side_by_side_threads_tests.rs"]
mod tests;