use std::{marker, mem};
use crate::depot::{index::Initialized, queue::links};
#[repr(transparent)]
pub struct Fifo<K: crate::depot::raw::Key, P = ()> {
pub(super) raw: links::Chain,
invariant: Domain<K, P>,
}
impl<K: crate::depot::raw::Key, P> Default for Fifo<K, P> {
fn default() -> Self {
Self::new()
}
}
impl<K: crate::depot::raw::Key, P> Fifo<K, P> {
pub fn front<S: crate::depot::raw::KeySource<P, Key = K>>(
source: crate::depot::raw::Proof<S, super::NonEmpty>,
) -> crate::depot::raw::Proof<(S, links::Index), Initialized<P>> {
let source = source.into_inner();
let index = unsafe { source.fifo().raw.front_key() };
unsafe { crate::depot::raw::Proof::new((source, index)) }
}
pub const fn new() -> Self {
Self {
raw: links::Chain::new(),
invariant: marker::PhantomData,
}
}
pub fn is_empty(&self) -> bool {
self.raw.is_empty()
}
}
const _: () = {
assert!(
mem::size_of::<Fifo<crate::depot::arena::slab::key::Handle>>() == 2 * mem::size_of::<u32>()
);
};
impl<K: crate::depot::raw::Key, P> Fifo<K, P> {
pub fn first<S: crate::depot::raw::KeySource<P, Key = K>>(
source: S,
) -> Option<crate::depot::raw::Proof<(S, links::Index), Initialized<P>>> {
let index = source.fifo().raw.first()?;
Some(unsafe { crate::depot::raw::Proof::new((source, index)) })
}
pub fn last<S: crate::depot::raw::KeySource<P, Key = K>>(
source: S,
) -> Option<crate::depot::raw::Proof<(S, links::Index), Initialized<P>>> {
let index = source.fifo().raw.last()?;
Some(unsafe { crate::depot::raw::Proof::new((source, index)) })
}
}
impl<K: crate::depot::raw::Key, P> Fifo<K, P> {
pub fn append<S: crate::depot::raw::KeyJoin<P, Key = K>>(source: S) {
let Some(head) = Self::first(source) else {
return;
};
let owner = head.source();
let source = &owner.fifo().raw;
let target = &owner.target().raw;
let first = S::link(unsafe { head.as_ref() });
let last = target.last().map(|index| {
S::link(unsafe { crate::depot::raw::Proof::new((owner, index)) })
});
unsafe {
crate::depot::raw::Splice::resolved(
target,
source,
&first.raw,
last.map(|link| &link.raw),
)
}
.commit();
}
}
type Domain<K, P> = marker::PhantomData<fn(K, P) -> (K, P)>;