diff options
author | Emilio Cobos Álvarez <emilio@crisal.io> | 2019-04-09 09:37:26 +0000 |
---|---|---|
committer | Emilio Cobos Álvarez <emilio@crisal.io> | 2019-04-12 12:20:04 +0200 |
commit | c3ab3f0963da8f4476c1840ff56aa029f8336fac (patch) | |
tree | 8e466f48ff7be7a255f2d3724598412a289bce3c /components/style_derive/to_computed_value.rs | |
parent | ae32e4df40747c60605f64e6db1edb2e75635f08 (diff) | |
download | servo-c3ab3f0963da8f4476c1840ff56aa029f8336fac.tar.gz servo-c3ab3f0963da8f4476c1840ff56aa029f8336fac.zip |
style: Share more code between ToAnimatedValue and ToComputedValue derive.
I'm going to add a ToResolvedValue, and I don't want to add more copy-pasta.
This shouldn't change behavior.
Differential Revision: https://phabricator.services.mozilla.com/D26289
Diffstat (limited to 'components/style_derive/to_computed_value.rs')
-rw-r--r-- | components/style_derive/to_computed_value.rs | 139 |
1 files changed, 91 insertions, 48 deletions
diff --git a/components/style_derive/to_computed_value.rs b/components/style_derive/to_computed_value.rs index 21efae17c66..87d4f8ba014 100644 --- a/components/style_derive/to_computed_value.rs +++ b/components/style_derive/to_computed_value.rs @@ -3,53 +3,70 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use derive_common::cg; -use proc_macro2::{Span, TokenStream}; -use syn::{DeriveInput, Ident}; -use synstructure::BindStyle; +use proc_macro2::TokenStream; +use syn::{DeriveInput, Ident, Path}; +use synstructure::{BindStyle, BindingInfo}; -pub fn derive(mut input: DeriveInput) -> TokenStream { +pub fn derive_to_value( + mut input: DeriveInput, + trait_path: Path, + output_type_name: Ident, + bind_style: BindStyle, + // Returns whether to apply the field bound for a given item. + mut field_bound: impl FnMut(&BindingInfo) -> bool, + // Returns a token stream of the form: trait_path::from_foo(#binding) + mut call_from: impl FnMut(&BindingInfo) -> TokenStream, + mut call_to: impl FnMut(&BindingInfo) -> TokenStream, + // Returns a tokenstream of the form: + // fn from_function_syntax(foobar) -> Baz { + // #first_arg + // } + // + // fn to_function_syntax(foobar) -> Baz { + // #second_arg + // } + 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 { let mut where_clause = input.generics.where_clause.take(); cg::propagate_clauses_to_output_type( &mut where_clause, &input.generics, - parse_quote!(crate::values::computed::ToComputedValue), - parse_quote!(ComputedValue), + &trait_path, + &output_type_name, ); let (to_body, from_body) = { let params = input.generics.type_params().collect::<Vec<_>>(); for param in ¶ms { cg::add_predicate( &mut where_clause, - parse_quote!(#param: crate::values::computed::ToComputedValue), + parse_quote!(#param: #trait_path), ); } - let to_body = cg::fmap_match(&input, BindStyle::Ref, |binding| { - let attrs = cg::parse_field_attrs::<ComputedValueAttrs>(&binding.ast()); - if attrs.field_bound { + let to_body = cg::fmap_match(&input, bind_style, |binding| { + if field_bound(&binding) { let ty = &binding.ast().ty; let output_type = cg::map_type_params( ty, ¶ms, - &mut |ident| parse_quote!(<#ident as crate::values::computed::ToComputedValue>::ComputedValue), + &mut |ident| parse_quote!(<#ident as #trait_path>::#output_type_name), ); cg::add_predicate( &mut where_clause, parse_quote!( - #ty: crate::values::computed::ToComputedValue<ComputedValue = #output_type> + #ty: #trait_path<#output_type_name = #output_type> ), ); } - quote! { - crate::values::computed::ToComputedValue::to_computed_value(#binding, context) - } + call_to(&binding) }); - let from_body = cg::fmap_match(&input, BindStyle::Ref, |binding| { - quote! { - crate::values::computed::ToComputedValue::from_computed_value(#binding) - } + let from_body = cg::fmap_match(&input, bind_style, |binding| { + call_from(&binding) }); (to_body, from_body) @@ -58,39 +75,44 @@ pub fn derive(mut input: DeriveInput) -> TokenStream { input.generics.where_clause = where_clause; let name = &input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - if input.generics.type_params().next().is_none() { - return quote! { - impl #impl_generics crate::values::computed::ToComputedValue for #name #ty_generics - #where_clause - { - type ComputedValue = Self; - - #[inline] - fn to_computed_value( - &self, - _context: &crate::values::computed::Context, - ) -> Self::ComputedValue { - std::clone::Clone::clone(self) + if let Some(non_generic_implementation) = non_generic_implementation() { + return quote! { + impl #impl_generics #trait_path for #name #ty_generics + #where_clause + { + #non_generic_implementation } - - #[inline] - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - std::clone::Clone::clone(computed) - } - } - }; + }; + } } let computed_value_type = cg::fmap_trait_output( &input, - &parse_quote!(crate::values::computed::ToComputedValue), - Ident::new("ComputedValue", Span::call_site()), + &trait_path, + &output_type_name, ); + let impl_ = trait_impl(from_body, to_body); + quote! { - impl #impl_generics crate::values::computed::ToComputedValue for #name #ty_generics #where_clause { - type ComputedValue = #computed_value_type; + impl #impl_generics #trait_path for #name #ty_generics #where_clause { + type #output_type_name = #computed_value_type; + + #impl_ + } + } +} + +pub fn derive(input: DeriveInput) -> TokenStream { + let trait_impl = |from_body, to_body| { + quote! { + #[inline] + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + match *computed { + #from_body + } + } #[allow(unused_variables)] #[inline] @@ -99,15 +121,36 @@ pub fn derive(mut input: DeriveInput) -> TokenStream { #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 { - match *computed { - #from_body - } + std::clone::Clone::clone(computed) } - } - } + }) + }; + + derive_to_value( + input, + parse_quote!(crate::values::computed::ToComputedValue), + parse_quote!(ComputedValue), + BindStyle::Ref, + |binding| cg::parse_field_attrs::<ComputedValueAttrs>(&binding.ast()).field_bound, + |binding| quote!(crate::values::computed::ToComputedValue::from_computed_value(#binding)), + |binding| quote!(crate::values::computed::ToComputedValue::to_computed_value(#binding, context)), + trait_impl, + non_generic_implementation, + ) } #[darling(attributes(compute), default)] |