usenetnews-dynexp2 0.1.2

USENET news server expiry time dynamic tuning (for INN2)
Documentation
// Copyright 2022 Ian Jackson
// SPDX-License-Identifier: GPL-3.0-or-later
// There is NO WARRANTY.

use crate::prelude::*;
pub use crate::numbers::*;

pub const ROUNDING_ERROR: Days = Days(0.01);
pub const MIN_INTERVAL: Days = Days(1.00 - ROUNDING_ERROR.0);

pub trait FromSettings: Sized {
  fn from_settings(settings: &mut SettingsConverter) -> AR<Self>;
}

macro_rules! with_from_settings { {
  $( #[ $attrs:meta ] )*
  $vis:vis struct $Struct:ident {
    $(
      $fvis:vis $fname:ident : $fty:ty $( = $def:expr )?
    ),* $(,)?
  }
} => {
  $( #[ $attrs ] )*
  $vis struct $Struct {
    $(
      $fvis $fname : $fty,
    )*
  }
  impl FromSettings for $Struct {
    fn from_settings(settings: &mut SettingsConverter) -> AR<Self> {
      Ok($Struct {
        $(
          $fname: settings.obtain1(
            stringify!($fname),
            IntoIterator::into_iter([ $( (&|| $def) as _ )? ]).next(),
          )?,
        )*
      })
    }
  }
} }

with_from_settings!{
  #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
  pub struct SpoolSpec {
    pub spool: String,
  }
}

with_from_settings!{
  #[derive(Debug, Clone)]
  pub struct Parameters {
    pub history: String,

    pub flood: Space,
    pub highwater: Space,
    pub lowwater: Space,

    pub mindays: Days,
    pub maxdays: DaysOrNever = DaysOrNever::never(),
    pub flooddrain: Days,
    pub increase: Days,
    pub reduce: Days,
  }
}  

#[derive(Debug, Clone)]
pub struct ExpireLine {
  pub pattern: String,
  pub flag: String,
  pub min: Days,
  pub def: Days,
  pub max: DaysOrNever,
}

#[derive(Debug, Clone)]
pub struct ActiveData {
  pub params: Parameters,
  pub line: ExpireLine,
  pub maxdays: Days,
  pub was: Days,
}

pub type ActiveEntry = Rc<RefCell<ActiveData>>;

#[derive(Debug, Clone)]
pub enum FileLine {
  Inert(String),
  Active(ActiveEntry),
}

#[derive(Debug, Clone)]
pub struct SpoolEntries {
  pub entries: Vec<ActiveEntry>,
}

#[derive(Debug, Clone)]
pub struct Loaded {
  pub(crate) lines: Vec<FileLine>,
  #[allow(dead_code)]
  pub(crate) spools: BTreeMap<SpoolSpec, SpoolEntries>,
}

#[derive(Debug,Copy,Clone,Ord,PartialOrd,Eq,PartialEq,Hash)]
pub enum Situation {
  Low,
  Ok,
  High,
  Flood,
}

impl Display for Situation {
  #[allow(clippy::recursive_format_impl)]
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    if f.alternate() {
      write!(f, "{:5}", self)
    } else {
      let s = format!("{:?}", self);
      f.pad(&s)
    }
  }
}