use super::*;
use core::{marker::PhantomData, ops::Deref};
pub struct Pool(Box<TP_CALLBACK_ENVIRON_V3>);
impl Pool {
pub fn new() -> Self {
let mut e = TP_CALLBACK_ENVIRON_V3 {
Version: 3,
CallbackPriority: TP_CALLBACK_PRIORITY_NORMAL,
Size: core::mem::size_of::<TP_CALLBACK_ENVIRON_V3>() as u32,
..Default::default()
};
unsafe {
e.Pool = check(CreateThreadpool(core::ptr::null()));
e.CleanupGroup = check(CreateThreadpoolCleanupGroup());
}
Self(Box::new(e))
}
pub fn with_scope<'env, F>(f: F)
where
F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>),
{
let pool = Pool::new();
pool.scope(f);
}
pub fn set_thread_limits(&self, min: u32, max: u32) {
unsafe {
check(SetThreadpoolThreadMinimum(self.0.Pool, min));
SetThreadpoolThreadMaximum(self.0.Pool, max);
}
}
pub fn submit<F: FnOnce() + Send + 'static>(&self, f: F) {
unsafe {
try_submit(&*self.0, f);
}
}
pub fn scope<'env, F>(&self, f: F)
where
F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>),
{
struct DropGuard<'a>(&'a Pool);
impl Drop for DropGuard<'_> {
fn drop(&mut self) {
self.0.join();
}
}
let _guard = DropGuard(self);
let scope = Scope {
pool: self,
env: PhantomData,
scope: PhantomData,
};
f(&scope);
}
pub fn join(&self) {
unsafe {
CloseThreadpoolCleanupGroupMembers(self.0.CleanupGroup, 0, core::ptr::null_mut());
}
}
}
impl Default for Pool {
fn default() -> Self {
Self::new()
}
}
unsafe impl Sync for Pool {}
unsafe impl Send for Pool {}
impl Drop for Pool {
fn drop(&mut self) {
self.join();
unsafe {
CloseThreadpoolCleanupGroup(self.0.CleanupGroup);
CloseThreadpool(self.0.Pool);
}
}
}
pub struct Scope<'scope, 'env: 'scope> {
pool: &'scope Pool,
scope: PhantomData<&'scope mut &'scope ()>,
env: PhantomData<&'env mut &'env ()>,
}
impl<'scope, 'env> Scope<'scope, 'env> {
pub fn submit<F: FnOnce() + Send + 'scope>(&'scope self, f: F) {
unsafe {
try_submit(&*self.pool.0, f);
}
}
}
impl Deref for Scope<'_, '_> {
type Target = Pool;
fn deref(&self) -> &Self::Target {
self.pool
}
}