use core::time::Duration;
#[allow(clippy::module_name_repetitions)]
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum MetricType {
ServiceLevel(Duration),
AverageWorkTime,
AverageSpeedAnswer,
AverageTimeToAbandon,
AbandonRate,
AverageTimeInQueue,
UtilisationTime,
AnswerCount,
}
#[derive(Clone, Debug)]
pub enum Aggregate {
Meanable(Meanable),
Countable(Countable),
Percentable(Percentable),
}
impl std::fmt::Display for Aggregate {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Meanable(a) => write!(f, "{a}"),
Self::Countable(a) => write!(f, "{a}"),
Self::Percentable(a) => write!(f, "{a}"),
}
}
}
#[derive(Clone, Debug)]
pub struct Meanable {
sum: Duration,
count: u32,
target: Duration,
}
impl std::fmt::Display for Meanable {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.count == 0 {
return write!(f, "None");
}
write!(f, "{:?}", self.sum / self.count)
}
}
impl Meanable {
pub fn report_duration(&mut self, value: Duration) {
self.sum += value;
self.count += 1;
}
pub fn with_target(target: Duration) -> Self {
Self {
sum: Duration::ZERO,
count: 0,
target,
}
}
pub fn on_target(&self) -> bool {
match self.count {
0 => false,
_ => self.target < (self.sum / self.count),
}
}
}
#[derive(Clone, Debug)]
pub struct Countable {
count: usize,
target: usize,
}
impl std::fmt::Display for Countable {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.count)
}
}
impl Countable {
pub fn report(&mut self) {
self.count += 1;
}
pub fn with_target(target: usize) -> Self {
Self { count: 0, target }
}
pub fn on_target(&self) -> bool {
match self.count {
0 => false,
_ => self.target < self.count,
}
}
}
#[derive(Clone, Debug)]
pub struct Percentable {
sum: usize,
count: usize,
target: f64,
}
impl std::fmt::Display for Percentable {
#[allow(clippy::cast_precision_loss)]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.count == 0 {
return write!(f, "None");
}
write!(f, "{}", self.sum as f64 / self.count as f64)
}
}
impl Percentable {
pub fn report_bool(&mut self, value: bool) {
if value {
self.sum += 1;
}
self.count += 1;
}
pub fn with_target(target: f64) -> Self {
Self {
sum: 0,
count: 0,
target,
}
}
#[allow(clippy::cast_precision_loss)]
pub fn on_target(&self) -> bool {
match self.count {
0 => false,
_ => self.target < (self.sum as f64 / self.count as f64),
}
}
}
#[derive(Clone, Debug)]
pub struct Metric {
metric_type: MetricType,
aggregate: Aggregate,
}
impl std::fmt::Display for Metric {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.aggregate)
}
}
#[allow(clippy::module_name_repetitions)]
#[derive(Clone, Debug)]
pub struct MetricError {}
impl Metric {
#[allow(clippy::match_wildcard_for_single_variants)]
pub fn with_target_duration(
metric_type: MetricType,
target: Duration,
) -> Result<Self, MetricError> {
match metric_type {
MetricType::AverageWorkTime
| MetricType::AverageSpeedAnswer
| MetricType::AverageTimeInQueue
| MetricType::AverageTimeToAbandon => Ok(Self {
metric_type,
aggregate: Aggregate::Meanable(Meanable::with_target(target)),
}),
_ => Err(MetricError {}),
}
}
#[allow(clippy::match_wildcard_for_single_variants)]
pub fn with_target_f64(metric_type: MetricType, target: f64) -> Result<Self, MetricError> {
match metric_type {
MetricType::UtilisationTime | MetricType::ServiceLevel(_) | MetricType::AbandonRate => {
Ok(Self {
metric_type,
aggregate: Aggregate::Percentable(Percentable::with_target(target)),
})
}
_ => Err(MetricError {}),
}
}
pub fn with_target_usize(metric_type: MetricType, target: usize) -> Result<Self, MetricError> {
match metric_type {
MetricType::AnswerCount => Ok(Self {
metric_type,
aggregate: Aggregate::Countable(Countable::with_target(target)),
}),
_ => Err(MetricError {}),
}
}
pub fn metric(&self) -> MetricType {
self.metric_type
}
pub fn on_target(&self) -> bool {
match &self.aggregate {
Aggregate::Meanable(a) => a.on_target(),
Aggregate::Percentable(a) => a.on_target(),
Aggregate::Countable(a) => a.on_target(),
}
}
}
impl Metric {
pub fn report(&mut self) {
match &mut self.aggregate {
Aggregate::Countable(a) => a.report(),
_ => todo!(),
}
}
pub fn report_bool(&mut self, value: bool) {
match &mut self.aggregate {
Aggregate::Percentable(a) => a.report_bool(value),
_ => todo!(),
}
}
pub fn report_duration(&mut self, value: Duration) {
match &mut self.aggregate {
Aggregate::Meanable(a) => a.report_duration(value),
_ => todo!(),
}
}
}