use crate::index::Cursor as CursorTrait;
use prometheus_client::metrics::{counter::Counter, gauge::Gauge};
#[derive(PartialEq, Eq)]
pub(super) struct Record<V: Eq + Send + Sync> {
pub(super) value: V,
pub(super) next: Option<Box<Self>>,
}
pub(super) trait IndexEntry<V: Eq + Send + Sync>: Send + Sync {
fn get(&self) -> &V;
fn get_mut(&mut self) -> &mut Record<V>;
fn remove(self);
}
const MUST_CALL_NEXT: &str = "must call Cursor::next()";
const NO_ACTIVE_ITEM: &str = "no active item in Cursor";
#[derive(PartialEq, Eq)]
enum Phase<V: Eq + Send + Sync> {
Initial,
Entry,
Next(Box<Record<V>>),
Done,
EntryDeleted,
PostDeleteEntry,
PostDeleteNext(Option<Box<Record<V>>>),
PostInsert(Box<Record<V>>),
}
pub(super) struct Cursor<'a, V: Eq + Send + Sync, E: IndexEntry<V>> {
phase: Phase<V>,
entry: Option<E>,
past: Option<Box<Record<V>>>,
past_tail: Option<*mut Record<V>>,
past_pushed_list: bool,
keys: &'a Gauge,
items: &'a Gauge,
pruned: &'a Counter,
}
impl<'a, V: Eq + Send + Sync, E: IndexEntry<V>> Cursor<'a, V, E> {
pub(super) const fn new(
entry: E,
keys: &'a Gauge,
items: &'a Gauge,
pruned: &'a Counter,
) -> Self {
Self {
phase: Phase::Initial,
entry: Some(entry),
past: None,
past_tail: None,
past_pushed_list: false,
keys,
items,
pruned,
}
}
pub(super) fn past_push(&mut self, next: Box<Record<V>>) {
assert!(!self.past_pushed_list);
self.past_pushed_list = next.next.is_some();
if let Some(past_tail) = self.past_tail {
unsafe {
assert!((*past_tail).next.is_none());
(*past_tail).next = Some(next);
let tail_next = (*past_tail).next.as_mut().unwrap();
self.past_tail = Some(&mut **tail_next as *mut Record<V>);
}
} else {
self.past = Some(next);
self.past_tail = self.past.as_mut().map(|b| &mut **b as *mut Record<V>);
}
}
pub(super) fn value(&self) -> Option<&V> {
match &self.phase {
Phase::Initial => unreachable!(),
Phase::Entry => self.entry.as_ref().map(|e| e.get()),
Phase::Next(current) => Some(¤t.value),
Phase::Done | Phase::EntryDeleted => None,
Phase::PostDeleteEntry | Phase::PostDeleteNext(_) | Phase::PostInsert(_) => {
unreachable!()
}
}
}
}
impl<V: Eq + Send + Sync, E: IndexEntry<V>> CursorTrait for Cursor<'_, V, E> {
type Value = V;
fn update(&mut self, v: V) {
match &mut self.phase {
Phase::Initial => unreachable!("{MUST_CALL_NEXT}"),
Phase::Entry => {
self.entry.as_mut().unwrap().get_mut().value = v;
}
Phase::Next(next) => {
next.value = v;
}
Phase::Done
| Phase::EntryDeleted
| Phase::PostDeleteEntry
| Phase::PostDeleteNext(_)
| Phase::PostInsert(_) => unreachable!("{NO_ACTIVE_ITEM}"),
}
}
fn next(&mut self) -> Option<&V> {
match std::mem::replace(&mut self.phase, Phase::Done) {
Phase::Initial | Phase::PostDeleteEntry => {
self.phase = Phase::Entry;
}
Phase::Entry => {
if let Some(next) = self.entry.as_mut().unwrap().get_mut().next.take() {
self.phase = Phase::Next(next);
}
}
Phase::Next(mut current) | Phase::PostInsert(mut current) => {
let next = current.next.take();
self.past_push(current);
if let Some(next) = next {
self.phase = Phase::Next(next);
}
}
Phase::Done => {}
Phase::EntryDeleted => {
self.phase = Phase::EntryDeleted;
}
Phase::PostDeleteNext(current) => {
if let Some(current) = current {
self.phase = Phase::Next(current);
}
}
}
self.value()
}
fn insert(&mut self, v: V) {
self.items.inc();
match std::mem::replace(&mut self.phase, Phase::Done) {
Phase::Initial => unreachable!("{MUST_CALL_NEXT}"),
Phase::Entry => {
let new = Box::new(Record {
value: v,
next: self.entry.as_mut().unwrap().get_mut().next.take(),
});
self.phase = Phase::PostInsert(new);
}
Phase::Next(mut current) => {
let next = current.next.take();
self.past_push(current);
let new = Box::new(Record { value: v, next });
self.phase = Phase::PostInsert(new);
}
Phase::Done => {
let new = Box::new(Record {
value: v,
next: None,
});
self.past_push(new);
}
Phase::EntryDeleted => {
self.entry.as_mut().unwrap().get_mut().value = v;
}
Phase::PostDeleteEntry | Phase::PostDeleteNext(_) | Phase::PostInsert(_) => {
unreachable!("{MUST_CALL_NEXT}")
}
}
}
fn delete(&mut self) {
self.pruned.inc();
self.items.dec();
match std::mem::replace(&mut self.phase, Phase::Done) {
Phase::Initial => unreachable!("{MUST_CALL_NEXT}"),
Phase::Entry => {
let entry = self.entry.as_mut().unwrap().get_mut();
if let Some(next) = entry.next.take() {
entry.value = next.value;
entry.next = next.next;
self.phase = Phase::PostDeleteEntry;
return;
}
self.phase = Phase::EntryDeleted;
}
Phase::Next(mut current) => {
let next = current.next.take();
self.phase = Phase::PostDeleteNext(next);
}
Phase::Done | Phase::EntryDeleted => unreachable!("{NO_ACTIVE_ITEM}"),
Phase::PostDeleteEntry | Phase::PostDeleteNext(_) | Phase::PostInsert(_) => {
unreachable!("{MUST_CALL_NEXT}")
}
}
}
fn prune(&mut self, predicate: &impl Fn(&V) -> bool) {
while let Some(old) = self.next() {
if predicate(old) {
self.delete();
}
}
}
}
unsafe impl<'a, V, E> Send for Cursor<'a, V, E>
where
V: Eq + Send + Sync,
E: IndexEntry<V>,
{
}
unsafe impl<'a, V, E> Sync for Cursor<'a, V, E>
where
V: Eq + Send + Sync,
E: IndexEntry<V>,
{
}
impl<V: Eq + Send + Sync, E: IndexEntry<V>> Drop for Cursor<'_, V, E> {
fn drop(&mut self) {
let mut entry = self.entry.take().unwrap();
match std::mem::replace(&mut self.phase, Phase::Done) {
Phase::Initial | Phase::Entry => {
}
Phase::Next(next) => {
self.past_push(next);
}
Phase::Done => {
}
Phase::EntryDeleted => {
self.keys.dec();
entry.remove();
return;
}
Phase::PostDeleteEntry => {
}
Phase::PostDeleteNext(Some(next)) => {
self.past_push(next);
}
Phase::PostDeleteNext(None) => {
}
Phase::PostInsert(next) => {
self.past_push(next);
}
}
if let Some(past) = self.past.take() {
entry.get_mut().next = Some(past);
}
}
}
pub struct ImmutableCursor<'a, V: Eq + Send + Sync> {
current: Option<&'a Record<V>>,
}
impl<'a, V: Eq + Send + Sync> ImmutableCursor<'a, V> {
pub(super) const fn new(record: &'a Record<V>) -> Self {
Self {
current: Some(record),
}
}
}
impl<'a, V: Eq + Send + Sync> Iterator for ImmutableCursor<'a, V> {
type Item = &'a V;
fn next(&mut self) -> Option<Self::Item> {
self.current.map(|record| {
let value = &record.value;
self.current = record.next.as_deref();
value
})
}
}