use {
crate::pos_vec::{
pos::private::{AllocationView, Borrower, Data, Owner, TypeState},
tag::Tag,
},
alloc::boxed::Box,
core::{marker::PhantomData, mem::ManuallyDrop, ptr::NonNull},
};
#[derive(Debug)]
pub struct Pos<T: TypeState> {
data: NonNull<Data>,
_phantom: PhantomData<T>,
}
mod private {
use crate::pos_vec::tag::Tag;
pub struct Data {
#[cfg_attr(not(test), expect(dead_code))]
pub tag: Tag,
pub pos: usize,
}
pub trait TypeState {
type AllocationView: AllocationView;
}
pub struct Owner;
pub struct Borrower;
pub trait AllocationView {
const OWNER: bool;
}
impl AllocationView for Owner {
const OWNER: bool = true;
}
impl AllocationView for Borrower {
const OWNER: bool = false;
}
}
#[derive(Debug)]
pub(crate) struct InUse;
#[derive(Debug)]
pub(crate) struct Free;
#[derive(Debug)]
pub(super) struct Stored;
impl TypeState for InUse {
type AllocationView = Borrower;
}
impl TypeState for Free {
type AllocationView = Owner;
}
impl TypeState for Stored {
type AllocationView = Owner;
}
impl<T: TypeState> Drop for Pos<T> {
fn drop(&mut self) {
if <T::AllocationView as AllocationView>::OWNER {
unsafe {
let _ = Box::from_raw(self.data.as_ptr());
}
}
}
}
impl Pos<InUse> {
pub(super) unsafe fn deactivate(self, stored: Pos<Stored>) -> Pos<Free> {
#[cfg(test)]
assert_eq!(self.data, stored.data);
let _ = ManuallyDrop::new(stored);
Pos {
data: self.data,
_phantom: PhantomData,
}
}
}
impl Pos<Free> {
pub unsafe fn new(tag: Tag, pos: usize) -> Self {
Self {
data: Box::leak(Box::new(Data { tag, pos })).into(),
_phantom: PhantomData,
}
}
pub(super) fn activate(self) -> (Pos<InUse>, Pos<Stored>) {
let slf = ManuallyDrop::new(self);
let active = Pos {
data: slf.data,
_phantom: PhantomData,
};
let borrow = Pos {
data: slf.data,
_phantom: PhantomData,
};
(active, borrow)
}
}
impl Pos<Stored> {
pub(crate) unsafe fn set(&mut self, pos: Pos<Free>) -> usize {
#[cfg(test)]
assert_eq!(self.tag(), pos.tag());
let idx = pos.get();
unsafe {
self.data.as_mut().pos = idx;
}
idx
}
}
impl<T: TypeState<AllocationView = Owner>> Pos<T> {
#[cfg(test)]
pub(super) fn tag(&self) -> Tag {
unsafe {
self.data.as_ref().tag
}
}
pub(super) fn get(&self) -> usize {
unsafe {
self.data.as_ref().pos
}
}
}
impl<T: TypeState<AllocationView = Borrower>> Pos<T> {
pub(crate) unsafe fn get_unchecked(&self) -> usize {
unsafe {
self.data.as_ref().pos
}
}
#[cfg(test)]
pub(super) unsafe fn tag_unchecked(&self) -> Tag {
unsafe {
self.data.as_ref().tag
}
}
}
impl PartialEq for Pos<Free> {
fn eq(&self, other: &Self) -> bool {
self.get() == other.get()
}
}
impl PartialOrd for Pos<Free> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Eq for Pos<Free> {}
impl Ord for Pos<Free> {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.get().cmp(&other.get())
}
}