diff options
-rw-r--r-- | components/style/values/animated/mod.rs | 3 | ||||
-rw-r--r-- | components/style_derive/animate.rs | 41 |
2 files changed, 28 insertions, 16 deletions
diff --git a/components/style/values/animated/mod.rs b/components/style/values/animated/mod.rs index a4e79074ef6..00410e177fb 100644 --- a/components/style/values/animated/mod.rs +++ b/components/style/values/animated/mod.rs @@ -113,7 +113,8 @@ pub fn animate_multiplicative_factor( /// function has been specified through `#[animate(fallback)]`. /// /// Trait bounds for type parameter `Foo` can be opted out of with -/// `#[animation(no_bound(Foo))]` on the type definition. +/// `#[animation(no_bound(Foo))]` on the type definition, trait bounds for +/// fields can be opted into with `#[animation(field_bound)]` on the field. pub trait Animate: Sized { /// Animate a value towards another one, given an animation procedure. fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()>; diff --git a/components/style_derive/animate.rs b/components/style_derive/animate.rs index 905b0ad0e1f..6686d2f4453 100644 --- a/components/style_derive/animate.rs +++ b/components/style_derive/animate.rs @@ -6,7 +6,7 @@ use crate::cg; use darling::util::IdentList; use proc_macro2::TokenStream; use quote::TokenStreamExt; -use syn::{DeriveInput, Path}; +use syn::{DeriveInput, Path, WhereClause}; use synstructure::{Structure, VariantInfo}; pub fn derive(mut input: DeriveInput) -> TokenStream { @@ -21,21 +21,24 @@ pub fn derive(mut input: DeriveInput) -> TokenStream { ); } } - input.generics.where_clause = where_clause; + let (mut match_body, append_error_clause) = { + let s = Structure::new(&input); + let mut append_error_clause = s.variants().len() > 1; - let s = Structure::new(&input); - let mut append_error_clause = s.variants().len() > 1; + let mut match_body = s.variants().iter().fold(quote!(), |body, variant| { + let arm = match derive_variant_arm(variant, &mut where_clause) { + Ok(arm) => arm, + Err(()) => { + append_error_clause = true; + return body; + }, + }; + quote! { #body #arm } + }); + (match_body, append_error_clause) + }; - let mut match_body = s.variants().iter().fold(quote!(), |body, variant| { - let arm = match derive_variant_arm(variant) { - Ok(arm) => arm, - Err(()) => { - append_error_clause = true; - return body; - }, - }; - quote! { #body #arm } - }); + input.generics.where_clause = where_clause; if append_error_clause { let input_attrs = cg::parse_input_attrs::<AnimateInputAttrs>(&input); @@ -68,7 +71,10 @@ pub fn derive(mut input: DeriveInput) -> TokenStream { } } -fn derive_variant_arm(variant: &VariantInfo) -> Result<TokenStream, ()> { +fn derive_variant_arm( + variant: &VariantInfo, + where_clause: &mut Option<WhereClause>, +) -> Result<TokenStream, ()> { let variant_attrs = cg::parse_variant_attrs_from_ast::<AnimationVariantAttrs>(&variant.ast()); if variant_attrs.error { return Err(()); @@ -80,6 +86,10 @@ fn derive_variant_arm(variant: &VariantInfo) -> Result<TokenStream, ()> { let iter = result_info.iter().zip(this_info.iter().zip(&other_info)); computations.append_all(iter.map(|(result, (this, other))| { let field_attrs = cg::parse_field_attrs::<AnimationFieldAttrs>(&result.ast()); + if field_attrs.field_bound { + let ty = &this.ast().ty; + cg::add_predicate(where_clause, parse_quote!(#ty: crate::values::animated::Animate)); + } if field_attrs.constant { quote! { if #this != #other { @@ -127,4 +137,5 @@ pub struct AnimationVariantAttrs { #[derive(Default, FromField)] pub struct AnimationFieldAttrs { pub constant: bool, + pub field_bound: bool, } |