1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
use ordered_float::OrderedFloat;
use serde::{Deserialize, Serialize};
use std::ops::Deref;

// TODO: Consider removing (use `rillrate-protocol::Range` instead)
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Range {
    min: OrderedFloat<f64>,
    max: OrderedFloat<f64>,
}

impl Range {
    pub fn new(mut min: f64, mut max: f64) -> Self {
        if min > max {
            std::mem::swap(&mut min, &mut max);
        }
        Self {
            min: OrderedFloat::from(min),
            max: OrderedFloat::from(max),
        }
    }

    pub fn min(&self) -> f64 {
        *self.min
    }

    pub fn max(&self) -> f64 {
        *self.max
    }

    pub fn diff(&self) -> f64 {
        *(self.max - self.min)
    }

    pub fn clamp(&self, value: &mut f64) {
        if *value < *self.min {
            *value = *self.min
        } else if *value > *self.max {
            *value = *self.max
        }
    }

    pub fn pct(&self, value: f64) -> Pct {
        Pct::from_range(value, self)
    }
}

impl From<(f64, f64)> for Range {
    fn from((min, max): (f64, f64)) -> Self {
        Range::new(min, max)
    }
}

#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
pub struct Pct(f64);

impl Default for Pct {
    fn default() -> Self {
        Self(0.0)
    }
}

impl Pct {
    pub fn from_value(mut value: f64) -> Self {
        // TODO: Use `clamp` here.
        if value < 0.0 {
            value = 0.0;
        } else if value > 1.0 {
            value = 1.0;
        }
        Self(value)
    }

    pub fn from_div(value: f64, total: f64) -> Self {
        let pct = {
            if total == 0.0 {
                0.0
            } else {
                value / total
            }
        };
        Pct::from_value(pct)
    }

    pub fn from_range(value: f64, range: &Range) -> Self {
        let value = value - range.min();
        let diff = range.diff();
        Pct::from_div(value, diff)
    }

    pub fn to_cent(self) -> f64 {
        (self.0 * 100.0).round()
    }
}

impl Deref for Pct {
    type Target = f64;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}