use clap::ValueEnum;
use std::fmt::{Debug, Display};
pub trait Restarter: Debug + Clone {
fn new() -> Self;
fn restarts_in(&self) -> usize;
fn increment_restarts_in(&mut self);
fn restart(&mut self);
fn num_restarts(&self) -> usize;
fn should_restart(&mut self) -> bool {
if self.restarts_in() == 0 {
self.restart();
true
} else {
self.increment_restarts_in();
false
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Luby<const N: usize> {
restarts: usize,
restarts_in: usize,
restarts_interval: usize,
restarts_next: usize,
first: usize,
second: usize,
}
impl<const N: usize> Iterator for Luby<N> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
if self.first & self.first.wrapping_neg() == self.second {
self.first += 1;
self.second = 1;
} else {
self.second *= 2;
}
Some(self.second * N)
}
}
impl<const N: usize> Luby<N> {
#[allow(dead_code)]
fn luby(x: usize) -> usize {
let mut k = 1_usize;
while (1 << (k - 1)) <= x {
k = k.wrapping_add(1);
}
if x == (1 << (k - 2)) {
1 << (k - 2)
} else {
Self::luby(x - (1 << (k - 2)))
}
}
}
impl<const N: usize> Restarter for Luby<N> {
fn new() -> Self {
Self {
restarts: 0,
restarts_in: 0,
restarts_interval: N,
restarts_next: 1,
first: 1,
second: 1,
}
}
fn restarts_in(&self) -> usize {
self.restarts_in
}
fn increment_restarts_in(&mut self) {
self.restarts_in = self.restarts_in.wrapping_sub(1);
}
fn restart(&mut self) {
self.restarts = self.restarts.wrapping_add(1);
self.restarts_in = self.restarts_interval;
if let Some(next_interval) = self.next() {
self.restarts_interval = next_interval;
} else {
self.restarts_interval = N;
}
}
fn num_restarts(&self) -> usize {
self.restarts
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Geometric<const N: usize> {
restarts: usize,
restarts_in: usize,
restarts_interval: usize,
}
impl<const N: usize> Restarter for Geometric<N> {
fn new() -> Self {
Self {
restarts: 0,
restarts_in: 0,
restarts_interval: 1,
}
}
fn restarts_in(&self) -> usize {
self.restarts_in
}
fn increment_restarts_in(&mut self) {
self.restarts_in = self.restarts_in.wrapping_sub(1);
}
fn restart(&mut self) {
self.restarts = self.restarts.wrapping_add(1);
self.restarts_in = self.restarts_interval;
self.restarts_interval = self.restarts_interval.wrapping_mul(N);
}
fn num_restarts(&self) -> usize {
self.restarts
}
fn should_restart(&mut self) -> bool {
if self.restarts_in == 0 {
self.restart();
true
} else {
self.restarts_in = self.restarts_in.wrapping_sub(1);
false
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Fixed<const N: usize> {
restarts: usize,
restarts_in: usize,
restarts_interval: usize,
}
impl<const N: usize> Restarter for Fixed<N> {
fn new() -> Self {
assert!(N > 0, "Fixed interval N must be positive.");
Self {
restarts: 0,
restarts_in: 0,
restarts_interval: N,
}
}
fn restarts_in(&self) -> usize {
self.restarts_in
}
fn increment_restarts_in(&mut self) {
self.restarts_in = self.restarts_in.wrapping_sub(1);
}
fn restart(&mut self) {
self.restarts = self.restarts.wrapping_add(1);
self.restarts_in = self.restarts_interval;
}
fn num_restarts(&self) -> usize {
self.restarts
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Never {}
impl Restarter for Never {
fn new() -> Self {
Self {}
}
fn restarts_in(&self) -> usize {
usize::MAX
}
fn increment_restarts_in(&mut self) {}
fn restart(&mut self) {}
fn num_restarts(&self) -> usize {
0
}
fn should_restart(&mut self) -> bool {
false
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Linear<const N: usize> {
restarts: usize,
restarts_in: usize,
restarts_interval: usize,
}
impl<const N: usize> Restarter for Linear<N> {
fn new() -> Self {
assert!(N > 0, "Linear increment N must be positive.");
Self {
restarts: 0,
restarts_in: 0,
restarts_interval: N,
}
}
fn restarts_in(&self) -> usize {
self.restarts_in
}
fn increment_restarts_in(&mut self) {
self.restarts_in -= 1;
}
fn restart(&mut self) {
self.restarts = self.restarts.wrapping_add(1);
self.restarts_in = self.restarts_interval;
self.restarts_interval = self.restarts_interval.wrapping_add(N);
}
fn num_restarts(&self) -> usize {
self.restarts
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RestarterImpls<const N: usize> {
Luby(Luby<N>),
Geometric(Geometric<N>),
Fixed(Fixed<N>),
Linear(Linear<N>),
Never(Never),
}
impl<const N: usize> Restarter for RestarterImpls<N> {
fn new() -> Self {
Self::Luby(Luby::new())
}
fn restarts_in(&self) -> usize {
match self {
Self::Luby(r) => r.restarts_in(),
Self::Geometric(r) => r.restarts_in(),
Self::Fixed(r) => r.restarts_in(),
Self::Linear(r) => r.restarts_in(),
Self::Never(r) => r.restarts_in(),
}
}
fn increment_restarts_in(&mut self) {
match self {
Self::Luby(r) => r.increment_restarts_in(),
Self::Geometric(r) => r.increment_restarts_in(),
Self::Fixed(r) => r.increment_restarts_in(),
Self::Linear(r) => r.increment_restarts_in(),
Self::Never(_) => {}
}
}
fn restart(&mut self) {
match self {
Self::Luby(r) => r.restart(),
Self::Geometric(r) => r.restart(),
Self::Fixed(r) => r.restart(),
Self::Linear(r) => r.restart(),
Self::Never(_) => {}
}
}
fn num_restarts(&self) -> usize {
match self {
Self::Luby(r) => r.num_restarts(),
Self::Geometric(r) => r.num_restarts(),
Self::Fixed(r) => r.num_restarts(),
Self::Linear(r) => r.num_restarts(),
Self::Never(_) => 0,
}
}
fn should_restart(&mut self) -> bool {
match self {
Self::Luby(r) => r.should_restart(),
Self::Geometric(r) => r.should_restart(),
Self::Fixed(r) => r.should_restart(),
Self::Linear(r) => r.should_restart(),
Self::Never(_) => false,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash, Default, ValueEnum)]
pub enum RestarterType {
#[default]
Luby,
Geometric,
Fixed,
Linear,
Never,
}
impl Display for RestarterType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Luby => write!(f, "luby"),
Self::Geometric => write!(f, "geometric"),
Self::Fixed => write!(f, "fixed"),
Self::Linear => write!(f, "linear"),
Self::Never => write!(f, "never"),
}
}
}
impl RestarterType {
#[must_use]
pub fn to_impl(self) -> RestarterImpls<3> {
match self {
Self::Luby => RestarterImpls::Luby(Luby::new()),
Self::Geometric => RestarterImpls::Geometric(Geometric::new()),
Self::Fixed => RestarterImpls::Fixed(Fixed::new()),
Self::Linear => RestarterImpls::Linear(Linear::new()),
Self::Never => RestarterImpls::Never(Never::new()),
}
}
}