1use core::cmp::Ordering;
15
16use bun_alloc::Arena; use bun_collections::VecExt;
18pub use bun_wyhash::Wyhash;
25
26use crate::SmallList;
27use crate::css_parser as css;
28use crate::css_parser::CssResult;
29use crate::css_parser::{Parser, ParserOptions};
30use crate::printer::Printer;
31use crate::values::angle::Angle;
32use crate::values::ident::{
33 CustomIdent, CustomIdentFns, DashedIdent, DashedIdentFns, Ident, IdentFns,
34};
35use crate::values::number::{CSSInteger, CSSIntegerFns, CSSNumber, CSSNumberFns};
36use crate::values::rect::Rect;
37use crate::values::size::Size2D;
38use crate::{PrintErr, VendorPrefix};
39#[cfg(bao_nightly)]
40type ParseListVec<T> = Vec<T>;
41#[cfg(not(bao_nightly))]
42type ParseListVec<T> = ::allocator_api2::vec::Vec<T, ::bun_alloc::core_alloc::Global>;
43
44pub type ArrayList<'bump, T> = bun_alloc::ArenaVec<'bump, T>;
47
48pub trait DeepClone<'bump>: Sized {
58 fn deep_clone(&self, bump: &'bump Arena) -> Self;
59}
60
61pub use bun_css_derive::DeepClone;
67
68#[inline]
69pub fn implement_deep_clone<'bump, T: DeepClone<'bump>>(this: &T, bump: &'bump Arena) -> T {
70 this.deep_clone(bump)
74}
75
76pub use implement_deep_clone as deep_clone;
83
84impl<'bump, T: DeepClone<'bump>> DeepClone<'bump> for Option<T> {
87 #[inline]
88 fn deep_clone(&self, bump: &'bump Arena) -> Self {
89 self.as_ref().map(|v| v.deep_clone(bump))
90 }
91}
92
93impl<'bump, T: DeepClone<'bump>> DeepClone<'bump> for &'bump T {
94 #[inline]
95 fn deep_clone(&self, bump: &'bump Arena) -> Self {
96 bump.alloc((**self).deep_clone(bump))
98 }
99}
100
101impl<'bump, T: DeepClone<'bump>> DeepClone<'bump> for &'bump [T] {
102 fn deep_clone(&self, bump: &'bump Arena) -> Self {
103 bump.alloc_slice_fill_iter(self.iter().map(|e| e.deep_clone(bump)))
107 }
108}
109
110impl<'bump, T: DeepClone<'bump>> DeepClone<'bump> for ArrayList<'bump, T> {
111 #[inline]
112 fn deep_clone(&self, bump: &'bump Arena) -> Self {
113 let mut out = ArrayList::with_capacity_in(self.len(), bump);
116 for item in self.iter() {
117 out.push(item.deep_clone(bump));
118 }
119 out
120 }
121}
122
123#[cfg(not(bao_nightly))]
124impl<'bump, T: DeepClone<'bump>> DeepClone<'bump> for ::allocator_api2::vec::Vec<T, ::bun_alloc::core_alloc::Global> {
125 #[inline]
126 fn deep_clone(&self, bump: &'bump Arena) -> Self {
127 self.deep_clone_with(|e| e.deep_clone(bump))
128 }
129}
130
131#[cfg(bao_nightly)]
132impl<'bump, T: DeepClone<'bump>> DeepClone<'bump> for Vec<T> {
133 #[inline]
134 fn deep_clone(&self, bump: &'bump Arena) -> Self {
135 self.deep_clone_with(|e| e.deep_clone(bump))
138 }
139}
140
141impl<'bump, T: DeepClone<'bump>, const N: usize> DeepClone<'bump> for SmallList<T, N> {
142 #[inline]
143 fn deep_clone(&self, bump: &'bump Arena) -> Self {
144 let mut ret = SmallList::<T, N>::init_capacity(self.len());
145 for item in self.slice() {
146 ret.append(item.deep_clone(bump));
147 }
148 ret
149 }
150}
151
152macro_rules! deep_clone_copy {
154 ($($t:ty),* $(,)?) => {$(
155 impl<'bump> DeepClone<'bump> for $t {
156 #[inline]
157 fn deep_clone(&self, _bump: &'bump Arena) -> Self { *self }
158 }
159 )*};
160}
161deep_clone_copy!(f32, f64, i32, u32, i64, u64, usize, isize, u16, bool);
166
167impl<'bump> DeepClone<'bump> for &'bump [u8] {
168 #[inline]
169 fn deep_clone(&self, _bump: &'bump Arena) -> Self {
170 *self
173 }
174}
175
176impl<'bump> DeepClone<'bump> for &'bump str {
177 #[inline]
178 fn deep_clone(&self, _bump: &'bump Arena) -> Self {
179 *self
181 }
182}
183
184impl<'bump, T: DeepClone<'bump>> DeepClone<'bump> for Box<T> {
185 #[inline]
186 fn deep_clone(&self, bump: &'bump Arena) -> Self {
187 Box::new((**self).deep_clone(bump))
188 }
189}
190
191impl<'bump> DeepClone<'bump> for bun_ast::Loc {
192 #[inline]
193 fn deep_clone(&self, _bump: &'bump Arena) -> Self {
194 *self
195 }
196}
197
198pub trait CssEql {
207 fn eql(&self, other: &Self) -> bool;
208}
209
210pub use bun_css_derive::CssEql;
215
216#[inline]
217pub fn implement_eql<T: CssEql>(this: &T, other: &T) -> bool {
218 this.eql(other)
221}
222
223#[inline]
224pub(crate) fn eql<T: CssEql>(lhs: &T, rhs: &T) -> bool {
225 lhs.eql(rhs)
226}
227
228pub(crate) fn eql_list<T: CssEql>(lhs: &ArrayList<'_, T>, rhs: &ArrayList<'_, T>) -> bool {
229 if lhs.len() != rhs.len() {
230 return false;
231 }
232 debug_assert_eq!(lhs.len(), rhs.len());
233 for (left, right) in lhs.iter().zip(rhs.iter()) {
234 if !left.eql(right) {
235 return false;
236 }
237 }
238 true
239}
240
241impl<T: CssEql> CssEql for Option<T> {
244 #[inline]
245 fn eql(&self, other: &Self) -> bool {
246 match (self, other) {
247 (None, None) => true,
248 (Some(a), Some(b)) => a.eql(b),
249 _ => false,
250 }
251 }
252}
253
254impl<T: CssEql + ?Sized> CssEql for &T {
255 #[inline]
256 fn eql(&self, other: &Self) -> bool {
257 (**self).eql(&**other)
258 }
259}
260
261impl<T: CssEql> CssEql for [T] {
262 fn eql(&self, other: &Self) -> bool {
263 if self.len() != other.len() {
264 return false;
265 }
266 for (a, b) in self.iter().zip(other.iter()) {
267 if !a.eql(b) {
268 return false;
269 }
270 }
271 true
272 }
273}
274
275impl<'bump, T: CssEql> CssEql for ArrayList<'bump, T> {
276 #[inline]
277 fn eql(&self, other: &Self) -> bool {
278 eql_list(self, other)
279 }
280}
281
282#[cfg(not(bao_nightly))]
283impl<T: CssEql> CssEql for ::allocator_api2::vec::Vec<T, ::bun_alloc::core_alloc::Global> {
284 #[inline]
285 fn eql(&self, other: &Self) -> bool {
286 self.slice_const().eql(other.slice_const())
287 }
288}
289
290#[cfg(bao_nightly)]
291impl<T: CssEql> CssEql for Vec<T> {
292 #[inline]
293 fn eql(&self, other: &Self) -> bool {
294 self.slice_const().eql(other.slice_const())
295 }
296}
297
298impl<T: CssEql, const N: usize> CssEql for SmallList<T, N> {
299 #[inline]
300 fn eql(&self, other: &Self) -> bool {
301 self.slice().eql(other.slice())
302 }
303}
304
305macro_rules! eql_simple {
306 ($($t:ty),* $(,)?) => {$(
307 impl CssEql for $t {
308 #[inline]
309 fn eql(&self, other: &Self) -> bool { *self == *other }
310 }
311 )*};
312}
313eql_simple!(f32, f64, i32, u32, i64, u64, usize, isize, u16, bool);
315
316#[macro_export]
332macro_rules! css_eql_partialeq {
333 ($($t:ty),+ $(,)?) => {$(
334 impl $crate::generics::CssEql for $t {
335 #[inline]
336 fn eql(&self, other: &Self) -> bool { self == other }
337 }
338 )+};
339}
340impl CssEql for [u8] {
344 #[inline]
345 fn eql(&self, other: &Self) -> bool {
346 bun_core::eql(self, other)
347 }
348}
349
350impl CssEql for str {
351 #[inline]
352 fn eql(&self, other: &Self) -> bool {
353 bun_core::eql(self.as_bytes(), other.as_bytes())
354 }
355}
356
357impl<T: CssEql, const N: usize> CssEql for [T; N] {
358 #[inline]
359 fn eql(&self, other: &Self) -> bool {
360 for (a, b) in self.iter().zip(other.iter()) {
362 if !a.eql(b) {
363 return false;
364 }
365 }
366 true
367 }
368}
369
370impl<T: CssEql + ?Sized> CssEql for Box<T> {
371 #[inline]
372 fn eql(&self, other: &Self) -> bool {
373 (**self).eql(&**other)
374 }
375}
376
377impl CssEql for VendorPrefix {
378 #[inline]
379 fn eql(&self, other: &Self) -> bool {
380 *self == *other
382 }
383}
384
385impl CssEql for bun_ast::Loc {
386 #[inline]
387 fn eql(&self, other: &Self) -> bool {
388 self.start == other.start
389 }
390}
391
392impl CssEql for () {
393 #[inline]
394 fn eql(&self, _other: &Self) -> bool {
395 true
396 }
397}
398
399mod ident_eql {
403 use super::CssEql;
404 use crate::values::ident::{CustomIdent, DashedIdent, Ident};
405
406 macro_rules! ident_eql_impl {
407 ($($t:ty),* $(,)?) => {$(
408 impl CssEql for $t {
409 #[inline]
410 fn eql(&self, other: &Self) -> bool {
411 bun_core::eql(self.v(), other.v())
413 }
414 }
415 )*};
416 }
417 ident_eql_impl!(CustomIdent, DashedIdent, Ident);
418}
419
420mod inherent_bridge {
431 use super::{Arena, CssEql, CssHash, DeepClone, Wyhash};
432
433 macro_rules! bridge_eql {
434 ($($t:ty),* $(,)?) => {$(
435 impl CssEql for $t {
436 #[inline]
437 fn eql(&self, other: &Self) -> bool { <$t>::eql(self, other) }
438 }
439 )*};
440 }
441 macro_rules! bridge_hash {
442 ($($t:ty),* $(,)?) => {$(
443 impl CssHash for $t {
444 #[inline]
445 fn hash(&self, hasher: &mut Wyhash) { <$t>::hash(self, hasher) }
446 }
447 )*};
448 }
449 macro_rules! bridge_deep_clone {
450 ($($t:ty),* $(,)?) => {$(
451 impl<'bump> DeepClone<'bump> for $t {
452 #[inline]
453 fn deep_clone(&self, bump: &'bump Arena) -> Self { <$t>::deep_clone(self, bump) }
454 }
455 )*};
456 }
457 macro_rules! bridge_deep_clone_copy {
458 ($($t:ty),* $(,)?) => {$(
459 impl<'bump> DeepClone<'bump> for $t {
460 #[inline]
461 fn deep_clone(&self, _bump: &'bump Arena) -> Self { Clone::clone(self) }
462 }
463 )*};
464 }
465
466 use crate::values::ident::{CustomIdent, DashedIdent, DashedIdentReference, Ident};
467 bridge_hash!(CustomIdent, DashedIdent, Ident, DashedIdentReference);
468 bridge_eql!(DashedIdentReference);
469 bridge_deep_clone!(CustomIdent, DashedIdent, Ident, DashedIdentReference);
470
471 use crate::values::color::CssColor;
472 bridge_hash!(CssColor);
473 bridge_deep_clone!(CssColor);
474
475 use crate::values::url::Url;
476 bridge_eql!(Url);
477 bridge_hash!(Url);
478 bridge_deep_clone!(Url);
479
480 use crate::properties::animation::AnimationName;
481 bridge_eql!(AnimationName);
482 bridge_hash!(AnimationName);
483 bridge_deep_clone!(AnimationName);
484
485 use crate::properties::custom::UAEnvironmentVariable;
486 impl CssEql for UAEnvironmentVariable {
487 #[inline]
488 fn eql(&self, other: &Self) -> bool {
489 UAEnvironmentVariable::eql(*self, *other)
490 }
491 }
492 bridge_deep_clone_copy!(UAEnvironmentVariable);
494
495 use crate::selectors::parser::{ViewTransitionPartName, WebKitScrollbarPseudoElement};
497 impl CssEql for WebKitScrollbarPseudoElement {
498 #[inline]
499 fn eql(&self, other: &Self) -> bool {
500 WebKitScrollbarPseudoElement::eql(*self, *other)
501 }
502 }
503 bridge_eql!(ViewTransitionPartName);
504 bridge_hash!(ViewTransitionPartName);
506 bridge_deep_clone_copy!(WebKitScrollbarPseudoElement, ViewTransitionPartName);
507
508 macro_rules! bridge_eql_partialeq {
516 ($($t:ty),* $(,)?) => {$(
517 impl CssEql for $t {
518 #[inline]
519 fn eql(&self, other: &Self) -> bool { PartialEq::eq(self, other) }
520 }
521 )*};
522 }
523 macro_rules! bridge_is_compatible {
525 ($($t:ty),* $(,)?) => {$(
526 impl super::IsCompatible for $t {
527 #[inline]
528 fn is_compatible(&self, browsers: &crate::targets::Browsers) -> bool {
529 <$t>::is_compatible(self, browsers)
530 }
531 }
532 )*};
533 }
534 macro_rules! bridge_clone_partialeq {
536 ($($t:ty),* $(,)?) => {
537 bridge_deep_clone_copy!($($t),*);
538 bridge_eql_partialeq!($($t),*);
539 };
540 }
541
542 use crate::values::length::{Length, LengthOrNumber, LengthPercentageOrAuto};
544 bridge_clone_partialeq!(LengthPercentageOrAuto, LengthOrNumber, Length);
545 bridge_is_compatible!(LengthPercentageOrAuto, LengthOrNumber, Length);
546
547 use crate::values::easing::EasingFunction;
548 bridge_clone_partialeq!(EasingFunction);
549
550 use crate::values::alpha::AlphaValue;
551 bridge_clone_partialeq!(AlphaValue);
552
553 use crate::values::image::Image;
554 bridge_eql!(Image);
555 bridge_deep_clone!(Image);
556 bridge_is_compatible!(Image);
557 use crate::values::gradient::{
561 ConicGradient, LinearGradient, RadialGradient, WebKitGradientLinear, WebKitGradientRadial,
562 };
563 bridge_deep_clone!(
564 LinearGradient,
565 RadialGradient,
566 ConicGradient,
567 WebKitGradientLinear,
568 WebKitGradientRadial
569 );
570
571 use crate::values::position::{
572 HorizontalPositionKeyword, Position, PositionComponent, VerticalPositionKeyword,
573 };
574 bridge_clone_partialeq!(Position, HorizontalPositionKeyword, VerticalPositionKeyword);
575 impl<S: Clone + PartialEq> CssEql for PositionComponent<S> {
578 #[inline]
579 fn eql(&self, other: &Self) -> bool {
580 PartialEq::eq(self, other)
581 }
582 }
583 impl<'bump, S: Clone + PartialEq> DeepClone<'bump> for PositionComponent<S> {
584 #[inline]
585 fn deep_clone(&self, _bump: &'bump Arena) -> Self {
586 Clone::clone(self)
587 }
588 }
589
590 use crate::values::rect::Rect;
591 impl<T: PartialEq> CssEql for Rect<T> {
592 #[inline]
593 fn eql(&self, other: &Self) -> bool {
594 Rect::<T>::eql(self, other)
595 }
596 }
597 impl<'bump, T: Clone> DeepClone<'bump> for Rect<T> {
598 #[inline]
599 fn deep_clone(&self, bump: &'bump Arena) -> Self {
600 Rect::<T>::deep_clone(self, bump)
601 }
602 }
603
604 use crate::values::size::Size2D;
605 impl<T: Clone + PartialEq> CssEql for Size2D<T> {
606 #[inline]
607 fn eql(&self, other: &Self) -> bool {
608 Size2D::<T>::eql(self, other)
609 }
610 }
611 impl<'bump, T: Clone + PartialEq> DeepClone<'bump> for Size2D<T> {
612 #[inline]
613 fn deep_clone(&self, bump: &'bump Arena) -> Self {
614 Size2D::<T>::deep_clone(self, bump)
615 }
616 }
617
618 bridge_is_compatible!(CssColor);
619
620 use crate::properties::border::{
622 BorderBlockColor, BorderBlockStyle, BorderBlockWidth, BorderColor, BorderInlineColor,
623 BorderInlineStyle, BorderInlineWidth, BorderSideWidth, BorderStyle, BorderWidth,
624 GenericBorder, LineStyle,
625 };
626 bridge_eql_partialeq!(LineStyle);
627 bridge_deep_clone!(BorderSideWidth);
628 bridge_deep_clone_copy!(LineStyle);
629 impl super::IsCompatible for BorderSideWidth {
630 #[inline]
631 fn is_compatible(&self, browsers: &crate::targets::Browsers) -> bool {
632 BorderSideWidth::is_compatible(self, browsers)
633 }
634 }
635 impl super::IsCompatible for LineStyle {
636 #[inline]
637 fn is_compatible(&self, browsers: &crate::targets::Browsers) -> bool {
638 LineStyle::is_compatible(*self, browsers)
639 }
640 }
641 bridge_clone_partialeq!(
642 BorderColor,
643 BorderStyle,
644 BorderWidth,
645 BorderBlockColor,
646 BorderBlockStyle,
647 BorderBlockWidth,
648 BorderInlineColor,
649 BorderInlineStyle,
650 BorderInlineWidth,
651 );
652 impl<S: CssEql, const P: u8> CssEql for GenericBorder<S, P> {
653 #[inline]
654 fn eql(&self, other: &Self) -> bool {
655 self.width.eql(&other.width)
656 && self.style.eql(&other.style)
657 && self.color.eql(&other.color)
658 }
659 }
660 impl<'bump, S: DeepClone<'bump>, const P: u8> DeepClone<'bump> for GenericBorder<S, P> {
661 #[inline]
662 fn deep_clone(&self, bump: &'bump Arena) -> Self {
663 GenericBorder {
664 width: self.width.deep_clone(bump),
665 style: self.style.deep_clone(bump),
666 color: self.color.deep_clone(bump),
667 }
668 }
669 }
670
671 use crate::properties::outline::OutlineStyle;
672 bridge_clone_partialeq!(OutlineStyle);
673
674 use crate::properties::border_image::{
675 BorderImage, BorderImageRepeat, BorderImageSideWidth, BorderImageSlice,
676 };
677 bridge_deep_clone!(BorderImageRepeat, BorderImageSideWidth, BorderImageSlice);
681 bridge_eql!(BorderImageRepeat, BorderImageSlice);
682 bridge_deep_clone!(BorderImage);
683 bridge_eql!(BorderImage);
684
685 use crate::properties::border_radius::BorderRadius;
686 bridge_deep_clone!(BorderRadius);
689 bridge_eql!(BorderRadius);
690
691 use crate::properties::background::{
693 Background, BackgroundAttachment, BackgroundClip, BackgroundOrigin, BackgroundPosition,
694 BackgroundRepeat, BackgroundSize,
695 };
696 bridge_eql!(Background);
697 bridge_deep_clone!(Background, BackgroundSize, BackgroundPosition);
698 bridge_deep_clone_copy!(BackgroundRepeat);
699 bridge_clone_partialeq!(BackgroundAttachment, BackgroundClip, BackgroundOrigin);
700
701 use crate::properties::align::{
703 AlignContent, AlignItems, AlignSelf, Gap, GapValue, JustifyContent, JustifyItems,
704 JustifySelf, PlaceContent, PlaceItems, PlaceSelf,
705 };
706 bridge_clone_partialeq!(
707 AlignContent,
708 AlignItems,
709 AlignSelf,
710 JustifyContent,
711 JustifyItems,
712 JustifySelf,
713 PlaceContent,
714 PlaceItems,
715 PlaceSelf,
716 Gap,
717 GapValue,
718 );
719
720 use crate::properties::flex::{
722 BoxAlign, BoxDirection, BoxLines, BoxOrient, BoxPack, Flex, FlexDirection, FlexFlow,
723 FlexItemAlign, FlexLinePack, FlexPack, FlexWrap,
724 };
725 bridge_clone_partialeq!(
726 FlexDirection,
727 FlexWrap,
728 FlexFlow,
729 Flex,
730 BoxOrient,
731 BoxDirection,
732 BoxAlign,
733 BoxPack,
734 BoxLines,
735 FlexPack,
736 FlexItemAlign,
737 FlexLinePack,
738 );
739
740 use crate::properties::font::{
742 FontFamily, FontSize, FontStretch, FontStyle, FontVariantCaps, FontWeight, LineHeight,
743 };
744 bridge_clone_partialeq!(
745 FontWeight,
746 FontSize,
747 FontStretch,
748 FontStyle,
749 FontVariantCaps,
750 LineHeight,
751 );
752 impl super::IsCompatible for FontWeight {
753 #[inline]
754 fn is_compatible(&self, browsers: &crate::targets::Browsers) -> bool {
755 FontWeight::is_compatible(self, browsers)
756 }
757 }
758 impl super::IsCompatible for FontSize {
759 #[inline]
760 fn is_compatible(&self, browsers: &crate::targets::Browsers) -> bool {
761 FontSize::is_compatible(self, browsers)
762 }
763 }
764 impl super::IsCompatible for FontStretch {
765 #[inline]
766 fn is_compatible(&self, browsers: &crate::targets::Browsers) -> bool {
767 FontStretch::is_compatible(*self, browsers)
768 }
769 }
770 impl super::IsCompatible for FontStyle {
771 #[inline]
772 fn is_compatible(&self, browsers: &crate::targets::Browsers) -> bool {
773 FontStyle::is_compatible(*self, browsers)
774 }
775 }
776 impl super::IsCompatible for FontVariantCaps {
777 #[inline]
778 fn is_compatible(&self, browsers: &crate::targets::Browsers) -> bool {
779 FontVariantCaps::is_compatible(*self, browsers)
780 }
781 }
782 impl super::IsCompatible for LineHeight {
783 #[inline]
784 fn is_compatible(&self, browsers: &crate::targets::Browsers) -> bool {
785 LineHeight::is_compatible(self, browsers)
786 }
787 }
788 impl super::IsCompatible for FontFamily {
789 #[inline]
790 fn is_compatible(&self, browsers: &crate::targets::Browsers) -> bool {
791 FontFamily::is_compatible(self, browsers)
792 }
793 }
794 bridge_clone_partialeq!(FontFamily);
795 use crate::properties::size::{AspectRatio, BoxSizing, MaxSize, Size};
799 bridge_eql!(Size, MaxSize, AspectRatio);
800 bridge_deep_clone!(Size, MaxSize, AspectRatio);
801 bridge_clone_partialeq!(BoxSizing);
802
803 use crate::properties::display::{Display, Visibility};
805 bridge_deep_clone_copy!(Display);
806 bridge_eql_partialeq!(Display);
807 bridge_clone_partialeq!(Visibility);
808
809 use crate::properties::overflow::{Overflow, OverflowKeyword, TextOverflow};
811 bridge_clone_partialeq!(Overflow, OverflowKeyword, TextOverflow);
812
813 use crate::properties::position::Position as PositionProp;
815 bridge_clone_partialeq!(PositionProp);
816
817 use crate::properties::text::{Direction as TextDirection, TextShadow};
819 bridge_clone_partialeq!(TextDirection);
820 bridge_deep_clone!(TextShadow);
822 bridge_eql_partialeq!(TextShadow);
823
824 use crate::properties::transform::{
826 BackfaceVisibility, Perspective, Rotate, Scale, TransformBox, TransformList,
827 TransformStyle, Translate,
828 };
829 bridge_deep_clone!(TransformList, Translate, Rotate, Scale, Perspective);
830 bridge_clone_partialeq!(TransformStyle, TransformBox, BackfaceVisibility);
832
833 use crate::properties::transition::Transition;
835 bridge_deep_clone!(Transition);
836 bridge_eql!(Transition);
837
838 use crate::properties::masking::{
840 GeometryBox, MaskBorderMode, MaskClip, MaskComposite, MaskMode, MaskType,
841 WebKitMaskComposite, WebKitMaskSourceType,
842 };
843 bridge_clone_partialeq!(
844 GeometryBox,
845 MaskMode,
846 MaskClip,
847 MaskComposite,
848 MaskType,
849 MaskBorderMode,
850 WebKitMaskComposite,
851 WebKitMaskSourceType,
852 );
853 use crate::properties::ui::ColorScheme;
858 bridge_deep_clone_copy!(ColorScheme);
859 bridge_eql_partialeq!(ColorScheme);
860
861 use crate::properties::css_modules::Composes;
863 bridge_deep_clone!(Composes);
864 bridge_eql!(Composes);
865
866 use crate::properties::margin_padding::{
868 Inset, InsetBlock, InsetInline, Margin, MarginBlock, MarginInline, Padding, PaddingBlock,
869 PaddingInline, ScrollMargin, ScrollMarginBlock, ScrollMarginInline, ScrollPadding,
870 ScrollPaddingBlock, ScrollPaddingInline,
871 };
872 bridge_clone_partialeq!(
873 Margin,
874 MarginBlock,
875 MarginInline,
876 Padding,
877 PaddingBlock,
878 PaddingInline,
879 ScrollMargin,
880 ScrollMarginBlock,
881 ScrollMarginInline,
882 ScrollPadding,
883 ScrollPaddingBlock,
884 ScrollPaddingInline,
885 Inset,
886 InsetBlock,
887 InsetInline,
888 );
889
890 use crate::properties::PropertyId;
892 bridge_deep_clone_copy!(PropertyId);
893 bridge_eql_partialeq!(PropertyId);
894}
895
896pub const HASH_SEED: u64 = 0;
905
906pub trait CssHash {
908 fn hash(&self, hasher: &mut Wyhash);
909}
910
911pub use bun_css_derive::CssHash;
916
917#[inline]
918pub fn implement_hash<T: CssHash>(this: &T, hasher: &mut Wyhash) {
919 this.hash(hasher)
922}
923
924#[inline]
925pub fn hash<T: CssHash>(this: &T, hasher: &mut Wyhash) {
926 this.hash(hasher)
927}
928
929pub(crate) fn hash_array_list<V: CssHash>(this: &ArrayList<'_, V>, hasher: &mut Wyhash) {
930 for item in this.iter() {
931 item.hash(hasher);
932 }
933}
934
935#[cfg(bao_nightly)]
936pub(crate) fn hash_baby_list<V: CssHash>(this: &[V], hasher: &mut Wyhash) {
937 for item in this {
938 item.hash(hasher);
939 }
940}
941
942impl CssHash for () {
943 #[inline]
944 fn hash(&self, _hasher: &mut Wyhash) {}
945}
946
947impl<T: CssHash> CssHash for Option<T> {
948 #[inline]
949 fn hash(&self, hasher: &mut Wyhash) {
950 if let Some(v) = self {
954 v.hash(hasher);
955 }
956 }
957}
958
959impl<T: CssHash + ?Sized> CssHash for &T {
960 #[inline]
961 fn hash(&self, hasher: &mut Wyhash) {
962 (**self).hash(hasher)
963 }
964}
965
966impl<T: CssHash> CssHash for [T] {
967 fn hash(&self, hasher: &mut Wyhash) {
968 for item in self {
970 item.hash(hasher);
971 }
972 }
973}
974
975impl<T: CssHash, const N: usize> CssHash for [T; N] {
976 fn hash(&self, hasher: &mut Wyhash) {
977 hasher.update(&self.len().to_ne_bytes());
983 for item in self {
984 item.hash(hasher);
985 }
986 }
987}
988
989impl<'bump, T: CssHash> CssHash for ArrayList<'bump, T> {
990 #[inline]
991 fn hash(&self, hasher: &mut Wyhash) {
992 hash_array_list(self, hasher)
993 }
994}
995
996#[cfg(not(bao_nightly))]
997impl<T: CssHash> CssHash for ::allocator_api2::vec::Vec<T, ::bun_alloc::core_alloc::Global> {
998 #[inline]
999 fn hash(&self, hasher: &mut Wyhash) {
1000 for item in self.slice_const() {
1001 item.hash(hasher);
1002 }
1003 }
1004}
1005
1006#[cfg(bao_nightly)]
1007impl<T: CssHash> CssHash for Vec<T> {
1008 #[inline]
1009 fn hash(&self, hasher: &mut Wyhash) {
1010 hash_baby_list(self, hasher)
1011 }
1012}
1013
1014impl<T: CssHash, const N: usize> CssHash for SmallList<T, N> {
1015 #[inline]
1016 fn hash(&self, hasher: &mut Wyhash) {
1017 for item in self.slice() {
1018 item.hash(hasher);
1019 }
1020 }
1021}
1022
1023macro_rules! hash_simple {
1024 ($($t:ty),* $(,)?) => {$(
1025 impl CssHash for $t {
1026 #[inline]
1027 fn hash(&self, hasher: &mut Wyhash) {
1028 hasher.update(&self.to_ne_bytes());
1030 }
1031 }
1032 )*};
1033}
1034hash_simple!(f32, f64, i32, u32, i64, u64, usize, isize, u16);
1036
1037impl CssHash for bool {
1038 #[inline]
1039 fn hash(&self, hasher: &mut Wyhash) {
1040 hasher.update(&[*self as u8]);
1041 }
1042}
1043
1044impl CssHash for [u8] {
1045 #[inline]
1046 fn hash(&self, hasher: &mut Wyhash) {
1047 hasher.update(self);
1048 }
1049}
1050
1051impl CssHash for str {
1052 #[inline]
1053 fn hash(&self, hasher: &mut Wyhash) {
1054 hasher.update(self.as_bytes());
1055 }
1056}
1057
1058impl<T: CssHash + ?Sized> CssHash for Box<T> {
1059 #[inline]
1060 fn hash(&self, hasher: &mut Wyhash) {
1061 (**self).hash(hasher)
1062 }
1063}
1064
1065impl CssHash for VendorPrefix {
1066 #[inline]
1067 fn hash(&self, hasher: &mut Wyhash) {
1068 hasher.update(&[self.as_bits()]);
1070 }
1071}
1072
1073impl CssHash for bun_ast::Loc {
1074 #[inline]
1075 fn hash(&self, hasher: &mut Wyhash) {
1076 hasher.update(&self.start.to_ne_bytes());
1080 }
1081}
1082
1083pub trait ListContainer {
1089 type Item;
1090 fn slice(&self) -> &[Self::Item];
1091}
1092
1093impl<'bump, T> ListContainer for ArrayList<'bump, T> {
1094 type Item = T;
1095 #[inline]
1096 fn slice(&self) -> &[T] {
1097 self.as_slice()
1098 }
1099}
1100impl<T> ListContainer for Vec<T> {
1101 type Item = T;
1102 #[inline]
1103 fn slice(&self) -> &[T] {
1104 self.as_slice()
1105 }
1106}
1107#[cfg(not(bao_nightly))]
1108impl<T> ListContainer for ::allocator_api2::vec::Vec<T, ::bun_alloc::core_alloc::Global> {
1109 type Item = T;
1110 #[inline]
1111 fn slice(&self) -> &[T] {
1112 self.as_slice()
1113 }
1114}
1115impl<T, const N: usize> ListContainer for SmallList<T, N> {
1116 type Item = T;
1117 #[inline]
1118 fn slice(&self) -> &[T] {
1119 SmallList::slice(self)
1120 }
1121}
1122
1123#[inline]
1124pub fn slice<L: ListContainer>(val: &L) -> &[L::Item] {
1125 val.slice()
1126}
1127
1128pub trait IsCompatible {
1129 fn is_compatible(&self, browsers: &crate::targets::Browsers) -> bool;
1130}
1131
1132pub use bun_css_derive::IsCompatible;
1138
1139#[inline]
1140pub(crate) fn is_compatible<T: IsCompatible>(val: &T, browsers: &crate::targets::Browsers) -> bool {
1141 val.is_compatible(browsers)
1142}
1143
1144impl<T: IsCompatible + ?Sized> IsCompatible for &T {
1145 #[inline]
1146 fn is_compatible(&self, browsers: &crate::targets::Browsers) -> bool {
1147 (**self).is_compatible(browsers)
1148 }
1149}
1150
1151impl<T: IsCompatible + ?Sized> IsCompatible for Box<T> {
1152 #[inline]
1153 fn is_compatible(&self, browsers: &crate::targets::Browsers) -> bool {
1154 (**self).is_compatible(browsers)
1155 }
1156}
1157
1158impl<T: IsCompatible> IsCompatible for Option<T> {
1159 #[inline]
1160 fn is_compatible(&self, browsers: &crate::targets::Browsers) -> bool {
1161 match self {
1165 Some(v) => v.is_compatible(browsers),
1166 None => true,
1167 }
1168 }
1169}
1170
1171impl<T: IsCompatible> IsCompatible for [T] {
1172 #[inline]
1173 fn is_compatible(&self, browsers: &crate::targets::Browsers) -> bool {
1174 for item in self {
1175 if !item.is_compatible(browsers) {
1176 return false;
1177 }
1178 }
1179 true
1180 }
1181}
1182
1183impl<T: IsCompatible, const N: usize> IsCompatible for [T; N] {
1184 #[inline]
1185 fn is_compatible(&self, browsers: &crate::targets::Browsers) -> bool {
1186 self.as_slice().is_compatible(browsers)
1187 }
1188}
1189
1190#[cfg(not(bao_nightly))]
1191impl<T: IsCompatible> IsCompatible for ::allocator_api2::vec::Vec<T, ::bun_alloc::core_alloc::Global> {
1192 #[inline]
1193 fn is_compatible(&self, browsers: &crate::targets::Browsers) -> bool {
1194 self.as_slice().is_compatible(browsers)
1195 }
1196}
1197
1198#[cfg(bao_nightly)]
1199impl<T: IsCompatible> IsCompatible for Vec<T> {
1200 #[inline]
1201 fn is_compatible(&self, browsers: &crate::targets::Browsers) -> bool {
1202 self.as_slice().is_compatible(browsers)
1203 }
1204}
1205
1206macro_rules! is_compatible_container {
1211 ($(($($gen:tt)*) $ty:ty),* $(,)?) => {$(
1212 impl<$($gen)*> IsCompatible for $ty
1213 where
1214 <$ty as ListContainer>::Item: IsCompatible,
1215 {
1216 fn is_compatible(&self, browsers: &crate::targets::Browsers) -> bool {
1217 for item in ListContainer::slice(self) {
1218 if !item.is_compatible(browsers) {
1219 return false;
1220 }
1221 }
1222 true
1223 }
1224 }
1225 )*};
1226}
1227is_compatible_container!(
1228 ('bump, T) ArrayList<'bump, T>,
1229 (T, const N: usize) SmallList<T, N>,
1230);
1231
1232pub trait Parse: Sized {
1249 fn parse(input: &mut Parser) -> CssResult<Self>;
1250}
1251
1252pub trait ParseWithOptions: Sized {
1262 fn parse_with_options(input: &mut Parser, options: &ParserOptions) -> CssResult<Self>;
1263}
1264
1265#[inline]
1266pub fn parse_with_options<T: ParseWithOptions>(
1267 input: &mut Parser,
1268 options: &ParserOptions,
1269) -> CssResult<T> {
1270 T::parse_with_options(input, options)
1271}
1272
1273#[inline]
1274pub fn parse<T: Parse>(input: &mut Parser) -> CssResult<T> {
1275 T::parse(input)
1276}
1277
1278#[inline]
1279pub fn parse_for<T: Parse>() -> fn(&mut Parser) -> CssResult<T> {
1280 |input| T::parse(input)
1281}
1282
1283impl<T: Parse> Parse for Option<T> {
1286 #[inline]
1287 fn parse(input: &mut Parser) -> CssResult<Self> {
1288 Ok(input.try_parse(T::parse).ok())
1289 }
1290}
1291impl<T: Parse> ParseWithOptions for Option<T> {
1292 #[inline]
1293 fn parse_with_options(input: &mut Parser, _options: &ParserOptions) -> CssResult<Self> {
1294 <Self as Parse>::parse(input)
1295 }
1296}
1297
1298#[cfg(bao_nightly)]
1299impl<T: Parse> Parse for Vec<T> {
1300 #[inline]
1301 fn parse(input: &mut Parser) -> CssResult<Self> {
1302 input.parse_comma_separated(T::parse)
1303 }
1304}
1305#[cfg(not(bao_nightly))]
1306impl<T: Parse> Parse for ::allocator_api2::vec::Vec<T, ::bun_alloc::core_alloc::Global> {
1307 #[inline]
1308 fn parse(input: &mut Parser) -> CssResult<Self> {
1309 input.parse_comma_separated(T::parse)
1310 }
1311}
1312
1313#[cfg(bao_nightly)]
1314impl<T: Parse> ParseWithOptions for Vec<T> {
1315 #[inline]
1316 fn parse_with_options(input: &mut Parser, _options: &ParserOptions) -> CssResult<Self> {
1317 <Self as Parse>::parse(input)
1318 }
1319}
1320#[cfg(not(bao_nightly))]
1321impl<T: Parse> ParseWithOptions for ::allocator_api2::vec::Vec<T, ::bun_alloc::core_alloc::Global> {
1322 #[inline]
1323 fn parse_with_options(input: &mut Parser, _options: &ParserOptions) -> CssResult<Self> {
1324 <Self as Parse>::parse(input)
1325 }
1326}
1327
1328impl<T: Parse> Parse for Box<T> {
1330 #[inline]
1331 fn parse(input: &mut Parser) -> CssResult<Self> {
1332 T::parse(input).map(Box::new)
1333 }
1334}
1335impl<T: Parse> ParseWithOptions for Box<T> {
1336 #[inline]
1337 fn parse_with_options(input: &mut Parser, _options: &ParserOptions) -> CssResult<Self> {
1338 <Self as Parse>::parse(input)
1339 }
1340}
1341
1342impl<T: Parse, const N: usize> Parse for SmallList<T, N> {
1343 #[inline]
1344 fn parse(input: &mut Parser) -> CssResult<Self> {
1345 input
1346 .parse_comma_separated(T::parse)
1347 .map(|v: ParseListVec<T>| SmallList::from_list(v.into_iter().collect()))
1348 }
1349}
1350impl<T: Parse, const N: usize> ParseWithOptions for SmallList<T, N> {
1351 #[inline]
1352 fn parse_with_options(input: &mut Parser, _options: &ParserOptions) -> CssResult<Self> {
1353 <Self as Parse>::parse(input)
1354 }
1355}
1356
1357impl<T: Parse + Clone + PartialEq> Parse for Size2D<T> {
1358 #[inline]
1359 fn parse(input: &mut Parser) -> CssResult<Self> {
1360 Size2D::<T>::parse(input)
1361 }
1362}
1363impl<T: Parse + Clone + PartialEq> ParseWithOptions for Size2D<T> {
1364 #[inline]
1365 fn parse_with_options(input: &mut Parser, _options: &ParserOptions) -> CssResult<Self> {
1366 Size2D::<T>::parse(input)
1367 }
1368}
1369
1370impl<T: Parse + Clone> Parse for Rect<T> {
1371 #[inline]
1372 fn parse(input: &mut Parser) -> CssResult<Self> {
1373 Rect::<T>::parse(input)
1374 }
1375}
1376impl<T: Parse + Clone> ParseWithOptions for Rect<T> {
1377 #[inline]
1378 fn parse_with_options(input: &mut Parser, _options: &ParserOptions) -> CssResult<Self> {
1379 Rect::<T>::parse(input)
1380 }
1381}
1382
1383impl Parse for f32 {
1384 #[inline]
1385 fn parse(input: &mut Parser) -> CssResult<Self> {
1386 CSSNumberFns::parse(input)
1387 }
1388}
1389impl Parse for CSSInteger {
1390 #[inline]
1391 fn parse(input: &mut Parser) -> CssResult<Self> {
1392 CSSIntegerFns::parse(input)
1393 }
1394}
1395impl Parse for CustomIdent {
1396 #[inline]
1397 fn parse(input: &mut Parser) -> CssResult<Self> {
1398 CustomIdentFns::parse(input)
1399 }
1400}
1401impl Parse for DashedIdent {
1402 #[inline]
1403 fn parse(input: &mut Parser) -> CssResult<Self> {
1404 DashedIdentFns::parse(input)
1405 }
1406}
1407impl Parse for Ident {
1408 #[inline]
1409 fn parse(input: &mut Parser) -> CssResult<Self> {
1410 IdentFns::parse(input)
1411 }
1412}
1413
1414pub trait ToCss {
1419 fn to_css(&self, dest: &mut Printer) -> core::result::Result<(), PrintErr>;
1420}
1421
1422#[inline]
1423pub(crate) fn to_css<T: ToCss>(this: &T, dest: &mut Printer) -> core::result::Result<(), PrintErr> {
1424 this.to_css(dest)
1425}
1426
1427impl<T: ToCss + ?Sized> ToCss for &T {
1428 #[inline]
1429 fn to_css(&self, dest: &mut Printer) -> core::result::Result<(), PrintErr> {
1430 (**self).to_css(dest)
1431 }
1432}
1433
1434impl<T: ToCss + ?Sized> ToCss for Box<T> {
1436 #[inline]
1437 fn to_css(&self, dest: &mut Printer) -> core::result::Result<(), PrintErr> {
1438 (**self).to_css(dest)
1439 }
1440}
1441
1442impl<T: ToCss> ToCss for Option<T> {
1443 #[inline]
1444 fn to_css(&self, dest: &mut Printer) -> core::result::Result<(), PrintErr> {
1445 if let Some(val) = self {
1446 return val.to_css(dest);
1447 }
1448 Ok(())
1449 }
1450}
1451
1452impl<'bump, T: ToCss> ToCss for ArrayList<'bump, T> {
1453 #[inline]
1454 fn to_css(&self, dest: &mut Printer) -> core::result::Result<(), PrintErr> {
1455 css::to_css::from_list(self.as_slice(), dest)
1456 }
1457}
1458
1459#[cfg(not(bao_nightly))]
1460impl<T: ToCss> ToCss for ::allocator_api2::vec::Vec<T, ::bun_alloc::core_alloc::Global> {
1461 #[inline]
1462 fn to_css(&self, dest: &mut Printer) -> core::result::Result<(), PrintErr> {
1463 css::to_css::from_list(self.as_slice(), dest)
1464 }
1465}
1466
1467#[cfg(bao_nightly)]
1468impl<T: ToCss> ToCss for Vec<T> {
1469 #[inline]
1470 fn to_css(&self, dest: &mut Printer) -> core::result::Result<(), PrintErr> {
1471 css::to_css::from_list(self.as_slice(), dest)
1472 }
1473}
1474
1475impl<T: ToCss, const N: usize> ToCss for SmallList<T, N> {
1476 #[inline]
1477 fn to_css(&self, dest: &mut Printer) -> core::result::Result<(), PrintErr> {
1478 css::to_css::from_list(self.slice(), dest)
1479 }
1480}
1481
1482impl<T: ToCss + Clone + PartialEq> ToCss for Size2D<T> {
1483 #[inline]
1484 fn to_css(&self, dest: &mut Printer) -> core::result::Result<(), PrintErr> {
1485 Size2D::<T>::to_css(self, dest)
1486 }
1487}
1488
1489impl<T: ToCss + PartialEq> ToCss for Rect<T> {
1490 #[inline]
1491 fn to_css(&self, dest: &mut Printer) -> core::result::Result<(), PrintErr> {
1492 Rect::<T>::to_css(self, dest)
1493 }
1494}
1495
1496impl ToCss for f32 {
1497 #[inline]
1498 fn to_css(&self, dest: &mut Printer) -> core::result::Result<(), PrintErr> {
1499 CSSNumberFns::to_css(*self, dest)
1500 }
1501}
1502impl ToCss for CSSInteger {
1503 #[inline]
1504 fn to_css(&self, dest: &mut Printer) -> core::result::Result<(), PrintErr> {
1505 CSSIntegerFns::to_css(*self, dest)
1506 }
1507}
1508impl ToCss for CustomIdent {
1509 #[inline]
1510 fn to_css(&self, dest: &mut Printer) -> core::result::Result<(), PrintErr> {
1511 CustomIdentFns::to_css(self, dest)
1512 }
1513}
1514impl ToCss for DashedIdent {
1515 #[inline]
1516 fn to_css(&self, dest: &mut Printer) -> core::result::Result<(), PrintErr> {
1517 DashedIdentFns::to_css(self, dest)
1518 }
1519}
1520impl ToCss for Ident {
1521 #[inline]
1522 fn to_css(&self, dest: &mut Printer) -> core::result::Result<(), PrintErr> {
1523 IdentFns::to_css(self, dest)
1524 }
1525}
1526
1527#[macro_export]
1542macro_rules! impl_parse_tocss_via_inherent {
1543 ($($ty:ty),+ $(,)?) => {$(
1544 impl $crate::generics::Parse for $ty {
1545 #[inline]
1546 fn parse(input: &mut $crate::css_parser::Parser) -> $crate::css_parser::CssResult<Self> {
1547 <$ty>::parse(input)
1548 }
1549 }
1550 impl $crate::generics::ParseWithOptions for $ty {
1551 #[inline]
1552 fn parse_with_options(
1553 input: &mut $crate::css_parser::Parser,
1554 _options: &$crate::css_parser::ParserOptions,
1555 ) -> $crate::css_parser::CssResult<Self> {
1556 <$ty>::parse(input)
1557 }
1558 }
1559 impl $crate::generics::ToCss for $ty {
1560 #[inline]
1561 fn to_css(
1562 &self,
1563 dest: &mut $crate::printer::Printer,
1564 ) -> ::core::result::Result<(), $crate::PrintErr> {
1565 (*self).to_css(dest)
1566 }
1567 }
1568 )+};
1569}
1570
1571macro_rules! impl_pwo_via_parse {
1574 ($($ty:ty),+ $(,)?) => {$(
1575 impl ParseWithOptions for $ty {
1576 #[inline]
1577 fn parse_with_options(input: &mut Parser, _options: &ParserOptions) -> CssResult<Self> {
1578 <$ty as Parse>::parse(input)
1579 }
1580 }
1581 )+};
1582}
1583impl_pwo_via_parse!(f32, CSSInteger, CustomIdent, DashedIdent, Ident);
1584
1585pub trait TryFromAngle: Sized {
1590 fn try_from_angle(angle: Angle) -> Option<Self>;
1591}
1592
1593impl TryFromAngle for CSSNumber {
1594 #[inline]
1595 fn try_from_angle(angle: Angle) -> Option<Self> {
1596 CSSNumberFns::try_from_angle(angle)
1597 }
1598}
1599
1600pub trait TrySign {
1601 fn try_sign(&self) -> Option<f32>;
1602}
1603
1604impl TrySign for CSSNumber {
1605 #[inline]
1606 fn try_sign(&self) -> Option<f32> {
1607 Some(CSSNumberFns::sign(*self))
1608 }
1609}
1610pub trait TryMap: Sized {
1614 fn try_map(&self, map_fn: impl Fn(f32) -> f32) -> Option<Self>;
1616}
1617
1618impl TryMap for CSSNumber {
1619 #[inline]
1620 fn try_map(&self, map_fn: impl Fn(f32) -> f32) -> Option<Self> {
1621 Some(map_fn(*self))
1622 }
1623}
1624
1625pub trait TryOpTo: Sized {
1626 fn try_op_to<R, C>(&self, rhs: &Self, ctx: C, op_fn: impl Fn(C, f32, f32) -> R) -> Option<R>;
1630}
1631
1632impl TryOpTo for CSSNumber {
1633 #[inline]
1634 fn try_op_to<R, C>(&self, rhs: &Self, ctx: C, op_fn: impl Fn(C, f32, f32) -> R) -> Option<R> {
1635 Some(op_fn(ctx, *self, *rhs))
1636 }
1637}
1638
1639impl IsCompatible for CSSNumber {
1640 #[inline]
1641 fn is_compatible(&self, _: &crate::targets::Browsers) -> bool {
1642 true
1643 }
1644}
1645
1646pub trait TryOp: Sized {
1647 fn try_op<C>(&self, rhs: &Self, ctx: C, op_fn: impl Fn(C, f32, f32) -> f32) -> Option<Self>;
1649}
1650
1651impl TryOp for CSSNumber {
1652 #[inline]
1653 fn try_op<C>(&self, rhs: &Self, ctx: C, op_fn: impl Fn(C, f32, f32) -> f32) -> Option<Self> {
1654 Some(op_fn(ctx, *self, *rhs))
1655 }
1656}
1657
1658pub trait PartialCmp {
1659 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering>;
1660}
1661
1662#[inline]
1663pub(crate) fn partial_cmp_f32(lhs: f32, rhs: f32) -> Option<Ordering> {
1664 let lte = lhs <= rhs;
1665 let rte = lhs >= rhs;
1666 if !lte && !rte {
1667 return None;
1668 }
1669 if !lte && rte {
1670 return Some(Ordering::Greater);
1671 }
1672 if lte && !rte {
1673 return Some(Ordering::Less);
1674 }
1675 Some(Ordering::Equal)
1676}
1677
1678impl PartialCmp for f32 {
1679 #[inline]
1680 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
1681 partial_cmp_f32(*self, *rhs)
1682 }
1683}
1684impl PartialCmp for CSSInteger {
1685 #[inline]
1686 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
1687 Some(Ord::cmp(self, rhs))
1688 }
1689}
1690
1691pub trait Zero: Sized {
1699 fn zero() -> Self;
1700 fn is_zero(&self) -> bool;
1701}
1702pub trait MulF32: Sized {
1704 fn mul_f32(self, rhs: f32) -> Self;
1705}
1706pub trait TryAdd: Sized {
1708 fn try_add(&self, rhs: &Self) -> Option<Self>;
1709}
1710
1711impl MulF32 for CSSNumber {
1712 #[inline]
1713 fn mul_f32(self, rhs: f32) -> Self {
1714 self * rhs
1715 }
1716}
1717
1718