use std::cell::Cell;
use std::iter::Map;
use std::thread::{Builder, JoinHandle};
use std::vec::IntoIter;
pub(crate) struct IteratorGuard<'a, T: Send>(
#[allow(clippy::type_complexity)]
Map<IntoIter<JoinGuard<'a, T>>, fn(JoinGuard<'a, T>) -> T>,
);
impl<T: Send> Iterator for IteratorGuard<'_, T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<T: Send> Drop for IteratorGuard<'_, T> {
fn drop(&mut self) {
while self.0.next().is_some() {}
}
}
struct JoinGuard<'a, T: Send> {
handle: Option<JoinHandle<T>>,
panicked: &'a Cell<bool>,
}
impl<'a, T: Send> JoinGuard<'a, T> {
fn new(handle: JoinHandle<T>, panicked: &'a Cell<bool>) -> Self {
Self {
handle: Some(handle),
panicked,
}
}
fn join(mut self) -> T {
let handle = unsafe { self.handle.take().unwrap_unchecked() };
let ret = handle.join();
if ret.is_err() {
self.panicked.set(true);
}
ret.unwrap()
}
}
impl<T: Send> Drop for JoinGuard<'_, T> {
fn drop(&mut self) {
if let Some(x) = self.handle.take() {
let handle = x.join();
if !self.panicked.get() {
self.panicked.set(true);
let _ = handle.unwrap();
}
}
}
}
pub(crate) fn spawn_threads<'a, I, M, R, T, U, V>(
it: I,
map: M,
reduce: R,
panicked: &'a Cell<bool>,
) -> V
where
I: Iterator<Item = T>,
I::Item: Send,
M: Fn(I::Item) -> U + Sync,
U: Send,
R: FnOnce(IteratorGuard<'a, U>) -> V,
{
let map = ↦
let it = it
.map(|chunk| {
let handle = unsafe { Builder::new().spawn_unchecked(move || map(chunk)).unwrap() };
JoinGuard::new(handle, panicked)
})
.collect::<Vec<_>>()
.into_iter()
.map(JoinGuard::join as _);
reduce(IteratorGuard(it))
}