From 7d438cd816221d10d4cfe0f9a8a6c8019e77df0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 26 Mar 2020 13:04:20 +0000 Subject: [PATCH] style: Ensure that derived types are right for optimized-away implementations. We have this optimization where, for non-generic structs, we generate just a clone / move as the ToComputedValue / ToResolvedValue implementation. This moves the optimization a bit further down, and refines it so that we still generate all the relevant where clauses that make it sound, that is, that all the ToComputedValue implementations of the fields return the same type. Otherwise this wouldn't be sound and the type would need to become generic. We add an escape hatch (no_field_bound) for fields that need to be cloned but which don't implement the trait. This is right now only for the RefPtr<> in the shared font-family list, and a piece of code in PaintWorklet which looks kinda fishy, and probably should be fixed (but we don't ship it in Firefox and there's a pre-existing FIXME for servo, so I punted on it for now). The other thing this patch does is adding a bunch of ToComputedValue / ToResolvedValue implementations that are trivial and were missing. Differential Revision: https://phabricator.services.mozilla.com/D67913 --- components/style/counter_style/mod.rs | 4 +- .../style/gecko_string_cache/namespace.rs | 2 +- .../style/properties/properties.mako.rs | 4 +- components/style/values/computed/font.rs | 20 ++- components/style/values/computed/length.rs | 1 + components/style/values/computed/mod.rs | 44 ++++- components/style/values/generics/image.rs | 2 + components/style/values/resolved/mod.rs | 43 +++++ components/style/values/specified/align.rs | 2 +- components/style/values/specified/border.rs | 13 +- components/style/values/specified/font.rs | 30 ++-- components/style/values/specified/position.rs | 24 ++- components/style/values/specified/svg_path.rs | 11 +- components/style/values/specified/text.rs | 17 +- components/style_derive/to_animated_value.rs | 16 +- components/style_derive/to_computed_value.rs | 161 +++++++++++------- components/style_derive/to_resolved_value.rs | 39 ++--- components/style_traits/arc_slice.rs | 8 +- 18 files changed, 295 insertions(+), 146 deletions(-) diff --git a/components/style/counter_style/mod.rs b/components/style/counter_style/mod.rs index d131f350393..bffedd845e3 100644 --- a/components/style/counter_style/mod.rs +++ b/components/style/counter_style/mod.rs @@ -408,7 +408,7 @@ impl ToCss for System { } /// -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)] +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToCss, ToShmem)] #[repr(u8)] pub enum Symbol { /// @@ -554,7 +554,7 @@ impl Parse for Fallback { } /// -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)] +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToCss, ToShmem)] #[repr(C)] pub struct Symbols(#[css(iterable)] pub crate::OwnedSlice); diff --git a/components/style/gecko_string_cache/namespace.rs b/components/style/gecko_string_cache/namespace.rs index 2dba484e002..dd3b52d2506 100644 --- a/components/style/gecko_string_cache/namespace.rs +++ b/components/style/gecko_string_cache/namespace.rs @@ -24,7 +24,7 @@ macro_rules! ns { } /// A Gecko namespace is just a wrapped atom. -#[derive(Clone, Debug, Default, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)] +#[derive(Clone, Debug, Default, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] #[repr(transparent)] pub struct Namespace(pub Atom); diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index a232b275c88..c39dc6f23da 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -1044,7 +1044,7 @@ pub enum LogicalGroup { } /// An identifier for a given longhand property. -#[derive(Clone, Copy, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)] +#[derive(Clone, Copy, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] #[repr(u16)] pub enum LonghandId { % for i, property in enumerate(data.longhands): @@ -1353,7 +1353,7 @@ where } /// An identifier for a given shorthand property. -#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)] +#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] #[repr(u16)] pub enum ShorthandId { % for i, property in enumerate(data.shorthands): diff --git a/components/style/values/computed/font.rs b/components/style/values/computed/font.rs index 6d17f9fa699..bafcf620530 100644 --- a/components/style/values/computed/font.rs +++ b/components/style/values/computed/font.rs @@ -178,7 +178,7 @@ impl ToAnimatedValue for FontSize { } } -#[derive(Clone, Debug, Eq, PartialEq, ToResolvedValue)] +#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToResolvedValue)] #[cfg_attr(feature = "servo", derive(Hash, MallocSizeOf))] /// Specifies a prioritized list of font family names or generic family names. pub struct FontFamily { @@ -227,7 +227,7 @@ impl ToCss for FontFamily { } } -#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToResolvedValue, ToShmem)] +#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] /// The name of a font family of choice pub struct FamilyName { @@ -270,7 +270,7 @@ impl ToCss for FamilyName { } } -#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToResolvedValue, ToShmem)] +#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] /// Font family names must either be given quoted as strings, /// or unquoted as a sequence of one or more identifiers. @@ -285,7 +285,7 @@ pub enum FontFamilyNameSyntax { Identifiers, } -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToResolvedValue, ToShmem)] +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToComputedValue, ToResolvedValue, ToShmem)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize, Hash))] /// A set of faces that vary in weight, width or slope. pub enum SingleFontFamily { @@ -301,7 +301,7 @@ pub enum SingleFontFamily { /// `gfxPlatformFontList.h`s ranged array and `gfxFontFamilyList`'s /// sSingleGenerics are updated as well. #[derive( - Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, Parse, ToCss, ToResolvedValue, ToShmem, + Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, Parse, ToCss, ToComputedValue, ToResolvedValue, ToShmem, )] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[repr(u8)] @@ -427,16 +427,20 @@ impl SingleFontFamily { } #[cfg(feature = "servo")] -#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToResolvedValue, ToShmem)] +#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] /// A list of SingleFontFamily pub struct FontFamilyList(Box<[SingleFontFamily]>); #[cfg(feature = "gecko")] -#[derive(Clone, Debug)] +#[derive(Clone, Debug, ToComputedValue, ToResolvedValue)] /// A list of SingleFontFamily pub enum FontFamilyList { /// A strong reference to a Gecko SharedFontList object. - SharedFontList(RefPtr), + SharedFontList( + #[compute(no_field_bound)] + #[resolve(no_field_bound)] + RefPtr, + ), /// A font-family generic ID. Generic(GenericFontFamily), } diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index 9dac232d0d4..8c6dde8c738 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -203,6 +203,7 @@ impl Size { Serialize, ToAnimatedValue, ToAnimatedZero, + ToComputedValue, ToResolvedValue, ToShmem, )] diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 01bbfcf5cbd..ec9424468c9 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -21,10 +21,11 @@ use crate::media_queries::Device; use crate::properties; use crate::properties::{ComputedValues, LonghandId, StyleBuilder}; use crate::rule_cache::RuleCacheConditions; -use crate::Atom; +use crate::{ArcSlice, Atom}; #[cfg(feature = "servo")] use crate::Prefix; use euclid::default::Size2D; +use servo_arc::Arc; use std::cell::RefCell; use std::cmp; use std::f32; @@ -450,6 +451,46 @@ where } } +// NOTE(emilio): This is implementable more generically, but it's unlikely +// what you want there, as it forces you to have an extra allocation. +// +// We could do that if needed, ideally with specialization for the case where +// ComputedValue = T. But we don't need it for now. +impl ToComputedValue for Arc +where + T: ToComputedValue, +{ + type ComputedValue = Self; + + #[inline] + fn to_computed_value(&self, _: &Context) -> Self { + self.clone() + } + + #[inline] + fn from_computed_value(computed: &Self) -> Self { + computed.clone() + } +} + +// Same caveat as above applies. +impl ToComputedValue for ArcSlice +where + T: ToComputedValue, +{ + type ComputedValue = Self; + + #[inline] + fn to_computed_value(&self, _: &Context) -> Self { + self.clone() + } + + #[inline] + fn from_computed_value(computed: &Self) -> Self { + computed.clone() + } +} + trivial_to_computed_value!(()); trivial_to_computed_value!(bool); trivial_to_computed_value!(f32); @@ -464,6 +505,7 @@ trivial_to_computed_value!(Prefix); trivial_to_computed_value!(String); trivial_to_computed_value!(Box); trivial_to_computed_value!(crate::OwnedStr); +trivial_to_computed_value!(style_traits::values::specified::AllowedNumericType); #[allow(missing_docs)] #[derive( diff --git a/components/style/values/generics/image.rs b/components/style/values/generics/image.rs index dc64063ba08..9e70d68f3c7 100644 --- a/components/style/values/generics/image.rs +++ b/components/style/values/generics/image.rs @@ -237,6 +237,8 @@ pub struct PaintWorklet { /// The arguments for the worklet. /// TODO: store a parsed representation of the arguments. #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")] + #[compute(no_field_bound)] + #[resolve(no_field_bound)] pub arguments: Vec>, } diff --git a/components/style/values/resolved/mod.rs b/components/style/values/resolved/mod.rs index 022cb7893c6..633bcd47997 100644 --- a/components/style/values/resolved/mod.rs +++ b/components/style/values/resolved/mod.rs @@ -6,7 +6,9 @@ //! there are used values. use crate::properties::ComputedValues; +use crate::ArcSlice; use cssparser; +use servo_arc::Arc; use smallvec::SmallVec; mod color; @@ -79,6 +81,7 @@ trivial_to_resolved_value!(computed::url::ComputedImageUrl); #[cfg(feature = "servo")] trivial_to_resolved_value!(html5ever::Prefix); trivial_to_resolved_value!(computed::LengthPercentage); +trivial_to_resolved_value!(style_traits::values::specified::AllowedNumericType); impl ToResolvedValue for (A, B) where @@ -214,3 +217,43 @@ where Self::from(Box::from_resolved_value(resolved.into_box())) } } + +// NOTE(emilio): This is implementable more generically, but it's unlikely what +// you want there, as it forces you to have an extra allocation. +// +// We could do that if needed, ideally with specialization for the case where +// ResolvedValue = T. But we don't need it for now. +impl ToResolvedValue for Arc +where + T: ToResolvedValue, +{ + type ResolvedValue = Self; + + #[inline] + fn to_resolved_value(self, _: &Context) -> Self { + self + } + + #[inline] + fn from_resolved_value(resolved: Self) -> Self { + resolved + } +} + +// Same caveat as above applies. +impl ToResolvedValue for ArcSlice +where + T: ToResolvedValue, +{ + type ResolvedValue = Self; + + #[inline] + fn to_resolved_value(self, _: &Context) -> Self { + self + } + + #[inline] + fn from_resolved_value(resolved: Self) -> Self { + resolved + } +} diff --git a/components/style/values/specified/align.rs b/components/style/values/specified/align.rs index d0160a32ae6..10f7f3efbfc 100644 --- a/components/style/values/specified/align.rs +++ b/components/style/values/specified/align.rs @@ -556,7 +556,7 @@ impl SpecifiedValueInfo for AlignItems { /// Value of the `justify-items` property /// /// -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToShmem)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToResolvedValue, ToShmem)] #[repr(C)] pub struct JustifyItems(pub AlignFlags); diff --git a/components/style/values/specified/border.rs b/components/style/values/specified/border.rs index 1b1ed74d568..28be8177cf4 100644 --- a/components/style/values/specified/border.rs +++ b/components/style/values/specified/border.rs @@ -234,7 +234,18 @@ impl Parse for BorderSpacing { #[allow(missing_docs)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[derive( - Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem, + Clone, + Copy, + Debug, + Eq, + MallocSizeOf, + Parse, + PartialEq, + SpecifiedValueInfo, + ToComputedValue, + ToCss, + ToResolvedValue, + ToShmem, )] pub enum BorderImageRepeatKeyword { Stretch, diff --git a/components/style/values/specified/font.rs b/components/style/values/specified/font.rs index 94c28d068f9..dd9f9d3b86d 100644 --- a/components/style/values/specified/font.rs +++ b/components/style/values/specified/font.rs @@ -492,7 +492,9 @@ impl ToComputedValue for FontStretch { SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, + ToComputedValue, ToCss, + ToResolvedValue, ToShmem, )] #[allow(missing_docs)] @@ -534,7 +536,9 @@ impl Default for KeywordSize { PartialEq, ToAnimatedValue, ToAnimatedZero, + ToComputedValue, ToCss, + ToResolvedValue, ToShmem, )] /// Additional information for keyword-derived font sizes. @@ -567,7 +571,7 @@ impl KeywordInfo { /// Computes the final size for this font-size keyword, accounting for /// text-zoom. fn to_computed_value(&self, context: &Context) -> CSSPixelLength { - let base = context.maybe_zoom_text(self.kw.to_computed_value(context).0); + let base = context.maybe_zoom_text(self.kw.to_length(context).0); base * self.factor + context.maybe_zoom_text(self.offset) } @@ -760,11 +764,10 @@ const LARGER_FONT_SIZE_RATIO: f32 = 1.2; /// The default font size. pub const FONT_MEDIUM_PX: i32 = 16; -#[cfg(feature = "servo")] -impl ToComputedValue for KeywordSize { - type ComputedValue = NonNegativeLength; +impl KeywordSize { #[inline] - fn to_computed_value(&self, _: &Context) -> NonNegativeLength { + #[cfg(feature = "servo")] + fn to_length(&self, _: &Context) -> NonNegativeLength { let medium = Length::new(FONT_MEDIUM_PX as f32); // https://drafts.csswg.org/css-fonts-3/#font-size-prop NonNegative(match *self { @@ -779,17 +782,9 @@ impl ToComputedValue for KeywordSize { }) } + #[cfg(feature = "gecko")] #[inline] - fn from_computed_value(_: &NonNegativeLength) -> Self { - unreachable!() - } -} - -#[cfg(feature = "gecko")] -impl ToComputedValue for KeywordSize { - type ComputedValue = NonNegativeLength; - #[inline] - fn to_computed_value(&self, cx: &Context) -> NonNegativeLength { + fn to_length(&self, cx: &Context) -> NonNegativeLength { use crate::context::QuirksMode; // The tables in this function are originally from @@ -857,11 +852,6 @@ impl ToComputedValue for KeywordSize { base_size * FONT_SIZE_FACTORS[html_size] as f32 / 100.0 }) } - - #[inline] - fn from_computed_value(_: &NonNegativeLength) -> Self { - unreachable!() - } } impl FontSize { diff --git a/components/style/values/specified/position.rs b/components/style/values/specified/position.rs index 35385b75817..ae21e739973 100644 --- a/components/style/values/specified/position.rs +++ b/components/style/values/specified/position.rs @@ -539,7 +539,7 @@ impl TemplateAreas { Ok(TemplateAreas { areas: areas.into(), strings: strings.into(), - width: width, + width, }) } } @@ -589,7 +589,16 @@ impl Parse for TemplateAreasArc { /// A range of rows or columns. Using this instead of std::ops::Range for FFI /// purposes. #[repr(C)] -#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToShmem)] +#[derive( + Clone, + Debug, + MallocSizeOf, + PartialEq, + SpecifiedValueInfo, + ToComputedValue, + ToResolvedValue, + ToShmem, +)] pub struct UnsignedRange { /// The start of the range. pub start: u32, @@ -597,7 +606,16 @@ pub struct UnsignedRange { pub end: u32, } -#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToShmem)] +#[derive( + Clone, + Debug, + MallocSizeOf, + PartialEq, + SpecifiedValueInfo, + ToComputedValue, + ToResolvedValue, + ToShmem, +)] #[repr(C)] /// Not associated with any particular grid item, but can be referenced from the /// grid-placement properties. diff --git a/components/style/values/specified/svg_path.rs b/components/style/values/specified/svg_path.rs index 288f396b73c..edd2a10ba4b 100644 --- a/components/style/values/specified/svg_path.rs +++ b/components/style/values/specified/svg_path.rs @@ -35,7 +35,8 @@ use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; pub struct SVGPathData( // TODO(emilio): Should probably measure this somehow only from the // specified values. - #[ignore_malloc_size_of = "Arc"] pub crate::ArcSlice, + #[ignore_malloc_size_of = "Arc"] + pub crate::ArcSlice, ); impl SVGPathData { @@ -159,6 +160,8 @@ impl ComputeSquaredDistance for SVGPathData { Serialize, SpecifiedValueInfo, ToAnimatedZero, + ToComputedValue, + ToResolvedValue, ToShmem, )] #[allow(missing_docs)] @@ -488,6 +491,8 @@ impl ToCss for PathCommand { Serialize, SpecifiedValueInfo, ToAnimatedZero, + ToComputedValue, + ToResolvedValue, ToShmem, )] #[repr(u8)] @@ -518,7 +523,9 @@ impl IsAbsolute { Serialize, SpecifiedValueInfo, ToAnimatedZero, + ToComputedValue, ToCss, + ToResolvedValue, ToShmem, )] #[repr(C)] @@ -534,7 +541,7 @@ impl CoordPair { /// The EllipticalArc flag type. #[derive( - Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, SpecifiedValueInfo, ToShmem, + Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem, )] #[repr(C)] pub struct ArcFlag(bool); diff --git a/components/style/values/specified/text.rs b/components/style/values/specified/text.rs index 8f9a9bcb1cd..2a86cdbbc78 100644 --- a/components/style/values/specified/text.rs +++ b/components/style/values/specified/text.rs @@ -122,7 +122,7 @@ impl ToComputedValue for LineHeight { } /// A generic value for the `text-overflow` property. -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, ToResolvedValue, ToShmem)] #[repr(C, u8)] pub enum TextOverflowSide { /// Clip inline content. @@ -687,7 +687,7 @@ pub enum TextEmphasisStyle { } /// Fill mode for the text-emphasis-style property -#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] +#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToComputedValue, ToResolvedValue, ToShmem)] #[repr(u8)] pub enum TextEmphasisFillMode { /// `filled` @@ -706,7 +706,18 @@ impl TextEmphasisFillMode { /// Shape keyword for the text-emphasis-style property #[derive( - Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem, + Clone, + Copy, + Debug, + Eq, + MallocSizeOf, + Parse, + PartialEq, + SpecifiedValueInfo, + ToCss, + ToComputedValue, + ToResolvedValue, + ToShmem, )] #[repr(u8)] pub enum TextEmphasisShapeKeyword { diff --git a/components/style_derive/to_animated_value.rs b/components/style_derive/to_animated_value.rs index 51a73cbf4e1..45282f0c448 100644 --- a/components/style_derive/to_animated_value.rs +++ b/components/style_derive/to_animated_value.rs @@ -11,33 +11,25 @@ pub fn derive(input: DeriveInput) -> TokenStream { let trait_impl = |from_body, to_body| { quote! { #[inline] - fn from_animated_value(animated: Self::AnimatedValue) -> Self { - match animated { - #from_body - } + fn from_animated_value(from: Self::AnimatedValue) -> Self { + #from_body } #[inline] fn to_animated_value(self) -> Self::AnimatedValue { - match self { - #to_body - } + #to_body } } }; - // TODO(emilio): Consider optimizing away non-generic cases as well? - let non_generic_implementation = || None; - to_computed_value::derive_to_value( input, parse_quote!(crate::values::animated::ToAnimatedValue), parse_quote!(AnimatedValue), BindStyle::Move, - |_| false, + |_| Default::default(), |binding| quote!(crate::values::animated::ToAnimatedValue::from_animated_value(#binding)), |binding| quote!(crate::values::animated::ToAnimatedValue::to_animated_value(#binding)), trait_impl, - non_generic_implementation, ) } diff --git a/components/style_derive/to_computed_value.rs b/components/style_derive/to_computed_value.rs index ed6e07a2f5a..a109ffb1752 100644 --- a/components/style_derive/to_computed_value.rs +++ b/components/style_derive/to_computed_value.rs @@ -13,7 +13,7 @@ pub fn derive_to_value( output_type_name: Ident, bind_style: BindStyle, // Returns whether to apply the field bound for a given item. - mut field_bound: impl FnMut(&BindingInfo) -> bool, + mut binding_attrs: impl FnMut(&BindingInfo) -> ToValueAttrs, // Returns a token stream of the form: trait_path::from_foo(#binding) mut call_from: impl FnMut(&BindingInfo) -> TokenStream, mut call_to: impl FnMut(&BindingInfo) -> TokenStream, @@ -26,25 +26,9 @@ pub fn derive_to_value( // #second_arg // } mut trait_impl: impl FnMut(TokenStream, TokenStream) -> TokenStream, - // if this is provided, the derive for non-generic types will be simplified - // to this token stream, which should be the body of the impl block. - non_generic_implementation: impl FnOnce() -> Option, ) -> TokenStream { let name = &input.ident; - if input.generics.type_params().next().is_none() { - if let Some(non_generic_implementation) = non_generic_implementation() { - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - return quote! { - impl #impl_generics #trait_path for #name #ty_generics - #where_clause - { - #non_generic_implementation - } - }; - } - } - let mut where_clause = input.generics.where_clause.take(); cg::propagate_clauses_to_output_type( &mut where_clause, @@ -52,33 +36,96 @@ pub fn derive_to_value( &trait_path, &output_type_name, ); - let (to_body, from_body) = { - let params = input.generics.type_params().collect::>(); - for param in ¶ms { - cg::add_predicate(&mut where_clause, parse_quote!(#param: #trait_path)); + + let moves = match bind_style { + BindStyle::Move | BindStyle::MoveMut => true, + BindStyle::Ref | BindStyle::RefMut => false, + }; + + let params = input.generics.type_params().collect::>(); + for param in ¶ms { + cg::add_predicate(&mut where_clause, parse_quote!(#param: #trait_path)); + } + + let mut add_field_bound = |binding: &BindingInfo| { + let ty = &binding.ast().ty; + + let output_type = cg::map_type_params( + ty, + ¶ms, + &mut |ident| parse_quote!(<#ident as #trait_path>::#output_type_name), + ); + + cg::add_predicate( + &mut where_clause, + parse_quote!( + #ty: #trait_path<#output_type_name = #output_type> + ), + ); + }; + + let (to_body, from_body) = if params.is_empty() { + let mut s = synstructure::Structure::new(&input); + s.variants_mut().iter_mut().for_each(|v| { + v.bind_with(|_| bind_style); + }); + + for variant in s.variants() { + for binding in variant.bindings() { + let attrs = binding_attrs(&binding); + assert!( + !attrs.field_bound, + "It is default on a non-generic implementation", + ); + if !attrs.no_field_bound { + // Add field bounds to all bindings except the manually + // excluded. This ensures the correctness of the clone() / + // move based implementation. + add_field_bound(binding); + } + } } + let to_body = if moves { + quote! { self } + } else { + quote! { std::clone::Clone::clone(self) } + }; + + let from_body = if moves { + quote! { from } + } else { + quote! { std::clone::Clone::clone(from) } + }; + + (to_body, from_body) + } else { let to_body = cg::fmap_match(&input, bind_style, |binding| { - if field_bound(&binding) { - let ty = &binding.ast().ty; - - let output_type = cg::map_type_params( - ty, - ¶ms, - &mut |ident| parse_quote!(<#ident as #trait_path>::#output_type_name), - ); - - cg::add_predicate( - &mut where_clause, - parse_quote!( - #ty: #trait_path<#output_type_name = #output_type> - ), - ); + let attrs = binding_attrs(&binding); + assert!(!attrs.no_field_bound, "It doesn't make sense on a generic implementation"); + if attrs.field_bound { + add_field_bound(&binding); } call_to(&binding) }); + let from_body = cg::fmap_match(&input, bind_style, |binding| call_from(&binding)); + let self_ = if moves { quote! { self } } else { quote! { *self } }; + let from_ = if moves { quote! { from } } else { quote! { *from } }; + + let to_body = quote! { + match #self_ { + #to_body + } + }; + + let from_body = quote! { + match #from_ { + #from_body + } + }; + (to_body, from_body) }; @@ -101,53 +148,45 @@ pub fn derive(input: DeriveInput) -> TokenStream { let trait_impl = |from_body, to_body| { quote! { #[inline] - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - match *computed { - #from_body - } + fn from_computed_value(from: &Self::ComputedValue) -> Self { + #from_body } #[allow(unused_variables)] #[inline] fn to_computed_value(&self, context: &crate::values::computed::Context) -> Self::ComputedValue { - match *self { - #to_body - } + #to_body } } }; - let non_generic_implementation = || { - Some(quote! { - type ComputedValue = Self; - - #[inline] - fn to_computed_value(&self, _: &crate::values::computed::Context) -> Self::ComputedValue { - std::clone::Clone::clone(self) - } - - #[inline] - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - std::clone::Clone::clone(computed) - } - }) - }; - derive_to_value( input, parse_quote!(crate::values::computed::ToComputedValue), parse_quote!(ComputedValue), BindStyle::Ref, - |binding| cg::parse_field_attrs::(&binding.ast()).field_bound, + |binding| { + let attrs = cg::parse_field_attrs::(&binding.ast()); + ToValueAttrs { + field_bound: attrs.field_bound, + no_field_bound: attrs.no_field_bound, + } + }, |binding| quote!(crate::values::computed::ToComputedValue::from_computed_value(#binding)), |binding| quote!(crate::values::computed::ToComputedValue::to_computed_value(#binding, context)), trait_impl, - non_generic_implementation, ) } +#[derive(Default)] +pub struct ToValueAttrs { + pub field_bound: bool, + pub no_field_bound: bool, +} + #[darling(attributes(compute), default)] #[derive(Default, FromField)] struct ComputedValueAttrs { field_bound: bool, + no_field_bound: bool, } diff --git a/components/style_derive/to_resolved_value.rs b/components/style_derive/to_resolved_value.rs index 040cda954a8..f7ba2645e89 100644 --- a/components/style_derive/to_resolved_value.rs +++ b/components/style_derive/to_resolved_value.rs @@ -12,10 +12,8 @@ pub fn derive(input: DeriveInput) -> TokenStream { let trait_impl = |from_body, to_body| { quote! { #[inline] - fn from_resolved_value(resolved: Self::ResolvedValue) -> Self { - match resolved { - #from_body - } + fn from_resolved_value(from: Self::ResolvedValue) -> Self { + #from_body } #[inline] @@ -23,42 +21,26 @@ pub fn derive(input: DeriveInput) -> TokenStream { self, context: &crate::values::resolved::Context, ) -> Self::ResolvedValue { - match self { - #to_body - } + #to_body } } }; - let non_generic_implementation = || { - Some(quote! { - type ResolvedValue = Self; - - #[inline] - fn from_resolved_value(resolved: Self::ResolvedValue) -> Self { - resolved - } - - #[inline] - fn to_resolved_value( - self, - context: &crate::values::resolved::Context, - ) -> Self { - self - } - }) - }; - to_computed_value::derive_to_value( input, parse_quote!(crate::values::resolved::ToResolvedValue), parse_quote!(ResolvedValue), BindStyle::Move, - |binding| cg::parse_field_attrs::(&binding.ast()).field_bound, + |binding| { + let attrs = cg::parse_field_attrs::(&binding.ast()); + to_computed_value::ToValueAttrs { + field_bound: attrs.field_bound, + no_field_bound: attrs.no_field_bound, + } + }, |binding| quote!(crate::values::resolved::ToResolvedValue::from_resolved_value(#binding)), |binding| quote!(crate::values::resolved::ToResolvedValue::to_resolved_value(#binding, context)), trait_impl, - non_generic_implementation, ) } @@ -66,4 +48,5 @@ pub fn derive(input: DeriveInput) -> TokenStream { #[derive(Default, FromField)] struct ResolvedValueAttrs { field_bound: bool, + no_field_bound: bool, } diff --git a/components/style_traits/arc_slice.rs b/components/style_traits/arc_slice.rs index f5d0c56e7fc..8d55beff3c5 100644 --- a/components/style_traits/arc_slice.rs +++ b/components/style_traits/arc_slice.rs @@ -26,7 +26,7 @@ const ARC_SLICE_CANARY: u64 = 0xf3f3f3f3f3f3f3f3; /// cbindgen:derive-eq=false /// cbindgen:derive-neq=false #[repr(C)] -#[derive(Clone, Debug, Eq, PartialEq, ToShmem)] +#[derive(Debug, Eq, PartialEq, ToShmem)] pub struct ArcSlice(#[shmem(field_bound)] ThinArc); impl Deref for ArcSlice { @@ -39,6 +39,12 @@ impl Deref for ArcSlice { } } +impl Clone for ArcSlice { + fn clone(&self) -> Self { + ArcSlice(self.0.clone()) + } +} + lazy_static! { // ThinArc doesn't support alignments greater than align_of::. static ref EMPTY_ARC_SLICE: ArcSlice = {