use std::cell::{Cell, UnsafeCell};
use std::ptr;
use nexus_slab::SlotCell;
pub(crate) type EntryPtr<T> = *mut SlotCell<WheelEntry<T>>;
#[inline]
pub(crate) fn null_entry<T>() -> EntryPtr<T> {
ptr::null_mut()
}
#[repr(C)]
pub struct WheelEntry<T> {
prev: Cell<EntryPtr<T>>,
next: Cell<EntryPtr<T>>,
deadline_ticks: Cell<u64>,
refs: Cell<u8>,
level: Cell<u8>,
slot_idx: Cell<u16>,
value: UnsafeCell<Option<T>>,
}
#[allow(clippy::non_send_fields_in_send_ty)]
unsafe impl<T: Send> Send for WheelEntry<T> {}
impl<T> WheelEntry<T> {
#[inline]
pub(crate) fn new(deadline_ticks: u64, value: T, refs: u8) -> Self {
WheelEntry {
prev: Cell::new(null_entry()),
next: Cell::new(null_entry()),
deadline_ticks: Cell::new(deadline_ticks),
refs: Cell::new(refs),
level: Cell::new(0),
slot_idx: Cell::new(0),
value: UnsafeCell::new(Some(value)),
}
}
#[inline]
pub(crate) fn prev(&self) -> EntryPtr<T> {
self.prev.get()
}
#[inline]
pub(crate) fn next(&self) -> EntryPtr<T> {
self.next.get()
}
#[inline]
pub(crate) fn set_prev(&self, ptr: EntryPtr<T>) {
self.prev.set(ptr);
}
#[inline]
pub(crate) fn set_next(&self, ptr: EntryPtr<T>) {
self.next.set(ptr);
}
#[inline]
pub(crate) fn deadline_ticks(&self) -> u64 {
self.deadline_ticks.get()
}
#[inline]
pub(crate) fn set_deadline_ticks(&self, ticks: u64) {
self.deadline_ticks.set(ticks);
}
#[inline]
pub(crate) fn refs(&self) -> u8 {
self.refs.get()
}
#[inline]
pub(crate) fn dec_refs(&self) -> u8 {
let r = self.refs.get() - 1;
self.refs.set(r);
r
}
#[inline]
pub(crate) fn level(&self) -> u8 {
self.level.get()
}
#[inline]
pub(crate) fn slot_idx(&self) -> u16 {
self.slot_idx.get()
}
#[inline]
pub(crate) fn set_location(&self, level: u8, slot_idx: u16) {
self.level.set(level);
self.slot_idx.set(slot_idx);
}
#[inline]
pub(crate) unsafe fn take_value(&self) -> Option<T> {
unsafe { (*self.value.get()).take() }
}
}
#[inline]
pub(crate) unsafe fn entry_ref<'a, T>(ptr: EntryPtr<T>) -> &'a WheelEntry<T> {
unsafe { (*ptr).value_ref() }
}