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