1//! Contains the [`Number`] type and associated methods
2
3use core::ops::{Add, Div, Mul, Sub};
4
5/// A [`f32`] that may be undefined
6///
7/// NOTE: this should *really* be an [`Option<f32>`],
8/// but we're optimizing for backwards compatibility for now.
9#[derive(Copy, Clone, PartialEq, Debug)]
10#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
11pub enum Number {
12 /// Pretend this is [`Some(f32)`]
13 ///
14 /// WARNING: the contained value may be NaN
15 Defined(f32),
16 /// Pretend this is [`None`]
17 Undefined,
18}
19
20/// An extension method used for [`Number`]
21pub trait OrElse<T> {
22 /// Returns the contained value if it is defined, otherwise returns `other`
23 fn or_else(self, other: T) -> T;
24}
25
26impl Default for Number {
27 fn default() -> Self {
28 Self::Undefined
29 }
30}
31
32impl OrElse<f32> for Number {
33 fn or_else(self, other: f32) -> f32 {
34 match self {
35 Number::Defined(val) => val,
36 Number::Undefined => other,
37 }
38 }
39}
40
41impl OrElse<Self> for Number {
42 fn or_else(self, other: Self) -> Self {
43 match self {
44 Number::Defined(_) => self,
45 Number::Undefined => other,
46 }
47 }
48}
49
50impl Number {
51 /// Is the number defined?
52 pub fn is_defined(self) -> bool {
53 match self {
54 Number::Defined(_) => true,
55 Number::Undefined => false,
56 }
57 }
58
59 /// Is the number undefined?
60 pub fn is_undefined(self) -> bool {
61 match self {
62 Number::Defined(_) => false,
63 Number::Undefined => true,
64 }
65 }
66}
67
68/// An extension trait for [`Number`]
69pub trait MinMax<In, Out> {
70 /// Returns the minimum of self and rhs
71 ///
72 /// If either either value is invalid, returns the other value.
73 fn maybe_min(self, rhs: In) -> Out;
74 /// Returns the maximum of self and rhs
75 ///
76 /// If either either value is invalid, returns the other value.
77 fn maybe_max(self, rhs: In) -> Out;
78}
79
80impl MinMax<Self, Self> for Number {
81 fn maybe_min(self, rhs: Self) -> Self {
82 match (self, rhs) {
83 (Number::Defined(l), Number::Defined(r)) => Number::Defined(l.min(r)),
84 (Number::Defined(_), _) => self,
85 _ => Number::Undefined,
86 }
87 }
88
89 fn maybe_max(self, rhs: Self) -> Self {
90 match (self, rhs) {
91 (Number::Defined(l), Number::Defined(r)) => Number::Defined(l.max(r)),
92 (Number::Defined(_), _) => self,
93 _ => Number::Undefined,
94 }
95 }
96}
97
98impl MinMax<f32, Number> for Number {
99 fn maybe_min(self, rhs: f32) -> Self {
100 match self {
101 Number::Defined(val) => Number::Defined(val.min(rhs)),
102 Number::Undefined => Number::Undefined,
103 }
104 }
105
106 fn maybe_max(self, rhs: f32) -> Self {
107 match self {
108 Number::Defined(val) => Number::Defined(val.max(rhs)),
109 Number::Undefined => Number::Undefined,
110 }
111 }
112}
113
114impl MinMax<Number, f32> for f32 {
115 fn maybe_min(self, rhs: Number) -> f32 {
116 match rhs {
117 Number::Defined(val) => self.min(val),
118 Number::Undefined => self,
119 }
120 }
121
122 fn maybe_max(self, rhs: Number) -> f32 {
123 match rhs {
124 Number::Defined(val) => self.max(val),
125 Number::Undefined => self,
126 }
127 }
128}
129
130impl From<f32> for Number {
131 #[must_use]
132 fn from(v: f32) -> Self {
133 Self::Defined(v)
134 }
135}
136
137impl Add<f32> for Number {
138 type Output = Number;
139
140 fn add(self, rhs: f32) -> Self {
141 match self {
142 Number::Defined(val) => Number::Defined(val + rhs),
143 Number::Undefined => Number::Undefined,
144 }
145 }
146}
147
148impl Add<Number> for Number {
149 type Output = Number;
150
151 fn add(self, rhs: Self) -> Self {
152 match (self, rhs) {
153 (Number::Defined(l), Number::Defined(r)) => Number::Defined(l + r),
154 (Number::Defined(_), _) => self,
155 _ => Number::Undefined,
156 }
157 }
158}
159
160impl Sub<f32> for Number {
161 type Output = Number;
162
163 fn sub(self, rhs: f32) -> Self {
164 match self {
165 Number::Defined(val) => Number::Defined(val - rhs),
166 Number::Undefined => Number::Undefined,
167 }
168 }
169}
170
171impl Sub<Number> for Number {
172 type Output = Number;
173
174 fn sub(self, rhs: Self) -> Self {
175 match (self, rhs) {
176 (Number::Defined(l), Number::Defined(r)) => Number::Defined(l - r),
177 (Number::Defined(_), _) => self,
178 _ => Number::Undefined,
179 }
180 }
181}
182
183impl Mul<f32> for Number {
184 type Output = Number;
185
186 fn mul(self, rhs: f32) -> Self {
187 match self {
188 Number::Defined(val) => Number::Defined(val * rhs),
189 Number::Undefined => Number::Undefined,
190 }
191 }
192}
193
194impl Mul<Number> for Number {
195 type Output = Number;
196
197 fn mul(self, rhs: Self) -> Self {
198 match (self, rhs) {
199 (Number::Defined(l), Number::Defined(r)) => Number::Defined(l * r),
200 (Number::Defined(_), _) => self,
201 _ => Number::Undefined,
202 }
203 }
204}
205
206impl Div<f32> for Number {
207 type Output = Number;
208
209 fn div(self, rhs: f32) -> Self {
210 match self {
211 Number::Defined(val) => Number::Defined(val / rhs),
212 Number::Undefined => Number::Undefined,
213 }
214 }
215}
216
217impl Div<Number> for Number {
218 type Output = Number;
219
220 fn div(self, rhs: Self) -> Self {
221 match (self, rhs) {
222 (Number::Defined(l), Number::Defined(r)) => Number::Defined(l / r),
223 (Number::Defined(_), _) => self,
224 _ => Number::Undefined,
225 }
226 }
227}