1use crate::derives::*;
10use crate::typed_om::{MathSum, NumericValue, ToTyped, TypedValue};
11use crate::values::generics::length::GenericAnchorSizeFunction;
12use crate::values::generics::position::{GenericAnchorFunction, GenericAnchorSide};
13use crate::values::generics::Optional;
14use num_traits::Zero;
15use smallvec::SmallVec;
16use std::convert::AsRef;
17use std::fmt::{self, Write};
18use std::ops::{Add, Mul, Neg, Rem, Sub};
19use std::{cmp, mem};
20use strum_macros::AsRefStr;
21use style_traits::{CssWriter, ToCss};
22
23use thin_vec::ThinVec;
24
25#[derive(
27 Clone,
28 Copy,
29 Debug,
30 Deserialize,
31 MallocSizeOf,
32 PartialEq,
33 Serialize,
34 ToAnimatedZero,
35 ToResolvedValue,
36 ToShmem,
37)]
38#[repr(u8)]
39pub enum MinMaxOp {
40 Min,
42 Max,
44}
45
46#[derive(
48 Clone,
49 Copy,
50 Debug,
51 Deserialize,
52 MallocSizeOf,
53 PartialEq,
54 Serialize,
55 ToAnimatedZero,
56 ToResolvedValue,
57 ToShmem,
58)]
59#[repr(u8)]
60pub enum ModRemOp {
61 Mod,
63 Rem,
65}
66
67impl ModRemOp {
68 fn apply(self, dividend: f32, divisor: f32) -> f32 {
69 if matches!(self, Self::Mod)
73 && divisor.is_infinite()
74 && dividend.is_sign_negative() != divisor.is_sign_negative()
75 {
76 return f32::NAN;
77 }
78
79 let (r, same_sign_as) = match self {
80 Self::Mod => (dividend - divisor * (dividend / divisor).floor(), divisor),
81 Self::Rem => (dividend - divisor * (dividend / divisor).trunc(), dividend),
82 };
83 if r == 0.0 && same_sign_as.is_sign_negative() {
84 -0.0
85 } else {
86 r
87 }
88 }
89}
90
91#[derive(
93 Clone,
94 Copy,
95 Debug,
96 Deserialize,
97 MallocSizeOf,
98 PartialEq,
99 Serialize,
100 ToAnimatedZero,
101 ToResolvedValue,
102 ToShmem,
103)]
104#[repr(u8)]
105pub enum RoundingStrategy {
106 Nearest,
109 Up,
112 Down,
115 ToZero,
118}
119
120#[derive(
124 AsRefStr, Clone, Copy, Debug, Eq, Ord, Parse, PartialEq, PartialOrd, MallocSizeOf, ToShmem,
125)]
126#[strum(serialize_all = "lowercase")]
127#[allow(missing_docs)]
128pub enum SortKey {
129 #[strum(serialize = "")]
130 Number,
131 #[css(skip)]
132 #[strum(serialize = "%")]
133 Percentage,
134 Cap,
135 Ch,
136 Cqb,
137 Cqh,
138 Cqi,
139 Cqmax,
140 Cqmin,
141 Cqw,
142 Deg,
143 Dppx,
144 Dvb,
145 Dvh,
146 Dvi,
147 Dvmax,
148 Dvmin,
149 Dvw,
150 Em,
151 Ex,
152 Ic,
153 Lh,
154 Lvb,
155 Lvh,
156 Lvi,
157 Lvmax,
158 Lvmin,
159 Lvw,
160 Ms,
161 Px,
162 Rcap,
163 Rch,
164 Rem,
165 Rex,
166 Ric,
167 Rlh,
168 S, Svb,
170 Svh,
171 Svi,
172 Svmax,
173 Svmin,
174 Svw,
175 Vb,
176 Vh,
177 Vi,
178 Vmax,
179 Vmin,
180 Vw,
181 #[css(skip)]
182 ColorComponent,
183 #[css(skip)]
184 Other,
185}
186
187#[repr(C)]
196#[derive(
197 Clone,
198 Debug,
199 Deserialize,
200 MallocSizeOf,
201 PartialEq,
202 Serialize,
203 ToAnimatedZero,
204 ToResolvedValue,
205 ToShmem,
206)]
207pub struct GenericAnchorFunctionFallback<L> {
208 #[animation(constant)]
210 is_calc_node: bool,
211 pub node: GenericCalcNode<L>,
214}
215
216impl<L> GenericAnchorFunctionFallback<L> {
217 pub fn new(is_calc_node: bool, node: GenericCalcNode<L>) -> Self {
219 Self { is_calc_node, node }
220 }
221}
222
223impl<L: CalcNodeLeaf> ToCss for GenericAnchorFunctionFallback<L> {
224 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
225 where
226 W: Write,
227 {
228 self.node.to_css_impl(
229 dest,
230 if self.is_calc_node {
231 ArgumentLevel::CalculationRoot
232 } else {
233 ArgumentLevel::ArgumentRoot
234 },
235 )
236 }
237}
238
239pub type GenericCalcAnchorFunction<L> =
241 GenericAnchorFunction<Box<GenericCalcNode<L>>, Box<GenericAnchorFunctionFallback<L>>>;
242pub type GenericCalcAnchorSizeFunction<L> =
244 GenericAnchorSizeFunction<Box<GenericAnchorFunctionFallback<L>>>;
245
246#[repr(u8)]
258#[derive(
259 Clone,
260 Debug,
261 Deserialize,
262 MallocSizeOf,
263 PartialEq,
264 Serialize,
265 ToAnimatedZero,
266 ToResolvedValue,
267 ToShmem,
268)]
269pub enum GenericCalcNode<L> {
270 Leaf(L),
272 Negate(Box<Self>),
274 Invert(Box<Self>),
277 Sum(crate::OwnedSlice<Self>),
280 Product(crate::OwnedSlice<Self>),
283 MinMax(crate::OwnedSlice<Self>, MinMaxOp),
285 Clamp {
287 min: Box<Self>,
289 center: Box<Self>,
291 max: Box<Self>,
293 },
294 Round {
296 strategy: RoundingStrategy,
298 value: Box<Self>,
300 step: Box<Self>,
302 },
303 ModRem {
305 dividend: Box<Self>,
307 divisor: Box<Self>,
309 op: ModRemOp,
311 },
312 Sin(Box<Self>),
314 Cos(Box<Self>),
316 Tan(Box<Self>),
318 Asin(Box<Self>),
320 Acos(Box<Self>),
322 Atan(Box<Self>),
324 Atan2(Box<Self>, Box<Self>),
326 Pow(Box<Self>, Box<Self>),
328 Sqrt(Box<Self>),
330 Hypot(crate::OwnedSlice<Self>),
332 Log(Box<Self>, Optional<Box<Self>>),
334 Exp(Box<Self>),
336 Abs(Box<Self>),
338 Sign(Box<Self>),
340 Anchor(Box<GenericCalcAnchorFunction<L>>),
342 AnchorSize(Box<GenericCalcAnchorSizeFunction<L>>),
344}
345
346pub use self::GenericCalcNode as CalcNode;
347
348bitflags! {
349 #[derive(Clone, Copy, PartialEq, Eq)]
355 pub struct CalcUnits: u8 {
356 const LENGTH = 1 << 0;
358 const PERCENTAGE = 1 << 1;
360 const ANGLE = 1 << 2;
362 const TIME = 1 << 3;
364 const RESOLUTION = 1 << 4;
366 const LENGTH_PERCENTAGE = Self::LENGTH.bits() | Self::PERCENTAGE.bits();
368 const ALL = Self::LENGTH.bits() | Self::PERCENTAGE.bits() | Self::ANGLE.bits() |
371 Self::TIME.bits() | Self::RESOLUTION.bits();
372 }
373}
374
375impl CalcUnits {
376 #[inline]
379 fn is_single_unit(&self) -> bool {
380 self.bits() == 0 || self.bits() & (self.bits() - 1) == 0
381 }
382
383 #[inline]
385 fn can_sum_with(&self, other: Self) -> bool {
386 match *self {
387 Self::LENGTH => other.intersects(Self::LENGTH | Self::PERCENTAGE),
388 Self::PERCENTAGE => other.intersects(Self::LENGTH | Self::PERCENTAGE),
389 Self::LENGTH_PERCENTAGE => other.intersects(Self::LENGTH | Self::PERCENTAGE),
390 u => u.is_single_unit() && other == u,
391 }
392 }
393}
394
395pub enum PositivePercentageBasis {
398 Unknown,
400 Yes,
402}
403
404macro_rules! compare_helpers {
405 () => {
406 #[allow(unused)]
408 fn gt(&self, other: &Self, basis_positive: PositivePercentageBasis) -> bool {
409 self.compare(other, basis_positive) == Some(cmp::Ordering::Greater)
410 }
411
412 fn lt(&self, other: &Self, basis_positive: PositivePercentageBasis) -> bool {
414 self.compare(other, basis_positive) == Some(cmp::Ordering::Less)
415 }
416
417 fn lte(&self, other: &Self, basis_positive: PositivePercentageBasis) -> bool {
419 match self.compare(other, basis_positive) {
420 Some(cmp::Ordering::Less) => true,
421 Some(cmp::Ordering::Equal) => true,
422 Some(cmp::Ordering::Greater) => false,
423 None => false,
424 }
425 }
426 };
427}
428
429pub trait CalcNodeLeaf: Clone + Sized + PartialEq + ToCss + ToTyped {
431 fn unit(&self) -> CalcUnits;
433
434 fn unitless_value(&self) -> Option<f32>;
436
437 fn as_angle_radians(&self) -> Option<f32>;
439
440 fn new_angle_from_radians(radians: f32) -> Self;
442
443 fn is_same_unit_as(&self, other: &Self) -> bool {
446 std::mem::discriminant(self) == std::mem::discriminant(other)
447 }
448
449 fn compare(
451 &self,
452 other: &Self,
453 base_is_positive: PositivePercentageBasis,
454 ) -> Option<cmp::Ordering>;
455 compare_helpers!();
456
457 fn new_number(value: f32) -> Self;
459
460 fn as_number(&self) -> Option<f32>;
462
463 fn as_number_or_angle_radians(&self) -> Option<f32> {
465 self.as_number().or_else(|| self.as_angle_radians())
466 }
467
468 fn is_negative(&self) -> Result<bool, ()> {
470 self.unitless_value()
471 .map(|v| Ok(v.is_sign_negative()))
472 .unwrap_or_else(|| Err(()))
473 }
474
475 fn is_infinite(&self) -> Result<bool, ()> {
477 self.unitless_value()
478 .map(|v| Ok(v.is_infinite()))
479 .unwrap_or_else(|| Err(()))
480 }
481
482 fn is_zero(&self) -> Result<bool, ()> {
484 self.unitless_value()
485 .map(|v| Ok(v.is_zero()))
486 .unwrap_or_else(|| Err(()))
487 }
488
489 fn is_nan(&self) -> Result<bool, ()> {
491 self.unitless_value()
492 .map(|v| Ok(v.is_nan()))
493 .unwrap_or_else(|| Err(()))
494 }
495
496 fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()>;
498
499 fn try_product_in_place(&mut self, other: &mut Self) -> bool;
502
503 fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
505 where
506 O: Fn(f32, f32) -> f32;
507
508 fn map(&mut self, op: impl FnMut(f32) -> f32) -> Result<(), ()>;
510
511 fn simplify(&mut self);
513
514 fn sort_key(&self) -> SortKey;
516
517 fn sign_from(leaf: &impl CalcNodeLeaf) -> Result<Self, ()> {
519 let Some(value) = leaf.unitless_value() else {
520 return Err(());
521 };
522
523 Ok(Self::new_number(if value.is_nan() {
524 f32::NAN
525 } else if value.is_zero() {
526 value
527 } else if value.is_sign_negative() {
528 -1.0
529 } else {
530 1.0
531 }))
532 }
533}
534
535#[derive(Clone)]
537enum ArgumentLevel {
538 CalculationRoot,
540 ArgumentRoot,
543 Nested,
545}
546
547impl<L: CalcNodeLeaf> CalcNode<L> {
548 fn dummy() -> Self {
550 Self::MinMax(Default::default(), MinMaxOp::Max)
551 }
552
553 fn coerce_to_value(&mut self, value: f32) -> Result<(), ()> {
557 self.map(|_| value)
558 }
559
560 #[inline]
564 pub fn is_product_distributive(&self) -> bool {
565 match self {
566 Self::Leaf(l) => l.unitless_value().is_some(),
568 Self::Sum(children) => children.iter().all(|c| c.is_product_distributive()),
569 _ => false,
570 }
571 }
572
573 pub fn unit(&self) -> Result<CalcUnits, ()> {
575 Ok(match self {
576 CalcNode::Leaf(l) => l.unit(),
577 CalcNode::Negate(child) | CalcNode::Abs(child) => child.unit()?,
578 CalcNode::Sum(children) => {
579 let mut unit = children.first().unwrap().unit()?;
580 for child in children.iter().skip(1) {
581 let child_unit = child.unit()?;
582 if !child_unit.can_sum_with(unit) {
583 return Err(());
584 }
585 unit |= child_unit;
586 }
587 unit
588 },
589 CalcNode::Product(children) => {
590 let mut unit = None;
592 for child in children.iter() {
593 let child_unit = child.unit()?;
594 if child_unit.is_empty() {
595 continue;
597 }
598
599 if unit.is_some() {
600 return Err(());
602 }
603
604 unit = Some(child_unit);
606 }
607 unit.unwrap_or(CalcUnits::empty())
610 },
611 CalcNode::MinMax(children, _) | CalcNode::Hypot(children) => {
612 let mut unit = children.first().unwrap().unit()?;
613 for child in children.iter().skip(1) {
614 let child_unit = child.unit()?;
615 if !child_unit.can_sum_with(unit) {
616 return Err(());
617 }
618 unit |= child_unit;
619 }
620 unit
621 },
622 CalcNode::Clamp { min, center, max } => {
623 let min_unit = min.unit()?;
624 let center_unit = center.unit()?;
625
626 if !min_unit.can_sum_with(center_unit) {
627 return Err(());
628 }
629
630 let max_unit = max.unit()?;
631
632 if !center_unit.can_sum_with(max_unit) {
633 return Err(());
634 }
635
636 min_unit | center_unit | max_unit
637 },
638 CalcNode::Round { value, step, .. } => {
639 let value_unit = value.unit()?;
640 let step_unit = step.unit()?;
641 if !step_unit.can_sum_with(value_unit) {
642 return Err(());
643 }
644 value_unit | step_unit
645 },
646 CalcNode::ModRem {
647 dividend, divisor, ..
648 } => {
649 let dividend_unit = dividend.unit()?;
650 let divisor_unit = divisor.unit()?;
651 if !divisor_unit.can_sum_with(dividend_unit) {
652 return Err(());
653 }
654 dividend_unit | divisor_unit
655 },
656 CalcNode::Sign(ref child) => {
657 let _ = child.unit()?;
660 CalcUnits::empty()
661 },
662 CalcNode::Anchor(..) | CalcNode::AnchorSize(..) => CalcUnits::LENGTH_PERCENTAGE,
663 CalcNode::Sin(ref child) | CalcNode::Cos(ref child) | CalcNode::Tan(ref child) => {
664 let child_unit = child.unit()?;
665 if !child_unit.is_empty() && !child_unit.intersects(CalcUnits::ANGLE) {
666 return Err(());
667 }
668 CalcUnits::empty()
669 },
670 CalcNode::Asin(ref child) | CalcNode::Acos(ref child) | CalcNode::Atan(ref child) => {
671 let child_unit = child.unit()?;
672 if !child_unit.is_empty() {
673 return Err(());
674 }
675 CalcUnits::ANGLE
676 },
677 CalcNode::Atan2(ref a, ref b) => {
678 let a_unit = a.unit()?;
679 let b_unit = b.unit()?;
680 if !a_unit.can_sum_with(b_unit) {
681 return Err(());
682 }
683 CalcUnits::ANGLE
684 },
685 CalcNode::Pow(ref a, ref b) => {
686 let a_unit = a.unit()?;
687 let b_unit = b.unit()?;
688 if !a_unit.is_empty() || !b_unit.is_empty() {
689 return Err(());
690 }
691 CalcUnits::empty()
692 },
693 CalcNode::Invert(ref c) | CalcNode::Sqrt(ref c) | CalcNode::Exp(ref c) => {
694 let child_unit = c.unit()?;
695 if !child_unit.is_empty() {
696 return Err(());
697 }
698 CalcUnits::empty()
699 },
700 CalcNode::Log(ref a, ref b) => {
701 let a_unit = a.unit()?;
702 let b_unit = match b {
703 Optional::Some(b) => b.unit()?,
704 Optional::None => CalcUnits::empty(),
705 };
706 if !a_unit.is_empty() || !b_unit.is_empty() {
707 return Err(());
708 }
709 CalcUnits::empty()
710 },
711 })
712 }
713
714 pub fn negate(&mut self) {
717 fn wrap_self_in_negate<L: CalcNodeLeaf>(s: &mut CalcNode<L>) {
719 let result = mem::replace(s, CalcNode::dummy());
720 *s = CalcNode::Negate(Box::new(result));
721 }
722
723 match *self {
724 CalcNode::Leaf(ref mut leaf) => {
725 if leaf.map(std::ops::Neg::neg).is_err() {
726 wrap_self_in_negate(self)
727 }
728 },
729 CalcNode::Negate(ref mut value) => {
730 let result = mem::replace(value.as_mut(), Self::dummy());
732 *self = result;
733 },
734 CalcNode::Invert(_) => {
735 wrap_self_in_negate(self)
737 },
738 CalcNode::Sum(ref mut children) => {
739 for child in children.iter_mut() {
740 child.negate();
741 }
742 },
743 CalcNode::Product(_) => {
744 wrap_self_in_negate(self);
746 },
747 CalcNode::MinMax(ref mut children, ref mut op) => {
748 for child in children.iter_mut() {
749 child.negate();
750 }
751
752 *op = match *op {
754 MinMaxOp::Min => MinMaxOp::Max,
755 MinMaxOp::Max => MinMaxOp::Min,
756 };
757 },
758 CalcNode::Clamp {
759 ref mut min,
760 ref mut center,
761 ref mut max,
762 } => {
763 if min.lte(max, PositivePercentageBasis::Unknown) {
764 min.negate();
765 center.negate();
766 max.negate();
767
768 mem::swap(min, max);
769 } else {
770 wrap_self_in_negate(self);
771 }
772 },
773 CalcNode::Round {
774 ref mut strategy,
775 ref mut value,
776 ref mut step,
777 } => {
778 match *strategy {
779 RoundingStrategy::Nearest => {
780 wrap_self_in_negate(self);
785 return;
786 },
787 RoundingStrategy::Up => *strategy = RoundingStrategy::Down,
788 RoundingStrategy::Down => *strategy = RoundingStrategy::Up,
789 RoundingStrategy::ToZero => (),
790 }
791 value.negate();
792 step.negate();
793 },
794 CalcNode::ModRem {
795 ref mut dividend,
796 ref mut divisor,
797 ..
798 } => {
799 dividend.negate();
800 divisor.negate();
801 },
802 CalcNode::Hypot(ref mut children) => {
803 for child in children.iter_mut() {
804 child.negate();
805 }
806 },
807 CalcNode::Sign(ref mut child) => {
808 child.negate();
809 },
810 CalcNode::Sin(..)
811 | CalcNode::Cos(..)
812 | CalcNode::Tan(..)
813 | CalcNode::Asin(..)
814 | CalcNode::Acos(..)
815 | CalcNode::Atan(..)
816 | CalcNode::Atan2(..)
817 | CalcNode::Pow(..)
818 | CalcNode::Sqrt(..)
819 | CalcNode::Log(..)
820 | CalcNode::Exp(..)
821 | CalcNode::Abs(..)
822 | CalcNode::Anchor(..)
823 | CalcNode::AnchorSize(..) => {
824 wrap_self_in_negate(self);
825 },
826 }
827 }
828
829 fn sort_key(&self) -> SortKey {
830 match *self {
831 Self::Leaf(ref l) => l.sort_key(),
832 Self::Anchor(..) | Self::AnchorSize(..) => SortKey::Px,
833 _ => SortKey::Other,
834 }
835 }
836
837 pub fn as_leaf(&self) -> Option<&L> {
839 match *self {
840 Self::Leaf(ref l) => Some(l),
841 _ => None,
842 }
843 }
844
845 pub fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()> {
847 match (self, other) {
848 (&mut CalcNode::Leaf(ref mut one), &CalcNode::Leaf(ref other)) => {
849 one.try_sum_in_place(other)
850 },
851 _ => Err(()),
852 }
853 }
854
855 pub fn try_product_in_place(&mut self, other: &mut Self) -> bool {
857 if let Ok(resolved) = other.resolve() {
858 if let Some(number) = resolved.as_number() {
859 if number == 1.0 {
860 return true;
861 }
862
863 if self.is_product_distributive() {
864 if self.map(|v| v * number).is_err() {
865 return false;
866 }
867 return true;
868 }
869 }
870 }
871
872 if let Ok(resolved) = self.resolve() {
873 if let Some(number) = resolved.as_number() {
874 if number == 1.0 {
875 std::mem::swap(self, other);
876 return true;
877 }
878
879 if other.is_product_distributive() {
880 if other.map(|v| v * number).is_err() {
881 return false;
882 }
883 std::mem::swap(self, other);
884 return true;
885 }
886 }
887 }
888
889 false
890 }
891
892 fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
894 where
895 O: Fn(f32, f32) -> f32,
896 {
897 match (self, other) {
898 (&CalcNode::Leaf(ref one), &CalcNode::Leaf(ref other)) => {
899 Ok(CalcNode::Leaf(one.try_op(other, op)?))
900 },
901 _ => Err(()),
902 }
903 }
904
905 pub fn map(&mut self, mut op: impl FnMut(f32) -> f32) -> Result<(), ()> {
907 fn map_internal<L: CalcNodeLeaf>(
908 node: &mut CalcNode<L>,
909 op: &mut impl FnMut(f32) -> f32,
910 ) -> Result<(), ()> {
911 match node {
912 CalcNode::Leaf(l) => l.map(op),
913 CalcNode::Negate(v) | CalcNode::Invert(v) => map_internal(v, op),
914 CalcNode::Sum(children) | CalcNode::Product(children) => {
915 for node in &mut **children {
916 map_internal(node, op)?;
917 }
918 Ok(())
919 },
920 CalcNode::MinMax(children, _) => {
921 for node in &mut **children {
922 map_internal(node, op)?;
923 }
924 Ok(())
925 },
926 CalcNode::Clamp { min, center, max } => {
927 map_internal(min, op)?;
928 map_internal(center, op)?;
929 map_internal(max, op)
930 },
931 CalcNode::Round { value, step, .. } => {
932 map_internal(value, op)?;
933 map_internal(step, op)
934 },
935 CalcNode::ModRem {
936 dividend, divisor, ..
937 } => {
938 map_internal(dividend, op)?;
939 map_internal(divisor, op)
940 },
941 CalcNode::Hypot(children) => {
942 for node in &mut **children {
943 map_internal(node, op)?;
944 }
945 Ok(())
946 },
947 CalcNode::Abs(child) | CalcNode::Sign(child) => map_internal(child, op),
948 CalcNode::Anchor(_) | CalcNode::AnchorSize(_) => Err(()),
951 CalcNode::Sin(_)
954 | CalcNode::Cos(_)
955 | CalcNode::Tan(_)
956 | CalcNode::Asin(_)
957 | CalcNode::Acos(_)
958 | CalcNode::Atan(_)
959 | CalcNode::Atan2(..)
960 | CalcNode::Pow(..)
961 | CalcNode::Sqrt(_)
962 | CalcNode::Log(..)
963 | CalcNode::Exp(_) => Err(()),
964 }
965 }
966
967 map_internal(self, &mut op)
968 }
969
970 pub fn map_leaves<O, F>(&self, mut map: F) -> CalcNode<O>
972 where
973 O: CalcNodeLeaf,
974 F: FnMut(&L) -> O,
975 {
976 self.map_leaves_internal(&mut map)
977 }
978
979 fn map_leaves_internal<O, F>(&self, map: &mut F) -> CalcNode<O>
980 where
981 O: CalcNodeLeaf,
982 F: FnMut(&L) -> O,
983 {
984 fn map_children<L, O, F>(
985 children: &[CalcNode<L>],
986 map: &mut F,
987 ) -> crate::OwnedSlice<CalcNode<O>>
988 where
989 L: CalcNodeLeaf,
990 O: CalcNodeLeaf,
991 F: FnMut(&L) -> O,
992 {
993 children
994 .iter()
995 .map(|c| c.map_leaves_internal(map))
996 .collect()
997 }
998
999 match *self {
1000 Self::Leaf(ref l) => CalcNode::Leaf(map(l)),
1001 Self::Negate(ref c) => CalcNode::Negate(Box::new(c.map_leaves_internal(map))),
1002 Self::Invert(ref c) => CalcNode::Invert(Box::new(c.map_leaves_internal(map))),
1003 Self::Sum(ref c) => CalcNode::Sum(map_children(c, map)),
1004 Self::Product(ref c) => CalcNode::Product(map_children(c, map)),
1005 Self::MinMax(ref c, op) => CalcNode::MinMax(map_children(c, map), op),
1006 Self::Clamp {
1007 ref min,
1008 ref center,
1009 ref max,
1010 } => {
1011 let min = Box::new(min.map_leaves_internal(map));
1012 let center = Box::new(center.map_leaves_internal(map));
1013 let max = Box::new(max.map_leaves_internal(map));
1014 CalcNode::Clamp { min, center, max }
1015 },
1016 Self::Round {
1017 strategy,
1018 ref value,
1019 ref step,
1020 } => {
1021 let value = Box::new(value.map_leaves_internal(map));
1022 let step = Box::new(step.map_leaves_internal(map));
1023 CalcNode::Round {
1024 strategy,
1025 value,
1026 step,
1027 }
1028 },
1029 Self::ModRem {
1030 ref dividend,
1031 ref divisor,
1032 op,
1033 } => {
1034 let dividend = Box::new(dividend.map_leaves_internal(map));
1035 let divisor = Box::new(divisor.map_leaves_internal(map));
1036 CalcNode::ModRem {
1037 dividend,
1038 divisor,
1039 op,
1040 }
1041 },
1042 Self::Sin(ref c) => CalcNode::Sin(Box::new(c.map_leaves_internal(map))),
1043 Self::Cos(ref c) => CalcNode::Cos(Box::new(c.map_leaves_internal(map))),
1044 Self::Tan(ref c) => CalcNode::Tan(Box::new(c.map_leaves_internal(map))),
1045 Self::Asin(ref c) => CalcNode::Asin(Box::new(c.map_leaves_internal(map))),
1046 Self::Acos(ref c) => CalcNode::Acos(Box::new(c.map_leaves_internal(map))),
1047 Self::Atan(ref c) => CalcNode::Atan(Box::new(c.map_leaves_internal(map))),
1048 Self::Atan2(ref a, ref b) => CalcNode::Atan2(
1049 Box::new(a.map_leaves_internal(map)),
1050 Box::new(b.map_leaves_internal(map)),
1051 ),
1052 Self::Pow(ref a, ref b) => CalcNode::Pow(
1053 Box::new(a.map_leaves_internal(map)),
1054 Box::new(b.map_leaves_internal(map)),
1055 ),
1056 Self::Sqrt(ref c) => CalcNode::Sqrt(Box::new(c.map_leaves_internal(map))),
1057 Self::Hypot(ref c) => CalcNode::Hypot(map_children(c, map)),
1058 Self::Log(ref a, ref b) => CalcNode::Log(
1059 Box::new(a.map_leaves_internal(map)),
1060 b.as_ref()
1061 .map(|b| Box::new(b.map_leaves_internal(map)))
1062 .into(),
1063 ),
1064 Self::Exp(ref c) => CalcNode::Exp(Box::new(c.map_leaves_internal(map))),
1065 Self::Abs(ref c) => CalcNode::Abs(Box::new(c.map_leaves_internal(map))),
1066 Self::Sign(ref c) => CalcNode::Sign(Box::new(c.map_leaves_internal(map))),
1067 Self::Anchor(ref f) => CalcNode::Anchor(Box::new(GenericAnchorFunction {
1068 target_element: f.target_element.clone(),
1069 side: match &f.side {
1070 GenericAnchorSide::Keyword(k) => GenericAnchorSide::Keyword(*k),
1071 GenericAnchorSide::Percentage(p) => {
1072 GenericAnchorSide::Percentage(Box::new(p.map_leaves_internal(map)))
1073 },
1074 },
1075 fallback: f
1076 .fallback
1077 .as_ref()
1078 .map(|fb| {
1079 Box::new(GenericAnchorFunctionFallback::new(
1080 fb.is_calc_node,
1081 fb.node.map_leaves_internal(map),
1082 ))
1083 })
1084 .into(),
1085 })),
1086 Self::AnchorSize(ref f) => CalcNode::AnchorSize(Box::new(GenericAnchorSizeFunction {
1087 target_element: f.target_element.clone(),
1088 size: f.size,
1089 fallback: f
1090 .fallback
1091 .as_ref()
1092 .map(|fb| {
1093 Box::new(GenericAnchorFunctionFallback::new(
1094 fb.is_calc_node,
1095 fb.node.map_leaves_internal(map),
1096 ))
1097 })
1098 .into(),
1099 })),
1100 }
1101 }
1102
1103 pub fn resolve(&self) -> Result<L, ()> {
1105 self.resolve_map(|l| Ok(l.clone()))
1106 }
1107
1108 pub fn resolve_map<F>(&self, mut leaf_to_output_fn: F) -> Result<L, ()>
1110 where
1111 F: FnMut(&L) -> Result<L, ()>,
1112 {
1113 self.resolve_internal(&mut leaf_to_output_fn)
1114 }
1115
1116 fn resolve_internal<F>(&self, leaf_to_output_fn: &mut F) -> Result<L, ()>
1117 where
1118 F: FnMut(&L) -> Result<L, ()>,
1119 {
1120 match self {
1121 Self::Leaf(l) => leaf_to_output_fn(l),
1122 Self::Negate(child) => {
1123 let mut result = child.resolve_internal(leaf_to_output_fn)?;
1124 result.map(|v| v.neg())?;
1125 Ok(result)
1126 },
1127 Self::Invert(child) => {
1128 let mut result = child.resolve_internal(leaf_to_output_fn)?;
1129 result.map(|v| 1.0 / v)?;
1130 Ok(result)
1131 },
1132 Self::Sum(children) => {
1133 let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
1134
1135 for child in children.iter().skip(1) {
1136 let right = child.resolve_internal(leaf_to_output_fn)?;
1137 result = result.try_op(&right, |left, right| left + right)?;
1139 }
1140
1141 Ok(result)
1142 },
1143 Self::Product(children) => {
1144 let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
1145
1146 for child in children.iter().skip(1) {
1147 let right = child.resolve_internal(leaf_to_output_fn)?;
1148 match result.as_number() {
1150 Some(left) => {
1151 result = right;
1153 result.map(|v| v * left)?;
1154 },
1155 None => {
1156 match right.as_number() {
1158 Some(right) => {
1159 result.map(|v| v * right)?;
1160 },
1161 None => {
1162 return Err(());
1164 },
1165 }
1166 },
1167 }
1168 }
1169
1170 Ok(result)
1171 },
1172 Self::MinMax(children, op) => {
1173 let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
1174
1175 if result.is_nan()? {
1176 return Ok(result);
1177 }
1178
1179 for child in children.iter().skip(1) {
1180 let candidate = child.resolve_internal(leaf_to_output_fn)?;
1181
1182 if !result.is_same_unit_as(&candidate) {
1184 return Err(());
1185 }
1186
1187 if candidate.is_nan()? {
1188 result = candidate;
1189 break;
1190 }
1191
1192 let candidate_wins = match op {
1193 MinMaxOp::Min => candidate.lt(&result, PositivePercentageBasis::Yes),
1194 MinMaxOp::Max => candidate.gt(&result, PositivePercentageBasis::Yes),
1195 };
1196
1197 if candidate_wins {
1198 result = candidate;
1199 }
1200 }
1201
1202 Ok(result)
1203 },
1204 Self::Clamp { min, center, max } => {
1205 let min = min.resolve_internal(leaf_to_output_fn)?;
1206 let center = center.resolve_internal(leaf_to_output_fn)?;
1207 let max = max.resolve_internal(leaf_to_output_fn)?;
1208
1209 if !min.is_same_unit_as(¢er) || !max.is_same_unit_as(¢er) {
1210 return Err(());
1211 }
1212
1213 if min.is_nan()? {
1214 return Ok(min);
1215 }
1216
1217 if center.is_nan()? {
1218 return Ok(center);
1219 }
1220
1221 if max.is_nan()? {
1222 return Ok(max);
1223 }
1224
1225 let mut result = center;
1226 if result.gt(&max, PositivePercentageBasis::Yes) {
1227 result = max;
1228 }
1229 if result.lt(&min, PositivePercentageBasis::Yes) {
1230 result = min
1231 }
1232
1233 Ok(result)
1234 },
1235 Self::Round {
1236 strategy,
1237 value,
1238 step,
1239 } => {
1240 let mut value = value.resolve_internal(leaf_to_output_fn)?;
1241 let step = step.resolve_internal(leaf_to_output_fn)?;
1242
1243 if !value.is_same_unit_as(&step) {
1244 return Err(());
1245 }
1246
1247 let Some(step) = step.unitless_value() else {
1248 return Err(());
1249 };
1250 let step = step.abs();
1251
1252 value.map(|value| {
1253 if step.is_zero() {
1257 return f32::NAN;
1258 }
1259
1260 if value.is_infinite() {
1261 if step.is_infinite() {
1262 return f32::NAN;
1263 }
1264 return value;
1265 }
1266
1267 if step.is_infinite() {
1268 match strategy {
1269 RoundingStrategy::Nearest | RoundingStrategy::ToZero => {
1270 return if value.is_sign_negative() { -0.0 } else { 0.0 }
1271 },
1272 RoundingStrategy::Up => {
1273 return if !value.is_sign_negative() && !value.is_zero() {
1274 f32::INFINITY
1275 } else if !value.is_sign_negative() && value.is_zero() {
1276 value
1277 } else {
1278 -0.0
1279 }
1280 },
1281 RoundingStrategy::Down => {
1282 return if value.is_sign_negative() && !value.is_zero() {
1283 -f32::INFINITY
1284 } else if value.is_sign_negative() && value.is_zero() {
1285 value
1286 } else {
1287 0.0
1288 }
1289 },
1290 }
1291 }
1292
1293 let div = value / step;
1294 let lower_bound = div.floor() * step;
1295 let upper_bound = div.ceil() * step;
1296
1297 match strategy {
1298 RoundingStrategy::Nearest => {
1299 if value - lower_bound < upper_bound - value {
1301 lower_bound
1302 } else {
1303 upper_bound
1304 }
1305 },
1306 RoundingStrategy::Up => upper_bound,
1307 RoundingStrategy::Down => lower_bound,
1308 RoundingStrategy::ToZero => {
1309 if lower_bound.abs() < upper_bound.abs() {
1311 lower_bound
1312 } else {
1313 upper_bound
1314 }
1315 },
1316 }
1317 })?;
1318
1319 Ok(value)
1320 },
1321 Self::ModRem {
1322 dividend,
1323 divisor,
1324 op,
1325 } => {
1326 let mut dividend = dividend.resolve_internal(leaf_to_output_fn)?;
1327 let divisor = divisor.resolve_internal(leaf_to_output_fn)?;
1328
1329 if !dividend.is_same_unit_as(&divisor) {
1330 return Err(());
1331 }
1332
1333 let Some(divisor) = divisor.unitless_value() else {
1334 return Err(());
1335 };
1336 dividend.map(|dividend| op.apply(dividend, divisor))?;
1337 Ok(dividend)
1338 },
1339 Self::Sin(ref c) => {
1340 let result = c.resolve_internal(leaf_to_output_fn)?;
1341 let radians = result.as_number_or_angle_radians().ok_or(())?;
1342 Ok(L::new_number(radians.sin()))
1343 },
1344 Self::Cos(ref c) => {
1345 let result = c.resolve_internal(leaf_to_output_fn)?;
1346 let radians = result.as_number_or_angle_radians().ok_or(())?;
1347 Ok(L::new_number(radians.cos()))
1348 },
1349 Self::Tan(ref c) => {
1350 let result = c.resolve_internal(leaf_to_output_fn)?;
1351 let radians = result.as_number_or_angle_radians().ok_or(())?;
1352 Ok(L::new_number(radians.tan()))
1353 },
1354 Self::Asin(ref c) => {
1355 let result = c.resolve_internal(leaf_to_output_fn)?;
1356 let value = result.as_number().ok_or(())?;
1357 Ok(L::new_angle_from_radians(value.asin()))
1358 },
1359 Self::Acos(ref c) => {
1360 let result = c.resolve_internal(leaf_to_output_fn)?;
1361 let value = result.as_number().ok_or(())?;
1362 Ok(L::new_angle_from_radians(value.acos()))
1363 },
1364 Self::Atan(ref c) => {
1365 let result = c.resolve_internal(leaf_to_output_fn)?;
1366 let value = result.as_number().ok_or(())?;
1367 Ok(L::new_angle_from_radians(value.atan()))
1368 },
1369 Self::Atan2(ref a, ref b) => {
1370 let a = a.resolve_internal(leaf_to_output_fn)?;
1371 let b = b.resolve_internal(leaf_to_output_fn)?;
1372 if !a.is_same_unit_as(&b) {
1373 return Err(());
1374 }
1375 let a_val = a.unitless_value().ok_or(())?;
1376 let b_val = b.unitless_value().ok_or(())?;
1377 Ok(L::new_angle_from_radians(a_val.atan2(b_val)))
1378 },
1379 Self::Pow(ref a, ref b) => {
1380 let a = a.resolve_internal(leaf_to_output_fn)?;
1381 let b = b.resolve_internal(leaf_to_output_fn)?;
1382 let a_val = a.as_number().ok_or(())?;
1383 let b_val = b.as_number().ok_or(())?;
1384 Ok(L::new_number(a_val.powf(b_val)))
1385 },
1386 Self::Sqrt(ref c) => {
1387 let result = c.resolve_internal(leaf_to_output_fn)?;
1388 let value = result.as_number().ok_or(())?;
1389 Ok(L::new_number(value.sqrt()))
1390 },
1391 Self::Hypot(children) => {
1392 let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
1393 result.map(|v| v.powi(2))?;
1394
1395 for child in children.iter().skip(1) {
1396 let child_value = child.resolve_internal(leaf_to_output_fn)?;
1397
1398 if !result.is_same_unit_as(&child_value) {
1399 return Err(());
1400 }
1401
1402 let Some(child_value) = child_value.unitless_value() else {
1403 return Err(());
1404 };
1405 result.map(|v| v + child_value.powi(2))?;
1406 }
1407
1408 result.map(|v| v.sqrt())?;
1409 Ok(result)
1410 },
1411 Self::Log(ref a, ref b) => {
1412 let a = a.resolve_internal(leaf_to_output_fn)?;
1413 let a_val = a.as_number().ok_or(())?;
1414 let result = match b {
1415 Optional::Some(ref b) => {
1416 let b = b.resolve_internal(leaf_to_output_fn)?;
1417 let b_val = b.as_number().ok_or(())?;
1418 a_val.log(b_val)
1419 },
1420 Optional::None => a_val.ln(),
1421 };
1422 Ok(L::new_number(result))
1423 },
1424 Self::Exp(ref c) => {
1425 let result = c.resolve_internal(leaf_to_output_fn)?;
1426 let value = result.as_number().ok_or(())?;
1427 Ok(L::new_number(value.exp()))
1428 },
1429 Self::Abs(ref c) => {
1430 let mut result = c.resolve_internal(leaf_to_output_fn)?;
1431
1432 result.map(|v| v.abs())?;
1433
1434 Ok(result)
1435 },
1436 Self::Sign(ref c) => {
1437 let result = c.resolve_internal(leaf_to_output_fn)?;
1438 Ok(L::sign_from(&result)?)
1439 },
1440 Self::Anchor(_) | Self::AnchorSize(_) => Err(()),
1441 }
1442 }
1443
1444 pub fn map_node<F>(&mut self, mut mapping_fn: F) -> Result<(), ()>
1446 where
1447 F: FnMut(&CalcNode<L>) -> Result<Option<CalcNode<L>>, ()>,
1448 {
1449 self.map_node_internal(&mut mapping_fn)
1450 }
1451
1452 fn map_node_internal<F>(&mut self, mapping_fn: &mut F) -> Result<(), ()>
1453 where
1454 F: FnMut(&CalcNode<L>) -> Result<Option<CalcNode<L>>, ()>,
1455 {
1456 if let Some(node) = mapping_fn(self)? {
1457 *self = node;
1458 return Ok(());
1460 }
1461 match self {
1462 Self::Leaf(_) | Self::Anchor(_) | Self::AnchorSize(_) => (),
1463 Self::Negate(child)
1464 | Self::Invert(child)
1465 | Self::Abs(child)
1466 | Self::Sign(child)
1467 | Self::Sin(child)
1468 | Self::Cos(child)
1469 | Self::Tan(child)
1470 | Self::Asin(child)
1471 | Self::Acos(child)
1472 | Self::Atan(child)
1473 | Self::Sqrt(child)
1474 | Self::Exp(child) => {
1475 child.map_node_internal(mapping_fn)?;
1476 },
1477 Self::Atan2(a, b) => {
1478 a.map_node_internal(mapping_fn)?;
1479 b.map_node_internal(mapping_fn)?;
1480 },
1481 Self::Pow(a, b) => {
1482 a.map_node_internal(mapping_fn)?;
1483 b.map_node_internal(mapping_fn)?;
1484 },
1485 Self::Log(a, b) => {
1486 a.map_node_internal(mapping_fn)?;
1487 if let Optional::Some(b) = b {
1488 b.map_node_internal(mapping_fn)?;
1489 }
1490 },
1491 Self::Sum(children)
1492 | Self::Product(children)
1493 | Self::Hypot(children)
1494 | Self::MinMax(children, _) => {
1495 for child in children.iter_mut() {
1496 child.map_node_internal(mapping_fn)?;
1497 }
1498 },
1499 Self::Clamp { min, center, max } => {
1500 min.map_node_internal(mapping_fn)?;
1501 center.map_node_internal(mapping_fn)?;
1502 max.map_node_internal(mapping_fn)?;
1503 },
1504 Self::Round { value, step, .. } => {
1505 value.map_node_internal(mapping_fn)?;
1506 step.map_node_internal(mapping_fn)?;
1507 },
1508 Self::ModRem {
1509 dividend, divisor, ..
1510 } => {
1511 dividend.map_node_internal(mapping_fn)?;
1512 divisor.map_node_internal(mapping_fn)?;
1513 },
1514 };
1515 Ok(())
1516 }
1517
1518 fn is_negative_leaf(&self) -> Result<bool, ()> {
1519 Ok(match *self {
1520 Self::Leaf(ref l) => l.is_negative()?,
1521 _ => false,
1522 })
1523 }
1524
1525 fn is_zero_leaf(&self) -> Result<bool, ()> {
1526 Ok(match *self {
1527 Self::Leaf(ref l) => l.is_zero()?,
1528 _ => false,
1529 })
1530 }
1531
1532 fn is_infinite_leaf(&self) -> Result<bool, ()> {
1533 Ok(match *self {
1534 Self::Leaf(ref l) => l.is_infinite()?,
1535 _ => false,
1536 })
1537 }
1538
1539 fn is_nan_leaf(&self) -> Result<bool, ()> {
1540 Ok(match *self {
1541 Self::Leaf(ref l) => l.is_nan()?,
1542 _ => false,
1543 })
1544 }
1545
1546 pub fn visit_depth_first(&mut self, mut f: impl FnMut(&mut Self)) {
1552 self.visit_depth_first_internal(&mut f)
1553 }
1554
1555 fn visit_depth_first_internal(&mut self, f: &mut impl FnMut(&mut Self)) {
1556 match *self {
1557 Self::Clamp {
1558 ref mut min,
1559 ref mut center,
1560 ref mut max,
1561 } => {
1562 min.visit_depth_first_internal(f);
1563 center.visit_depth_first_internal(f);
1564 max.visit_depth_first_internal(f);
1565 },
1566 Self::Round {
1567 ref mut value,
1568 ref mut step,
1569 ..
1570 } => {
1571 value.visit_depth_first_internal(f);
1572 step.visit_depth_first_internal(f);
1573 },
1574 Self::ModRem {
1575 ref mut dividend,
1576 ref mut divisor,
1577 ..
1578 } => {
1579 dividend.visit_depth_first_internal(f);
1580 divisor.visit_depth_first_internal(f);
1581 },
1582 Self::Sum(ref mut children)
1583 | Self::Product(ref mut children)
1584 | Self::MinMax(ref mut children, _)
1585 | Self::Hypot(ref mut children) => {
1586 for child in &mut **children {
1587 child.visit_depth_first_internal(f);
1588 }
1589 },
1590 Self::Negate(ref mut value) | Self::Invert(ref mut value) => {
1591 value.visit_depth_first_internal(f);
1592 },
1593 Self::Sin(ref mut value)
1594 | Self::Cos(ref mut value)
1595 | Self::Tan(ref mut value)
1596 | Self::Asin(ref mut value)
1597 | Self::Acos(ref mut value)
1598 | Self::Atan(ref mut value)
1599 | Self::Sqrt(ref mut value)
1600 | Self::Exp(ref mut value) => {
1601 value.visit_depth_first_internal(f);
1602 },
1603 Self::Atan2(ref mut a, ref mut b) => {
1604 a.visit_depth_first_internal(f);
1605 b.visit_depth_first_internal(f);
1606 },
1607 Self::Pow(ref mut a, ref mut b) => {
1608 a.visit_depth_first_internal(f);
1609 b.visit_depth_first_internal(f);
1610 },
1611 Self::Log(ref mut a, ref mut b) => {
1612 a.visit_depth_first_internal(f);
1613 if let Optional::Some(b) = b {
1614 b.visit_depth_first_internal(f);
1615 }
1616 },
1617 Self::Abs(ref mut value) | Self::Sign(ref mut value) => {
1618 value.visit_depth_first_internal(f);
1619 },
1620 Self::Leaf(..) | Self::Anchor(..) | Self::AnchorSize(..) => {},
1621 }
1622 f(self);
1623 }
1624
1625 pub fn simplify_and_sort_direct_children(&mut self) {
1636 macro_rules! replace_self_with {
1637 ($slot:expr) => {{
1638 let result = mem::replace($slot, Self::dummy());
1639 *self = result;
1640 }};
1641 }
1642
1643 macro_rules! value_or_stop {
1644 ($op:expr) => {{
1645 match $op {
1646 Ok(value) => value,
1647 Err(_) => return,
1648 }
1649 }};
1650 }
1651
1652 match *self {
1653 Self::Clamp {
1654 ref mut min,
1655 ref mut center,
1656 ref mut max,
1657 } => {
1658 let min_cmp_center = match min.compare(¢er, PositivePercentageBasis::Unknown) {
1660 Some(o) => o,
1661 None => return,
1662 };
1663
1664 if matches!(min_cmp_center, cmp::Ordering::Greater) {
1667 replace_self_with!(&mut **min);
1668 return;
1669 }
1670
1671 let max_cmp_center = match max.compare(¢er, PositivePercentageBasis::Unknown) {
1673 Some(o) => o,
1674 None => return,
1675 };
1676
1677 if matches!(max_cmp_center, cmp::Ordering::Less) {
1678 let max_cmp_min = match max.compare(&min, PositivePercentageBasis::Unknown) {
1681 Some(o) => o,
1682 None => return,
1683 };
1684
1685 if matches!(max_cmp_min, cmp::Ordering::Less) {
1686 replace_self_with!(&mut **min);
1687 return;
1688 }
1689
1690 replace_self_with!(&mut **max);
1691 return;
1692 }
1693
1694 replace_self_with!(&mut **center);
1696 },
1697 Self::Round {
1698 strategy,
1699 ref mut value,
1700 ref mut step,
1701 } => {
1702 if value_or_stop!(step.is_zero_leaf()) {
1703 value_or_stop!(value.coerce_to_value(f32::NAN));
1704 replace_self_with!(&mut **value);
1705 return;
1706 }
1707
1708 if value_or_stop!(value.is_infinite_leaf())
1709 && value_or_stop!(step.is_infinite_leaf())
1710 {
1711 value_or_stop!(value.coerce_to_value(f32::NAN));
1712 replace_self_with!(&mut **value);
1713 return;
1714 }
1715
1716 if value_or_stop!(value.is_infinite_leaf()) {
1717 replace_self_with!(&mut **value);
1718 return;
1719 }
1720
1721 if value_or_stop!(step.is_infinite_leaf()) {
1722 match strategy {
1723 RoundingStrategy::Nearest | RoundingStrategy::ToZero => {
1724 value_or_stop!(value.coerce_to_value(0.0));
1725 replace_self_with!(&mut **value);
1726 return;
1727 },
1728 RoundingStrategy::Up => {
1729 if !value_or_stop!(value.is_negative_leaf())
1730 && !value_or_stop!(value.is_zero_leaf())
1731 {
1732 value_or_stop!(value.coerce_to_value(f32::INFINITY));
1733 replace_self_with!(&mut **value);
1734 return;
1735 } else if !value_or_stop!(value.is_negative_leaf())
1736 && value_or_stop!(value.is_zero_leaf())
1737 {
1738 replace_self_with!(&mut **value);
1739 return;
1740 } else {
1741 value_or_stop!(value.coerce_to_value(0.0));
1742 replace_self_with!(&mut **value);
1743 return;
1744 }
1745 },
1746 RoundingStrategy::Down => {
1747 if value_or_stop!(value.is_negative_leaf())
1748 && !value_or_stop!(value.is_zero_leaf())
1749 {
1750 value_or_stop!(value.coerce_to_value(-f32::INFINITY));
1751 replace_self_with!(&mut **value);
1752 return;
1753 } else if value_or_stop!(value.is_negative_leaf())
1754 && value_or_stop!(value.is_zero_leaf())
1755 {
1756 replace_self_with!(&mut **value);
1757 return;
1758 } else {
1759 value_or_stop!(value.coerce_to_value(0.0));
1760 replace_self_with!(&mut **value);
1761 return;
1762 }
1763 },
1764 }
1765 }
1766
1767 if value_or_stop!(step.is_negative_leaf()) {
1768 step.negate();
1769 }
1770
1771 let remainder = value_or_stop!(value.try_op(step, Rem::rem));
1772 if value_or_stop!(remainder.is_zero_leaf()) {
1773 replace_self_with!(&mut **value);
1774 return;
1775 }
1776
1777 let (mut lower_bound, mut upper_bound) = if value_or_stop!(value.is_negative_leaf())
1778 {
1779 let upper_bound = value_or_stop!(value.try_op(&remainder, Sub::sub));
1780 let lower_bound = value_or_stop!(upper_bound.try_op(&step, Sub::sub));
1781
1782 (lower_bound, upper_bound)
1783 } else {
1784 let lower_bound = value_or_stop!(value.try_op(&remainder, Sub::sub));
1785 let upper_bound = value_or_stop!(lower_bound.try_op(&step, Add::add));
1786
1787 (lower_bound, upper_bound)
1788 };
1789
1790 match strategy {
1791 RoundingStrategy::Nearest => {
1792 let lower_diff = value_or_stop!(value.try_op(&lower_bound, Sub::sub));
1793 let upper_diff = value_or_stop!(upper_bound.try_op(value, Sub::sub));
1794 if lower_diff.lt(&upper_diff, PositivePercentageBasis::Unknown) {
1796 replace_self_with!(&mut lower_bound);
1797 } else {
1798 replace_self_with!(&mut upper_bound);
1799 }
1800 },
1801 RoundingStrategy::Up => {
1802 replace_self_with!(&mut upper_bound);
1803 },
1804 RoundingStrategy::Down => {
1805 replace_self_with!(&mut lower_bound);
1806 },
1807 RoundingStrategy::ToZero => {
1808 let mut lower_diff = lower_bound.clone();
1809 let mut upper_diff = upper_bound.clone();
1810
1811 if value_or_stop!(lower_diff.is_negative_leaf()) {
1812 lower_diff.negate();
1813 }
1814
1815 if value_or_stop!(upper_diff.is_negative_leaf()) {
1816 upper_diff.negate();
1817 }
1818
1819 if lower_diff.lt(&upper_diff, PositivePercentageBasis::Unknown) {
1821 replace_self_with!(&mut lower_bound);
1822 } else {
1823 replace_self_with!(&mut upper_bound);
1824 }
1825 },
1826 };
1827 },
1828 Self::ModRem {
1829 ref dividend,
1830 ref divisor,
1831 op,
1832 } => {
1833 let mut result = value_or_stop!(dividend.try_op(divisor, |a, b| op.apply(a, b)));
1834 replace_self_with!(&mut result);
1835 },
1836 Self::MinMax(ref mut children, op) => {
1837 let winning_order = match op {
1838 MinMaxOp::Min => cmp::Ordering::Less,
1839 MinMaxOp::Max => cmp::Ordering::Greater,
1840 };
1841
1842 if value_or_stop!(children[0].is_nan_leaf()) {
1843 replace_self_with!(&mut children[0]);
1844 return;
1845 }
1846
1847 let mut result = 0;
1848 for i in 1..children.len() {
1849 if value_or_stop!(children[i].is_nan_leaf()) {
1850 replace_self_with!(&mut children[i]);
1851 return;
1852 }
1853 let o = match children[i]
1854 .compare(&children[result], PositivePercentageBasis::Unknown)
1855 {
1856 None => return,
1863 Some(o) => o,
1864 };
1865
1866 if o == winning_order {
1867 result = i;
1868 }
1869 }
1870
1871 replace_self_with!(&mut children[result]);
1872 },
1873 Self::Sum(ref mut children_slot) => {
1874 let mut sums_to_merge = SmallVec::<[_; 3]>::new();
1875 let mut extra_kids = 0;
1876 for (i, child) in children_slot.iter().enumerate() {
1877 if let Self::Sum(ref children) = *child {
1878 extra_kids += children.len();
1879 sums_to_merge.push(i);
1880 }
1881 }
1882
1883 if children_slot.len() == 1 {
1887 replace_self_with!(&mut children_slot[0]);
1888 return;
1889 }
1890
1891 let mut children = mem::take(children_slot).into_vec();
1892
1893 if !sums_to_merge.is_empty() {
1894 children.reserve(extra_kids - sums_to_merge.len());
1895 for i in sums_to_merge.drain(..).rev() {
1898 let kid_children = match children.swap_remove(i) {
1899 Self::Sum(c) => c,
1900 _ => unreachable!(),
1901 };
1902
1903 children.extend(kid_children.into_vec());
1906 }
1907 }
1908
1909 debug_assert!(children.len() >= 2, "Should still have multiple kids!");
1910
1911 children.sort_unstable_by_key(|c| c.sort_key());
1913
1914 children.dedup_by(|a, b| b.try_sum_in_place(a).is_ok());
1917
1918 if children.len() == 1 {
1919 replace_self_with!(&mut children[0]);
1921 } else {
1922 *children_slot = children.into_boxed_slice().into();
1924 }
1925 },
1926 Self::Product(ref mut children_slot) => {
1927 let mut products_to_merge = SmallVec::<[_; 3]>::new();
1928 let mut extra_kids = 0;
1929 for (i, child) in children_slot.iter().enumerate() {
1930 if let Self::Product(ref children) = *child {
1931 extra_kids += children.len();
1932 products_to_merge.push(i);
1933 }
1934 }
1935
1936 if children_slot.len() == 1 {
1940 replace_self_with!(&mut children_slot[0]);
1941 return;
1942 }
1943
1944 let mut children = mem::take(children_slot).into_vec();
1945
1946 if !products_to_merge.is_empty() {
1947 children.reserve(extra_kids - products_to_merge.len());
1948 for i in products_to_merge.drain(..).rev() {
1951 let kid_children = match children.swap_remove(i) {
1952 Self::Product(c) => c,
1953 _ => unreachable!(),
1954 };
1955
1956 children.extend(kid_children.into_vec());
1959 }
1960 }
1961
1962 debug_assert!(children.len() >= 2, "Should still have multiple kids!");
1963
1964 children.sort_unstable_by_key(|c| c.sort_key());
1966
1967 children.dedup_by(|right, left| left.try_product_in_place(right));
1970
1971 if children.len() == 1 {
1972 replace_self_with!(&mut children[0]);
1974 } else {
1975 *children_slot = children.into_boxed_slice().into();
1977 }
1978 },
1979 Self::Sin(ref mut child) => {
1980 if let CalcNode::Leaf(ref leaf) = **child {
1981 if let Some(radians) = leaf.as_number_or_angle_radians() {
1982 let mut result = Self::Leaf(L::new_number(radians.sin()));
1983 replace_self_with!(&mut result);
1984 }
1985 }
1986 },
1987 Self::Cos(ref mut child) => {
1988 if let CalcNode::Leaf(ref leaf) = **child {
1989 if let Some(radians) = leaf.as_number_or_angle_radians() {
1990 let mut result = Self::Leaf(L::new_number(radians.cos()));
1991 replace_self_with!(&mut result);
1992 }
1993 }
1994 },
1995 Self::Tan(ref mut child) => {
1996 if let CalcNode::Leaf(ref leaf) = **child {
1997 if let Some(radians) = leaf.as_number_or_angle_radians() {
1998 let mut result = Self::Leaf(L::new_number(radians.tan()));
1999 replace_self_with!(&mut result);
2000 }
2001 }
2002 },
2003 Self::Asin(ref mut child) => {
2004 if let CalcNode::Leaf(ref leaf) = **child {
2005 if let Some(value) = leaf.as_number() {
2006 let mut result = Self::Leaf(L::new_angle_from_radians(value.asin()));
2007 replace_self_with!(&mut result);
2008 }
2009 }
2010 },
2011 Self::Acos(ref mut child) => {
2012 if let CalcNode::Leaf(ref leaf) = **child {
2013 if let Some(value) = leaf.as_number() {
2014 let mut result = Self::Leaf(L::new_angle_from_radians(value.acos()));
2015 replace_self_with!(&mut result);
2016 }
2017 }
2018 },
2019 Self::Atan(ref mut child) => {
2020 if let CalcNode::Leaf(ref leaf) = **child {
2021 if let Some(value) = leaf.as_number() {
2022 let mut result = Self::Leaf(L::new_angle_from_radians(value.atan()));
2023 replace_self_with!(&mut result);
2024 }
2025 }
2026 },
2027 Self::Atan2(ref mut a, ref mut b) => {
2028 if let (CalcNode::Leaf(ref la), CalcNode::Leaf(ref lb)) = (&**a, &**b) {
2029 if la.is_same_unit_as(lb) {
2030 if let (Some(a_val), Some(b_val)) =
2031 (la.unitless_value(), lb.unitless_value())
2032 {
2033 let mut result =
2034 Self::Leaf(L::new_angle_from_radians(a_val.atan2(b_val)));
2035 replace_self_with!(&mut result);
2036 }
2037 }
2038 }
2039 },
2040 Self::Pow(ref mut a, ref mut b) => {
2041 if let (CalcNode::Leaf(ref la), CalcNode::Leaf(ref lb)) = (&**a, &**b) {
2042 if let (Some(a_val), Some(b_val)) = (la.as_number(), lb.as_number()) {
2043 let mut result = Self::Leaf(L::new_number(a_val.powf(b_val)));
2044 replace_self_with!(&mut result);
2045 }
2046 }
2047 },
2048 Self::Sqrt(ref mut child) => {
2049 if let CalcNode::Leaf(ref leaf) = **child {
2050 if let Some(value) = leaf.as_number() {
2051 let mut result = Self::Leaf(L::new_number(value.sqrt()));
2052 replace_self_with!(&mut result);
2053 }
2054 }
2055 },
2056 Self::Hypot(ref children) => {
2057 let mut result = value_or_stop!(children[0].try_op(&children[0], Mul::mul));
2058
2059 for child in children.iter().skip(1) {
2060 let square = value_or_stop!(child.try_op(&child, Mul::mul));
2061 result = value_or_stop!(result.try_op(&square, Add::add));
2062 }
2063
2064 result = value_or_stop!(result.try_op(&result, |a, _| a.sqrt()));
2065
2066 replace_self_with!(&mut result);
2067 },
2068 Self::Log(ref mut a, ref mut b) => {
2069 if let CalcNode::Leaf(ref la) = **a {
2070 if let Some(a_val) = la.as_number() {
2071 let folded = match b {
2072 Optional::Some(ref b) => {
2073 if let CalcNode::Leaf(ref lb) = **b {
2074 lb.as_number().map(|b_val| a_val.log(b_val))
2075 } else {
2076 None
2077 }
2078 },
2079 Optional::None => Some(a_val.ln()),
2080 };
2081 if let Some(number) = folded {
2082 let mut result = Self::Leaf(L::new_number(number));
2083 replace_self_with!(&mut result);
2084 }
2085 }
2086 }
2087 },
2088 Self::Exp(ref mut child) => {
2089 if let CalcNode::Leaf(ref leaf) = **child {
2090 if let Some(value) = leaf.as_number() {
2091 let mut result = Self::Leaf(L::new_number(value.exp()));
2092 replace_self_with!(&mut result);
2093 }
2094 }
2095 },
2096 Self::Abs(ref mut child) => {
2097 if let CalcNode::Leaf(leaf) = child.as_mut() {
2098 value_or_stop!(leaf.map(|v| v.abs()));
2099 replace_self_with!(&mut **child);
2100 }
2101 },
2102 Self::Sign(ref mut child) => {
2103 if let CalcNode::Leaf(leaf) = child.as_mut() {
2104 let mut result = Self::Leaf(value_or_stop!(L::sign_from(leaf)));
2105 replace_self_with!(&mut result);
2106 }
2107 },
2108 Self::Negate(ref mut child) => {
2109 match &mut **child {
2111 CalcNode::Leaf(_) => {
2112 child.negate();
2115 replace_self_with!(&mut **child);
2116 },
2117 CalcNode::Negate(value) => {
2118 replace_self_with!(&mut **value);
2120 },
2121 _ => {
2122 },
2124 }
2125 },
2126 Self::Invert(ref mut child) => {
2127 match &mut **child {
2129 CalcNode::Leaf(leaf) => {
2130 if leaf.unit().is_empty() {
2133 value_or_stop!(child.map(|v| 1.0 / v));
2134 replace_self_with!(&mut **child);
2135 }
2136 },
2137 CalcNode::Invert(value) => {
2138 replace_self_with!(&mut **value);
2140 },
2141 _ => {
2142 },
2144 }
2145 },
2146 Self::Leaf(ref mut l) => {
2147 l.simplify();
2148 },
2149 Self::Anchor(ref mut f) => {
2150 if let GenericAnchorSide::Percentage(ref mut n) = f.side {
2151 n.simplify_and_sort();
2152 }
2153 if let Some(fallback) = f.fallback.as_mut() {
2154 fallback.node.simplify_and_sort();
2155 }
2156 },
2157 Self::AnchorSize(ref mut f) => {
2158 if let Some(fallback) = f.fallback.as_mut() {
2159 fallback.node.simplify_and_sort();
2160 }
2161 },
2162 }
2163 }
2164
2165 pub fn simplify_and_sort(&mut self) {
2167 self.visit_depth_first(|node| node.simplify_and_sort_direct_children())
2168 }
2169
2170 fn to_css_impl<W>(&self, dest: &mut CssWriter<W>, level: ArgumentLevel) -> fmt::Result
2171 where
2172 W: Write,
2173 {
2174 let write_closing_paren = match *self {
2175 Self::MinMax(_, op) => {
2176 dest.write_str(match op {
2177 MinMaxOp::Max => "max(",
2178 MinMaxOp::Min => "min(",
2179 })?;
2180 true
2181 },
2182 Self::Clamp { .. } => {
2183 dest.write_str("clamp(")?;
2184 true
2185 },
2186 Self::Round { strategy, .. } => {
2187 match strategy {
2188 RoundingStrategy::Nearest => dest.write_str("round("),
2189 RoundingStrategy::Up => dest.write_str("round(up, "),
2190 RoundingStrategy::Down => dest.write_str("round(down, "),
2191 RoundingStrategy::ToZero => dest.write_str("round(to-zero, "),
2192 }?;
2193
2194 true
2195 },
2196 Self::ModRem { op, .. } => {
2197 dest.write_str(match op {
2198 ModRemOp::Mod => "mod(",
2199 ModRemOp::Rem => "rem(",
2200 })?;
2201
2202 true
2203 },
2204 Self::Sin(_) => {
2205 dest.write_str("sin(")?;
2206 true
2207 },
2208 Self::Cos(_) => {
2209 dest.write_str("cos(")?;
2210 true
2211 },
2212 Self::Tan(_) => {
2213 dest.write_str("tan(")?;
2214 true
2215 },
2216 Self::Asin(_) => {
2217 dest.write_str("asin(")?;
2218 true
2219 },
2220 Self::Acos(_) => {
2221 dest.write_str("acos(")?;
2222 true
2223 },
2224 Self::Atan(_) => {
2225 dest.write_str("atan(")?;
2226 true
2227 },
2228 Self::Atan2(..) => {
2229 dest.write_str("atan2(")?;
2230 true
2231 },
2232 Self::Pow(..) => {
2233 dest.write_str("pow(")?;
2234 true
2235 },
2236 Self::Sqrt(_) => {
2237 dest.write_str("sqrt(")?;
2238 true
2239 },
2240 Self::Hypot(_) => {
2241 dest.write_str("hypot(")?;
2242 true
2243 },
2244 Self::Log(..) => {
2245 dest.write_str("log(")?;
2246 true
2247 },
2248 Self::Exp(_) => {
2249 dest.write_str("exp(")?;
2250 true
2251 },
2252 Self::Abs(_) => {
2253 dest.write_str("abs(")?;
2254 true
2255 },
2256 Self::Sign(_) => {
2257 dest.write_str("sign(")?;
2258 true
2259 },
2260 Self::Negate(_) => {
2261 debug_assert!(
2265 false,
2266 "We never serialize Negate nodes as they are handled inside Sum nodes."
2267 );
2268 dest.write_str("(-1 * ")?;
2269 true
2270 },
2271 Self::Invert(_) => {
2272 if matches!(level, ArgumentLevel::CalculationRoot) {
2273 dest.write_str("calc")?;
2274 }
2275 dest.write_str("(1 / ")?;
2276 true
2277 },
2278 Self::Sum(_) | Self::Product(_) => match level {
2279 ArgumentLevel::CalculationRoot => {
2280 dest.write_str("calc(")?;
2281 true
2282 },
2283 ArgumentLevel::ArgumentRoot => false,
2284 ArgumentLevel::Nested => {
2285 dest.write_str("(")?;
2286 true
2287 },
2288 },
2289 Self::Leaf(_) => match level {
2290 ArgumentLevel::CalculationRoot => {
2291 dest.write_str("calc(")?;
2292 true
2293 },
2294 ArgumentLevel::ArgumentRoot | ArgumentLevel::Nested => false,
2295 },
2296 Self::Anchor(_) | Self::AnchorSize(_) => false,
2297 };
2298
2299 match *self {
2300 Self::MinMax(ref children, _) | Self::Hypot(ref children) => {
2301 let mut first = true;
2302 for child in &**children {
2303 if !first {
2304 dest.write_str(", ")?;
2305 }
2306 first = false;
2307 child.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2308 }
2309 },
2310 Self::Negate(ref value) | Self::Invert(ref value) => {
2311 value.to_css_impl(dest, ArgumentLevel::Nested)?
2312 },
2313 Self::Sum(ref children) => {
2314 let mut first = true;
2315 for child in &**children {
2316 if !first {
2317 match child {
2318 Self::Leaf(l) => {
2319 if let Ok(true) = l.is_negative() {
2320 dest.write_str(" - ")?;
2321 let mut negated = l.clone();
2322 negated.map(std::ops::Neg::neg).unwrap();
2325 negated.to_css(dest)?;
2326 } else {
2327 dest.write_str(" + ")?;
2328 l.to_css(dest)?;
2329 }
2330 },
2331 Self::Negate(n) => {
2332 dest.write_str(" - ")?;
2333 n.to_css_impl(dest, ArgumentLevel::Nested)?;
2334 },
2335 _ => {
2336 dest.write_str(" + ")?;
2337 child.to_css_impl(dest, ArgumentLevel::Nested)?;
2338 },
2339 }
2340 } else {
2341 first = false;
2342 child.to_css_impl(dest, ArgumentLevel::Nested)?;
2343 }
2344 }
2345 },
2346 Self::Product(ref children) => {
2347 let mut first = true;
2348 for child in &**children {
2349 if !first {
2350 match child {
2351 Self::Invert(n) => {
2352 dest.write_str(" / ")?;
2353 n.to_css_impl(dest, ArgumentLevel::Nested)?;
2354 },
2355 _ => {
2356 dest.write_str(" * ")?;
2357 child.to_css_impl(dest, ArgumentLevel::Nested)?;
2358 },
2359 }
2360 } else {
2361 first = false;
2362 child.to_css_impl(dest, ArgumentLevel::Nested)?;
2363 }
2364 }
2365 },
2366 Self::Clamp {
2367 ref min,
2368 ref center,
2369 ref max,
2370 } => {
2371 min.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2372 dest.write_str(", ")?;
2373 center.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2374 dest.write_str(", ")?;
2375 max.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2376 },
2377 Self::Round {
2378 ref value,
2379 ref step,
2380 ..
2381 } => {
2382 value.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2383 dest.write_str(", ")?;
2384 step.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2385 },
2386 Self::ModRem {
2387 ref dividend,
2388 ref divisor,
2389 ..
2390 } => {
2391 dividend.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2392 dest.write_str(", ")?;
2393 divisor.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2394 },
2395 Self::Sin(ref v)
2396 | Self::Cos(ref v)
2397 | Self::Tan(ref v)
2398 | Self::Asin(ref v)
2399 | Self::Acos(ref v)
2400 | Self::Atan(ref v) => v.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?,
2401 Self::Atan2(ref a, ref b) => {
2402 a.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2403 dest.write_str(", ")?;
2404 b.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2405 },
2406 Self::Pow(ref a, ref b) => {
2407 a.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2408 dest.write_str(", ")?;
2409 b.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2410 },
2411 Self::Sqrt(ref v) | Self::Exp(ref v) => {
2412 v.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?
2413 },
2414 Self::Log(ref a, ref b) => {
2415 a.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2416 if let Optional::Some(ref b) = b {
2417 dest.write_str(", ")?;
2418 b.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2419 }
2420 },
2421 Self::Abs(ref v) | Self::Sign(ref v) => {
2422 v.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?
2423 },
2424 Self::Leaf(ref l) => l.to_css(dest)?,
2425 Self::Anchor(ref f) => f.to_css(dest)?,
2426 Self::AnchorSize(ref f) => f.to_css(dest)?,
2427 }
2428
2429 if write_closing_paren {
2430 dest.write_char(')')?;
2431 }
2432 Ok(())
2433 }
2434
2435 fn to_typed_impl(
2436 &self,
2437 dest: &mut ThinVec<TypedValue>,
2438 level: ArgumentLevel,
2439 ) -> Result<(), ()> {
2440 match *self {
2442 Self::Sum(ref children) => {
2443 let mut values = ThinVec::new();
2444 for child in &**children {
2445 let nested = CalcNodeWithLevel {
2446 node: child,
2447 level: ArgumentLevel::Nested,
2448 };
2449 if let Some(TypedValue::Numeric(inner)) = nested.to_typed_value() {
2450 values.push(inner);
2451 }
2452 }
2453 dest.push(TypedValue::Numeric(NumericValue::Sum(MathSum { values })));
2454 Ok(())
2455 },
2456 Self::Leaf(ref l) => match l.to_typed_value() {
2457 Some(TypedValue::Numeric(inner)) => {
2458 match level {
2459 ArgumentLevel::CalculationRoot => {
2460 dest.push(TypedValue::Numeric(NumericValue::Sum(MathSum {
2461 values: ThinVec::from([inner]),
2462 })));
2463 },
2464 ArgumentLevel::ArgumentRoot | ArgumentLevel::Nested => {
2465 dest.push(TypedValue::Numeric(inner));
2466 },
2467 }
2468 Ok(())
2469 },
2470 _ => Err(()),
2471 },
2472 _ => Err(()),
2473 }
2474 }
2475
2476 fn compare(
2477 &self,
2478 other: &Self,
2479 basis_positive: PositivePercentageBasis,
2480 ) -> Option<cmp::Ordering> {
2481 match (self, other) {
2482 (&CalcNode::Leaf(ref one), &CalcNode::Leaf(ref other)) => {
2483 one.compare(other, basis_positive)
2484 },
2485 _ => None,
2486 }
2487 }
2488
2489 compare_helpers!();
2490}
2491
2492impl<L: CalcNodeLeaf> ToCss for CalcNode<L> {
2493 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
2495 where
2496 W: Write,
2497 {
2498 self.to_css_impl(dest, ArgumentLevel::CalculationRoot)
2499 }
2500}
2501
2502impl<L: CalcNodeLeaf> ToTyped for CalcNode<L> {
2503 fn to_typed(&self, dest: &mut ThinVec<TypedValue>) -> Result<(), ()> {
2504 self.to_typed_impl(dest, ArgumentLevel::CalculationRoot)
2505 }
2506}
2507
2508struct CalcNodeWithLevel<'a, L> {
2509 node: &'a CalcNode<L>,
2510 level: ArgumentLevel,
2511}
2512
2513impl<'a, L: CalcNodeLeaf> ToTyped for CalcNodeWithLevel<'a, L> {
2514 fn to_typed(&self, dest: &mut ThinVec<TypedValue>) -> Result<(), ()> {
2515 self.node.to_typed_impl(dest, self.level.clone())
2516 }
2517}
2518
2519#[cfg(test)]
2520mod tests {
2521 use super::*;
2522
2523 #[test]
2524 fn can_sum_with_checks() {
2525 assert!(CalcUnits::LENGTH.can_sum_with(CalcUnits::LENGTH));
2526 assert!(CalcUnits::LENGTH.can_sum_with(CalcUnits::PERCENTAGE));
2527 assert!(CalcUnits::LENGTH.can_sum_with(CalcUnits::LENGTH_PERCENTAGE));
2528
2529 assert!(CalcUnits::PERCENTAGE.can_sum_with(CalcUnits::LENGTH));
2530 assert!(CalcUnits::PERCENTAGE.can_sum_with(CalcUnits::PERCENTAGE));
2531 assert!(CalcUnits::PERCENTAGE.can_sum_with(CalcUnits::LENGTH_PERCENTAGE));
2532
2533 assert!(CalcUnits::LENGTH_PERCENTAGE.can_sum_with(CalcUnits::LENGTH));
2534 assert!(CalcUnits::LENGTH_PERCENTAGE.can_sum_with(CalcUnits::PERCENTAGE));
2535 assert!(CalcUnits::LENGTH_PERCENTAGE.can_sum_with(CalcUnits::LENGTH_PERCENTAGE));
2536
2537 assert!(!CalcUnits::ANGLE.can_sum_with(CalcUnits::TIME));
2538 assert!(CalcUnits::ANGLE.can_sum_with(CalcUnits::ANGLE));
2539
2540 assert!(!(CalcUnits::ANGLE | CalcUnits::TIME).can_sum_with(CalcUnits::ANGLE));
2541 assert!(!CalcUnits::ANGLE.can_sum_with(CalcUnits::ANGLE | CalcUnits::TIME));
2542 assert!(
2543 !(CalcUnits::ANGLE | CalcUnits::TIME).can_sum_with(CalcUnits::ANGLE | CalcUnits::TIME)
2544 );
2545 }
2546}