use std::{marker, mem, ptr};
use crate::{
alloc,
base::marker::ThreadBound,
depot::{
self, arena,
heap::{
self, indexed,
indexed::resident::{
Borrowed, Control, Entry, Min, Owned, Peek, Phase, Slot, Vacant, Value, Values,
phase,
},
},
index::Initialized,
queue::links,
},
};
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Tag {
Common,
Control,
Data,
Active,
}
type Fields<T> = arena::raw::StagedValue<
(),
<T as Values>::Scheduled,
arena::raw::StagedValue<
(),
<T as Values>::Idle,
arena::raw::StagedValue<
(),
<T as Values>::Control,
arena::raw::StagedValue<(), <T as Values>::Data, <T as Values>::Active>,
>,
>,
>;
pub(super) struct Stored<T: Values>(Fields<T>);
impl<T: Values> Stored<T> {
fn new(value: Owned<T>) -> Self {
Self(match value {
Value::Scheduled(value) => arena::raw::StagedValue::queued((), value),
Value::Idle(value) => {
arena::raw::StagedValue::parked((), arena::raw::StagedValue::queued((), value))
}
Value::Control(value) => arena::raw::StagedValue::parked(
(),
arena::raw::StagedValue::parked((), arena::raw::StagedValue::queued((), value)),
),
Value::Data(value) => arena::raw::StagedValue::parked(
(),
arena::raw::StagedValue::parked(
(),
arena::raw::StagedValue::parked((), arena::raw::StagedValue::queued((), value)),
),
),
Value::Active(value) => arena::raw::StagedValue::parked(
(),
arena::raw::StagedValue::parked(
(),
arena::raw::StagedValue::parked((), arena::raw::StagedValue::parked((), value)),
),
),
})
}
unsafe fn get<F>(&self) -> &F {
unsafe { &*ptr::addr_of!(self.0).cast::<F>() }
}
unsafe fn get_mut<F>(&mut self) -> &mut F {
unsafe { &mut *ptr::addr_of_mut!(self.0).cast::<F>() }
}
unsafe fn take<F>(&mut self) -> F {
unsafe { ptr::read(ptr::addr_of!(self.0).cast::<F>()) }
}
unsafe fn drop_field<F>(&mut self) {
if mem::needs_drop::<F>() {
unsafe { ptr::drop_in_place(ptr::addr_of_mut!(self.0).cast::<F>()) };
}
}
}
pub(super) struct Node<T: Values> {
pub(super) common: T::Common,
hook: links::Hook,
tag: Tag,
value: Stored<T>,
}
impl<T: Values> Node<T> {
pub(super) fn scheduled(index: usize, common: T::Common, value: T::Scheduled) -> Self {
Self {
common,
hook: links::Hook::vacant(index as u32, links::Index::END),
tag: Tag::Common,
value: Stored::new(Value::Scheduled(value)),
}
}
}
pub(super) struct Core<T: Values> {
pub(super) nodes: Box<[Node<T>]>,
pub(super) control: links::Chain,
pub(super) data: links::Chain,
pub(super) active: u32,
_thread: ThreadBound,
}
impl<T: Values> Core<T> {
pub(super) fn new(nodes: Box<[Node<T>]>) -> Self {
Self {
nodes,
control: links::Chain::new(),
data: links::Chain::new(),
active: 0,
_thread: ThreadBound::NEW,
}
}
}
unsafe impl<T: Values> depot::raw::Hooks for Core<T> {
unsafe fn hook_raw(&self, index: links::Index) -> &links::Hook {
unsafe { &self.nodes.get_unchecked(index.get()).hook }
}
}
pub(super) struct Held<'a, T: Values, F: Phase<T>> {
core: &'a mut Core<T>,
index: links::Index,
field: marker::PhantomData<fn() -> F>,
}
impl<'a, T: Values, F: Phase<T>> Held<'a, T, F> {
unsafe fn new(core: &'a mut Core<T>, index: links::Index) -> Self {
Self {
core,
index,
field: marker::PhantomData,
}
}
pub(super) fn index(&self) -> usize {
self.index.get()
}
pub(super) fn get(&self) -> (&T::Common, &F::Item) {
let node = unsafe { self.core.nodes.get_unchecked(self.index.get()) };
(&node.common, unsafe { node.value.get() })
}
pub(super) fn get_mut(&mut self) -> (&mut T::Common, &mut F::Item) {
let node = unsafe { self.core.nodes.get_unchecked_mut(self.index.get()) };
(&mut node.common, unsafe { node.value.get_mut() })
}
pub(super) fn change<G: Phase<T>>(self, value: G::Item) -> (Held<'a, T, G>, F::Item) {
let value = Stored::new(G::value(value));
if F::TAG != G::TAG {
unsafe {
match F::TAG {
Tag::Control => {
self.core.control.unlink(self.core, self.index);
}
Tag::Data => {
self.core.data.unlink(self.core, self.index);
}
Tag::Active => {
self.core.active -= 1;
}
Tag::Common => {}
}
match G::TAG {
Tag::Control => self.core.control.link_back(self.core, self.index),
Tag::Data => self.core.data.link_back(self.core, self.index),
Tag::Active => {
self.core.active += 1;
}
Tag::Common => {}
}
}
}
let node = unsafe { self.core.nodes.get_unchecked_mut(self.index.get()) };
let old = unsafe { node.value.take::<F::Item>() };
node.value = value;
node.tag = G::TAG;
(
Held {
core: self.core,
index: self.index,
field: marker::PhantomData,
},
old,
)
}
}
pub(super) fn view<P: Ord, T: Values, C: alloc::raw::Extent>(
owner: &Min<P, T, C>,
index: usize,
) -> Option<(&T::Common, Borrowed<'_, T>)> {
use heap::raw::Store as _;
let node = owner.core.nodes.get(index)?;
let value = unsafe {
match node.tag {
Tag::Common
if *owner.order.positions().get_unchecked(index)
!= <u32 as depot::raw::Link>::NONE =>
{
Value::Scheduled(node.value.get())
}
Tag::Common => Value::Idle(node.value.get()),
Tag::Control => Value::Control(node.value.get()),
Tag::Data => Value::Data(node.value.get()),
Tag::Active => Value::Active(node.value.get()),
}
};
Some((&node.common, value))
}
pub(super) fn peek<P: Ord, T: Values, C: alloc::raw::Extent>(
owner: &Min<P, T, C>,
) -> Option<Peek<'_, P, T>> {
let (index, priority) = owner.order.peek()?;
let node = unsafe { owner.core.nodes.get_unchecked(index) };
let value = if node.tag == Tag::Control {
None
} else {
Some(unsafe { node.value.get() })
};
Some((index, priority, &node.common, value))
}
unsafe fn vacant<'a, P: Ord, T: Values, C: alloc::raw::Extent, F: Phase<T>>(
order: &'a mut indexed::Min<P, C>,
core: &'a mut Core<T>,
index: links::Index,
) -> Vacant<'a, P, T, F, C> {
let live: depot::raw::Proof<_, Initialized<indexed::Empty>> =
unsafe { depot::raw::Proof::new(((order, core), index.position())) };
let (order, core) = indexed::Slot::from_source(live).entry();
Slot {
order,
field: unsafe { Held::new(core, index) },
}
}
pub(super) fn entry<P: Ord, T: Values, C: alloc::raw::Extent>(
owner: &mut Min<P, T, C>,
index: usize,
) -> Option<Entry<'_, P, T, C>> {
let tag = owner.core.nodes.get(index)?.tag;
let index = unsafe { links::Index::new_usize(index) };
let Min { order, core } = owner;
Some(match tag {
Tag::Data => Entry::Data(unsafe { vacant(order, core, index) }),
Tag::Active => Entry::Active(unsafe { vacant(order, core, index) }),
Tag::Common | Tag::Control => {
let live: depot::raw::Proof<_, Initialized<()>> =
unsafe { depot::raw::Proof::new(((order, core), index.position())) };
let (order, core) = indexed::Slot::from_source(live).entry();
match (tag, order) {
(Tag::Control, indexed::Entry::Occupied(order)) => {
Entry::Control(Control::Full(Slot {
order,
field: unsafe { Held::new(core, index) },
}))
}
(Tag::Control, indexed::Entry::Vacant(order)) => {
Entry::Control(Control::Empty(Slot {
order,
field: unsafe { Held::new(core, index) },
}))
}
(_, indexed::Entry::Occupied(order)) => Entry::Scheduled(Slot {
order,
field: unsafe { Held::new(core, index) },
}),
(_, indexed::Entry::Vacant(order)) => Entry::Idle(Slot {
order,
field: unsafe { Held::new(core, index) },
}),
}
}
})
}
pub(super) fn control<P: Ord, T: Values, C: alloc::raw::Extent>(
owner: &mut Min<P, T, C>,
) -> Option<Control<'_, P, T, C>> {
let Min { order, core } = owner;
let index = core.control.first()?;
let live: depot::raw::Proof<_, Initialized<()>> =
unsafe { depot::raw::Proof::new(((order, core), index.position())) };
let (order, core) = indexed::Slot::from_source(live).entry();
Some(match order {
indexed::Entry::Occupied(order) => Control::Full(Slot {
order,
field: unsafe { Held::new(core, index) },
}),
indexed::Entry::Vacant(order) => Control::Empty(Slot {
order,
field: unsafe { Held::new(core, index) },
}),
})
}
pub(super) fn data<P: Ord, T: Values, C: alloc::raw::Extent>(
owner: &mut Min<P, T, C>,
) -> Option<Vacant<'_, P, T, phase::Data, C>> {
let Min { order, core } = owner;
let index = core.data.first()?;
Some(unsafe { vacant(order, core, index) })
}
pub(super) fn clear<P: Ord, T: Values, C: alloc::raw::Extent>(
owner: &mut Min<P, T, C>,
mut convert: impl FnMut(&mut T::Common, T::Scheduled) -> T::Idle,
) {
use heap::raw::Store as _;
for (node, &position) in owner.core.nodes.iter_mut().zip(owner.order.positions()) {
if position != <u32 as depot::raw::Link>::NONE && node.tag == Tag::Common {
let old = unsafe { node.value.take::<T::Scheduled>() };
node.value = Stored::new(Value::Idle(convert(&mut node.common, old)));
}
}
owner.order.clear();
}
pub(super) fn destroy<P: Ord, T: Values, C: alloc::raw::Extent>(owner: &mut Min<P, T, C>) {
use heap::raw::Store as _;
for (node, &position) in owner.core.nodes.iter_mut().zip(owner.order.positions()) {
unsafe {
match node.tag {
Tag::Common if position != <u32 as depot::raw::Link>::NONE => {
node.value.drop_field::<T::Scheduled>()
}
Tag::Common => node.value.drop_field::<T::Idle>(),
Tag::Control => node.value.drop_field::<T::Control>(),
Tag::Data => node.value.drop_field::<T::Data>(),
Tag::Active => node.value.drop_field::<T::Active>(),
}
}
}
}