use std::fmt::Debug;
pub trait AggregateNumber: Copy + PartialEq + PartialOrd + Debug + 'static {
type Average: Copy + PartialEq + PartialOrd + Debug + 'static;
const ZERO: Self;
fn plus(self, other: Self) -> Self;
fn minus(self, other: Self) -> Self;
fn average(sum: Self, count: i32) -> Self::Average;
fn to_average(self) -> Self::Average;
}
impl AggregateNumber for i32 {
type Average = f64;
const ZERO: i32 = 0;
fn plus(self, other: i32) -> i32 {
self.wrapping_add(other)
}
fn minus(self, other: i32) -> i32 {
self.wrapping_sub(other)
}
fn average(sum: i32, count: i32) -> f64 {
f64::from(sum) / f64::from(count)
}
fn to_average(self) -> f64 {
f64::from(self)
}
}
impl AggregateNumber for i64 {
type Average = f64;
const ZERO: i64 = 0;
fn plus(self, other: i64) -> i64 {
self.wrapping_add(other)
}
fn minus(self, other: i64) -> i64 {
self.wrapping_sub(other)
}
fn average(sum: i64, count: i32) -> f64 {
sum as f64 / f64::from(count)
}
fn to_average(self) -> f64 {
self as f64
}
}
impl AggregateNumber for f32 {
type Average = f32;
const ZERO: f32 = 0.0;
fn plus(self, other: f32) -> f32 {
self + other
}
fn minus(self, other: f32) -> f32 {
self - other
}
fn average(sum: f32, count: i32) -> f32 {
sum / count as f32
}
fn to_average(self) -> f32 {
self
}
}
impl AggregateNumber for f64 {
type Average = f64;
const ZERO: f64 = 0.0;
fn plus(self, other: f64) -> f64 {
self + other
}
fn minus(self, other: f64) -> f64 {
self - other
}
fn average(sum: f64, count: i32) -> f64 {
sum / f64::from(count)
}
fn to_average(self) -> f64 {
self
}
}
pub trait AggregateValue: Copy + 'static {
type Number: AggregateNumber;
fn number(self) -> Self::Number;
}
macro_rules! impl_aggregate_value {
($($ty:ty),*) => {
$(
impl AggregateValue for $ty {
type Number = $ty;
fn number(self) -> $ty {
self
}
}
)*
};
}
impl_aggregate_value!(i32, i64, f32, f64);
impl<X: AggregateNumber> AggregateValue for Option<X> {
type Number = X;
fn number(self) -> X {
self.unwrap_or(X::ZERO)
}
}