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
This commit is contained in:
Emilio Cobos Álvarez 2020-03-26 13:04:20 +00:00
parent 0514059618
commit 7d438cd816
18 changed files with 295 additions and 146 deletions

View file

@ -408,7 +408,7 @@ impl ToCss for System {
} }
/// <https://drafts.csswg.org/css-counter-styles/#typedef-symbol> /// <https://drafts.csswg.org/css-counter-styles/#typedef-symbol>
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)] #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToCss, ToShmem)]
#[repr(u8)] #[repr(u8)]
pub enum Symbol { pub enum Symbol {
/// <string> /// <string>
@ -554,7 +554,7 @@ impl Parse for Fallback {
} }
/// <https://drafts.csswg.org/css-counter-styles/#descdef-counter-style-symbols> /// <https://drafts.csswg.org/css-counter-styles/#descdef-counter-style-symbols>
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)] #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToCss, ToShmem)]
#[repr(C)] #[repr(C)]
pub struct Symbols(#[css(iterable)] pub crate::OwnedSlice<Symbol>); pub struct Symbols(#[css(iterable)] pub crate::OwnedSlice<Symbol>);

View file

@ -24,7 +24,7 @@ macro_rules! ns {
} }
/// A Gecko namespace is just a wrapped atom. /// 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)] #[repr(transparent)]
pub struct Namespace(pub Atom); pub struct Namespace(pub Atom);

View file

@ -1044,7 +1044,7 @@ pub enum LogicalGroup {
} }
/// An identifier for a given longhand property. /// 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)] #[repr(u16)]
pub enum LonghandId { pub enum LonghandId {
% for i, property in enumerate(data.longhands): % for i, property in enumerate(data.longhands):
@ -1353,7 +1353,7 @@ where
} }
/// An identifier for a given shorthand property. /// 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)] #[repr(u16)]
pub enum ShorthandId { pub enum ShorthandId {
% for i, property in enumerate(data.shorthands): % for i, property in enumerate(data.shorthands):

View file

@ -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))] #[cfg_attr(feature = "servo", derive(Hash, MallocSizeOf))]
/// Specifies a prioritized list of font family names or generic family names. /// Specifies a prioritized list of font family names or generic family names.
pub struct FontFamily { 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))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
/// The name of a font family of choice /// The name of a font family of choice
pub struct FamilyName { 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))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
/// Font family names must either be given quoted as strings, /// Font family names must either be given quoted as strings,
/// or unquoted as a sequence of one or more identifiers. /// or unquoted as a sequence of one or more identifiers.
@ -285,7 +285,7 @@ pub enum FontFamilyNameSyntax {
Identifiers, 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))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize, Hash))]
/// A set of faces that vary in weight, width or slope. /// A set of faces that vary in weight, width or slope.
pub enum SingleFontFamily { pub enum SingleFontFamily {
@ -301,7 +301,7 @@ pub enum SingleFontFamily {
/// `gfxPlatformFontList.h`s ranged array and `gfxFontFamilyList`'s /// `gfxPlatformFontList.h`s ranged array and `gfxFontFamilyList`'s
/// sSingleGenerics are updated as well. /// sSingleGenerics are updated as well.
#[derive( #[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))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[repr(u8)] #[repr(u8)]
@ -427,16 +427,20 @@ impl SingleFontFamily {
} }
#[cfg(feature = "servo")] #[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 /// A list of SingleFontFamily
pub struct FontFamilyList(Box<[SingleFontFamily]>); pub struct FontFamilyList(Box<[SingleFontFamily]>);
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
#[derive(Clone, Debug)] #[derive(Clone, Debug, ToComputedValue, ToResolvedValue)]
/// A list of SingleFontFamily /// A list of SingleFontFamily
pub enum FontFamilyList { pub enum FontFamilyList {
/// A strong reference to a Gecko SharedFontList object. /// A strong reference to a Gecko SharedFontList object.
SharedFontList(RefPtr<structs::SharedFontList>), SharedFontList(
#[compute(no_field_bound)]
#[resolve(no_field_bound)]
RefPtr<structs::SharedFontList>,
),
/// A font-family generic ID. /// A font-family generic ID.
Generic(GenericFontFamily), Generic(GenericFontFamily),
} }

View file

@ -203,6 +203,7 @@ impl Size {
Serialize, Serialize,
ToAnimatedValue, ToAnimatedValue,
ToAnimatedZero, ToAnimatedZero,
ToComputedValue,
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]

View file

@ -21,10 +21,11 @@ use crate::media_queries::Device;
use crate::properties; use crate::properties;
use crate::properties::{ComputedValues, LonghandId, StyleBuilder}; use crate::properties::{ComputedValues, LonghandId, StyleBuilder};
use crate::rule_cache::RuleCacheConditions; use crate::rule_cache::RuleCacheConditions;
use crate::Atom; use crate::{ArcSlice, Atom};
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
use crate::Prefix; use crate::Prefix;
use euclid::default::Size2D; use euclid::default::Size2D;
use servo_arc::Arc;
use std::cell::RefCell; use std::cell::RefCell;
use std::cmp; use std::cmp;
use std::f32; 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<T> ToComputedValue for Arc<T>
where
T: ToComputedValue<ComputedValue = T>,
{
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<T> ToComputedValue for ArcSlice<T>
where
T: ToComputedValue<ComputedValue = T>,
{
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!(());
trivial_to_computed_value!(bool); trivial_to_computed_value!(bool);
trivial_to_computed_value!(f32); trivial_to_computed_value!(f32);
@ -464,6 +505,7 @@ trivial_to_computed_value!(Prefix);
trivial_to_computed_value!(String); trivial_to_computed_value!(String);
trivial_to_computed_value!(Box<str>); trivial_to_computed_value!(Box<str>);
trivial_to_computed_value!(crate::OwnedStr); trivial_to_computed_value!(crate::OwnedStr);
trivial_to_computed_value!(style_traits::values::specified::AllowedNumericType);
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive( #[derive(

View file

@ -237,6 +237,8 @@ pub struct PaintWorklet {
/// The arguments for the worklet. /// The arguments for the worklet.
/// TODO: store a parsed representation of the arguments. /// TODO: store a parsed representation of the arguments.
#[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")] #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")]
#[compute(no_field_bound)]
#[resolve(no_field_bound)]
pub arguments: Vec<Arc<custom_properties::SpecifiedValue>>, pub arguments: Vec<Arc<custom_properties::SpecifiedValue>>,
} }

View file

@ -6,7 +6,9 @@
//! there are used values. //! there are used values.
use crate::properties::ComputedValues; use crate::properties::ComputedValues;
use crate::ArcSlice;
use cssparser; use cssparser;
use servo_arc::Arc;
use smallvec::SmallVec; use smallvec::SmallVec;
mod color; mod color;
@ -79,6 +81,7 @@ trivial_to_resolved_value!(computed::url::ComputedImageUrl);
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
trivial_to_resolved_value!(html5ever::Prefix); trivial_to_resolved_value!(html5ever::Prefix);
trivial_to_resolved_value!(computed::LengthPercentage); trivial_to_resolved_value!(computed::LengthPercentage);
trivial_to_resolved_value!(style_traits::values::specified::AllowedNumericType);
impl<A, B> ToResolvedValue for (A, B) impl<A, B> ToResolvedValue for (A, B)
where where
@ -214,3 +217,43 @@ where
Self::from(Box::from_resolved_value(resolved.into_box())) 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<T> ToResolvedValue for Arc<T>
where
T: ToResolvedValue<ResolvedValue = T>,
{
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<T> ToResolvedValue for ArcSlice<T>
where
T: ToResolvedValue<ResolvedValue = T>,
{
type ResolvedValue = Self;
#[inline]
fn to_resolved_value(self, _: &Context) -> Self {
self
}
#[inline]
fn from_resolved_value(resolved: Self) -> Self {
resolved
}
}

View file

@ -556,7 +556,7 @@ impl SpecifiedValueInfo for AlignItems {
/// Value of the `justify-items` property /// Value of the `justify-items` property
/// ///
/// <https://drafts.csswg.org/css-align/#justify-items-property> /// <https://drafts.csswg.org/css-align/#justify-items-property>
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToShmem)] #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToResolvedValue, ToShmem)]
#[repr(C)] #[repr(C)]
pub struct JustifyItems(pub AlignFlags); pub struct JustifyItems(pub AlignFlags);

View file

@ -234,7 +234,18 @@ impl Parse for BorderSpacing {
#[allow(missing_docs)] #[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive( #[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 { pub enum BorderImageRepeatKeyword {
Stretch, Stretch,

View file

@ -492,7 +492,9 @@ impl ToComputedValue for FontStretch {
SpecifiedValueInfo, SpecifiedValueInfo,
ToAnimatedValue, ToAnimatedValue,
ToAnimatedZero, ToAnimatedZero,
ToComputedValue,
ToCss, ToCss,
ToResolvedValue,
ToShmem, ToShmem,
)] )]
#[allow(missing_docs)] #[allow(missing_docs)]
@ -534,7 +536,9 @@ impl Default for KeywordSize {
PartialEq, PartialEq,
ToAnimatedValue, ToAnimatedValue,
ToAnimatedZero, ToAnimatedZero,
ToComputedValue,
ToCss, ToCss,
ToResolvedValue,
ToShmem, ToShmem,
)] )]
/// Additional information for keyword-derived font sizes. /// Additional information for keyword-derived font sizes.
@ -567,7 +571,7 @@ impl KeywordInfo {
/// Computes the final size for this font-size keyword, accounting for /// Computes the final size for this font-size keyword, accounting for
/// text-zoom. /// text-zoom.
fn to_computed_value(&self, context: &Context) -> CSSPixelLength { 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) 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. /// The default font size.
pub const FONT_MEDIUM_PX: i32 = 16; pub const FONT_MEDIUM_PX: i32 = 16;
#[cfg(feature = "servo")] impl KeywordSize {
impl ToComputedValue for KeywordSize {
type ComputedValue = NonNegativeLength;
#[inline] #[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); let medium = Length::new(FONT_MEDIUM_PX as f32);
// https://drafts.csswg.org/css-fonts-3/#font-size-prop // https://drafts.csswg.org/css-fonts-3/#font-size-prop
NonNegative(match *self { NonNegative(match *self {
@ -779,17 +782,9 @@ impl ToComputedValue for KeywordSize {
}) })
} }
#[inline]
fn from_computed_value(_: &NonNegativeLength) -> Self {
unreachable!()
}
}
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
impl ToComputedValue for KeywordSize {
type ComputedValue = NonNegativeLength;
#[inline] #[inline]
fn to_computed_value(&self, cx: &Context) -> NonNegativeLength { fn to_length(&self, cx: &Context) -> NonNegativeLength {
use crate::context::QuirksMode; use crate::context::QuirksMode;
// The tables in this function are originally from // 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 base_size * FONT_SIZE_FACTORS[html_size] as f32 / 100.0
}) })
} }
#[inline]
fn from_computed_value(_: &NonNegativeLength) -> Self {
unreachable!()
}
} }
impl FontSize { impl FontSize {

View file

@ -539,7 +539,7 @@ impl TemplateAreas {
Ok(TemplateAreas { Ok(TemplateAreas {
areas: areas.into(), areas: areas.into(),
strings: strings.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 /// A range of rows or columns. Using this instead of std::ops::Range for FFI
/// purposes. /// purposes.
#[repr(C)] #[repr(C)]
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToShmem)] #[derive(
Clone,
Debug,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToComputedValue,
ToResolvedValue,
ToShmem,
)]
pub struct UnsignedRange { pub struct UnsignedRange {
/// The start of the range. /// The start of the range.
pub start: u32, pub start: u32,
@ -597,7 +606,16 @@ pub struct UnsignedRange {
pub end: u32, pub end: u32,
} }
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToShmem)] #[derive(
Clone,
Debug,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToComputedValue,
ToResolvedValue,
ToShmem,
)]
#[repr(C)] #[repr(C)]
/// Not associated with any particular grid item, but can be referenced from the /// Not associated with any particular grid item, but can be referenced from the
/// grid-placement properties. /// grid-placement properties.

View file

@ -35,7 +35,8 @@ use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
pub struct SVGPathData( pub struct SVGPathData(
// TODO(emilio): Should probably measure this somehow only from the // TODO(emilio): Should probably measure this somehow only from the
// specified values. // specified values.
#[ignore_malloc_size_of = "Arc"] pub crate::ArcSlice<PathCommand>, #[ignore_malloc_size_of = "Arc"]
pub crate::ArcSlice<PathCommand>,
); );
impl SVGPathData { impl SVGPathData {
@ -159,6 +160,8 @@ impl ComputeSquaredDistance for SVGPathData {
Serialize, Serialize,
SpecifiedValueInfo, SpecifiedValueInfo,
ToAnimatedZero, ToAnimatedZero,
ToComputedValue,
ToResolvedValue,
ToShmem, ToShmem,
)] )]
#[allow(missing_docs)] #[allow(missing_docs)]
@ -488,6 +491,8 @@ impl ToCss for PathCommand {
Serialize, Serialize,
SpecifiedValueInfo, SpecifiedValueInfo,
ToAnimatedZero, ToAnimatedZero,
ToComputedValue,
ToResolvedValue,
ToShmem, ToShmem,
)] )]
#[repr(u8)] #[repr(u8)]
@ -518,7 +523,9 @@ impl IsAbsolute {
Serialize, Serialize,
SpecifiedValueInfo, SpecifiedValueInfo,
ToAnimatedZero, ToAnimatedZero,
ToComputedValue,
ToCss, ToCss,
ToResolvedValue,
ToShmem, ToShmem,
)] )]
#[repr(C)] #[repr(C)]
@ -534,7 +541,7 @@ impl CoordPair {
/// The EllipticalArc flag type. /// The EllipticalArc flag type.
#[derive( #[derive(
Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, SpecifiedValueInfo, ToShmem, Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem,
)] )]
#[repr(C)] #[repr(C)]
pub struct ArcFlag(bool); pub struct ArcFlag(bool);

View file

@ -122,7 +122,7 @@ impl ToComputedValue for LineHeight {
} }
/// A generic value for the `text-overflow` property. /// 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)] #[repr(C, u8)]
pub enum TextOverflowSide { pub enum TextOverflowSide {
/// Clip inline content. /// Clip inline content.
@ -687,7 +687,7 @@ pub enum TextEmphasisStyle {
} }
/// Fill mode for the text-emphasis-style property /// 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)] #[repr(u8)]
pub enum TextEmphasisFillMode { pub enum TextEmphasisFillMode {
/// `filled` /// `filled`
@ -706,7 +706,18 @@ impl TextEmphasisFillMode {
/// Shape keyword for the text-emphasis-style property /// Shape keyword for the text-emphasis-style property
#[derive( #[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)] #[repr(u8)]
pub enum TextEmphasisShapeKeyword { pub enum TextEmphasisShapeKeyword {

View file

@ -11,33 +11,25 @@ pub fn derive(input: DeriveInput) -> TokenStream {
let trait_impl = |from_body, to_body| { let trait_impl = |from_body, to_body| {
quote! { quote! {
#[inline] #[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self { fn from_animated_value(from: Self::AnimatedValue) -> Self {
match animated {
#from_body #from_body
} }
}
#[inline] #[inline]
fn to_animated_value(self) -> Self::AnimatedValue { 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( to_computed_value::derive_to_value(
input, input,
parse_quote!(crate::values::animated::ToAnimatedValue), parse_quote!(crate::values::animated::ToAnimatedValue),
parse_quote!(AnimatedValue), parse_quote!(AnimatedValue),
BindStyle::Move, BindStyle::Move,
|_| false, |_| Default::default(),
|binding| quote!(crate::values::animated::ToAnimatedValue::from_animated_value(#binding)), |binding| quote!(crate::values::animated::ToAnimatedValue::from_animated_value(#binding)),
|binding| quote!(crate::values::animated::ToAnimatedValue::to_animated_value(#binding)), |binding| quote!(crate::values::animated::ToAnimatedValue::to_animated_value(#binding)),
trait_impl, trait_impl,
non_generic_implementation,
) )
} }

View file

@ -13,7 +13,7 @@ pub fn derive_to_value(
output_type_name: Ident, output_type_name: Ident,
bind_style: BindStyle, bind_style: BindStyle,
// Returns whether to apply the field bound for a given item. // 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) // Returns a token stream of the form: trait_path::from_foo(#binding)
mut call_from: impl FnMut(&BindingInfo) -> TokenStream, mut call_from: impl FnMut(&BindingInfo) -> TokenStream,
mut call_to: impl FnMut(&BindingInfo) -> TokenStream, mut call_to: impl FnMut(&BindingInfo) -> TokenStream,
@ -26,25 +26,9 @@ pub fn derive_to_value(
// #second_arg // #second_arg
// } // }
mut trait_impl: impl FnMut(TokenStream, TokenStream) -> TokenStream, 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>,
) -> TokenStream { ) -> TokenStream {
let name = &input.ident; 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(); let mut where_clause = input.generics.where_clause.take();
cg::propagate_clauses_to_output_type( cg::propagate_clauses_to_output_type(
&mut where_clause, &mut where_clause,
@ -52,14 +36,18 @@ pub fn derive_to_value(
&trait_path, &trait_path,
&output_type_name, &output_type_name,
); );
let (to_body, from_body) = {
let moves = match bind_style {
BindStyle::Move | BindStyle::MoveMut => true,
BindStyle::Ref | BindStyle::RefMut => false,
};
let params = input.generics.type_params().collect::<Vec<_>>(); let params = input.generics.type_params().collect::<Vec<_>>();
for param in &params { for param in &params {
cg::add_predicate(&mut where_clause, parse_quote!(#param: #trait_path)); cg::add_predicate(&mut where_clause, parse_quote!(#param: #trait_path));
} }
let to_body = cg::fmap_match(&input, bind_style, |binding| { let mut add_field_bound = |binding: &BindingInfo| {
if field_bound(&binding) {
let ty = &binding.ast().ty; let ty = &binding.ast().ty;
let output_type = cg::map_type_params( let output_type = cg::map_type_params(
@ -74,11 +62,70 @@ pub fn derive_to_value(
#ty: #trait_path<#output_type_name = #output_type> #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| {
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) call_to(&binding)
}); });
let from_body = cg::fmap_match(&input, bind_style, |binding| call_from(&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) (to_body, from_body)
}; };
@ -101,36 +148,16 @@ pub fn derive(input: DeriveInput) -> TokenStream {
let trait_impl = |from_body, to_body| { let trait_impl = |from_body, to_body| {
quote! { quote! {
#[inline] #[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self { fn from_computed_value(from: &Self::ComputedValue) -> Self {
match *computed {
#from_body #from_body
} }
}
#[allow(unused_variables)] #[allow(unused_variables)]
#[inline] #[inline]
fn to_computed_value(&self, context: &crate::values::computed::Context) -> Self::ComputedValue { 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( derive_to_value(
@ -138,16 +165,28 @@ pub fn derive(input: DeriveInput) -> TokenStream {
parse_quote!(crate::values::computed::ToComputedValue), parse_quote!(crate::values::computed::ToComputedValue),
parse_quote!(ComputedValue), parse_quote!(ComputedValue),
BindStyle::Ref, BindStyle::Ref,
|binding| cg::parse_field_attrs::<ComputedValueAttrs>(&binding.ast()).field_bound, |binding| {
let attrs = cg::parse_field_attrs::<ComputedValueAttrs>(&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::from_computed_value(#binding)),
|binding| quote!(crate::values::computed::ToComputedValue::to_computed_value(#binding, context)), |binding| quote!(crate::values::computed::ToComputedValue::to_computed_value(#binding, context)),
trait_impl, trait_impl,
non_generic_implementation,
) )
} }
#[derive(Default)]
pub struct ToValueAttrs {
pub field_bound: bool,
pub no_field_bound: bool,
}
#[darling(attributes(compute), default)] #[darling(attributes(compute), default)]
#[derive(Default, FromField)] #[derive(Default, FromField)]
struct ComputedValueAttrs { struct ComputedValueAttrs {
field_bound: bool, field_bound: bool,
no_field_bound: bool,
} }

View file

@ -12,41 +12,18 @@ pub fn derive(input: DeriveInput) -> TokenStream {
let trait_impl = |from_body, to_body| { let trait_impl = |from_body, to_body| {
quote! { quote! {
#[inline] #[inline]
fn from_resolved_value(resolved: Self::ResolvedValue) -> Self { fn from_resolved_value(from: Self::ResolvedValue) -> Self {
match resolved {
#from_body #from_body
} }
}
#[inline] #[inline]
fn to_resolved_value( fn to_resolved_value(
self, self,
context: &crate::values::resolved::Context, context: &crate::values::resolved::Context,
) -> Self::ResolvedValue { ) -> 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( to_computed_value::derive_to_value(
@ -54,11 +31,16 @@ pub fn derive(input: DeriveInput) -> TokenStream {
parse_quote!(crate::values::resolved::ToResolvedValue), parse_quote!(crate::values::resolved::ToResolvedValue),
parse_quote!(ResolvedValue), parse_quote!(ResolvedValue),
BindStyle::Move, BindStyle::Move,
|binding| cg::parse_field_attrs::<ResolvedValueAttrs>(&binding.ast()).field_bound, |binding| {
let attrs = cg::parse_field_attrs::<ResolvedValueAttrs>(&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::from_resolved_value(#binding)),
|binding| quote!(crate::values::resolved::ToResolvedValue::to_resolved_value(#binding, context)), |binding| quote!(crate::values::resolved::ToResolvedValue::to_resolved_value(#binding, context)),
trait_impl, trait_impl,
non_generic_implementation,
) )
} }
@ -66,4 +48,5 @@ pub fn derive(input: DeriveInput) -> TokenStream {
#[derive(Default, FromField)] #[derive(Default, FromField)]
struct ResolvedValueAttrs { struct ResolvedValueAttrs {
field_bound: bool, field_bound: bool,
no_field_bound: bool,
} }

View file

@ -26,7 +26,7 @@ const ARC_SLICE_CANARY: u64 = 0xf3f3f3f3f3f3f3f3;
/// cbindgen:derive-eq=false /// cbindgen:derive-eq=false
/// cbindgen:derive-neq=false /// cbindgen:derive-neq=false
#[repr(C)] #[repr(C)]
#[derive(Clone, Debug, Eq, PartialEq, ToShmem)] #[derive(Debug, Eq, PartialEq, ToShmem)]
pub struct ArcSlice<T>(#[shmem(field_bound)] ThinArc<u64, T>); pub struct ArcSlice<T>(#[shmem(field_bound)] ThinArc<u64, T>);
impl<T> Deref for ArcSlice<T> { impl<T> Deref for ArcSlice<T> {
@ -39,6 +39,12 @@ impl<T> Deref for ArcSlice<T> {
} }
} }
impl<T> Clone for ArcSlice<T> {
fn clone(&self) -> Self {
ArcSlice(self.0.clone())
}
}
lazy_static! { lazy_static! {
// ThinArc doesn't support alignments greater than align_of::<u64>. // ThinArc doesn't support alignments greater than align_of::<u64>.
static ref EMPTY_ARC_SLICE: ArcSlice<u64> = { static ref EMPTY_ARC_SLICE: ArcSlice<u64> = {