1use ordered_float::OrderedFloat;
2use serde::{Deserialize, Serialize};
3use std::ops::Deref;
4
5#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
7pub struct Range {
8 min: OrderedFloat<f64>,
9 max: OrderedFloat<f64>,
10}
11
12impl Range {
13 pub fn new(mut min: f64, mut max: f64) -> Self {
14 if min > max {
15 std::mem::swap(&mut min, &mut max);
16 }
17 Self {
18 min: OrderedFloat::from(min),
19 max: OrderedFloat::from(max),
20 }
21 }
22
23 pub fn min(&self) -> f64 {
24 *self.min
25 }
26
27 pub fn max(&self) -> f64 {
28 *self.max
29 }
30
31 pub fn diff(&self) -> f64 {
32 *(self.max - self.min)
33 }
34
35 pub fn clamp(&self, value: &mut f64) {
36 if *value < *self.min {
37 *value = *self.min
38 } else if *value > *self.max {
39 *value = *self.max
40 }
41 }
42
43 pub fn pct(&self, value: f64) -> Pct {
44 Pct::from_range(value, self)
45 }
46}
47
48impl From<(f64, f64)> for Range {
49 fn from((min, max): (f64, f64)) -> Self {
50 Range::new(min, max)
51 }
52}
53
54#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
55pub struct Pct(f64);
56
57impl Default for Pct {
58 fn default() -> Self {
59 Self(0.0)
60 }
61}
62
63impl Pct {
64 pub fn from_value(mut value: f64) -> Self {
65 if value < 0.0 {
67 value = 0.0;
68 } else if value > 1.0 {
69 value = 1.0;
70 }
71 Self(value)
72 }
73
74 pub fn from_div(value: f64, total: f64) -> Self {
75 let pct = {
76 if total == 0.0 {
77 0.0
78 } else {
79 value / total
80 }
81 };
82 Pct::from_value(pct)
83 }
84
85 pub fn from_range(value: f64, range: &Range) -> Self {
86 let value = value - range.min();
87 let diff = range.diff();
88 Pct::from_div(value, diff)
89 }
90
91 pub fn to_cent(self) -> f64 {
92 (self.0 * 100.0).round()
93 }
94}
95
96impl Deref for Pct {
97 type Target = f64;
98
99 fn deref(&self) -> &Self::Target {
100 &self.0
101 }
102}