use std::{array, cell, fmt::Debug, mem::MaybeUninit, num::NonZero, ops, ptr};
pub(crate) use state::{Account, Live};
use crate::{
base::marker::ThreadBound,
mem::{rc, slot},
};
mod balance;
pub use balance::Balance;
mod bound;
pub use bound::Bound;
mod charge;
pub use charge::Charge;
mod grant;
pub use grant::Grant;
mod lane;
pub use lane::Lane;
mod pool;
pub use pool::Pool;
mod state;
pub use state::State;
mod owner;
pub use owner::Owner;
type Domain<Tag, W = ()> = std::marker::PhantomData<(fn(Tag) -> Tag, W, ThreadBound)>;
pub(crate) fn cast_uninit<T, U, const N: usize>(
source: &mut [MaybeUninit<T>; N],
) -> &mut [MaybeUninit<U>; N] {
const {
assert!(size_of::<U>() <= size_of::<T>(), "size");
assert!(align_of::<T>().is_multiple_of(align_of::<U>()), "align");
};
unsafe { &mut *ptr::from_mut(source).cast::<[MaybeUninit<U>; N]>() }
}
#[derive(Debug)]
#[repr(transparent)]
pub struct Occupied<'a, T> {
source: &'a mut Option<T>,
bound: ThreadBound,
}
#[derive(Debug)]
#[must_use]
#[repr(transparent)]
pub struct Vacant<'a, T> {
source: &'a mut Option<T>,
bound: ThreadBound,
}
pub(crate) unsafe fn project<T, M>(source: &slot::Storage<T, M>) -> &T {
unsafe { initialized(&source.value) }
}
pub(crate) unsafe fn initialized<T>(source: &Option<T>) -> &T {
unsafe { source.as_slice().get_unchecked(0) }
}
pub(crate) unsafe fn project_mut<T, M>(source: &mut slot::Storage<T, M>) -> &mut T {
unsafe { &mut *source.value.as_mut_slice().as_mut_ptr() }
}
pub(crate) unsafe fn occupy<T, M>(storage: &mut slot::Storage<T, M>) -> Occupied<'_, T> {
Occupied {
source: &mut storage.value,
bound: ThreadBound::NEW,
}
}
pub(crate) unsafe fn vacancy<T, M>(storage: &mut slot::Storage<T, M>) -> Vacant<'_, T> {
Vacant {
source: &mut storage.value,
bound: ThreadBound::NEW,
}
}
impl<'a, T> Occupied<'a, T> {
pub fn clear(self) {
*self.source = None;
}
pub fn get(&self) -> &T {
unsafe { initialized(self.source) }
}
pub fn get_mut(&mut self) -> &mut T {
unsafe { &mut *self.source.as_mut_slice().as_mut_ptr() }
}
pub fn into_mut(self) -> &'a mut T {
unsafe { &mut *self.source.as_mut_slice().as_mut_ptr() }
}
pub fn take(self) -> (T, Vacant<'a, T>) {
let value = unsafe {
let value = self.source.as_mut_slice().as_mut_ptr().read();
ptr::write(self.source, None);
value
};
(
value,
Vacant {
source: self.source,
bound: ThreadBound::NEW,
},
)
}
}
impl<'a, T> Vacant<'a, T> {
pub fn insert(self, value: T) -> Occupied<'a, T> {
unsafe { ptr::write(self.source, Some(value)) };
Occupied {
source: self.source,
bound: ThreadBound::NEW,
}
}
}
type Partition<S, const N: usize, A, P> = (
Grant<S, N, <P as Exact<N, <S as Source<N>>::Word, A>>::Left>,
Grant<S, N, <P as Exact<N, <S as Source<N>>::Word, A>>::Right>,
);
#[derive(Debug)]
#[repr(transparent)]
pub struct Count<W: Counter = u32> {
value: cell::Cell<W>,
thread: ThreadBound,
}
impl<W: Counter> Count<W> {
pub const fn empty() -> Self {
Self {
value: cell::Cell::new(W::ZERO),
thread: ThreadBound::NEW,
}
}
pub const fn one() -> Self {
Self {
value: cell::Cell::new(W::ONE),
thread: ThreadBound::NEW,
}
}
}
const _: () = assert!(size_of::<Count>() == size_of::<u32>());
pub unsafe trait Edge<W: Counter = u32> {
fn count(&self) -> &crate::mem::raw::Count<W>;
#[inline]
fn is_empty(&self) -> bool {
self.count().value.get() == W::ZERO
}
#[inline]
fn is_unique(&self) -> bool {
self.count().value.get() == W::ONE
}
#[inline]
unsafe fn activate(&self) {
self.count().value.set(W::ONE);
}
unsafe fn start_pair(&self) {
self.count().value.set(W::TWO);
}
unsafe fn retire(&self) {
self.count().value.set(W::ZERO);
}
#[inline]
unsafe fn try_retain(&self) -> Result<(), rc::Error> {
let count = self.count();
let current = unsafe { Live::new(count.value.get()) };
count.value.set(current.try_retain()?.get());
Ok(())
}
#[inline]
unsafe fn release(&self) -> rc::Release {
let count = self.count();
let (next, release) = match unsafe { Live::new(count.value.get()) }.release() {
None => (W::ZERO, rc::Release::Last),
Some(next) => (next.get(), rc::Release::Shared),
};
count.value.set(next);
release
}
}
pub unsafe trait Target<W: Counter = u32>: crate::mem::raw::Edge<W> + Sized {
unsafe fn destroy(pointer: ptr::NonNull<Self>);
}
pub unsafe trait Amount<const N: usize, W: crate::mem::raw::Word>: Copy + Eq {
fn get(self) -> [W; N];
}
unsafe impl<const N: usize, W: crate::mem::raw::Word> Amount<N, W> for [W; N] {
fn get(self) -> [W; N] {
self
}
}
pub type Accounts<'a, const N: usize, Tag, W = usize> =
(&'a cell::Cell<[W; N]>, &'a State<N, Tag, W>);
pub unsafe trait Source<const N: usize>: Copy {
type Tag;
type Word: Word;
unsafe fn accounts(&self) -> Accounts<'_, N, Self::Tag, Self::Word>;
fn held(&self) -> [Self::Word; N] {
unsafe { self.accounts() }.1.held.get()
}
fn reserve(&self) -> [Self::Word; N] {
unsafe { self.accounts() }.1.reserve
}
fn can_acquire(&self, amount: [Self::Word; N]) -> bool {
let (shared, state) = unsafe { self.accounts() };
Balance::new(state.held.get(), shared.get())
.try_acquire(state.reserve, amount)
.is_ok()
}
}
unsafe impl<const N: usize, W: Word> Sum<N, W> for [W; N] {
unsafe fn add_raw(self, other: Self) -> Self {
array::from_fn(|axis| self[axis].wrapping_add(other[axis]))
}
}
pub unsafe trait Sum<const N: usize, W: Word>: Amount<N, W> {
unsafe fn add_raw(self, other: Self) -> Self;
}
pub unsafe trait ExactRebind<const N: usize, W: Word, A: Amount<N, W>>: Sized {
type Output: Amount<N, W>;
fn rebind(self, source: A) -> Self::Output;
}
pub unsafe trait Rebind<const N: usize, W: Word, A: Amount<N, W>>:
ExactRebind<N, W, A>
{
}
pub unsafe trait Exact<const N: usize, W: Word, A: Amount<N, W>>: Sized {
type Input;
type Left: Amount<N, W>;
type Right: Amount<N, W>;
fn parts(self, source: A, input: Self::Input) -> (Self::Left, Self::Right);
}
pub unsafe trait Word:
Copy + Eq + Ord + ops::Add<Output = Self> + ops::Sub<Output = Self> + owner::Sealed
{
const ZERO: Self;
fn to_usize(self) -> usize;
fn wrap(value: usize) -> Self;
fn checked_add(self, other: Self) -> Option<Self>;
fn sub_or_zero(self, other: Self) -> Self;
fn wrapping_add(self, other: Self) -> Self {
Self::wrap(self.to_usize().wrapping_add(other.to_usize()))
}
fn wrapping_sub(self, other: Self) -> Self {
Self::wrap(self.to_usize().wrapping_sub(other.to_usize()))
}
}
unsafe impl Word for u32 {
const ZERO: Self = 0;
fn to_usize(self) -> usize {
self as usize
}
fn checked_add(self, other: Self) -> Option<Self> {
self.checked_add(other)
}
fn sub_or_zero(self, other: Self) -> Self {
self.saturating_sub(other)
}
fn wrap(value: usize) -> Self {
value as Self
}
}
const _: () = assert!(usize::BITS >= u32::BITS);
unsafe impl Word for usize {
const ZERO: Self = 0;
fn to_usize(self) -> usize {
self
}
fn checked_add(self, other: Self) -> Option<Self> {
self.checked_add(other)
}
fn sub_or_zero(self, other: Self) -> Self {
self.saturating_sub(other)
}
fn wrap(value: usize) -> Self {
value
}
}
use crate::base::cell::region;
#[must_use = "an unused proof must settle its matching reservation"]
#[repr(transparent)]
pub struct Unused<'id> {
amount: usize,
token: region::Token<region::Identity<'id>>,
}
impl<'id> Unused<'id> {
pub const unsafe fn new(amount: usize, token: region::Token<region::Identity<'id>>) -> Self {
Self { amount, token }
}
pub(in crate::mem) fn into_inner(self) -> (usize, region::Token<region::Identity<'id>>) {
(self.amount, self.token)
}
}
const _: () = assert!(size_of::<Unused<'static>>() == size_of::<usize>());
pub trait Counter: Word {
type NonZero: Copy + Debug;
const ONE: Self;
const TWO: Self;
const LIVE: Self::NonZero;
unsafe fn nonzero(self) -> Self::NonZero;
fn get(value: Self::NonZero) -> Self;
}
impl Counter for u32 {
type NonZero = NonZero<Self>;
const ONE: Self = 1;
const TWO: Self = 2;
const LIVE: Self::NonZero = NonZero::<Self>::MIN;
unsafe fn nonzero(self) -> Self::NonZero {
unsafe { NonZero::new_unchecked(self) }
}
fn get(value: Self::NonZero) -> Self {
value.get()
}
}
impl Counter for usize {
type NonZero = NonZero<Self>;
const ONE: Self = 1;
const TWO: Self = 2;
const LIVE: Self::NonZero = NonZero::<Self>::MIN;
unsafe fn nonzero(self) -> Self::NonZero {
unsafe { NonZero::new_unchecked(self) }
}
fn get(value: Self::NonZero) -> Self {
value.get()
}
}