use std::{mem, num::NonZero};
use dope_core::driver::route::{indices, table};
pub trait Policy {
type State: Default + State;
const AUTHORITATIVE: bool;
}
#[derive(Default)]
pub struct Frozen;
#[derive(Default)]
pub struct Scan {
next: indices::SlotIndex,
remaining: Option<(table::Capacity, NonZero<u32>)>,
}
pub trait State: sealed::State {
fn scan(&mut self) -> Option<&mut Scan>;
fn next(&mut self) -> Option<indices::SlotIndex>;
fn is_pending(&self) -> bool;
}
mod sealed {
pub trait State {}
impl State for super::Frozen {}
impl State for super::Scan {}
}
impl Scan {
pub(crate) fn arm(&mut self, cap: table::Capacity) {
self.remaining = NonZero::new(cap.count().raw()).map(|left| (cap, left));
}
}
impl State for Frozen {
fn scan(&mut self) -> Option<&mut Scan> {
None
}
fn next(&mut self) -> Option<indices::SlotIndex> {
None
}
fn is_pending(&self) -> bool {
false
}
}
impl State for Scan {
fn scan(&mut self) -> Option<&mut Scan> {
Some(self)
}
fn next(&mut self) -> Option<indices::SlotIndex> {
let (cap, left) = self.remaining?;
let slot = self.next;
self.next = cap.next(slot).unwrap_or(indices::SlotIndex::ZERO);
self.remaining = NonZero::new(left.get() - 1).map(|left| (cap, left));
Some(slot)
}
fn is_pending(&self) -> bool {
self.remaining.is_some()
}
}
#[derive(Clone, Copy)]
pub struct Preserve;
impl Policy for Preserve {
type State = Frozen;
const AUTHORITATIVE: bool = false;
}
#[derive(Clone, Copy)]
pub struct Replace;
impl Policy for Replace {
type State = Scan;
const AUTHORITATIVE: bool = true;
}
const _: () = assert!(mem::size_of::<Frozen>() == 0);
const _: () = assert!(mem::size_of::<Scan>() == 3 * mem::size_of::<u32>());