From 49a5ceca9b94acea2ac7837ae67880b928c8cc6c Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 24 Aug 2017 00:48:42 +0200 Subject: [PATCH 1/3] Derive ToAnimatedZero for Either --- .../helpers/animated_properties.mako.rs | 18 ------------------ components/style/values/mod.rs | 2 +- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index f0c65e018d7..02a60d209b1 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -2459,24 +2459,6 @@ impl ToAnimatedZero for TransformList { } } -impl ToAnimatedZero for Either -where - A: ToAnimatedZero, - B: ToAnimatedZero, -{ - #[inline] - fn to_animated_zero(&self) -> Result { - match *self { - Either::First(ref first) => { - Ok(Either::First(first.to_animated_zero()?)) - }, - Either::Second(ref second) => { - Ok(Either::Second(second.to_animated_zero()?)) - }, - } - } -} - /// Animated SVGPaint pub type IntermediateSVGPaint = SVGPaint; diff --git a/components/style/values/mod.rs b/components/style/values/mod.rs index 46a520400a0..6c54e434808 100644 --- a/components/style/values/mod.rs +++ b/components/style/values/mod.rs @@ -69,7 +69,7 @@ impl Parse for Impossible { /// A struct representing one of two kinds of values. #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[derive(Animate, Clone, ComputeSquaredDistance, Copy, HasViewportPercentage)] -#[derive(PartialEq, ToAnimatedValue, ToComputedValue, ToCss)] +#[derive(PartialEq, ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)] pub enum Either { /// The first value. First(A), From 17d97cf87ba924e6b8d15a289c7120242630e2ae Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 24 Aug 2017 00:48:59 +0200 Subject: [PATCH 2/3] Use darling in style_derive This allows use to handle #[css] in a way simpler fashion. --- Cargo.lock | 40 +++++++++++++++++++++++ components/style_derive/Cargo.toml | 1 + components/style_derive/cg.rs | 11 +++++++ components/style_derive/lib.rs | 1 + components/style_derive/to_css.rs | 52 ++++++------------------------ 5 files changed, 63 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e37ba34e518..dfd50495139 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -615,6 +615,36 @@ dependencies = [ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "darling" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "darling_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "darling_macro 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "darling_core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ident_case 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "darling_macro" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "darling_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "dbghelp-sys" version = "0.2.0" @@ -1306,6 +1336,11 @@ dependencies = [ "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ident_case" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "idna" version = "0.1.2" @@ -3073,6 +3108,7 @@ dependencies = [ name = "style_derive" version = "0.0.1" dependencies = [ + "darling 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3711,6 +3747,9 @@ dependencies = [ "checksum core-text 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "16ce16d9ed00181016c11ff48e561314bec92bfbce9fe48f319366618d4e5de6" "checksum cssparser 0.19.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1f9442c00898020a56c9485d64c9c8f14ae30ba45be89d15846046593383467f" "checksum cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "079adec4af52bb5275eadd004292028c79eb3c5f5b4ee8086a36d4197032f6df" +"checksum darling 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9861a8495606435477df581bc858ccf15a3469747edf175b94a4704fd9aaedac" +"checksum darling_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1486a8b00b45062c997f767738178b43219133dd0c8c826cb811e60563810821" +"checksum darling_macro 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a86ec160aa0c3dd492dd4a14ec8104ad8f1a9400a820624db857998cc1f80f9" "checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" "checksum dbus 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4aee01fb76ada3e5e7ca642ea6664ebf7308a810739ca2aca44909a1191ac254" "checksum debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a032eac705ca39214d169f83e3d3da290af06d8d1d344d1baad2fd002dca4b3" @@ -3769,6 +3808,7 @@ dependencies = [ "checksum hyper 0.10.10 (registry+https://github.com/rust-lang/crates.io-index)" = "36e108e0b1fa2d17491cbaac4bc460dc0956029d10ccf83c913dd0e5db3e7f07" "checksum hyper-openssl 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "85a372eb692590b3fe014c196c30f9f52d4c42f58cd49dd94caeee1593c9cc37" "checksum hyper_serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbe43f514f80494e9329c9fc47d61b85b167d245685424637a0f4a409177e444" +"checksum ident_case 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c9826188e666f2ed92071d2dadef6edc430b11b158b5b2b3f4babbcc891eaaa" "checksum idna 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2233d4940b1f19f0418c158509cd7396b8d70a5db5705ce410914dc8fa603b37" "checksum image 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d95816db758249fe16f23a4e23f1a3a817fe11892dbfd1c5836f625324702158" "checksum immeta 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0b9260463a221bfe3f02100c56e2d14c050d5ffe7e44a43d0a1b2b1f2b523502" diff --git a/components/style_derive/Cargo.toml b/components/style_derive/Cargo.toml index 9a04197cd71..69a62535aaa 100644 --- a/components/style_derive/Cargo.toml +++ b/components/style_derive/Cargo.toml @@ -10,6 +10,7 @@ path = "lib.rs" proc-macro = true [dependencies] +darling = "0.2" quote = "0.3.15" syn = { version = "0.11", features = ["visit"] } synstructure = "0.5.2" diff --git a/components/style_derive/cg.rs b/components/style_derive/cg.rs index af60591d7c6..b670da16737 100644 --- a/components/style_derive/cg.rs +++ b/components/style_derive/cg.rs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use darling::FromVariant; use quote::Tokens; use std::borrow::Cow; use std::iter; @@ -136,6 +137,16 @@ where } } +pub fn parse_variant_attrs(variant: &Variant) -> A +where + A: FromVariant, +{ + match A::from_variant(variant) { + Ok(attrs) => attrs, + Err(e) => panic!("failed to parse attributes: {}", e), + } +} + pub fn ref_pattern<'a>( name: &Ident, variant: &'a Variant, diff --git a/components/style_derive/lib.rs b/components/style_derive/lib.rs index e2b10dc47aa..b49b4597315 100644 --- a/components/style_derive/lib.rs +++ b/components/style_derive/lib.rs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#[macro_use] extern crate darling; extern crate proc_macro; #[macro_use] extern crate quote; extern crate syn; diff --git a/components/style_derive/to_css.rs b/components/style_derive/to_css.rs index fbbccb5a493..444c42e37da 100644 --- a/components/style_derive/to_css.rs +++ b/components/style_derive/to_css.rs @@ -16,47 +16,8 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let style = synstructure::BindStyle::Ref.into(); let match_body = synstructure::each_variant(&input, &style, |bindings, variant| { let mut identifier = to_css_identifier(variant.ident.as_ref()); - let mut css_attrs = variant.attrs.iter().filter(|attr| attr.name() == "css"); - let (is_function, use_comma) = css_attrs.next().map_or((false, false), |attr| { - match attr.value { - syn::MetaItem::List(ref ident, ref items) if ident.as_ref() == "css" => { - let mut nested = items.iter(); - let mut is_function = false; - let mut use_comma = false; - for attr in nested.by_ref() { - match *attr { - syn::NestedMetaItem::MetaItem(syn::MetaItem::Word(ref ident)) => { - match ident.as_ref() { - "function" => { - if is_function { - panic!("repeated `#[css(function)]` attribute"); - } - is_function = true; - }, - "comma" => { - if use_comma { - panic!("repeated `#[css(comma)]` attribute"); - } - use_comma = true; - }, - _ => panic!("only `#[css(function | comma)]` is supported for now"), - } - }, - _ => panic!("only `#[css()]` is supported for now"), - } - } - if nested.next().is_some() { - panic!("only `#[css()]` or `#[css()]` is supported for now") - } - (is_function, use_comma) - }, - _ => panic!("only `#[css(...)]` is supported for now"), - } - }); - if css_attrs.next().is_some() { - panic!("only a single `#[css(...)]` attribute is supported for now"); - } - let separator = if use_comma { ", " } else { " " }; + let css_attrs = cg::parse_variant_attrs::(variant); + let separator = if css_attrs.comma { ", " } else { " " }; let mut expr = if !bindings.is_empty() { let mut expr = quote! {}; for binding in bindings { @@ -80,7 +41,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { ::std::fmt::Write::write_str(dest, #identifier) } }; - if is_function { + if css_attrs.function { identifier.push_str("("); expr = quote! { ::std::fmt::Write::write_str(dest, #identifier)?; @@ -107,6 +68,13 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { } } +#[derive(Default, FromVariant)] +#[darling(attributes(css), default)] +struct CssAttrs { + function: bool, + comma: bool, +} + /// Transforms "FooBar" to "foo-bar". /// /// If the first Camel segment is "Moz" or "Webkit", the result string From ff67fc751d8e1df9ee0c08199bc87501fb99ae5c Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 24 Aug 2017 01:25:57 +0200 Subject: [PATCH 3/3] Introduce #[animation] For now, only #[animation(error)] is supported on variants and it makes both #[derive(Animate)] and #[derive(ComputeSquaredDistance)] ignore this particular variant. --- .../helpers/animated_properties.mako.rs | 34 ------------------- .../style/properties/longhand/box.mako.rs | 5 +-- components/style_derive/animate.rs | 20 ++++++++--- .../style_derive/compute_squared_distance.rs | 13 +++++-- components/style_derive/lib.rs | 4 +-- 5 files changed, 31 insertions(+), 45 deletions(-) diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 02a60d209b1..2f7aaafc63d 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -787,40 +787,6 @@ impl ToAnimatedZero for Visibility { } } -/// https://drafts.csswg.org/css-transitions/#animtype-length -impl Animate for VerticalAlign { - #[inline] - fn animate(&self, other: &Self, procedure: Procedure) -> Result { - match (self, other) { - ( - &VerticalAlign::LengthOrPercentage(ref this), - &VerticalAlign::LengthOrPercentage(ref other), - ) => { - Ok(VerticalAlign::LengthOrPercentage( - this.animate(other, procedure)? - )) - }, - _ => Err(()), - } - } -} - -impl ComputeSquaredDistance for VerticalAlign { - #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result { - match (self, other) { - (&VerticalAlign::LengthOrPercentage(ref this), &VerticalAlign::LengthOrPercentage(ref other)) => { - this.compute_squared_distance(other) - }, - _ => { - // FIXME(nox): Should this return `Ok(SquaredDistance::Value(0.))` - // if `self` and `other` are the same keyword value? - Err(()) - }, - } - } -} - impl ToAnimatedZero for VerticalAlign { #[inline] fn to_animated_zero(&self) -> Result { Err(()) } diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index 659d8c69307..ae22a94dc4f 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -370,11 +370,12 @@ ${helpers.single_keyword("position", "static absolute relative fixed", /// The keywords are the same, and the `LengthOrPercentage` is computed /// here. #[allow(non_camel_case_types)] - #[derive(Clone, Copy, Debug, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] + #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq)] pub enum T { % for keyword in vertical_align_keywords: - ${to_rust_ident(keyword)}, + #[animation(error)] // only animatable as a length + ${to_rust_ident(keyword)}, % endfor LengthOrPercentage(computed::LengthOrPercentage), } diff --git a/components/style_derive/animate.rs b/components/style_derive/animate.rs index 888a5e61c8e..94d14336087 100644 --- a/components/style_derive/animate.rs +++ b/components/style_derive/animate.rs @@ -14,7 +14,13 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let variants = cg::variants(&input); let mut match_body = quote!(); - match_body.append_all(variants.iter().map(|variant| { + let mut append_error_clause = variants.len() > 1; + match_body.append_all(variants.iter().flat_map(|variant| { + let attrs = cg::parse_variant_attrs::(variant); + if attrs.error { + append_error_clause = true; + return None; + } let name = cg::variant_ctor(&input, variant); let (this_pattern, this_info) = cg::ref_pattern(&name, variant, "this"); let (other_pattern, other_info) = cg::ref_pattern(&name, variant, "other"); @@ -29,15 +35,15 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let #result = ::values::animated::Animate::animate(#this, #other, procedure)?; } })); - quote! { + Some(quote! { (&#this_pattern, &#other_pattern) => { #computations Ok(#result_value) } - } + }) })); - if variants.len() > 1 { + if append_error_clause { match_body = quote! { #match_body, _ => Err(()), }; } @@ -57,3 +63,9 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { } } } + +#[derive(Default, FromVariant)] +#[darling(attributes(animate), default)] +pub struct AnimateAttrs { + pub error: bool, +} diff --git a/components/style_derive/compute_squared_distance.rs b/components/style_derive/compute_squared_distance.rs index df02d1312cc..860e568ea88 100644 --- a/components/style_derive/compute_squared_distance.rs +++ b/components/style_derive/compute_squared_distance.rs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use animate::AnimateAttrs; use cg; use quote; use syn; @@ -14,7 +15,13 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let variants = cg::variants(&input); let mut match_body = quote!(); + let mut append_error_clause = variants.len() > 1; match_body.append_all(variants.iter().map(|variant| { + let attrs = cg::parse_variant_attrs::(variant); + if attrs.error { + append_error_clause = true; + return None; + } let name = cg::variant_ctor(&input, variant); let (this_pattern, this_info) = cg::ref_pattern(&name, &variant, "this"); let (other_pattern, other_info) = cg::ref_pattern(&name, &variant, "other"); @@ -32,14 +39,14 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { }), "+"); sum }; - quote! { + Some(quote! { (&#this_pattern, &#other_pattern) => { Ok(#sum) } - } + }) })); - if variants.len() > 1 { + if append_error_clause { match_body = quote! { #match_body, _ => Err(()), }; } diff --git a/components/style_derive/lib.rs b/components/style_derive/lib.rs index b49b4597315..e589759f813 100644 --- a/components/style_derive/lib.rs +++ b/components/style_derive/lib.rs @@ -19,13 +19,13 @@ mod to_animated_zero; mod to_computed_value; mod to_css; -#[proc_macro_derive(Animate)] +#[proc_macro_derive(Animate, attributes(animation))] pub fn derive_animate(stream: TokenStream) -> TokenStream { let input = syn::parse_derive_input(&stream.to_string()).unwrap(); animate::derive(input).to_string().parse().unwrap() } -#[proc_macro_derive(ComputeSquaredDistance)] +#[proc_macro_derive(ComputeSquaredDistance, attributes(animation))] pub fn derive_compute_squared_distance(stream: TokenStream) -> TokenStream { let input = syn::parse_derive_input(&stream.to_string()).unwrap(); compute_squared_distance::derive(input).to_string().parse().unwrap()