1use 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#[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,
40 Max,
42}
43
44#[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,
61 Rem,
63}
64
65impl ModRemOp {
66 fn apply(self, dividend: f32, divisor: f32) -> f32 {
67 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#[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 Nearest,
107 Up,
110 Down,
113 ToZero,
116}
117
118#[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, 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#[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 #[animation(constant)]
208 is_calc_node: bool,
209 pub node: GenericCalcNode<L>,
212}
213
214impl<L> GenericAnchorFunctionFallback<L> {
215 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
240pub type GenericCalcAnchorFunction<L> =
242 GenericAnchorFunction<Box<GenericCalcNode<L>>, Box<GenericAnchorFunctionFallback<L>>>;
243pub type GenericCalcAnchorSizeFunction<L> =
245 GenericAnchorSizeFunction<Box<GenericAnchorFunctionFallback<L>>>;
246
247#[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 Leaf(L),
273 Negate(Box<GenericCalcNode<L>>),
275 Invert(Box<GenericCalcNode<L>>),
278 Sum(crate::OwnedSlice<GenericCalcNode<L>>),
281 Product(crate::OwnedSlice<GenericCalcNode<L>>),
284 MinMax(crate::OwnedSlice<GenericCalcNode<L>>, MinMaxOp),
286 Clamp {
288 min: Box<GenericCalcNode<L>>,
290 center: Box<GenericCalcNode<L>>,
292 max: Box<GenericCalcNode<L>>,
294 },
295 Round {
297 strategy: RoundingStrategy,
299 value: Box<GenericCalcNode<L>>,
301 step: Box<GenericCalcNode<L>>,
303 },
304 ModRem {
306 dividend: Box<GenericCalcNode<L>>,
308 divisor: Box<GenericCalcNode<L>>,
310 op: ModRemOp,
312 },
313 Hypot(crate::OwnedSlice<GenericCalcNode<L>>),
315 Abs(Box<GenericCalcNode<L>>),
317 Sign(Box<GenericCalcNode<L>>),
319 Anchor(Box<GenericCalcAnchorFunction<L>>),
321 AnchorSize(Box<GenericCalcAnchorSizeFunction<L>>),
323}
324
325pub use self::GenericCalcNode as CalcNode;
326
327bitflags! {
328 #[derive(Clone, Copy, PartialEq, Eq)]
334 pub struct CalcUnits: u8 {
335 const LENGTH = 1 << 0;
337 const PERCENTAGE = 1 << 1;
339 const ANGLE = 1 << 2;
341 const TIME = 1 << 3;
343 const RESOLUTION = 1 << 4;
345 const COLOR_COMPONENT = 1 << 5;
347
348 const LENGTH_PERCENTAGE = Self::LENGTH.bits() | Self::PERCENTAGE.bits();
350 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 #[inline]
361 fn is_single_unit(&self) -> bool {
362 self.bits() == 0 || self.bits() & (self.bits() - 1) == 0
363 }
364
365 #[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
377pub enum PositivePercentageBasis {
380 Unknown,
382 Yes,
384}
385
386macro_rules! compare_helpers {
387 () => {
388 #[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 fn lt(&self, other: &Self, basis_positive: PositivePercentageBasis) -> bool {
396 self.compare(other, basis_positive) == Some(cmp::Ordering::Less)
397 }
398
399 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
411pub trait CalcNodeLeaf: Clone + Sized + PartialEq + ToCss + ToTyped {
413 fn unit(&self) -> CalcUnits;
415
416 fn unitless_value(&self) -> Option<f32>;
418
419 fn is_same_unit_as(&self, other: &Self) -> bool {
422 std::mem::discriminant(self) == std::mem::discriminant(other)
423 }
424
425 fn compare(
427 &self,
428 other: &Self,
429 base_is_positive: PositivePercentageBasis,
430 ) -> Option<cmp::Ordering>;
431 compare_helpers!();
432
433 fn new_number(value: f32) -> Self;
435
436 fn as_number(&self) -> Option<f32>;
438
439 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 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 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 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 fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()>;
469
470 fn try_product_in_place(&mut self, other: &mut Self) -> bool;
473
474 fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
476 where
477 O: Fn(f32, f32) -> f32;
478
479 fn map(&mut self, op: impl FnMut(f32) -> f32) -> Result<(), ()>;
481
482 fn simplify(&mut self);
484
485 fn sort_key(&self) -> SortKey;
487
488 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#[derive(Clone)]
508enum ArgumentLevel {
509 CalculationRoot,
511 ArgumentRoot,
514 Nested,
516}
517
518impl<L: CalcNodeLeaf> CalcNode<L> {
519 fn dummy() -> Self {
521 Self::MinMax(Default::default(), MinMaxOp::Max)
522 }
523
524 fn coerce_to_value(&mut self, value: f32) -> Result<(), ()> {
528 self.map(|_| value)
529 }
530
531 #[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 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 let mut unit = None;
564 for child in children.iter() {
565 let child_unit = child.unit()?;
566 if child_unit.is_empty() {
567 continue;
569 }
570
571 if unit.is_some() {
572 return Err(());
574 }
575
576 unit = Some(child_unit);
578 }
579 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 let _ = child.unit()?;
632 CalcUnits::empty()
633 },
634 CalcNode::Anchor(..) | CalcNode::AnchorSize(..) => CalcUnits::LENGTH_PERCENTAGE,
635 })
636 }
637
638 pub fn negate(&mut self) {
641 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 let result = mem::replace(value.as_mut(), Self::dummy());
656 *self = result;
657 },
658 CalcNode::Invert(_) => {
659 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 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 *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 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 pub fn as_leaf(&self) -> Option<&L> {
753 match *self {
754 Self::Leaf(ref l) => Some(l),
755 _ => None,
756 }
757 }
758
759 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 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 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 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 CalcNode::Anchor(_) | CalcNode::AnchorSize(_) => Err(()),
865 }
866 }
867
868 map_internal(self, &mut op)
869 }
870
871 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 pub fn resolve(&self) -> Result<L, ()> {
984 self.resolve_map(|l| Ok(l.clone()))
985 }
986
987 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 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 match result.as_number() {
1029 Some(left) => {
1030 result = right;
1032 result.map(|v| v * left)?;
1033 },
1034 None => {
1035 match right.as_number() {
1037 Some(right) => {
1038 result.map(|v| v * right)?;
1039 },
1040 None => {
1041 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 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(¢er) || !max.is_same_unit_as(¢er) {
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 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 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 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 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 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 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 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 let min_cmp_center = match min.compare(¢er, PositivePercentageBasis::Unknown) {
1420 Some(o) => o,
1421 None => return,
1422 };
1423
1424 if matches!(min_cmp_center, cmp::Ordering::Greater) {
1427 replace_self_with!(&mut **min);
1428 return;
1429 }
1430
1431 let max_cmp_center = match max.compare(¢er, PositivePercentageBasis::Unknown) {
1433 Some(o) => o,
1434 None => return,
1435 };
1436
1437 if matches!(max_cmp_center, cmp::Ordering::Less) {
1438 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 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 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 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 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 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 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 children.extend(kid_children.into_vec());
1666 }
1667 }
1668
1669 debug_assert!(children.len() >= 2, "Should still have multiple kids!");
1670
1671 children.sort_unstable_by_key(|c| c.sort_key());
1673
1674 children.dedup_by(|a, b| b.try_sum_in_place(a).is_ok());
1677
1678 if children.len() == 1 {
1679 replace_self_with!(&mut children[0]);
1681 } else {
1682 *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 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 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 children.extend(kid_children.into_vec());
1719 }
1720 }
1721
1722 debug_assert!(children.len() >= 2, "Should still have multiple kids!");
1723
1724 children.sort_unstable_by_key(|c| c.sort_key());
1726
1727 children.dedup_by(|right, left| left.try_product_in_place(right));
1730
1731 if children.len() == 1 {
1732 replace_self_with!(&mut children[0]);
1734 } else {
1735 *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 match &mut **child {
1766 CalcNode::Leaf(_) => {
1767 child.negate();
1770 replace_self_with!(&mut **child);
1771 },
1772 CalcNode::Negate(value) => {
1773 replace_self_with!(&mut **value);
1775 },
1776 _ => {
1777 },
1779 }
1780 },
1781 Self::Invert(ref mut child) => {
1782 match &mut **child {
1784 CalcNode::Leaf(leaf) => {
1785 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 replace_self_with!(&mut **value);
1795 },
1796 _ => {
1797 },
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 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 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 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 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 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}