use crate::float::Float;
use crate::value::Value01;
use core::marker::PhantomData;
use witnessed::Witnessed;
pub fn metric(name: &'static str) -> MetricName {
MetricName { name }
}
pub struct MetricName {
name: &'static str,
}
impl MetricName {
pub fn measure(self) -> MeasureStage {
MeasureStage { name: self.name }
}
}
pub struct MeasureStage {
name: &'static str,
}
impl MeasureStage {
pub fn by<I, Raw, M>(self, measure: M) -> MeasureSet<I, Raw, M> {
MeasureSet {
name: self.name,
measure,
_phantom: PhantomData,
}
}
}
pub struct MeasureSet<I, Raw, M> {
name: &'static str,
measure: M,
_phantom: PhantomData<(I, Raw)>,
}
impl<I, Raw, M> MeasureSet<I, Raw, M> {
pub fn map01(self) -> Map01Stage<I, Raw, M> {
Map01Stage {
name: self.name,
measure: self.measure,
_phantom: PhantomData,
}
}
}
pub struct Map01Stage<I, Raw, M> {
name: &'static str,
measure: M,
_phantom: PhantomData<(I, Raw)>,
}
impl<I, Raw, M> Map01Stage<I, Raw, M> {
pub fn by<T: Float, F>(self, map01: F) -> Metric<T, I, Raw, M, F> {
Metric {
name: self.name,
measure: self.measure,
map01,
_phantom: PhantomData,
}
}
}
pub struct Metric<T, I, Raw, M, F> {
pub(crate) name: &'static str,
pub(crate) measure: M,
pub(crate) map01: F,
_phantom: PhantomData<(T, I, Raw)>,
}
impl<T: Float, I, Raw, M, F> Metric<T, I, Raw, M, F>
where
M: Fn(&I) -> Raw,
F: Fn(&Raw, &I) -> Witnessed<T, Value01>,
{
#[inline]
pub fn eval(&self, input: &I) -> Witnessed<T, Value01> {
let raw = (self.measure)(input);
(self.map01)(&raw, input)
}
#[inline]
pub fn name(&self) -> &str {
self.name
}
}
impl<T, I, Raw, M: Clone, F: Clone> Clone for Metric<T, I, Raw, M, F> {
fn clone(&self) -> Self {
Self {
name: self.name,
measure: self.measure.clone(),
map01: self.map01.clone(),
_phantom: PhantomData,
}
}
}
#[cfg(test)]
mod tests_for_metric;