Auto merge of #18208 - servo:derive-all-the-things, r=emilio

Use darling and derive more things

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/18208)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-08-24 04:05:03 -05:00 committed by GitHub
commit d3c2017b23
10 changed files with 95 additions and 106 deletions

40
Cargo.lock generated
View file

@ -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"

View file

@ -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<Self, ()> {
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<SquaredDistance, ()> {
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<Self, ()> { Err(()) }
@ -2459,24 +2425,6 @@ impl ToAnimatedZero for TransformList {
}
}
impl<A, B> ToAnimatedZero for Either<A, B>
where
A: ToAnimatedZero,
B: ToAnimatedZero,
{
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
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<AnimatedRGBA, ComputedUrl>;

View file

@ -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),
}

View file

@ -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<A, B> {
/// The first value.
First(A),

View file

@ -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"

View file

@ -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::<AnimateAttrs>(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,
}

View file

@ -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<A>(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,

View file

@ -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::<AnimateAttrs>(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(()), };
}

View file

@ -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;
@ -18,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()

View file

@ -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(<ident...>)]` is supported for now"),
}
}
if nested.next().is_some() {
panic!("only `#[css()]` or `#[css(<ident>)]` 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::<CssAttrs>(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