use crate::queue::Queue;
use crate::task_batch::TaskBatch;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread::{self, Thread};
pub struct Scope<'scope, 'env: 'scope> {
counter: AtomicUsize,
queue: &'env Queue,
thread: Thread,
_marker: PhantomData<(&'scope mut &'scope (), &'env mut &'env ())>,
}
impl<'scope, 'env> Scope<'scope, 'env> {
pub(crate) fn new(queue: &'env Queue) -> Self {
Self {
counter: AtomicUsize::new(0),
queue,
thread: thread::current(),
_marker: PhantomData,
}
}
#[inline]
pub fn run<T: 'scope>(&self, task_fn: fn(&T), params: &'scope [T]) {
if !params.is_empty() {
self.counter.fetch_add(params.len(), Ordering::Relaxed);
let batch = unsafe {
TaskBatch::new(
task_fn,
params,
Some((&raw const self.counter, self.thread.clone())),
)
};
self.queue.enqueue(batch, params.len());
}
}
#[inline]
pub fn wait(&self) {
while self.counter.load(Ordering::Acquire) != 0 {
thread::park();
}
}
#[must_use]
#[inline]
pub fn is_complete(&self) -> bool {
self.counter.load(Ordering::Acquire) == 0
}
}
pub(crate) struct ScopeGuard<'s, 'scope, 'env>(pub &'s Scope<'scope, 'env>);
impl Drop for ScopeGuard<'_, '_, '_> {
fn drop(&mut self) {
self.0.wait();
}
}