use super::{
ExactParallelSource, ExactSourceDescriptor, IntoExactParallelSource,
SimpleExactSourceDescriptor, SourceCleanup,
};
use std::cell::UnsafeCell;
use std::mem::MaybeUninit;
#[must_use = "iterator adaptors are lazy"]
pub struct ArrayParallelSource<T, const N: usize> {
array: [T; N],
}
impl<T: Send, const N: usize> IntoExactParallelSource for [T; N] {
type Item = T;
type Source = ArrayParallelSource<T, N>;
fn into_par_iter(self) -> Self::Source {
ArrayParallelSource { array: self }
}
}
impl<T: Send, const N: usize> ExactParallelSource for ArrayParallelSource<T, N> {
type Item = T;
fn exact_descriptor(self) -> impl ExactSourceDescriptor<Item = Self::Item> + Sync {
ArraySourceDescriptor {
array: ArrayWrapper::new(self.array),
}
}
}
struct ArraySourceDescriptor<T, const N: usize> {
array: ArrayWrapper<T, N>,
}
impl<T: Send, const N: usize> SourceCleanup for ArraySourceDescriptor<T, N> {
const NEEDS_CLEANUP: bool = std::mem::needs_drop::<T>();
fn len(&self) -> usize {
N
}
unsafe fn cleanup_item_range(&self, range: std::ops::Range<usize>) {
if Self::NEEDS_CLEANUP {
debug_assert!(range.start <= range.end);
debug_assert!(range.start <= N);
debug_assert!(range.end <= N);
let base_ptr: *mut T = self.array.start();
let start_ptr: *mut T = unsafe { base_ptr.add(range.start) };
let slice: *mut [T] =
std::ptr::slice_from_raw_parts_mut(start_ptr, range.end - range.start);
unsafe { std::ptr::drop_in_place(slice) };
}
}
}
impl<T: Send, const N: usize> SimpleExactSourceDescriptor for ArraySourceDescriptor<T, N> {
type Item = T;
unsafe fn simple_exact_fetch_item(&self, index: usize) -> Self::Item {
debug_assert!(index < N);
let base_ptr: *const T = self.array.start();
let item_ptr: *const T = unsafe { base_ptr.add(index) };
let item: T = unsafe { std::ptr::read(item_ptr) };
item
}
}
struct ArrayWrapper<T, const N: usize>(UnsafeCell<[MaybeUninit<T>; N]>);
impl<T, const N: usize> ArrayWrapper<T, N> {
fn new(array: [T; N]) -> Self {
let array: [MaybeUninit<T>; N] = MaybeUninit::new(array).transpose();
ArrayWrapper(UnsafeCell::new(array))
}
fn start(&self) -> *mut T {
let array_ptr: *mut [MaybeUninit<T>; N] = self.0.get();
let start_ptr: *mut MaybeUninit<T> = array_ptr.as_mut_ptr();
start_ptr as *mut T
}
}
unsafe impl<T: Send, const N: usize> Sync for ArrayWrapper<T, N> {}