pub(crate) fn map_slice<T, R, F>(input: &[T], function: F) -> Vec<R>
where
T: Copy + Sync,
R: Send,
F: Fn(T) -> R + Sync,
{
if input.len() < 2 {
return input.iter().copied().map(function).collect();
}
let workers = std::thread::available_parallelism()
.map_or(1, std::num::NonZeroUsize::get)
.min(input.len());
if workers == 1 {
return input.iter().copied().map(function).collect();
}
let chunk_size = input.len().div_ceil(workers);
std::thread::scope(|scope| {
let handles = input
.chunks(chunk_size)
.map(|chunk| {
let function = &function;
scope.spawn(move || chunk.iter().copied().map(function).collect::<Vec<_>>())
})
.collect::<Vec<_>>();
handles
.into_iter()
.flat_map(|handle| handle.join().expect("parallel repository worker panicked"))
.collect()
})
}
#[cfg(test)]
mod tests {
use super::map_slice;
#[test]
fn preserves_input_order() {
assert_eq!(map_slice(&[3, 1, 2], |value| value * 2), [6, 2, 4]);
assert!(map_slice::<u8, u8, _>(&[], |value| value).is_empty());
}
}