Skip to main content

style/values/generics/
calc.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! [Calc expressions][calc].
6//!
7//! [calc]: https://drafts.csswg.org/css-values/#calc-notation
8
9use crate::derives::*;
10use crate::values::generics::length::GenericAnchorSizeFunction;
11use crate::values::generics::position::{GenericAnchorFunction, GenericAnchorSide};
12use num_traits::Zero;
13use smallvec::SmallVec;
14use std::convert::AsRef;
15use std::fmt::{self, Write};
16use std::ops::{Add, Mul, Neg, Rem, Sub};
17use std::{cmp, mem};
18use strum_macros::AsRefStr;
19use style_traits::{CssWriter, MathSum, NumericValue, ToCss, ToTyped, TypedValue};
20
21use thin_vec::ThinVec;
22
23/// Whether we're a `min` or `max` function.
24#[derive(
25    Clone,
26    Copy,
27    Debug,
28    Deserialize,
29    MallocSizeOf,
30    PartialEq,
31    Serialize,
32    ToAnimatedZero,
33    ToResolvedValue,
34    ToShmem,
35)]
36#[repr(u8)]
37pub enum MinMaxOp {
38    /// `min()`
39    Min,
40    /// `max()`
41    Max,
42}
43
44/// Whether we're a `mod` or `rem` function.
45#[derive(
46    Clone,
47    Copy,
48    Debug,
49    Deserialize,
50    MallocSizeOf,
51    PartialEq,
52    Serialize,
53    ToAnimatedZero,
54    ToResolvedValue,
55    ToShmem,
56)]
57#[repr(u8)]
58pub enum ModRemOp {
59    /// `mod()`
60    Mod,
61    /// `rem()`
62    Rem,
63}
64
65impl ModRemOp {
66    fn apply(self, dividend: f32, divisor: f32) -> f32 {
67        // In mod(A, B) only, if B is infinite and A has opposite sign to B
68        // (including an oppositely-signed zero), the result is NaN.
69        // https://drafts.csswg.org/css-values/#round-infinities
70        if matches!(self, Self::Mod)
71            && divisor.is_infinite()
72            && dividend.is_sign_negative() != divisor.is_sign_negative()
73        {
74            return f32::NAN;
75        }
76
77        let (r, same_sign_as) = match self {
78            Self::Mod => (dividend - divisor * (dividend / divisor).floor(), divisor),
79            Self::Rem => (dividend - divisor * (dividend / divisor).trunc(), dividend),
80        };
81        if r == 0.0 && same_sign_as.is_sign_negative() {
82            -0.0
83        } else {
84            r
85        }
86    }
87}
88
89/// The strategy used in `round()`
90#[derive(
91    Clone,
92    Copy,
93    Debug,
94    Deserialize,
95    MallocSizeOf,
96    PartialEq,
97    Serialize,
98    ToAnimatedZero,
99    ToResolvedValue,
100    ToShmem,
101)]
102#[repr(u8)]
103pub enum RoundingStrategy {
104    /// `round(nearest, a, b)`
105    /// round a to the nearest multiple of b
106    Nearest,
107    /// `round(up, a, b)`
108    /// round a up to the nearest multiple of b
109    Up,
110    /// `round(down, a, b)`
111    /// round a down to the nearest multiple of b
112    Down,
113    /// `round(to-zero, a, b)`
114    /// round a to the nearest multiple of b that is towards zero
115    ToZero,
116}
117
118/// This determines the order in which we serialize members of a calc() sum.
119///
120/// See https://drafts.csswg.org/css-values-4/#sort-a-calculations-children
121#[derive(
122    AsRefStr, Clone, Copy, Debug, Eq, Ord, Parse, PartialEq, PartialOrd, MallocSizeOf, ToShmem,
123)]
124#[strum(serialize_all = "lowercase")]
125#[allow(missing_docs)]
126pub enum SortKey {
127    #[strum(serialize = "")]
128    Number,
129    #[css(skip)]
130    #[strum(serialize = "%")]
131    Percentage,
132    Cap,
133    Ch,
134    Cqb,
135    Cqh,
136    Cqi,
137    Cqmax,
138    Cqmin,
139    Cqw,
140    Deg,
141    Dppx,
142    Dvb,
143    Dvh,
144    Dvi,
145    Dvmax,
146    Dvmin,
147    Dvw,
148    Em,
149    Ex,
150    Ic,
151    Lh,
152    Lvb,
153    Lvh,
154    Lvi,
155    Lvmax,
156    Lvmin,
157    Lvw,
158    Ms,
159    Px,
160    Rcap,
161    Rch,
162    Rem,
163    Rex,
164    Ric,
165    Rlh,
166    S, // Sec
167    Svb,
168    Svh,
169    Svi,
170    Svmax,
171    Svmin,
172    Svw,
173    Vb,
174    Vh,
175    Vi,
176    Vmax,
177    Vmin,
178    Vw,
179    #[css(skip)]
180    ColorComponent,
181    #[css(skip)]
182    Other,
183}
184
185/// Fallback type for anchor functions within `calc()`.
186/// Ideally, the fallback type is initial type of the property (e.g.
187/// `GenericInset` for `left`), but that causes circular reference.
188/// TODO(dshin, bug 2034100): Investigate ways to not require this.
189/// This handles the parsing of unitless zeros, as well as ensuring
190/// that e.g. `calc(anchor(--foo left, 1px) + 10%)` round trips
191/// (sorting aside), instead of becoming
192/// `calc(anchor(--foo left, calc(1px)) + 10%)`.
193#[repr(C)]
194#[derive(
195    Clone,
196    Debug,
197    Deserialize,
198    MallocSizeOf,
199    PartialEq,
200    Serialize,
201    ToAnimatedZero,
202    ToResolvedValue,
203    ToShmem,
204)]
205pub struct GenericAnchorFunctionFallback<L> {
206    /// Was this node parsed as a calc node?
207    #[animation(constant)]
208    is_calc_node: bool,
209    /// The parsed fallback value. Stored as a calc node to break
210    /// the circular reference.
211    pub node: GenericCalcNode<L>,
212}
213
214impl<L> GenericAnchorFunctionFallback<L> {
215    /// Create a new anchor function fallback value.
216    pub fn new(is_calc_node: bool, node: GenericCalcNode<L>) -> Self {
217        Self {
218            is_calc_node,
219            node,
220        }
221    }
222}
223
224impl<L: CalcNodeLeaf> ToCss for GenericAnchorFunctionFallback<L> {
225    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
226    where
227        W: Write,
228    {
229        self.node.to_css_impl(
230            dest,
231            if self.is_calc_node {
232                ArgumentLevel::CalculationRoot
233            } else {
234                ArgumentLevel::ArgumentRoot
235            },
236        )
237    }
238}
239
240/// `anchor()` function used in math functions.
241pub type GenericCalcAnchorFunction<L> =
242    GenericAnchorFunction<Box<GenericCalcNode<L>>, Box<GenericAnchorFunctionFallback<L>>>;
243/// `anchor-size()` function used in math functions.
244pub type GenericCalcAnchorSizeFunction<L> =
245    GenericAnchorSizeFunction<Box<GenericAnchorFunctionFallback<L>>>;
246
247/// A generic node in a calc expression.
248///
249/// FIXME: This would be much more elegant if we used `Self` in the types below,
250/// but we can't because of https://github.com/serde-rs/serde/issues/1565.
251///
252/// FIXME: The following annotations are to workaround an LLVM inlining bug, see
253/// bug 1631929.
254///
255/// cbindgen:destructor-attributes=MOZ_NEVER_INLINE
256/// cbindgen:copy-constructor-attributes=MOZ_NEVER_INLINE
257/// cbindgen:eq-attributes=MOZ_NEVER_INLINE
258#[repr(u8)]
259#[derive(
260    Clone,
261    Debug,
262    Deserialize,
263    MallocSizeOf,
264    PartialEq,
265    Serialize,
266    ToAnimatedZero,
267    ToResolvedValue,
268    ToShmem,
269)]
270pub enum GenericCalcNode<L> {
271    /// A leaf node.
272    Leaf(L),
273    /// A node that negates its child, e.g. Negate(1) == -1.
274    Negate(Box<GenericCalcNode<L>>),
275    /// A node that inverts its child, e.g. Invert(10) == 1 / 10 == 0.1. The child must always
276    /// resolve to a number unit.
277    Invert(Box<GenericCalcNode<L>>),
278    /// A sum node, representing `a + b + c` where a, b, and c are the
279    /// arguments.
280    Sum(crate::OwnedSlice<GenericCalcNode<L>>),
281    /// A product node, representing `a * b * c` where a, b, and c are the
282    /// arguments.
283    Product(crate::OwnedSlice<GenericCalcNode<L>>),
284    /// A `min` or `max` function.
285    MinMax(crate::OwnedSlice<GenericCalcNode<L>>, MinMaxOp),
286    /// A `clamp()` function.
287    Clamp {
288        /// The minimum value.
289        min: Box<GenericCalcNode<L>>,
290        /// The central value.
291        center: Box<GenericCalcNode<L>>,
292        /// The maximum value.
293        max: Box<GenericCalcNode<L>>,
294    },
295    /// A `round()` function.
296    Round {
297        /// The rounding strategy.
298        strategy: RoundingStrategy,
299        /// The value to round.
300        value: Box<GenericCalcNode<L>>,
301        /// The step value.
302        step: Box<GenericCalcNode<L>>,
303    },
304    /// A `mod()` or `rem()` function.
305    ModRem {
306        /// The dividend calculation.
307        dividend: Box<GenericCalcNode<L>>,
308        /// The divisor calculation.
309        divisor: Box<GenericCalcNode<L>>,
310        /// Is the function mod or rem?
311        op: ModRemOp,
312    },
313    /// A `hypot()` function
314    Hypot(crate::OwnedSlice<GenericCalcNode<L>>),
315    /// An `abs()` function.
316    Abs(Box<GenericCalcNode<L>>),
317    /// A `sign()` function.
318    Sign(Box<GenericCalcNode<L>>),
319    /// An `anchor()` function.
320    Anchor(Box<GenericCalcAnchorFunction<L>>),
321    /// An `anchor-size()` function.
322    AnchorSize(Box<GenericCalcAnchorSizeFunction<L>>),
323}
324
325pub use self::GenericCalcNode as CalcNode;
326
327bitflags! {
328    /// Expected units we allow parsing within a `calc()` expression.
329    ///
330    /// This is used as a hint for the parser to fast-reject invalid
331    /// expressions. Numbers are always allowed because they multiply other
332    /// units.
333    #[derive(Clone, Copy, PartialEq, Eq)]
334    pub struct CalcUnits: u8 {
335        /// <length>
336        const LENGTH = 1 << 0;
337        /// <percentage>
338        const PERCENTAGE = 1 << 1;
339        /// <angle>
340        const ANGLE = 1 << 2;
341        /// <time>
342        const TIME = 1 << 3;
343        /// <resolution>
344        const RESOLUTION = 1 << 4;
345        /// A component of a color (r, g, b, h, s, l, alpha, etc.)
346        const COLOR_COMPONENT = 1 << 5;
347
348        /// <length-percentage>
349        const LENGTH_PERCENTAGE = Self::LENGTH.bits() | Self::PERCENTAGE.bits();
350        // NOTE: When you add to this, make sure to make Atan2 deal with these.
351        /// Allow all units.
352        const ALL = Self::LENGTH.bits() | Self::PERCENTAGE.bits() | Self::ANGLE.bits() |
353            Self::TIME.bits() | Self::RESOLUTION.bits() | Self::COLOR_COMPONENT.bits();
354    }
355}
356
357impl CalcUnits {
358    /// Returns whether the flags only represent a single unit. This will return true for 0, which
359    /// is a "number" this is also fine.
360    #[inline]
361    fn is_single_unit(&self) -> bool {
362        self.bits() == 0 || self.bits() & (self.bits() - 1) == 0
363    }
364
365    /// Returns true if this unit is allowed to be summed with the given unit, otherwise false.
366    #[inline]
367    fn can_sum_with(&self, other: Self) -> bool {
368        match *self {
369            Self::LENGTH => other.intersects(Self::LENGTH | Self::PERCENTAGE),
370            Self::PERCENTAGE => other.intersects(Self::LENGTH | Self::PERCENTAGE),
371            Self::LENGTH_PERCENTAGE => other.intersects(Self::LENGTH | Self::PERCENTAGE),
372            u => u.is_single_unit() && other == u,
373        }
374    }
375}
376
377/// For percentage resolution, sometimes we can't assume that the percentage basis is positive (so
378/// we don't know whether a percentage is larger than another).
379pub enum PositivePercentageBasis {
380    /// The percent basis is not known-positive, we can't compare percentages.
381    Unknown,
382    /// The percent basis is known-positive, we assume larger percentages are larger.
383    Yes,
384}
385
386macro_rules! compare_helpers {
387    () => {
388        /// Return whether a leaf is greater than another.
389        #[allow(unused)]
390        fn gt(&self, other: &Self, basis_positive: PositivePercentageBasis) -> bool {
391            self.compare(other, basis_positive) == Some(cmp::Ordering::Greater)
392        }
393
394        /// Return whether a leaf is less than another.
395        fn lt(&self, other: &Self, basis_positive: PositivePercentageBasis) -> bool {
396            self.compare(other, basis_positive) == Some(cmp::Ordering::Less)
397        }
398
399        /// Return whether a leaf is smaller or equal than another.
400        fn lte(&self, other: &Self, basis_positive: PositivePercentageBasis) -> bool {
401            match self.compare(other, basis_positive) {
402                Some(cmp::Ordering::Less) => true,
403                Some(cmp::Ordering::Equal) => true,
404                Some(cmp::Ordering::Greater) => false,
405                None => false,
406            }
407        }
408    };
409}
410
411/// A trait that represents all the stuff a valid leaf of a calc expression.
412pub trait CalcNodeLeaf: Clone + Sized + PartialEq + ToCss + ToTyped {
413    /// Returns the unit of the leaf.
414    fn unit(&self) -> CalcUnits;
415
416    /// Returns the unitless value of this leaf if one is available.
417    fn unitless_value(&self) -> Option<f32>;
418
419    /// Return true if the units of both leaves are equal. (NOTE: Does not take
420    /// the values into account)
421    fn is_same_unit_as(&self, other: &Self) -> bool {
422        std::mem::discriminant(self) == std::mem::discriminant(other)
423    }
424
425    /// Do a partial comparison of these values.
426    fn compare(
427        &self,
428        other: &Self,
429        base_is_positive: PositivePercentageBasis,
430    ) -> Option<cmp::Ordering>;
431    compare_helpers!();
432
433    /// Create a new leaf with a number value.
434    fn new_number(value: f32) -> Self;
435
436    /// Returns a float value if the leaf is a number.
437    fn as_number(&self) -> Option<f32>;
438
439    /// Whether this value is known-negative.
440    fn is_negative(&self) -> Result<bool, ()> {
441        self.unitless_value()
442            .map(|v| Ok(v.is_sign_negative()))
443            .unwrap_or_else(|| Err(()))
444    }
445
446    /// Whether this value is infinite.
447    fn is_infinite(&self) -> Result<bool, ()> {
448        self.unitless_value()
449            .map(|v| Ok(v.is_infinite()))
450            .unwrap_or_else(|| Err(()))
451    }
452
453    /// Whether this value is zero.
454    fn is_zero(&self) -> Result<bool, ()> {
455        self.unitless_value()
456            .map(|v| Ok(v.is_zero()))
457            .unwrap_or_else(|| Err(()))
458    }
459
460    /// Whether this value is NaN.
461    fn is_nan(&self) -> Result<bool, ()> {
462        self.unitless_value()
463            .map(|v| Ok(v.is_nan()))
464            .unwrap_or_else(|| Err(()))
465    }
466
467    /// Tries to merge one leaf into another using the sum, that is, perform `x` + `y`.
468    fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()>;
469
470    /// Try to merge the right leaf into the left by using a multiplication. Return true if the
471    /// merge was successful, otherwise false.
472    fn try_product_in_place(&mut self, other: &mut Self) -> bool;
473
474    /// Tries a generic arithmetic operation.
475    fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
476    where
477        O: Fn(f32, f32) -> f32;
478
479    /// Map the value of this node with the given operation.
480    fn map(&mut self, op: impl FnMut(f32) -> f32) -> Result<(), ()>;
481
482    /// Canonicalizes the expression if necessary.
483    fn simplify(&mut self);
484
485    /// Returns the sort key for simplification.
486    fn sort_key(&self) -> SortKey;
487
488    /// Create a new leaf containing the sign() result of the given leaf.
489    fn sign_from(leaf: &impl CalcNodeLeaf) -> Result<Self, ()> {
490        let Some(value) = leaf.unitless_value() else {
491            return Err(());
492        };
493
494        Ok(Self::new_number(if value.is_nan() {
495            f32::NAN
496        } else if value.is_zero() {
497            value
498        } else if value.is_sign_negative() {
499            -1.0
500        } else {
501            1.0
502        }))
503    }
504}
505
506/// The level of any argument being serialized in `to_css_impl`.
507#[derive(Clone)]
508enum ArgumentLevel {
509    /// The root of a calculation tree.
510    CalculationRoot,
511    /// The root of an operand node's argument, e.g. `min(10, 20)`, `10` and `20` will have this
512    /// level, but min in this case will have `TopMost`.
513    ArgumentRoot,
514    /// Any other values serialized in the tree.
515    Nested,
516}
517
518impl<L: CalcNodeLeaf> CalcNode<L> {
519    /// Create a dummy CalcNode that can be used to do replacements of other nodes.
520    fn dummy() -> Self {
521        Self::MinMax(Default::default(), MinMaxOp::Max)
522    }
523
524    /// Change all the leaf nodes to have the given value. This is useful when
525    /// you have `calc(1px * nan)` and you want to replace the product node with
526    /// `calc(nan)`, in which case the unit will be retained.
527    fn coerce_to_value(&mut self, value: f32) -> Result<(), ()> {
528        self.map(|_| value)
529    }
530
531    /// Return true if a product is distributive over this node.
532    /// Is distributive: (2 + 3) * 4 = 8 + 12
533    /// Not distributive: sign(2 + 3) * 4 != sign(8 + 12)
534    #[inline]
535    pub fn is_product_distributive(&self) -> bool {
536        match self {
537            Self::Leaf(l) => l.unit() != CalcUnits::COLOR_COMPONENT,
538            Self::Sum(children) => children.iter().all(|c| c.is_product_distributive()),
539            _ => false,
540        }
541    }
542
543    /// If the node has a valid unit outcome, then return it, otherwise fail.
544    pub fn unit(&self) -> Result<CalcUnits, ()> {
545        Ok(match self {
546            CalcNode::Leaf(l) => l.unit(),
547            CalcNode::Negate(child) | CalcNode::Invert(child) | CalcNode::Abs(child) => {
548                child.unit()?
549            },
550            CalcNode::Sum(children) => {
551                let mut unit = children.first().unwrap().unit()?;
552                for child in children.iter().skip(1) {
553                    let child_unit = child.unit()?;
554                    if !child_unit.can_sum_with(unit) {
555                        return Err(());
556                    }
557                    unit |= child_unit;
558                }
559                unit
560            },
561            CalcNode::Product(children) => {
562                // Only one node is allowed to have a unit, the rest must be numbers.
563                let mut unit = None;
564                for child in children.iter() {
565                    let child_unit = child.unit()?;
566                    if child_unit.is_empty() {
567                        // Numbers are always allowed in a product, so continue with the next.
568                        continue;
569                    }
570
571                    if unit.is_some() {
572                        // We already have a unit for the node, so another unit node is invalid.
573                        return Err(());
574                    }
575
576                    // We have the unit for the node.
577                    unit = Some(child_unit);
578                }
579                // We only keep track of specified units, so if we end up with a None and no failure
580                // so far, then we have a number.
581                unit.unwrap_or(CalcUnits::empty())
582            },
583            CalcNode::MinMax(children, _) | CalcNode::Hypot(children) => {
584                let mut unit = children.first().unwrap().unit()?;
585                for child in children.iter().skip(1) {
586                    let child_unit = child.unit()?;
587                    if !child_unit.can_sum_with(unit) {
588                        return Err(());
589                    }
590                    unit |= child_unit;
591                }
592                unit
593            },
594            CalcNode::Clamp { min, center, max } => {
595                let min_unit = min.unit()?;
596                let center_unit = center.unit()?;
597
598                if !min_unit.can_sum_with(center_unit) {
599                    return Err(());
600                }
601
602                let max_unit = max.unit()?;
603
604                if !center_unit.can_sum_with(max_unit) {
605                    return Err(());
606                }
607
608                min_unit | center_unit | max_unit
609            },
610            CalcNode::Round { value, step, .. } => {
611                let value_unit = value.unit()?;
612                let step_unit = step.unit()?;
613                if !step_unit.can_sum_with(value_unit) {
614                    return Err(());
615                }
616                value_unit | step_unit
617            },
618            CalcNode::ModRem {
619                dividend, divisor, ..
620            } => {
621                let dividend_unit = dividend.unit()?;
622                let divisor_unit = divisor.unit()?;
623                if !divisor_unit.can_sum_with(dividend_unit) {
624                    return Err(());
625                }
626                dividend_unit | divisor_unit
627            },
628            CalcNode::Sign(ref child) => {
629                // sign() always resolves to a number, but we still need to make sure that the
630                // child units make sense.
631                let _ = child.unit()?;
632                CalcUnits::empty()
633            },
634            CalcNode::Anchor(..) | CalcNode::AnchorSize(..) => CalcUnits::LENGTH_PERCENTAGE,
635        })
636    }
637
638    /// Negate the node inline.  If the node is distributive, it is replaced by the result,
639    /// otherwise the node is wrapped in a [`Negate`] node.
640    pub fn negate(&mut self) {
641        /// Node(params) -> Negate(Node(params))
642        fn wrap_self_in_negate<L: CalcNodeLeaf>(s: &mut CalcNode<L>) {
643            let result = mem::replace(s, CalcNode::dummy());
644            *s = CalcNode::Negate(Box::new(result));
645        }
646
647        match *self {
648            CalcNode::Leaf(ref mut leaf) => {
649                if leaf.map(std::ops::Neg::neg).is_err() {
650                    wrap_self_in_negate(self)
651                }
652            },
653            CalcNode::Negate(ref mut value) => {
654                // Don't negate the value here.  Replace `self` with it's child.
655                let result = mem::replace(value.as_mut(), Self::dummy());
656                *self = result;
657            },
658            CalcNode::Invert(_) => {
659                // -(1 / -10) == -(-0.1) == 0.1
660                wrap_self_in_negate(self)
661            },
662            CalcNode::Sum(ref mut children) => {
663                for child in children.iter_mut() {
664                    child.negate();
665                }
666            },
667            CalcNode::Product(_) => {
668                // -(2 * 3 / 4) == -(1.5)
669                wrap_self_in_negate(self);
670            },
671            CalcNode::MinMax(ref mut children, ref mut op) => {
672                for child in children.iter_mut() {
673                    child.negate();
674                }
675
676                // Negating min-max means the operation is swapped.
677                *op = match *op {
678                    MinMaxOp::Min => MinMaxOp::Max,
679                    MinMaxOp::Max => MinMaxOp::Min,
680                };
681            },
682            CalcNode::Clamp {
683                ref mut min,
684                ref mut center,
685                ref mut max,
686            } => {
687                if min.lte(max, PositivePercentageBasis::Unknown) {
688                    min.negate();
689                    center.negate();
690                    max.negate();
691
692                    mem::swap(min, max);
693                } else {
694                    wrap_self_in_negate(self);
695                }
696            },
697            CalcNode::Round {
698                ref mut strategy,
699                ref mut value,
700                ref mut step,
701            } => {
702                match *strategy {
703                    RoundingStrategy::Nearest => {
704                        // Nearest is tricky because we'd have to swap the
705                        // behavior at the half-way point from using the upper
706                        // to lower bound.
707                        // Simpler to just wrap self in a negate node.
708                        wrap_self_in_negate(self);
709                        return;
710                    },
711                    RoundingStrategy::Up => *strategy = RoundingStrategy::Down,
712                    RoundingStrategy::Down => *strategy = RoundingStrategy::Up,
713                    RoundingStrategy::ToZero => (),
714                }
715                value.negate();
716                step.negate();
717            },
718            CalcNode::ModRem {
719                ref mut dividend,
720                ref mut divisor,
721                ..
722            } => {
723                dividend.negate();
724                divisor.negate();
725            },
726            CalcNode::Hypot(ref mut children) => {
727                for child in children.iter_mut() {
728                    child.negate();
729                }
730            },
731            CalcNode::Abs(_) => {
732                wrap_self_in_negate(self);
733            },
734            CalcNode::Sign(ref mut child) => {
735                child.negate();
736            },
737            CalcNode::Anchor(_) | CalcNode::AnchorSize(_) => {
738                wrap_self_in_negate(self);
739            },
740        }
741    }
742
743    fn sort_key(&self) -> SortKey {
744        match *self {
745            Self::Leaf(ref l) => l.sort_key(),
746            Self::Anchor(..) | Self::AnchorSize(..) => SortKey::Px,
747            _ => SortKey::Other,
748        }
749    }
750
751    /// Returns the leaf if we can (if simplification has allowed it).
752    pub fn as_leaf(&self) -> Option<&L> {
753        match *self {
754            Self::Leaf(ref l) => Some(l),
755            _ => None,
756        }
757    }
758
759    /// Tries to merge one node into another using the sum, that is, perform `x` + `y`.
760    pub fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()> {
761        match (self, other) {
762            (&mut CalcNode::Leaf(ref mut one), &CalcNode::Leaf(ref other)) => {
763                one.try_sum_in_place(other)
764            },
765            _ => Err(()),
766        }
767    }
768
769    /// Tries to merge one node into another using the product, that is, perform `x` * `y`.
770    pub fn try_product_in_place(&mut self, other: &mut Self) -> bool {
771        if let Ok(resolved) = other.resolve() {
772            if let Some(number) = resolved.as_number() {
773                if number == 1.0 {
774                    return true;
775                }
776
777                if self.is_product_distributive() {
778                    if self.map(|v| v * number).is_err() {
779                        return false;
780                    }
781                    return true;
782                }
783            }
784        }
785
786        if let Ok(resolved) = self.resolve() {
787            if let Some(number) = resolved.as_number() {
788                if number == 1.0 {
789                    std::mem::swap(self, other);
790                    return true;
791                }
792
793                if other.is_product_distributive() {
794                    if other.map(|v| v * number).is_err() {
795                        return false;
796                    }
797                    std::mem::swap(self, other);
798                    return true;
799                }
800            }
801        }
802
803        false
804    }
805
806    /// Tries to apply a generic arithmetic operator
807    fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
808    where
809        O: Fn(f32, f32) -> f32,
810    {
811        match (self, other) {
812            (&CalcNode::Leaf(ref one), &CalcNode::Leaf(ref other)) => {
813                Ok(CalcNode::Leaf(one.try_op(other, op)?))
814            },
815            _ => Err(()),
816        }
817    }
818
819    /// Map the value of this node with the given operation.
820    pub fn map(&mut self, mut op: impl FnMut(f32) -> f32) -> Result<(), ()> {
821        fn map_internal<L: CalcNodeLeaf>(
822            node: &mut CalcNode<L>,
823            op: &mut impl FnMut(f32) -> f32,
824        ) -> Result<(), ()> {
825            match node {
826                CalcNode::Leaf(l) => l.map(op),
827                CalcNode::Negate(v) | CalcNode::Invert(v) => map_internal(v, op),
828                CalcNode::Sum(children) | CalcNode::Product(children) => {
829                    for node in &mut **children {
830                        map_internal(node, op)?;
831                    }
832                    Ok(())
833                },
834                CalcNode::MinMax(children, _) => {
835                    for node in &mut **children {
836                        map_internal(node, op)?;
837                    }
838                    Ok(())
839                },
840                CalcNode::Clamp { min, center, max } => {
841                    map_internal(min, op)?;
842                    map_internal(center, op)?;
843                    map_internal(max, op)
844                },
845                CalcNode::Round { value, step, .. } => {
846                    map_internal(value, op)?;
847                    map_internal(step, op)
848                },
849                CalcNode::ModRem {
850                    dividend, divisor, ..
851                } => {
852                    map_internal(dividend, op)?;
853                    map_internal(divisor, op)
854                },
855                CalcNode::Hypot(children) => {
856                    for node in &mut **children {
857                        map_internal(node, op)?;
858                    }
859                    Ok(())
860                },
861                CalcNode::Abs(child) | CalcNode::Sign(child) => map_internal(child, op),
862                // It is invalid to treat inner `CalcNode`s here - `anchor(--foo 50%) / 2` != `anchor(--foo 25%)`.
863                // Same applies to fallback, as we don't know if it will be used. Similar reasoning applies to `anchor-size()`.
864                CalcNode::Anchor(_) | CalcNode::AnchorSize(_) => Err(()),
865            }
866        }
867
868        map_internal(self, &mut op)
869    }
870
871    /// Convert this `CalcNode` into a `CalcNode` with a different leaf kind.
872    pub fn map_leaves<O, F>(&self, mut map: F) -> CalcNode<O>
873    where
874        O: CalcNodeLeaf,
875        F: FnMut(&L) -> O,
876    {
877        self.map_leaves_internal(&mut map)
878    }
879
880    fn map_leaves_internal<O, F>(&self, map: &mut F) -> CalcNode<O>
881    where
882        O: CalcNodeLeaf,
883        F: FnMut(&L) -> O,
884    {
885        fn map_children<L, O, F>(
886            children: &[CalcNode<L>],
887            map: &mut F,
888        ) -> crate::OwnedSlice<CalcNode<O>>
889        where
890            L: CalcNodeLeaf,
891            O: CalcNodeLeaf,
892            F: FnMut(&L) -> O,
893        {
894            children
895                .iter()
896                .map(|c| c.map_leaves_internal(map))
897                .collect()
898        }
899
900        match *self {
901            Self::Leaf(ref l) => CalcNode::Leaf(map(l)),
902            Self::Negate(ref c) => CalcNode::Negate(Box::new(c.map_leaves_internal(map))),
903            Self::Invert(ref c) => CalcNode::Invert(Box::new(c.map_leaves_internal(map))),
904            Self::Sum(ref c) => CalcNode::Sum(map_children(c, map)),
905            Self::Product(ref c) => CalcNode::Product(map_children(c, map)),
906            Self::MinMax(ref c, op) => CalcNode::MinMax(map_children(c, map), op),
907            Self::Clamp {
908                ref min,
909                ref center,
910                ref max,
911            } => {
912                let min = Box::new(min.map_leaves_internal(map));
913                let center = Box::new(center.map_leaves_internal(map));
914                let max = Box::new(max.map_leaves_internal(map));
915                CalcNode::Clamp { min, center, max }
916            },
917            Self::Round {
918                strategy,
919                ref value,
920                ref step,
921            } => {
922                let value = Box::new(value.map_leaves_internal(map));
923                let step = Box::new(step.map_leaves_internal(map));
924                CalcNode::Round {
925                    strategy,
926                    value,
927                    step,
928                }
929            },
930            Self::ModRem {
931                ref dividend,
932                ref divisor,
933                op,
934            } => {
935                let dividend = Box::new(dividend.map_leaves_internal(map));
936                let divisor = Box::new(divisor.map_leaves_internal(map));
937                CalcNode::ModRem {
938                    dividend,
939                    divisor,
940                    op,
941                }
942            },
943            Self::Hypot(ref c) => CalcNode::Hypot(map_children(c, map)),
944            Self::Abs(ref c) => CalcNode::Abs(Box::new(c.map_leaves_internal(map))),
945            Self::Sign(ref c) => CalcNode::Sign(Box::new(c.map_leaves_internal(map))),
946            Self::Anchor(ref f) => CalcNode::Anchor(Box::new(GenericAnchorFunction {
947                target_element: f.target_element.clone(),
948                side: match &f.side {
949                    GenericAnchorSide::Keyword(k) => GenericAnchorSide::Keyword(*k),
950                    GenericAnchorSide::Percentage(p) => {
951                        GenericAnchorSide::Percentage(Box::new(p.map_leaves_internal(map)))
952                    },
953                },
954                fallback: f
955                    .fallback
956                    .as_ref()
957                    .map(|fb| {
958                        Box::new(GenericAnchorFunctionFallback::new(
959                            fb.is_calc_node,
960                            fb.node.map_leaves_internal(map),
961                        ))
962                    })
963                    .into(),
964            })),
965            Self::AnchorSize(ref f) => CalcNode::AnchorSize(Box::new(GenericAnchorSizeFunction {
966                target_element: f.target_element.clone(),
967                size: f.size,
968                fallback: f
969                    .fallback
970                    .as_ref()
971                    .map(|fb| {
972                        Box::new(GenericAnchorFunctionFallback::new(
973                            fb.is_calc_node,
974                            fb.node.map_leaves_internal(map),
975                        ))
976                    })
977                    .into(),
978            })),
979        }
980    }
981
982    /// Resolve this node into a value.
983    pub fn resolve(&self) -> Result<L, ()> {
984        self.resolve_map(|l| Ok(l.clone()))
985    }
986
987    /// Resolve this node into a value, given a function that maps the leaf values.
988    pub fn resolve_map<F>(&self, mut leaf_to_output_fn: F) -> Result<L, ()>
989    where
990        F: FnMut(&L) -> Result<L, ()>,
991    {
992        self.resolve_internal(&mut leaf_to_output_fn)
993    }
994
995    fn resolve_internal<F>(&self, leaf_to_output_fn: &mut F) -> Result<L, ()>
996    where
997        F: FnMut(&L) -> Result<L, ()>,
998    {
999        match self {
1000            Self::Leaf(l) => leaf_to_output_fn(l),
1001            Self::Negate(child) => {
1002                let mut result = child.resolve_internal(leaf_to_output_fn)?;
1003                result.map(|v| v.neg())?;
1004                Ok(result)
1005            },
1006            Self::Invert(child) => {
1007                let mut result = child.resolve_internal(leaf_to_output_fn)?;
1008                result.map(|v| 1.0 / v)?;
1009                Ok(result)
1010            },
1011            Self::Sum(children) => {
1012                let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
1013
1014                for child in children.iter().skip(1) {
1015                    let right = child.resolve_internal(leaf_to_output_fn)?;
1016                    // try_op will make sure we only sum leaves with the same type.
1017                    result = result.try_op(&right, |left, right| left + right)?;
1018                }
1019
1020                Ok(result)
1021            },
1022            Self::Product(children) => {
1023                let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
1024
1025                for child in children.iter().skip(1) {
1026                    let right = child.resolve_internal(leaf_to_output_fn)?;
1027                    // Mutliply only allowed when either side is a number.
1028                    match result.as_number() {
1029                        Some(left) => {
1030                            // Left side is a number, so we use the right node as the result.
1031                            result = right;
1032                            result.map(|v| v * left)?;
1033                        },
1034                        None => {
1035                            // Left side is not a number, so check if the right side is.
1036                            match right.as_number() {
1037                                Some(right) => {
1038                                    result.map(|v| v * right)?;
1039                                },
1040                                None => {
1041                                    // Multiplying with both sides having units.
1042                                    return Err(());
1043                                },
1044                            }
1045                        },
1046                    }
1047                }
1048
1049                Ok(result)
1050            },
1051            Self::MinMax(children, op) => {
1052                let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
1053
1054                if result.is_nan()? {
1055                    return Ok(result);
1056                }
1057
1058                for child in children.iter().skip(1) {
1059                    let candidate = child.resolve_internal(leaf_to_output_fn)?;
1060
1061                    // Leaf types must match for each child.
1062                    if !result.is_same_unit_as(&candidate) {
1063                        return Err(());
1064                    }
1065
1066                    if candidate.is_nan()? {
1067                        result = candidate;
1068                        break;
1069                    }
1070
1071                    let candidate_wins = match op {
1072                        MinMaxOp::Min => candidate.lt(&result, PositivePercentageBasis::Yes),
1073                        MinMaxOp::Max => candidate.gt(&result, PositivePercentageBasis::Yes),
1074                    };
1075
1076                    if candidate_wins {
1077                        result = candidate;
1078                    }
1079                }
1080
1081                Ok(result)
1082            },
1083            Self::Clamp { min, center, max } => {
1084                let min = min.resolve_internal(leaf_to_output_fn)?;
1085                let center = center.resolve_internal(leaf_to_output_fn)?;
1086                let max = max.resolve_internal(leaf_to_output_fn)?;
1087
1088                if !min.is_same_unit_as(&center) || !max.is_same_unit_as(&center) {
1089                    return Err(());
1090                }
1091
1092                if min.is_nan()? {
1093                    return Ok(min);
1094                }
1095
1096                if center.is_nan()? {
1097                    return Ok(center);
1098                }
1099
1100                if max.is_nan()? {
1101                    return Ok(max);
1102                }
1103
1104                let mut result = center;
1105                if result.gt(&max, PositivePercentageBasis::Yes) {
1106                    result = max;
1107                }
1108                if result.lt(&min, PositivePercentageBasis::Yes) {
1109                    result = min
1110                }
1111
1112                Ok(result)
1113            },
1114            Self::Round {
1115                strategy,
1116                value,
1117                step,
1118            } => {
1119                let mut value = value.resolve_internal(leaf_to_output_fn)?;
1120                let step = step.resolve_internal(leaf_to_output_fn)?;
1121
1122                if !value.is_same_unit_as(&step) {
1123                    return Err(());
1124                }
1125
1126                let Some(step) = step.unitless_value() else {
1127                    return Err(());
1128                };
1129                let step = step.abs();
1130
1131                value.map(|value| {
1132                    // TODO(emilio): Seems like at least a few of these
1133                    // special-cases could be removed if we do the math in a
1134                    // particular order.
1135                    if step.is_zero() {
1136                        return f32::NAN;
1137                    }
1138
1139                    if value.is_infinite() {
1140                        if step.is_infinite() {
1141                            return f32::NAN;
1142                        }
1143                        return value;
1144                    }
1145
1146                    if step.is_infinite() {
1147                        match strategy {
1148                            RoundingStrategy::Nearest | RoundingStrategy::ToZero => {
1149                                return if value.is_sign_negative() { -0.0 } else { 0.0 }
1150                            },
1151                            RoundingStrategy::Up => {
1152                                return if !value.is_sign_negative() && !value.is_zero() {
1153                                    f32::INFINITY
1154                                } else if !value.is_sign_negative() && value.is_zero() {
1155                                    value
1156                                } else {
1157                                    -0.0
1158                                }
1159                            },
1160                            RoundingStrategy::Down => {
1161                                return if value.is_sign_negative() && !value.is_zero() {
1162                                    -f32::INFINITY
1163                                } else if value.is_sign_negative() && value.is_zero() {
1164                                    value
1165                                } else {
1166                                    0.0
1167                                }
1168                            },
1169                        }
1170                    }
1171
1172                    let div = value / step;
1173                    let lower_bound = div.floor() * step;
1174                    let upper_bound = div.ceil() * step;
1175
1176                    match strategy {
1177                        RoundingStrategy::Nearest => {
1178                            // In case of a tie, use the upper bound
1179                            if value - lower_bound < upper_bound - value {
1180                                lower_bound
1181                            } else {
1182                                upper_bound
1183                            }
1184                        },
1185                        RoundingStrategy::Up => upper_bound,
1186                        RoundingStrategy::Down => lower_bound,
1187                        RoundingStrategy::ToZero => {
1188                            // In case of a tie, use the upper bound
1189                            if lower_bound.abs() < upper_bound.abs() {
1190                                lower_bound
1191                            } else {
1192                                upper_bound
1193                            }
1194                        },
1195                    }
1196                })?;
1197
1198                Ok(value)
1199            },
1200            Self::ModRem {
1201                dividend,
1202                divisor,
1203                op,
1204            } => {
1205                let mut dividend = dividend.resolve_internal(leaf_to_output_fn)?;
1206                let divisor = divisor.resolve_internal(leaf_to_output_fn)?;
1207
1208                if !dividend.is_same_unit_as(&divisor) {
1209                    return Err(());
1210                }
1211
1212                let Some(divisor) = divisor.unitless_value() else {
1213                    return Err(());
1214                };
1215                dividend.map(|dividend| op.apply(dividend, divisor))?;
1216                Ok(dividend)
1217            },
1218            Self::Hypot(children) => {
1219                let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
1220                result.map(|v| v.powi(2))?;
1221
1222                for child in children.iter().skip(1) {
1223                    let child_value = child.resolve_internal(leaf_to_output_fn)?;
1224
1225                    if !result.is_same_unit_as(&child_value) {
1226                        return Err(());
1227                    }
1228
1229                    let Some(child_value) = child_value.unitless_value() else {
1230                        return Err(());
1231                    };
1232                    result.map(|v| v + child_value.powi(2))?;
1233                }
1234
1235                result.map(|v| v.sqrt())?;
1236                Ok(result)
1237            },
1238            Self::Abs(ref c) => {
1239                let mut result = c.resolve_internal(leaf_to_output_fn)?;
1240
1241                result.map(|v| v.abs())?;
1242
1243                Ok(result)
1244            },
1245            Self::Sign(ref c) => {
1246                let result = c.resolve_internal(leaf_to_output_fn)?;
1247                Ok(L::sign_from(&result)?)
1248            },
1249            Self::Anchor(_) | Self::AnchorSize(_) => Err(()),
1250        }
1251    }
1252
1253    /// Mutate nodes within this calc node tree using given the mapping function.
1254    pub fn map_node<F>(&mut self, mut mapping_fn: F) -> Result<(), ()>
1255    where
1256        F: FnMut(&CalcNode<L>) -> Result<Option<CalcNode<L>>, ()>,
1257    {
1258        self.map_node_internal(&mut mapping_fn)
1259    }
1260
1261    fn map_node_internal<F>(&mut self, mapping_fn: &mut F) -> Result<(), ()>
1262    where
1263        F: FnMut(&CalcNode<L>) -> Result<Option<CalcNode<L>>, ()>,
1264    {
1265        if let Some(node) = mapping_fn(self)? {
1266            *self = node;
1267            // Assume that any sub-nodes don't need to be mutated.
1268            return Ok(());
1269        }
1270        match self {
1271            Self::Leaf(_) | Self::Anchor(_) | Self::AnchorSize(_) => (),
1272            Self::Negate(child) | Self::Invert(child) | Self::Abs(child) | Self::Sign(child) => {
1273                child.map_node_internal(mapping_fn)?;
1274            },
1275            Self::Sum(children)
1276            | Self::Product(children)
1277            | Self::Hypot(children)
1278            | Self::MinMax(children, _) => {
1279                for child in children.iter_mut() {
1280                    child.map_node_internal(mapping_fn)?;
1281                }
1282            },
1283            Self::Clamp { min, center, max } => {
1284                min.map_node_internal(mapping_fn)?;
1285                center.map_node_internal(mapping_fn)?;
1286                max.map_node_internal(mapping_fn)?;
1287            },
1288            Self::Round { value, step, .. } => {
1289                value.map_node_internal(mapping_fn)?;
1290                step.map_node_internal(mapping_fn)?;
1291            },
1292            Self::ModRem {
1293                dividend, divisor, ..
1294            } => {
1295                dividend.map_node_internal(mapping_fn)?;
1296                divisor.map_node_internal(mapping_fn)?;
1297            },
1298        };
1299        Ok(())
1300    }
1301
1302    fn is_negative_leaf(&self) -> Result<bool, ()> {
1303        Ok(match *self {
1304            Self::Leaf(ref l) => l.is_negative()?,
1305            _ => false,
1306        })
1307    }
1308
1309    fn is_zero_leaf(&self) -> Result<bool, ()> {
1310        Ok(match *self {
1311            Self::Leaf(ref l) => l.is_zero()?,
1312            _ => false,
1313        })
1314    }
1315
1316    fn is_infinite_leaf(&self) -> Result<bool, ()> {
1317        Ok(match *self {
1318            Self::Leaf(ref l) => l.is_infinite()?,
1319            _ => false,
1320        })
1321    }
1322
1323    fn is_nan_leaf(&self) -> Result<bool, ()> {
1324        Ok(match *self {
1325            Self::Leaf(ref l) => l.is_nan()?,
1326            _ => false,
1327        })
1328    }
1329
1330    /// Visits all the nodes in this calculation tree recursively, starting by
1331    /// the leaves and bubbling all the way up.
1332    ///
1333    /// This is useful for simplification, but can also be used for validation
1334    /// and such.
1335    pub fn visit_depth_first(&mut self, mut f: impl FnMut(&mut Self)) {
1336        self.visit_depth_first_internal(&mut f)
1337    }
1338
1339    fn visit_depth_first_internal(&mut self, f: &mut impl FnMut(&mut Self)) {
1340        match *self {
1341            Self::Clamp {
1342                ref mut min,
1343                ref mut center,
1344                ref mut max,
1345            } => {
1346                min.visit_depth_first_internal(f);
1347                center.visit_depth_first_internal(f);
1348                max.visit_depth_first_internal(f);
1349            },
1350            Self::Round {
1351                ref mut value,
1352                ref mut step,
1353                ..
1354            } => {
1355                value.visit_depth_first_internal(f);
1356                step.visit_depth_first_internal(f);
1357            },
1358            Self::ModRem {
1359                ref mut dividend,
1360                ref mut divisor,
1361                ..
1362            } => {
1363                dividend.visit_depth_first_internal(f);
1364                divisor.visit_depth_first_internal(f);
1365            },
1366            Self::Sum(ref mut children)
1367            | Self::Product(ref mut children)
1368            | Self::MinMax(ref mut children, _)
1369            | Self::Hypot(ref mut children) => {
1370                for child in &mut **children {
1371                    child.visit_depth_first_internal(f);
1372                }
1373            },
1374            Self::Negate(ref mut value) | Self::Invert(ref mut value) => {
1375                value.visit_depth_first_internal(f);
1376            },
1377            Self::Abs(ref mut value) | Self::Sign(ref mut value) => {
1378                value.visit_depth_first_internal(f);
1379            },
1380            Self::Leaf(..) | Self::Anchor(..) | Self::AnchorSize(..) => {},
1381        }
1382        f(self);
1383    }
1384
1385    /// This function simplifies and sorts the calculation of the specified node. It simplifies
1386    /// directly nested nodes while assuming that all nodes below it have already been simplified.
1387    /// It is recommended to use this function in combination with `visit_depth_first()`.
1388    ///
1389    /// This function is necessary only if the node needs to be preserved after parsing,
1390    /// specifically for `<length-percentage>` cases where the calculation contains percentages or
1391    /// relative units. Otherwise, the node can be evaluated using `resolve()`, which will
1392    /// automatically provide a simplified value.
1393    ///
1394    /// <https://drafts.csswg.org/css-values-4/#calc-simplification>
1395    pub fn simplify_and_sort_direct_children(&mut self) {
1396        macro_rules! replace_self_with {
1397            ($slot:expr) => {{
1398                let result = mem::replace($slot, Self::dummy());
1399                *self = result;
1400            }};
1401        }
1402
1403        macro_rules! value_or_stop {
1404            ($op:expr) => {{
1405                match $op {
1406                    Ok(value) => value,
1407                    Err(_) => return,
1408                }
1409            }};
1410        }
1411
1412        match *self {
1413            Self::Clamp {
1414                ref mut min,
1415                ref mut center,
1416                ref mut max,
1417            } => {
1418                // NOTE: clamp() is max(min, min(center, max))
1419                let min_cmp_center = match min.compare(&center, PositivePercentageBasis::Unknown) {
1420                    Some(o) => o,
1421                    None => return,
1422                };
1423
1424                // So if we can prove that min is more than center, then we won,
1425                // as that's what we should always return.
1426                if matches!(min_cmp_center, cmp::Ordering::Greater) {
1427                    replace_self_with!(&mut **min);
1428                    return;
1429                }
1430
1431                // Otherwise try with max.
1432                let max_cmp_center = match max.compare(&center, PositivePercentageBasis::Unknown) {
1433                    Some(o) => o,
1434                    None => return,
1435                };
1436
1437                if matches!(max_cmp_center, cmp::Ordering::Less) {
1438                    // max is less than center, so we need to return effectively
1439                    // `max(min, max)`.
1440                    let max_cmp_min = match max.compare(&min, PositivePercentageBasis::Unknown) {
1441                        Some(o) => o,
1442                        None => return,
1443                    };
1444
1445                    if matches!(max_cmp_min, cmp::Ordering::Less) {
1446                        replace_self_with!(&mut **min);
1447                        return;
1448                    }
1449
1450                    replace_self_with!(&mut **max);
1451                    return;
1452                }
1453
1454                // Otherwise we're the center node.
1455                replace_self_with!(&mut **center);
1456            },
1457            Self::Round {
1458                strategy,
1459                ref mut value,
1460                ref mut step,
1461            } => {
1462                if value_or_stop!(step.is_zero_leaf()) {
1463                    value_or_stop!(value.coerce_to_value(f32::NAN));
1464                    replace_self_with!(&mut **value);
1465                    return;
1466                }
1467
1468                if value_or_stop!(value.is_infinite_leaf())
1469                    && value_or_stop!(step.is_infinite_leaf())
1470                {
1471                    value_or_stop!(value.coerce_to_value(f32::NAN));
1472                    replace_self_with!(&mut **value);
1473                    return;
1474                }
1475
1476                if value_or_stop!(value.is_infinite_leaf()) {
1477                    replace_self_with!(&mut **value);
1478                    return;
1479                }
1480
1481                if value_or_stop!(step.is_infinite_leaf()) {
1482                    match strategy {
1483                        RoundingStrategy::Nearest | RoundingStrategy::ToZero => {
1484                            value_or_stop!(value.coerce_to_value(0.0));
1485                            replace_self_with!(&mut **value);
1486                            return;
1487                        },
1488                        RoundingStrategy::Up => {
1489                            if !value_or_stop!(value.is_negative_leaf())
1490                                && !value_or_stop!(value.is_zero_leaf())
1491                            {
1492                                value_or_stop!(value.coerce_to_value(f32::INFINITY));
1493                                replace_self_with!(&mut **value);
1494                                return;
1495                            } else if !value_or_stop!(value.is_negative_leaf())
1496                                && value_or_stop!(value.is_zero_leaf())
1497                            {
1498                                replace_self_with!(&mut **value);
1499                                return;
1500                            } else {
1501                                value_or_stop!(value.coerce_to_value(0.0));
1502                                replace_self_with!(&mut **value);
1503                                return;
1504                            }
1505                        },
1506                        RoundingStrategy::Down => {
1507                            if value_or_stop!(value.is_negative_leaf())
1508                                && !value_or_stop!(value.is_zero_leaf())
1509                            {
1510                                value_or_stop!(value.coerce_to_value(f32::INFINITY));
1511                                replace_self_with!(&mut **value);
1512                                return;
1513                            } else if value_or_stop!(value.is_negative_leaf())
1514                                && value_or_stop!(value.is_zero_leaf())
1515                            {
1516                                replace_self_with!(&mut **value);
1517                                return;
1518                            } else {
1519                                value_or_stop!(value.coerce_to_value(0.0));
1520                                replace_self_with!(&mut **value);
1521                                return;
1522                            }
1523                        },
1524                    }
1525                }
1526
1527                if value_or_stop!(step.is_negative_leaf()) {
1528                    step.negate();
1529                }
1530
1531                let remainder = value_or_stop!(value.try_op(step, Rem::rem));
1532                if value_or_stop!(remainder.is_zero_leaf()) {
1533                    replace_self_with!(&mut **value);
1534                    return;
1535                }
1536
1537                let (mut lower_bound, mut upper_bound) = if value_or_stop!(value.is_negative_leaf())
1538                {
1539                    let upper_bound = value_or_stop!(value.try_op(&remainder, Sub::sub));
1540                    let lower_bound = value_or_stop!(upper_bound.try_op(&step, Sub::sub));
1541
1542                    (lower_bound, upper_bound)
1543                } else {
1544                    let lower_bound = value_or_stop!(value.try_op(&remainder, Sub::sub));
1545                    let upper_bound = value_or_stop!(lower_bound.try_op(&step, Add::add));
1546
1547                    (lower_bound, upper_bound)
1548                };
1549
1550                match strategy {
1551                    RoundingStrategy::Nearest => {
1552                        let lower_diff = value_or_stop!(value.try_op(&lower_bound, Sub::sub));
1553                        let upper_diff = value_or_stop!(upper_bound.try_op(value, Sub::sub));
1554                        // In case of a tie, use the upper bound
1555                        if lower_diff.lt(&upper_diff, PositivePercentageBasis::Unknown) {
1556                            replace_self_with!(&mut lower_bound);
1557                        } else {
1558                            replace_self_with!(&mut upper_bound);
1559                        }
1560                    },
1561                    RoundingStrategy::Up => {
1562                        replace_self_with!(&mut upper_bound);
1563                    },
1564                    RoundingStrategy::Down => {
1565                        replace_self_with!(&mut lower_bound);
1566                    },
1567                    RoundingStrategy::ToZero => {
1568                        let mut lower_diff = lower_bound.clone();
1569                        let mut upper_diff = upper_bound.clone();
1570
1571                        if value_or_stop!(lower_diff.is_negative_leaf()) {
1572                            lower_diff.negate();
1573                        }
1574
1575                        if value_or_stop!(upper_diff.is_negative_leaf()) {
1576                            upper_diff.negate();
1577                        }
1578
1579                        // In case of a tie, use the upper bound
1580                        if lower_diff.lt(&upper_diff, PositivePercentageBasis::Unknown) {
1581                            replace_self_with!(&mut lower_bound);
1582                        } else {
1583                            replace_self_with!(&mut upper_bound);
1584                        }
1585                    },
1586                };
1587            },
1588            Self::ModRem {
1589                ref dividend,
1590                ref divisor,
1591                op,
1592            } => {
1593                let mut result = value_or_stop!(dividend.try_op(divisor, |a, b| op.apply(a, b)));
1594                replace_self_with!(&mut result);
1595            },
1596            Self::MinMax(ref mut children, op) => {
1597                let winning_order = match op {
1598                    MinMaxOp::Min => cmp::Ordering::Less,
1599                    MinMaxOp::Max => cmp::Ordering::Greater,
1600                };
1601
1602                if value_or_stop!(children[0].is_nan_leaf()) {
1603                    replace_self_with!(&mut children[0]);
1604                    return;
1605                }
1606
1607                let mut result = 0;
1608                for i in 1..children.len() {
1609                    if value_or_stop!(children[i].is_nan_leaf()) {
1610                        replace_self_with!(&mut children[i]);
1611                        return;
1612                    }
1613                    let o = match children[i]
1614                        .compare(&children[result], PositivePercentageBasis::Unknown)
1615                    {
1616                        // We can't compare all the children, so we can't
1617                        // know which one will actually win. Bail out and
1618                        // keep ourselves as a min / max function.
1619                        //
1620                        // TODO: Maybe we could simplify compatible children,
1621                        // see https://github.com/w3c/csswg-drafts/issues/4756
1622                        None => return,
1623                        Some(o) => o,
1624                    };
1625
1626                    if o == winning_order {
1627                        result = i;
1628                    }
1629                }
1630
1631                replace_self_with!(&mut children[result]);
1632            },
1633            Self::Sum(ref mut children_slot) => {
1634                let mut sums_to_merge = SmallVec::<[_; 3]>::new();
1635                let mut extra_kids = 0;
1636                for (i, child) in children_slot.iter().enumerate() {
1637                    if let Self::Sum(ref children) = *child {
1638                        extra_kids += children.len();
1639                        sums_to_merge.push(i);
1640                    }
1641                }
1642
1643                // If we only have one kid, we've already simplified it, and it
1644                // doesn't really matter whether it's a sum already or not, so
1645                // lift it up and continue.
1646                if children_slot.len() == 1 {
1647                    replace_self_with!(&mut children_slot[0]);
1648                    return;
1649                }
1650
1651                let mut children = mem::take(children_slot).into_vec();
1652
1653                if !sums_to_merge.is_empty() {
1654                    children.reserve(extra_kids - sums_to_merge.len());
1655                    // Merge all our nested sums, in reverse order so that the
1656                    // list indices are not invalidated.
1657                    for i in sums_to_merge.drain(..).rev() {
1658                        let kid_children = match children.swap_remove(i) {
1659                            Self::Sum(c) => c,
1660                            _ => unreachable!(),
1661                        };
1662
1663                        // This would be nicer with
1664                        // https://github.com/rust-lang/rust/issues/59878 fixed.
1665                        children.extend(kid_children.into_vec());
1666                    }
1667                }
1668
1669                debug_assert!(children.len() >= 2, "Should still have multiple kids!");
1670
1671                // Sort by spec order.
1672                children.sort_unstable_by_key(|c| c.sort_key());
1673
1674                // NOTE: if the function returns true, by the docs of dedup_by,
1675                // a is removed.
1676                children.dedup_by(|a, b| b.try_sum_in_place(a).is_ok());
1677
1678                if children.len() == 1 {
1679                    // If only one children remains, lift it up, and carry on.
1680                    replace_self_with!(&mut children[0]);
1681                } else {
1682                    // Else put our simplified children back.
1683                    *children_slot = children.into_boxed_slice().into();
1684                }
1685            },
1686            Self::Product(ref mut children_slot) => {
1687                let mut products_to_merge = SmallVec::<[_; 3]>::new();
1688                let mut extra_kids = 0;
1689                for (i, child) in children_slot.iter().enumerate() {
1690                    if let Self::Product(ref children) = *child {
1691                        extra_kids += children.len();
1692                        products_to_merge.push(i);
1693                    }
1694                }
1695
1696                // If we only have one kid, we've already simplified it, and it
1697                // doesn't really matter whether it's a product already or not,
1698                // so lift it up and continue.
1699                if children_slot.len() == 1 {
1700                    replace_self_with!(&mut children_slot[0]);
1701                    return;
1702                }
1703
1704                let mut children = mem::take(children_slot).into_vec();
1705
1706                if !products_to_merge.is_empty() {
1707                    children.reserve(extra_kids - products_to_merge.len());
1708                    // Merge all our nested sums, in reverse order so that the
1709                    // list indices are not invalidated.
1710                    for i in products_to_merge.drain(..).rev() {
1711                        let kid_children = match children.swap_remove(i) {
1712                            Self::Product(c) => c,
1713                            _ => unreachable!(),
1714                        };
1715
1716                        // This would be nicer with
1717                        // https://github.com/rust-lang/rust/issues/59878 fixed.
1718                        children.extend(kid_children.into_vec());
1719                    }
1720                }
1721
1722                debug_assert!(children.len() >= 2, "Should still have multiple kids!");
1723
1724                // Sort by spec order.
1725                children.sort_unstable_by_key(|c| c.sort_key());
1726
1727                // NOTE: if the function returns true, by the docs of dedup_by,
1728                // a is removed.
1729                children.dedup_by(|right, left| left.try_product_in_place(right));
1730
1731                if children.len() == 1 {
1732                    // If only one children remains, lift it up, and carry on.
1733                    replace_self_with!(&mut children[0]);
1734                } else {
1735                    // Else put our simplified children back.
1736                    *children_slot = children.into_boxed_slice().into();
1737                }
1738            },
1739            Self::Hypot(ref children) => {
1740                let mut result = value_or_stop!(children[0].try_op(&children[0], Mul::mul));
1741
1742                for child in children.iter().skip(1) {
1743                    let square = value_or_stop!(child.try_op(&child, Mul::mul));
1744                    result = value_or_stop!(result.try_op(&square, Add::add));
1745                }
1746
1747                result = value_or_stop!(result.try_op(&result, |a, _| a.sqrt()));
1748
1749                replace_self_with!(&mut result);
1750            },
1751            Self::Abs(ref mut child) => {
1752                if let CalcNode::Leaf(leaf) = child.as_mut() {
1753                    value_or_stop!(leaf.map(|v| v.abs()));
1754                    replace_self_with!(&mut **child);
1755                }
1756            },
1757            Self::Sign(ref mut child) => {
1758                if let CalcNode::Leaf(leaf) = child.as_mut() {
1759                    let mut result = Self::Leaf(value_or_stop!(L::sign_from(leaf)));
1760                    replace_self_with!(&mut result);
1761                }
1762            },
1763            Self::Negate(ref mut child) => {
1764                // Step 6.
1765                match &mut **child {
1766                    CalcNode::Leaf(_) => {
1767                        // 1. If root’s child is a numeric value, return an equivalent numeric value, but
1768                        // with the value negated (0 - value).
1769                        child.negate();
1770                        replace_self_with!(&mut **child);
1771                    },
1772                    CalcNode::Negate(value) => {
1773                        // 2. If root’s child is a Negate node, return the child’s child.
1774                        replace_self_with!(&mut **value);
1775                    },
1776                    _ => {
1777                        // 3. Return root.
1778                    },
1779                }
1780            },
1781            Self::Invert(ref mut child) => {
1782                // Step 7.
1783                match &mut **child {
1784                    CalcNode::Leaf(leaf) => {
1785                        // 1. If root’s child is a number (not a percentage or dimension) return the
1786                        // reciprocal of the child’s value.
1787                        if leaf.unit().is_empty() {
1788                            value_or_stop!(child.map(|v| 1.0 / v));
1789                            replace_self_with!(&mut **child);
1790                        }
1791                    },
1792                    CalcNode::Invert(value) => {
1793                        // 2. If root’s child is an Invert node, return the child’s child.
1794                        replace_self_with!(&mut **value);
1795                    },
1796                    _ => {
1797                        // 3. Return root.
1798                    },
1799                }
1800            },
1801            Self::Leaf(ref mut l) => {
1802                l.simplify();
1803            },
1804            Self::Anchor(ref mut f) => {
1805                if let GenericAnchorSide::Percentage(ref mut n) = f.side {
1806                    n.simplify_and_sort();
1807                }
1808                if let Some(fallback) = f.fallback.as_mut() {
1809                    fallback.node.simplify_and_sort();
1810                }
1811            },
1812            Self::AnchorSize(ref mut f) => {
1813                if let Some(fallback) = f.fallback.as_mut() {
1814                    fallback.node.simplify_and_sort();
1815                }
1816            },
1817        }
1818    }
1819
1820    /// Simplifies and sorts the kids in the whole calculation subtree.
1821    pub fn simplify_and_sort(&mut self) {
1822        self.visit_depth_first(|node| node.simplify_and_sort_direct_children())
1823    }
1824
1825    fn to_css_impl<W>(&self, dest: &mut CssWriter<W>, level: ArgumentLevel) -> fmt::Result
1826    where
1827        W: Write,
1828    {
1829        let write_closing_paren = match *self {
1830            Self::MinMax(_, op) => {
1831                dest.write_str(match op {
1832                    MinMaxOp::Max => "max(",
1833                    MinMaxOp::Min => "min(",
1834                })?;
1835                true
1836            },
1837            Self::Clamp { .. } => {
1838                dest.write_str("clamp(")?;
1839                true
1840            },
1841            Self::Round { strategy, .. } => {
1842                match strategy {
1843                    RoundingStrategy::Nearest => dest.write_str("round("),
1844                    RoundingStrategy::Up => dest.write_str("round(up, "),
1845                    RoundingStrategy::Down => dest.write_str("round(down, "),
1846                    RoundingStrategy::ToZero => dest.write_str("round(to-zero, "),
1847                }?;
1848
1849                true
1850            },
1851            Self::ModRem { op, .. } => {
1852                dest.write_str(match op {
1853                    ModRemOp::Mod => "mod(",
1854                    ModRemOp::Rem => "rem(",
1855                })?;
1856
1857                true
1858            },
1859            Self::Hypot(_) => {
1860                dest.write_str("hypot(")?;
1861                true
1862            },
1863            Self::Abs(_) => {
1864                dest.write_str("abs(")?;
1865                true
1866            },
1867            Self::Sign(_) => {
1868                dest.write_str("sign(")?;
1869                true
1870            },
1871            Self::Negate(_) => {
1872                // We never generate a [`Negate`] node as the root of a calculation, only inside
1873                // [`Sum`] nodes as a child. Because negate nodes are handled by the [`Sum`] node
1874                // directly (see below), this node will never be serialized.
1875                debug_assert!(
1876                    false,
1877                    "We never serialize Negate nodes as they are handled inside Sum nodes."
1878                );
1879                dest.write_str("(-1 * ")?;
1880                true
1881            },
1882            Self::Invert(_) => {
1883                if matches!(level, ArgumentLevel::CalculationRoot) {
1884                    dest.write_str("calc")?;
1885                }
1886                dest.write_str("(1 / ")?;
1887                true
1888            },
1889            Self::Sum(_) | Self::Product(_) => match level {
1890                ArgumentLevel::CalculationRoot => {
1891                    dest.write_str("calc(")?;
1892                    true
1893                },
1894                ArgumentLevel::ArgumentRoot => false,
1895                ArgumentLevel::Nested => {
1896                    dest.write_str("(")?;
1897                    true
1898                },
1899            },
1900            Self::Leaf(_) => match level {
1901                ArgumentLevel::CalculationRoot => {
1902                    dest.write_str("calc(")?;
1903                    true
1904                },
1905                ArgumentLevel::ArgumentRoot | ArgumentLevel::Nested => false,
1906            },
1907            Self::Anchor(_) | Self::AnchorSize(_) => false,
1908        };
1909
1910        match *self {
1911            Self::MinMax(ref children, _) | Self::Hypot(ref children) => {
1912                let mut first = true;
1913                for child in &**children {
1914                    if !first {
1915                        dest.write_str(", ")?;
1916                    }
1917                    first = false;
1918                    child.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1919                }
1920            },
1921            Self::Negate(ref value) | Self::Invert(ref value) => {
1922                value.to_css_impl(dest, ArgumentLevel::Nested)?
1923            },
1924            Self::Sum(ref children) => {
1925                let mut first = true;
1926                for child in &**children {
1927                    if !first {
1928                        match child {
1929                            Self::Leaf(l) => {
1930                                if let Ok(true) = l.is_negative() {
1931                                    dest.write_str(" - ")?;
1932                                    let mut negated = l.clone();
1933                                    // We can unwrap here, because we already
1934                                    // checked if the value inside is negative.
1935                                    negated.map(std::ops::Neg::neg).unwrap();
1936                                    negated.to_css(dest)?;
1937                                } else {
1938                                    dest.write_str(" + ")?;
1939                                    l.to_css(dest)?;
1940                                }
1941                            },
1942                            Self::Negate(n) => {
1943                                dest.write_str(" - ")?;
1944                                n.to_css_impl(dest, ArgumentLevel::Nested)?;
1945                            },
1946                            _ => {
1947                                dest.write_str(" + ")?;
1948                                child.to_css_impl(dest, ArgumentLevel::Nested)?;
1949                            },
1950                        }
1951                    } else {
1952                        first = false;
1953                        child.to_css_impl(dest, ArgumentLevel::Nested)?;
1954                    }
1955                }
1956            },
1957            Self::Product(ref children) => {
1958                let mut first = true;
1959                for child in &**children {
1960                    if !first {
1961                        match child {
1962                            Self::Invert(n) => {
1963                                dest.write_str(" / ")?;
1964                                n.to_css_impl(dest, ArgumentLevel::Nested)?;
1965                            },
1966                            _ => {
1967                                dest.write_str(" * ")?;
1968                                child.to_css_impl(dest, ArgumentLevel::Nested)?;
1969                            },
1970                        }
1971                    } else {
1972                        first = false;
1973                        child.to_css_impl(dest, ArgumentLevel::Nested)?;
1974                    }
1975                }
1976            },
1977            Self::Clamp {
1978                ref min,
1979                ref center,
1980                ref max,
1981            } => {
1982                min.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1983                dest.write_str(", ")?;
1984                center.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1985                dest.write_str(", ")?;
1986                max.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1987            },
1988            Self::Round {
1989                ref value,
1990                ref step,
1991                ..
1992            } => {
1993                value.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1994                dest.write_str(", ")?;
1995                step.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1996            },
1997            Self::ModRem {
1998                ref dividend,
1999                ref divisor,
2000                ..
2001            } => {
2002                dividend.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2003                dest.write_str(", ")?;
2004                divisor.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2005            },
2006            Self::Abs(ref v) | Self::Sign(ref v) => {
2007                v.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?
2008            },
2009            Self::Leaf(ref l) => l.to_css(dest)?,
2010            Self::Anchor(ref f) => f.to_css(dest)?,
2011            Self::AnchorSize(ref f) => f.to_css(dest)?,
2012        }
2013
2014        if write_closing_paren {
2015            dest.write_char(')')?;
2016        }
2017        Ok(())
2018    }
2019
2020    fn to_typed_impl(
2021        &self,
2022        dest: &mut ThinVec<TypedValue>,
2023        level: ArgumentLevel,
2024    ) -> Result<(), ()> {
2025        // XXX Only supporting Sum and Leaf for now
2026        match *self {
2027            Self::Sum(ref children) => {
2028                let mut values = ThinVec::new();
2029                for child in &**children {
2030                    let nested = CalcNodeWithLevel {
2031                        node: child,
2032                        level: ArgumentLevel::Nested,
2033                    };
2034                    if let Some(TypedValue::Numeric(inner)) = nested.to_typed_value() {
2035                        values.push(inner);
2036                    }
2037                }
2038                dest.push(TypedValue::Numeric(NumericValue::Sum(MathSum { values })));
2039                Ok(())
2040            },
2041            Self::Leaf(ref l) => match l.to_typed_value() {
2042                Some(TypedValue::Numeric(inner)) => {
2043                    match level {
2044                        ArgumentLevel::CalculationRoot => {
2045                            dest.push(TypedValue::Numeric(NumericValue::Sum(MathSum {
2046                                values: ThinVec::from([inner]),
2047                            })));
2048                        },
2049                        ArgumentLevel::ArgumentRoot | ArgumentLevel::Nested => {
2050                            dest.push(TypedValue::Numeric(inner));
2051                        },
2052                    }
2053                    Ok(())
2054                },
2055                _ => Err(()),
2056            },
2057            _ => Err(()),
2058        }
2059    }
2060
2061    fn compare(
2062        &self,
2063        other: &Self,
2064        basis_positive: PositivePercentageBasis,
2065    ) -> Option<cmp::Ordering> {
2066        match (self, other) {
2067            (&CalcNode::Leaf(ref one), &CalcNode::Leaf(ref other)) => {
2068                one.compare(other, basis_positive)
2069            },
2070            _ => None,
2071        }
2072    }
2073
2074    compare_helpers!();
2075}
2076
2077impl<L: CalcNodeLeaf> ToCss for CalcNode<L> {
2078    /// <https://drafts.csswg.org/css-values/#calc-serialize>
2079    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
2080    where
2081        W: Write,
2082    {
2083        self.to_css_impl(dest, ArgumentLevel::CalculationRoot)
2084    }
2085}
2086
2087impl<L: CalcNodeLeaf> ToTyped for CalcNode<L> {
2088    fn to_typed(&self, dest: &mut ThinVec<TypedValue>) -> Result<(), ()> {
2089        self.to_typed_impl(dest, ArgumentLevel::CalculationRoot)
2090    }
2091}
2092
2093struct CalcNodeWithLevel<'a, L> {
2094    node: &'a CalcNode<L>,
2095    level: ArgumentLevel,
2096}
2097
2098impl<'a, L: CalcNodeLeaf> ToTyped for CalcNodeWithLevel<'a, L> {
2099    fn to_typed(&self, dest: &mut ThinVec<TypedValue>) -> Result<(), ()> {
2100        self.node.to_typed_impl(dest, self.level.clone())
2101    }
2102}
2103
2104#[cfg(test)]
2105mod tests {
2106    use super::*;
2107
2108    #[test]
2109    fn can_sum_with_checks() {
2110        assert!(CalcUnits::LENGTH.can_sum_with(CalcUnits::LENGTH));
2111        assert!(CalcUnits::LENGTH.can_sum_with(CalcUnits::PERCENTAGE));
2112        assert!(CalcUnits::LENGTH.can_sum_with(CalcUnits::LENGTH_PERCENTAGE));
2113
2114        assert!(CalcUnits::PERCENTAGE.can_sum_with(CalcUnits::LENGTH));
2115        assert!(CalcUnits::PERCENTAGE.can_sum_with(CalcUnits::PERCENTAGE));
2116        assert!(CalcUnits::PERCENTAGE.can_sum_with(CalcUnits::LENGTH_PERCENTAGE));
2117
2118        assert!(CalcUnits::LENGTH_PERCENTAGE.can_sum_with(CalcUnits::LENGTH));
2119        assert!(CalcUnits::LENGTH_PERCENTAGE.can_sum_with(CalcUnits::PERCENTAGE));
2120        assert!(CalcUnits::LENGTH_PERCENTAGE.can_sum_with(CalcUnits::LENGTH_PERCENTAGE));
2121
2122        assert!(!CalcUnits::ANGLE.can_sum_with(CalcUnits::TIME));
2123        assert!(CalcUnits::ANGLE.can_sum_with(CalcUnits::ANGLE));
2124
2125        assert!(!(CalcUnits::ANGLE | CalcUnits::TIME).can_sum_with(CalcUnits::ANGLE));
2126        assert!(!CalcUnits::ANGLE.can_sum_with(CalcUnits::ANGLE | CalcUnits::TIME));
2127        assert!(
2128            !(CalcUnits::ANGLE | CalcUnits::TIME).can_sum_with(CalcUnits::ANGLE | CalcUnits::TIME)
2129        );
2130    }
2131}