pax_runtime_api/
unit_value.rs1use super::*;
4
5#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
11#[serde(crate = "crate::serde")]
12pub enum UnitValue {
13 Unitless(Numeric),
15 Percent(Numeric),
17}
18
19impl Default for UnitValue {
20 fn default() -> Self {
21 Self::Unitless(Numeric::F64(0.0))
22 }
23}
24
25impl Display for UnitValue {
26 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27 match self {
28 Self::Unitless(value) => write!(f, "{}", value),
29 Self::Percent(value) => write!(f, "{}%", value),
30 }
31 }
32}
33
34impl UnitValue {
35 pub fn to_unit_float(&self) -> f64 {
40 match self {
41 Self::Unitless(value) => value.to_float(),
42 Self::Percent(value) => value.to_float() / 100.0,
43 }
44 }
45
46 pub fn to_clamped_unit_float(&self) -> f64 {
48 self.to_unit_float().clamp(0.0, 1.0)
49 }
50}
51
52impl Interpolatable for UnitValue {
53 fn interpolate(&self, other: &Self, t: f64) -> Self {
54 let start = self.to_unit_float();
55 let end = other.to_unit_float();
56 Self::Unitless(Numeric::F64(start + (end - start) * t))
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63 use crate::{CoercionRules, PaxValue, Percent};
64
65 #[test]
66 fn numeric_and_percent_resolve_to_same_unit_float() {
67 let numeric = UnitValue::Unitless(Numeric::F64(0.5));
68 let percent = UnitValue::Percent(Numeric::F64(50.0));
69
70 assert_eq!(numeric.to_unit_float(), percent.to_unit_float());
71 }
72
73 #[test]
74 fn coerces_numeric_and_percent_values() {
75 let numeric = UnitValue::try_coerce(PaxValue::Numeric(Numeric::F64(0.25))).unwrap();
76 let percent =
77 UnitValue::try_coerce(PaxValue::Percent(Percent(Numeric::F64(25.0)))).unwrap();
78
79 assert_eq!(numeric, UnitValue::Unitless(Numeric::F64(0.25)));
80 assert_eq!(percent, UnitValue::Percent(Numeric::F64(25.0)));
81 assert_eq!(numeric.to_unit_float(), percent.to_unit_float());
82 }
83
84 #[test]
85 fn clamped_unit_float_limits_out_of_range_values() {
86 assert_eq!(
87 UnitValue::Unitless(Numeric::F64(-0.25)).to_clamped_unit_float(),
88 0.0
89 );
90 assert_eq!(
91 UnitValue::Percent(Numeric::F64(125.0)).to_clamped_unit_float(),
92 1.0
93 );
94 }
95
96 #[test]
97 fn interpolation_resolves_mixed_units_to_unitless() {
98 let start = UnitValue::Unitless(Numeric::F64(0.25));
99 let end = UnitValue::Percent(Numeric::F64(75.0));
100
101 assert_eq!(
102 start.interpolate(&end, 0.5),
103 UnitValue::Unitless(Numeric::F64(0.5))
104 );
105 }
106}