summaryrefslogtreecommitdiff
path: root/src/proportion.rs
blob: aa8d1aeff7ae2a38762158bc3eb6cf3e6b34c526 (plain) (blame)
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
103
104
105
106
107
use crate::*;

#[derive(Copy, Clone)]
pub struct Proportion<T: Internal> {
    pub(crate) value: T,
}

impl<I: Internal> Proportion<I> {
    pub fn new(value: I) -> Self {
        Self { value: value.clamp() }
    }

    pub const MIN: Self = Proportion {
        value: <I as Internal>::MIN,
    };
    pub const MAX: Self = Proportion {
        value: <I as Internal>::MAX,
    };
    pub const ZERO: Self = Self::MIN;
    pub const ONE: Self = Self::MAX;

    pub fn set(&mut self, new_value: I) {
        self.value = new_value.clamp();
    }

    pub fn is_min(&self) -> bool {
        self.value == I::MIN
    }
    pub fn is_max(&self) -> bool {
        self.value == I::MAX
    }

    pub fn is_zero(&self) -> bool {
        self.is_min()
    }
    pub fn is_one(&self) -> bool {
        self.is_max()
    }

    pub fn as_u8(&self) -> u8 {
        self.value.as_u8()
    }
    pub fn as_f32(&self) -> f32 {
        self.value.as_f32()
    }
    pub fn as_f64(&self) -> f64 {
        self.value.as_f64()
    }

    pub fn invert(&self) -> Self {
        Self {
            value: I::MAX - self.value,
        }
    }

    pub fn value(&self) -> I {
        self.value
    }
}

macro_rules! impl_mul {
    ($type:ty, $method:ident) => {
        impl<I: Internal> std::ops::Mul<Proportion<I>> for $type {
            type Output = $type;
            fn mul(self, proportion: Proportion<I>) -> $type {
                proportion.value.$method(self)
            }
        }
        impl<I: Internal> std::ops::Mul<$type> for Proportion<I> {
            type Output = $type;
            fn mul(self, value: $type) -> $type {
                self.value.$method(value)
            }
        }
        impl<I: Internal> std::ops::Mul<&Proportion<I>> for $type {
            type Output = $type;
            fn mul(self, proportion: &Proportion<I>) -> $type {
                proportion.value.$method(self)
            }
        }
        impl<I: Internal> std::ops::Mul<$type> for &Proportion<I> {
            type Output = $type;
            fn mul(self, value: $type) -> $type {
                self.value.$method(value)
            }
        }
    };
}

impl_mul!(u8, mul_u8);
impl_mul!(u16, mul_u16);
impl_mul!(u32, mul_u32);
impl_mul!(f32, mul_f32);
impl_mul!(f64, mul_f64);

use std::fmt::{Debug, Display, Formatter};

impl<T: Internal> Debug for Proportion<T> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
        write!(f, "Proportion {{ {:.2} }}", self.as_f32())
    }
}
impl<T: Internal> Display for Proportion<T> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
        write!(f, "{:.2}", self.as_f32())
    }
}