1use super::{Angle, Length, Number, Percentage, Resolution, Time};
8use crate::derives::*;
9use crate::values::generics::calc::{
10 self, CalcUnits, PositivePercentageBasis, SimplificationResult,
11};
12use crate::Zero;
13use debug_unreachable::debug_unreachable;
14use serde::{Deserialize, Serialize};
15
16#[derive(
18 Clone,
19 Debug,
20 Deserialize,
21 MallocSizeOf,
22 PartialEq,
23 Serialize,
24 ToAnimatedZero,
25 ToCss,
26 ToResolvedValue,
27 ToTyped,
28)]
29#[allow(missing_docs)]
30#[repr(u8)]
31pub enum ComputedLeaf {
32 Length(Length),
33 Percentage(Percentage),
34 Number(Number),
35 Angle(Angle),
36 Time(Time),
37 Resolution(Resolution),
38}
39
40impl ComputedLeaf {
41 pub(super) fn is_zero_length(&self) -> bool {
42 match *self {
43 Self::Length(ref l) => l.is_zero(),
44 Self::Percentage(..)
45 | Self::Number(..)
46 | Self::Angle(..)
47 | Self::Time(..)
48 | Self::Resolution(..) => false,
49 }
50 }
51}
52
53impl calc::CalcNodeLeaf for ComputedLeaf {
54 fn unit(&self) -> CalcUnits {
55 match self {
56 Self::Length(_) => CalcUnits::LENGTH,
57 Self::Percentage(_) => CalcUnits::PERCENTAGE,
58 Self::Number(_) => CalcUnits::empty(),
59 Self::Angle(_) => CalcUnits::ANGLE,
60 Self::Time(_) => CalcUnits::TIME,
61 Self::Resolution(_) => CalcUnits::RESOLUTION,
62 }
63 }
64
65 fn unitless_value(&self) -> Option<f32> {
66 Some(match *self {
67 Self::Length(ref l) => l.px(),
68 Self::Percentage(ref p) => p.0,
69 Self::Number(n) => n,
70 Self::Angle(ref a) => a.degrees(),
71 Self::Time(ref t) => t.seconds(),
72 Self::Resolution(ref r) => r.dppx(),
73 })
74 }
75
76 fn new_number(value: f32) -> Self {
77 Self::Number(value)
78 }
79
80 fn as_number(&self) -> Option<f32> {
81 match *self {
82 Self::Length(_)
83 | Self::Percentage(_)
84 | Self::Angle(_)
85 | Self::Time(_)
86 | Self::Resolution(_) => None,
87 Self::Number(value) => Some(value),
88 }
89 }
90
91 fn as_angle_radians(&self) -> Option<f32> {
92 match *self {
93 Self::Angle(a) => Some(a.radians()),
94 _ => None,
95 }
96 }
97
98 fn new_angle_from_radians(radians: f32) -> Self {
99 Self::Angle(Angle::from_radians(radians))
100 }
101
102 fn compare(&self, other: &Self, basis: PositivePercentageBasis) -> Option<std::cmp::Ordering> {
103 use self::ComputedLeaf::*;
104 if std::mem::discriminant(self) != std::mem::discriminant(other) {
105 return None;
106 }
107
108 if matches!(self, Percentage(..)) && matches!(basis, PositivePercentageBasis::Unknown) {
109 return None;
110 }
111
112 let Ok(self_negative) = self.is_negative() else {
113 return None;
114 };
115 let Ok(other_negative) = other.is_negative() else {
116 return None;
117 };
118 if self_negative != other_negative {
119 return Some(if self_negative {
120 std::cmp::Ordering::Less
121 } else {
122 std::cmp::Ordering::Greater
123 });
124 }
125
126 match (self, other) {
127 (&Length(ref one), &Length(ref other)) => one.partial_cmp(other),
128 (&Percentage(ref one), &Percentage(ref other)) => one.partial_cmp(other),
129 (&Number(ref one), &Number(ref other)) => one.partial_cmp(other),
130 (&Angle(ref one), &Angle(ref other)) => one.partial_cmp(other),
131 (&Time(ref one), &Time(ref other)) => one.partial_cmp(other),
132 (&Resolution(ref one), &Resolution(ref other)) => one.partial_cmp(other),
133 _ => unsafe {
134 match *self {
135 Length(..) | Percentage(..) | Number(..) | Angle(..) | Time(..)
136 | Resolution(..) => {},
137 }
138 debug_unreachable!("Forgot to handle unit in compare()")
139 },
140 }
141 }
142
143 fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()> {
144 use self::ComputedLeaf::*;
145
146 if self.is_zero_length() {
148 *self = other.clone();
149 return Ok(());
150 }
151
152 if other.is_zero_length() {
153 return Ok(());
154 }
155
156 if std::mem::discriminant(self) != std::mem::discriminant(other) {
157 return Err(());
158 }
159
160 match (self, other) {
161 (&mut Length(ref mut one), &Length(ref other)) => {
162 *one += *other;
163 },
164 (&mut Percentage(ref mut one), &Percentage(ref other)) => {
165 one.0 += other.0;
166 },
167 (&mut Number(ref mut one), &Number(ref other)) => {
168 *one += *other;
169 },
170 (&mut Angle(ref mut one), &Angle(ref other)) => {
171 *one += *other;
172 },
173 (&mut Time(ref mut one), &Time(ref other)) => {
174 *one += *other;
175 },
176 (&mut Resolution(ref mut one), &Resolution(ref other)) => {
177 *one += *other;
178 },
179 _ => unsafe {
180 match *other {
181 Length(..) | Percentage(..) | Number(..) | Angle(..) | Time(..)
182 | Resolution(..) => {},
183 }
184 debug_unreachable!("Forgot to handle unit in try_sum_in_place()")
185 },
186 }
187
188 Ok(())
189 }
190
191 fn try_product_in_place(&mut self, other: &mut Self) -> bool {
192 if let Self::Number(ref mut left) = *self {
193 if let Self::Number(ref right) = *other {
194 *left *= *right;
196 true
197 } else {
198 if other.map(|v| v * *left).is_ok() {
201 std::mem::swap(self, other);
202 true
203 } else {
204 false
205 }
206 }
207 } else if let Self::Number(ref right) = *other {
208 self.map(|v| v * *right).is_ok()
211 } else {
212 false
214 }
215 }
216
217 fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
218 where
219 O: Fn(f32, f32) -> f32,
220 {
221 use self::ComputedLeaf::*;
222 if std::mem::discriminant(self) != std::mem::discriminant(other) {
223 return Err(());
224 }
225 Ok(match (self, other) {
226 (&Length(ref one), &Length(ref other)) => {
227 Length(super::Length::new(op(one.px(), other.px())))
228 },
229 (&Percentage(one), &Percentage(other)) => {
230 Self::Percentage(super::Percentage(op(one.0, other.0)))
231 },
232 (&Number(one), &Number(other)) => Self::Number(op(one, other)),
233 (&Angle(ref one), &Angle(ref other)) => Self::Angle(super::Angle::from_degrees(op(
234 one.degrees(),
235 other.degrees(),
236 ))),
237 (&Time(ref one), &Time(ref other)) => Self::Time(super::Time::from_seconds(op(
238 one.seconds(),
239 other.seconds(),
240 ))),
241 (&Resolution(ref one), &Resolution(ref other)) => {
242 Self::Resolution(super::Resolution::from_dppx(op(one.dppx(), other.dppx())))
243 },
244 _ => unsafe {
245 match *self {
246 Length(..) | Percentage(..) | Number(..) | Angle(..) | Time(..)
247 | Resolution(..) => {},
248 }
249 debug_unreachable!("Forgot to handle unit in try_op()")
250 },
251 })
252 }
253
254 fn map(&mut self, mut op: impl FnMut(f32) -> f32) -> Result<(), ()> {
255 Ok(match self {
256 Self::Length(value) => {
257 *value = Length::new(op(value.px()));
258 },
259 Self::Percentage(value) => {
260 *value = Percentage(op(value.0));
261 },
262 Self::Number(value) => {
263 *value = op(*value);
264 },
265 Self::Angle(value) => {
266 *value = Angle::from_degrees(op(value.degrees()));
267 },
268 Self::Time(value) => {
269 *value = Time::from_seconds(op(value.seconds()));
270 },
271 Self::Resolution(value) => {
272 *value = Resolution::from_dppx(op(value.dppx()));
273 },
274 })
275 }
276
277 fn simplify(&mut self) -> SimplificationResult {
278 return SimplificationResult::Unchanged;
279 }
280
281 fn sort_key(&self) -> calc::SortKey {
282 match *self {
283 Self::Length(..) => calc::SortKey::Px,
284 Self::Percentage(..) => calc::SortKey::Percentage,
285 Self::Number(..) => calc::SortKey::Number,
286 Self::Angle(..) => calc::SortKey::Deg,
287 Self::Time(..) => calc::SortKey::S,
288 Self::Resolution(..) => calc::SortKey::Dppx,
289 }
290 }
291}