use std::{mem, ptr};
use dope_sys::thread;
use crate::platform::thread::{Finished, Slot, Task};
pub(super) struct Group<T, O, P> {
pub(super) slots: Vec<Slot<T, O, P>>,
pub(super) started: usize,
}
impl<T, O, P> Drop for Group<T, O, P> {
fn drop(&mut self) {
self.take();
}
}
impl<T, O, P> Group<T, O, P> {
pub(super) fn parents_mut(&mut self) -> impl ExactSizeIterator<Item = &mut P> {
let slots = self.slots.as_mut_ptr();
(0..self.started).map(move |index| {
unsafe {
let slot = slots.add(index);
&mut *ptr::addr_of_mut!((*slot).parent)
}
})
}
pub(super) fn take(&mut self) -> Finished<T, O, P> {
for slot in unsafe { self.slots.get_unchecked(..self.started) } {
let handle = unsafe {
slot.thread
.replace(mem::MaybeUninit::uninit())
.assume_init()
};
handle.join();
}
let len = self.slots.len();
let slots = self.slots.as_mut_ptr();
unsafe { self.slots.set_len(self.started) };
for index in self.started..len {
let mut slot = unsafe { slots.add(index).read() };
unsafe { mem::ManuallyDrop::drop(&mut slot.value.get_mut().task) };
}
self.started = 0;
Finished {
slots: mem::take(&mut self.slots).into_iter(),
}
}
}
unsafe impl<T: Task<Output = O>, O, P> thread::raw::Task for Slot<T, O, P> {
unsafe fn run(context: ptr::NonNull<Self>) {
let slot = context.as_ptr();
let task = unsafe { mem::ManuallyDrop::take(&mut (*(*slot).value.get()).task) };
let output = task.run();
unsafe { (*(*slot).value.get()).output = mem::ManuallyDrop::new(output) };
}
}