mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
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:
commit
d3c2017b23
10 changed files with 95 additions and 106 deletions
|
@ -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>;
|
||||
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(()), };
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue