diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2017-08-23 10:01:15 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-23 10:01:15 -0500 |
commit | e629f8da7ba373f6575c2e9ccc6259b7f2c4e3e4 (patch) | |
tree | 841a4d436a7b0b27c42cfbdf024f3a8eb50bb55c | |
parent | 2e775abfa4563fc5db467c5c79f9d2507f6bb2e7 (diff) | |
parent | f2758950284610265b9245beed179c8729715a6b (diff) | |
download | servo-e629f8da7ba373f6575c2e9ccc6259b7f2c4e3e4.tar.gz servo-e629f8da7ba373f6575c2e9ccc6259b7f2c4e3e4.zip |
Auto merge of #18200 - servo:derive-all-the-things, r=emilio
Introduce style_derive::cg
<!-- 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/18200)
<!-- Reviewable:end -->
-rw-r--r-- | components/style_derive/animate.rs | 88 | ||||
-rw-r--r-- | components/style_derive/cg.rs | 219 | ||||
-rw-r--r-- | components/style_derive/compute_squared_distance.rs | 79 | ||||
-rw-r--r-- | components/style_derive/has_viewport_percentage.rs | 27 | ||||
-rw-r--r-- | components/style_derive/lib.rs | 1 | ||||
-rw-r--r-- | components/style_derive/to_animated_value.rs | 117 | ||||
-rw-r--r-- | components/style_derive/to_animated_zero.rs | 69 | ||||
-rw-r--r-- | components/style_derive/to_computed_value.rs | 118 | ||||
-rw-r--r-- | components/style_derive/to_css.rs | 58 |
9 files changed, 291 insertions, 485 deletions
diff --git a/components/style_derive/animate.rs b/components/style_derive/animate.rs index 5ce1040e94c..888a5e61c8e 100644 --- a/components/style_derive/animate.rs +++ b/components/style_derive/animate.rs @@ -2,56 +2,29 @@ * 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 cg; use quote; -use std::borrow::Cow; use syn; -use synstructure; pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let name = &input.ident; - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let mut where_clause = where_clause.clone(); - for param in &input.generics.ty_params { - where_clause.predicates.push(where_predicate(syn::Ty::Path(None, param.ident.clone().into()))) - } + let trait_path = &["values", "animated", "Animate"]; + let (impl_generics, ty_generics, mut where_clause) = + cg::trait_parts(&input, trait_path); - let variants = variants(&input); + let variants = cg::variants(&input); let mut match_body = quote!(); match_body.append_all(variants.iter().map(|variant| { - let name = match input.body { - syn::Body::Struct(_) => Cow::Borrowed(&input.ident), - syn::Body::Enum(_) => { - Cow::Owned(syn::Ident::from(format!("{}::{}", input.ident, variant.ident))) - }, - }; - let (this_pattern, this_info) = synstructure::match_pattern( - &name, - &variant.data, - &synstructure::BindOpts::with_prefix( - synstructure::BindStyle::Ref, - "this".to_owned(), - ), - ); - let (other_pattern, other_info) = synstructure::match_pattern( - &name, - &variant.data, - &synstructure::BindOpts::with_prefix( - synstructure::BindStyle::Ref, - "other".to_owned(), - ), - ); - let (result_value, result_info) = synstructure::match_pattern( - &name, - &variant.data, - &synstructure::BindOpts::with_prefix( - synstructure::BindStyle::Move, - "result".to_owned(), - ), - ); + 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"); + let (result_value, result_info) = cg::value(&name, variant, "result"); let mut computations = quote!(); let iter = result_info.iter().zip(this_info.iter().zip(&other_info)); computations.append_all(iter.map(|(result, (this, other))| { - where_clause.predicates.push(where_predicate(this.field.ty.clone())); + where_clause.predicates.push( + cg::where_predicate(this.field.ty.clone(), trait_path), + ); quote! { let #result = ::values::animated::Animate::animate(#this, #other, procedure)?; } @@ -84,40 +57,3 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { } } } - -fn variants(input: &syn::DeriveInput) -> Cow<[syn::Variant]> { - match input.body { - syn::Body::Enum(ref variants) => (&**variants).into(), - syn::Body::Struct(ref data) => { - vec![syn::Variant { - ident: input.ident.clone(), - attrs: input.attrs.clone(), - data: data.clone(), - discriminant: None, - }].into() - }, - } -} - -fn where_predicate(ty: syn::Ty) -> syn::WherePredicate { - syn::WherePredicate::BoundPredicate( - syn::WhereBoundPredicate { - bound_lifetimes: vec![], - bounded_ty: ty, - bounds: vec![syn::TyParamBound::Trait( - syn::PolyTraitRef { - bound_lifetimes: vec![], - trait_ref: syn::Path { - global: true, - segments: vec![ - "values".into(), - "animated".into(), - "Animate".into(), - ], - }, - }, - syn::TraitBoundModifier::None, - )], - }, - ) -} diff --git a/components/style_derive/cg.rs b/components/style_derive/cg.rs new file mode 100644 index 00000000000..af60591d7c6 --- /dev/null +++ b/components/style_derive/cg.rs @@ -0,0 +1,219 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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 quote::Tokens; +use std::borrow::Cow; +use std::iter; +use syn::{AngleBracketedParameterData, Body, DeriveInput, Ident, ImplGenerics}; +use syn::{Path, PathParameters, PathSegment, PolyTraitRef, QSelf}; +use syn::{TraitBoundModifier, Ty, TyGenerics, TyParam, TyParamBound, TypeBinding}; +use syn::{Variant, WhereBoundPredicate, WhereClause, WherePredicate}; +use syn::visit::{self, Visitor}; +use synstructure::{self, BindOpts, BindStyle, BindingInfo}; + +pub fn fmap_match<F>( + input: &DeriveInput, + bind_style: BindStyle, + mut f: F, +) -> Tokens +where + F: FnMut(BindingInfo) -> Tokens, +{ + synstructure::each_variant(input, &bind_style.into(), |fields, variant| { + let name = variant_ctor(input, variant); + let (mapped, mapped_fields) = value(&name, variant, "mapped"); + let fields_pairs = fields.into_iter().zip(mapped_fields); + let mut computations = quote!(); + computations.append_all(fields_pairs.map(|(field, mapped_field)| { + let expr = f(field); + quote! { let #mapped_field = #expr; } + })); + computations.append(mapped); + Some(computations) + }) +} + +pub fn fmap_trait_parts<'a>( + input: &'a DeriveInput, + trait_path: &[&str], + trait_output: &str, +) -> (ImplGenerics<'a>, TyGenerics<'a>, WhereClause, Path) { + let (impl_generics, ty_generics, where_clause) = trait_parts(input, trait_path); + let output_ty = PathSegment { + ident: input.ident.clone(), + parameters: PathParameters::AngleBracketed(AngleBracketedParameterData { + lifetimes: input.generics.lifetimes.iter().map(|l| l.lifetime.clone()).collect(), + types: input.generics.ty_params.iter().map(|ty| { + Ty::Path( + Some(QSelf { + ty: Box::new(Ty::Path(None, ty.ident.clone().into())), + position: trait_path.len(), + }), + path(trait_path.iter().chain(iter::once(&trait_output))), + ) + }).collect(), + .. Default::default() + }), + }.into(); + (impl_generics, ty_generics, where_clause, output_ty) +} + +fn fmap_trait_where_predicate( + bounded_ty: Ty, + trait_path: &[&str], + trait_output: Option<(&str, Ty)>, +) -> WherePredicate { + WherePredicate::BoundPredicate(WhereBoundPredicate { + bound_lifetimes: vec![], + bounded_ty, + bounds: vec![TyParamBound::Trait( + PolyTraitRef { + bound_lifetimes: vec![], + trait_ref: fmap_trait_ref(trait_path, trait_output), + }, + TraitBoundModifier::None + )], + }) +} + +fn fmap_trait_ref(path: &[&str], output: Option<(&str, Ty)>) -> Path { + let (name, parent) = path.split_last().unwrap(); + let last_segment = PathSegment { + ident: (*name).into(), + parameters: PathParameters::AngleBracketed( + AngleBracketedParameterData { + bindings: output.into_iter().map(|(param, ty)| { + TypeBinding { ident: param.into(), ty } + }).collect(), + .. Default::default() + } + ) + }; + Path { + global: true, + segments: { + parent + .iter() + .cloned() + .map(Into::into) + .chain(iter::once(last_segment)) + .collect() + }, + } +} + +pub fn is_parameterized(ty: &Ty, params: &[TyParam]) -> bool { + struct IsParameterized<'a> { + params: &'a [TyParam], + has_free: bool, + } + + impl<'a> Visitor for IsParameterized<'a> { + fn visit_path(&mut self, path: &Path) { + if !path.global && path.segments.len() == 1 { + if self.params.iter().any(|param| param.ident == path.segments[0].ident) { + self.has_free = true; + } + } + visit::walk_path(self, path); + } + } + + let mut visitor = IsParameterized { params: params, has_free: false }; + visitor.visit_ty(ty); + visitor.has_free +} + +pub fn path<S>(segments: S) -> Path +where + S: IntoIterator, + <S as IntoIterator>::Item: AsRef<str>, +{ + Path { + global: true, + segments: segments.into_iter().map(|s| s.as_ref().into()).collect(), + } +} + +pub fn ref_pattern<'a>( + name: &Ident, + variant: &'a Variant, + prefix: &str, +) -> (Tokens, Vec<BindingInfo<'a>>) { + synstructure::match_pattern( + &name, + &variant.data, + &BindOpts::with_prefix(BindStyle::Ref, prefix.to_owned()), + ) +} + +pub fn trait_parts<'a>( + input: &'a DeriveInput, + trait_path: &[&str], +) -> (ImplGenerics<'a>, TyGenerics<'a>, WhereClause) { + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + let mut where_clause = where_clause.clone(); + for param in &input.generics.ty_params { + where_clause.predicates.push(fmap_trait_where_predicate( + Ty::Path(None, param.ident.clone().into()), + trait_path, + None, + )); + } + (impl_generics, ty_generics, where_clause) +} + +pub fn value<'a>( + name: &Ident, + variant: &'a Variant, + prefix: &str, +) -> (Tokens, Vec<BindingInfo<'a>>) { + synstructure::match_pattern( + &name, + &variant.data, + &BindOpts::with_prefix(BindStyle::Move, prefix.to_owned()), + ) +} + +pub fn variant_ctor<'a>( + input: &'a DeriveInput, + variant: &Variant, +) -> Cow<'a, Ident> { + match input.body { + Body::Struct(_) => Cow::Borrowed(&input.ident), + Body::Enum(_) => { + Cow::Owned(Ident::from( + format!("{}::{}", input.ident, variant.ident), + )) + }, + } +} + +pub fn variants(input: &DeriveInput) -> Cow<[Variant]> { + match input.body { + Body::Enum(ref variants) => (&**variants).into(), + Body::Struct(ref data) => { + vec![Variant { + ident: input.ident.clone(), + attrs: input.attrs.clone(), + data: data.clone(), + discriminant: None, + }].into() + }, + } +} + +pub fn where_predicate(ty: Ty, segments: &[&str]) -> WherePredicate { + WherePredicate::BoundPredicate(WhereBoundPredicate { + bound_lifetimes: vec![], + bounded_ty: ty, + bounds: vec![TyParamBound::Trait( + PolyTraitRef { + bound_lifetimes: vec![], + trait_ref: path(segments), + }, + TraitBoundModifier::None, + )], + }) +} diff --git a/components/style_derive/compute_squared_distance.rs b/components/style_derive/compute_squared_distance.rs index 46aa376319d..df02d1312cc 100644 --- a/components/style_derive/compute_squared_distance.rs +++ b/components/style_derive/compute_squared_distance.rs @@ -2,50 +2,30 @@ * 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 cg; use quote; -use std::borrow::Cow; use syn; -use synstructure; pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let name = &input.ident; - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let mut where_clause = where_clause.clone(); - for param in &input.generics.ty_params { - where_clause.predicates.push(where_predicate(syn::Ty::Path(None, param.ident.clone().into()))) - } + let trait_path = &["values", "distance", "ComputeSquaredDistance"]; + let (impl_generics, ty_generics, mut where_clause) = + cg::trait_parts(&input, trait_path); - let variants = variants(&input); + let variants = cg::variants(&input); let mut match_body = quote!(); match_body.append_all(variants.iter().map(|variant| { - let name = match input.body { - syn::Body::Struct(_) => Cow::Borrowed(&input.ident), - syn::Body::Enum(_) => { - Cow::Owned(syn::Ident::from(format!("{}::{}", input.ident, variant.ident))) - }, - }; - let (this_pattern, this_info) = synstructure::match_pattern( - &name, - &variant.data, - &synstructure::BindOpts::with_prefix( - synstructure::BindStyle::Ref, - "this".to_owned(), - ), - ); - let (other_pattern, other_info) = synstructure::match_pattern( - &name, - &variant.data, - &synstructure::BindOpts::with_prefix( - synstructure::BindStyle::Ref, - "other".to_owned(), - ), - ); + 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"); let sum = if this_info.is_empty() { quote! { ::values::distance::SquaredDistance::Value(0.) } } else { let mut sum = quote!(); sum.append_separated(this_info.iter().zip(&other_info).map(|(this, other)| { - where_clause.predicates.push(where_predicate(this.field.ty.clone())); + where_clause.predicates.push( + cg::where_predicate(this.field.ty.clone(), trait_path), + ); quote! { ::values::distance::ComputeSquaredDistance::compute_squared_distance(#this, #other)? } @@ -78,40 +58,3 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { } } } - -fn variants(input: &syn::DeriveInput) -> Cow<[syn::Variant]> { - match input.body { - syn::Body::Enum(ref variants) => (&**variants).into(), - syn::Body::Struct(ref data) => { - vec![syn::Variant { - ident: input.ident.clone(), - attrs: input.attrs.clone(), - data: data.clone(), - discriminant: None, - }].into() - }, - } -} - -fn where_predicate(ty: syn::Ty) -> syn::WherePredicate { - syn::WherePredicate::BoundPredicate( - syn::WhereBoundPredicate { - bound_lifetimes: vec![], - bounded_ty: ty, - bounds: vec![syn::TyParamBound::Trait( - syn::PolyTraitRef { - bound_lifetimes: vec![], - trait_ref: syn::Path { - global: true, - segments: vec![ - "values".into(), - "distance".into(), - "ComputeSquaredDistance".into(), - ], - }, - }, - syn::TraitBoundModifier::None, - )], - }, - ) -} diff --git a/components/style_derive/has_viewport_percentage.rs b/components/style_derive/has_viewport_percentage.rs index 24e4b919c22..5f26d988b8a 100644 --- a/components/style_derive/has_viewport_percentage.rs +++ b/components/style_derive/has_viewport_percentage.rs @@ -2,17 +2,16 @@ * 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 cg; use quote; use syn; use synstructure; pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let name = &input.ident; - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let mut where_clause = where_clause.clone(); - for param in &input.generics.ty_params { - where_clause.predicates.push(where_predicate(syn::Ty::Path(None, param.ident.clone().into()))) - } + let trait_path = &["style_traits", "HasViewportPercentage"]; + let (impl_generics, ty_generics, mut where_clause) = + cg::trait_parts(&input, trait_path); let style = synstructure::BindStyle::Ref.into(); let match_body = synstructure::each_variant(&input, &style, |bindings, _| { @@ -22,7 +21,9 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { }; let mut expr = quote!(::style_traits::HasViewportPercentage::has_viewport_percentage(#first)); for binding in rest { - where_clause.predicates.push(where_predicate(binding.field.ty.clone())); + where_clause.predicates.push( + cg::where_predicate(binding.field.ty.clone(), trait_path), + ); expr = quote!(#expr || ::style_traits::HasViewportPercentage::has_viewport_percentage(#binding)); } Some(expr) @@ -40,17 +41,3 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { } } } - -fn where_predicate(ty: syn::Ty) -> syn::WherePredicate { - syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate { - bound_lifetimes: vec![], - bounded_ty: ty, - bounds: vec![syn::TyParamBound::Trait( - syn::PolyTraitRef { - bound_lifetimes: vec![], - trait_ref: syn::parse_path("::style_traits::HasViewportPercentage").unwrap(), - }, - syn::TraitBoundModifier::None - )], - }) -} diff --git a/components/style_derive/lib.rs b/components/style_derive/lib.rs index a41925ab410..e2b10dc47aa 100644 --- a/components/style_derive/lib.rs +++ b/components/style_derive/lib.rs @@ -10,6 +10,7 @@ extern crate synstructure; use proc_macro::TokenStream; mod animate; +mod cg; mod compute_squared_distance; mod has_viewport_percentage; mod to_animated_value; diff --git a/components/style_derive/to_animated_value.rs b/components/style_derive/to_animated_value.rs index ab13a26d5c8..5a66ddf65a4 100644 --- a/components/style_derive/to_animated_value.rs +++ b/components/style_derive/to_animated_value.rs @@ -2,49 +2,24 @@ * 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 cg; use quote; use syn; -use synstructure; +use synstructure::BindStyle; pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let name = &input.ident; - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let mut where_clause = where_clause.clone(); - for param in &input.generics.ty_params { - where_clause.predicates.push(where_predicate(syn::Ty::Path(None, param.ident.clone().into()), None)); - } - - let animated_value_type = syn::Path::from(syn::PathSegment { - ident: name.clone(), - parameters: syn::PathParameters::AngleBracketed(syn::AngleBracketedParameterData { - lifetimes: input.generics.lifetimes.iter().map(|l| { - l.lifetime.clone() - }).collect(), - types: input.generics.ty_params.iter().map(|ty| { - syn::Ty::Path( - Some(syn::QSelf { - ty: Box::new(syn::Ty::Path(None, ty.ident.clone().into())), - position: 3, - }), - syn::Path { - global: true, - segments: vec![ - "values".into(), - "animated".into(), - "ToAnimatedValue".into(), - "AnimatedValue".into(), - ], - }, - ) - }).collect(), - .. Default::default() - }), - }); - - let to_body = match_body(&input, |field| { + let (impl_generics, ty_generics, where_clause, animated_value_type) = + cg::fmap_trait_parts( + &input, + &["values", "animated", "ToAnimatedValue"], + "AnimatedValue", + ); + + let to_body = cg::fmap_match(&input, BindStyle::Move, |field| { quote!(::values::animated::ToAnimatedValue::to_animated_value(#field)) }); - let from_body = match_body(&input, |field| { + let from_body = cg::fmap_match(&input, BindStyle::Move, |field| { quote!(::values::animated::ToAnimatedValue::from_animated_value(#field)) }); @@ -69,73 +44,3 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { } } } - -fn match_body<F>(input: &syn::DeriveInput, f: F) -> quote::Tokens -where - F: Fn(&synstructure::BindingInfo) -> quote::Tokens, -{ - let by_value = synstructure::BindStyle::Move.into(); - synstructure::each_variant(&input, &by_value, |fields, variant| { - let name = if let syn::Body::Enum(_) = input.body { - format!("{}::{}", input.ident, variant.ident).into() - } else { - variant.ident.clone() - }; - let (animated_value, computed_fields) = synstructure::match_pattern(&name, &variant.data, &by_value); - let fields_pairs = fields.iter().zip(computed_fields.iter()); - let mut computations = quote!(); - computations.append_all(fields_pairs.map(|(field, computed_field)| { - let expr = f(field); - quote!(let #computed_field = #expr;) - })); - Some(quote!( - #computations - #animated_value - )) - }) -} - -/// `#ty: ::values::animated::ToAnimatedValue<AnimatedValue = #animated_value,>` -fn where_predicate(ty: syn::Ty, animated_value: Option<syn::Ty>) -> syn::WherePredicate { - syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate { - bound_lifetimes: vec![], - bounded_ty: ty, - bounds: vec![syn::TyParamBound::Trait( - syn::PolyTraitRef { - bound_lifetimes: vec![], - trait_ref: trait_ref(animated_value), - }, - syn::TraitBoundModifier::None - )], - }) -} - -/// `::values::animated::ToAnimatedValue<AnimatedValue = #animated_value,>` -fn trait_ref(animated_value: Option<syn::Ty>) -> syn::Path { - syn::Path { - global: true, - segments: vec![ - "values".into(), - "animated".into(), - syn::PathSegment { - ident: "ToAnimatedValue".into(), - parameters: syn::PathParameters::AngleBracketed( - syn::AngleBracketedParameterData { - bindings: trait_bindings(animated_value), - .. Default::default() - } - ), - } - ], - } -} - -/// `AnimatedValue = #animated_value,` -fn trait_bindings(animated_value: Option<syn::Ty>) -> Vec<syn::TypeBinding> { - animated_value.into_iter().map(|ty| { - syn::TypeBinding { - ident: "AnimatedValue".into(), - ty: ty, - } - }).collect() -} diff --git a/components/style_derive/to_animated_zero.rs b/components/style_derive/to_animated_zero.rs index f44443f4a34..d9e67a8a9fe 100644 --- a/components/style_derive/to_animated_zero.rs +++ b/components/style_derive/to_animated_zero.rs @@ -2,78 +2,31 @@ * 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 cg; use quote; use syn; -use synstructure; +use synstructure::BindStyle; pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let name = &input.ident; - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let mut where_clause = where_clause.clone(); - for param in &input.generics.ty_params { - where_clause.predicates.push( - where_predicate(syn::Ty::Path(None, param.ident.clone().into())), - ); - } + let (impl_generics, ty_generics, where_clause) = cg::trait_parts( + &input, + &["values", "animated", "ToAnimatedZero"], + ); - let to_body = match_body(&input); + let to_body = cg::fmap_match(&input, BindStyle::Ref, |field| { + quote! { ::values::animated::ToAnimatedZero::to_animated_zero(#field)? } + }); quote! { impl #impl_generics ::values::animated::ToAnimatedZero for #name #ty_generics #where_clause { #[allow(unused_variables)] #[inline] fn to_animated_zero(&self) -> Result<Self, ()> { - match *self { + Ok(match *self { #to_body - } + }) } } } } - -fn match_body(input: &syn::DeriveInput) -> quote::Tokens { - synstructure::each_variant(&input, &synstructure::BindStyle::Ref.into(), |fields, variant| { - let name = if let syn::Body::Enum(_) = input.body { - format!("{}::{}", input.ident, variant.ident).into() - } else { - variant.ident.clone() - }; - let (zero, computed_fields) = synstructure::match_pattern( - &name, - &variant.data, - &synstructure::BindStyle::Move.into(), - ); - let fields_pairs = fields.iter().zip(computed_fields.iter()); - let mut computations = quote!(); - computations.append_all(fields_pairs.map(|(field, computed_field)| { - quote! { - let #computed_field = ::values::animated::ToAnimatedZero::to_animated_zero(#field)?; - } - })); - Some(quote!( - #computations - Ok(#zero) - )) - }) -} - -fn where_predicate(ty: syn::Ty) -> syn::WherePredicate { - syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate { - bound_lifetimes: vec![], - bounded_ty: ty, - bounds: vec![syn::TyParamBound::Trait( - syn::PolyTraitRef { - bound_lifetimes: vec![], - trait_ref: syn::Path { - global: true, - segments: vec![ - "values".into(), - "animated".into(), - "ToAnimatedZero".into(), - ], - }, - }, - syn::TraitBoundModifier::None, - )], - }) -} diff --git a/components/style_derive/to_computed_value.rs b/components/style_derive/to_computed_value.rs index d7c4801dbf8..967f3320a37 100644 --- a/components/style_derive/to_computed_value.rs +++ b/components/style_derive/to_computed_value.rs @@ -2,49 +2,24 @@ * 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 cg; use quote; use syn; -use synstructure; +use synstructure::BindStyle; pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let name = &input.ident; - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let mut where_clause = where_clause.clone(); - for param in &input.generics.ty_params { - where_clause.predicates.push(where_predicate(syn::Ty::Path(None, param.ident.clone().into()), None)); - } - - let computed_value_type = syn::Path::from(syn::PathSegment { - ident: name.clone(), - parameters: syn::PathParameters::AngleBracketed(syn::AngleBracketedParameterData { - lifetimes: input.generics.lifetimes.iter().map(|l| { - l.lifetime.clone() - }).collect(), - types: input.generics.ty_params.iter().map(|ty| { - syn::Ty::Path( - Some(syn::QSelf { - ty: Box::new(syn::Ty::Path(None, ty.ident.clone().into())), - position: 3, - }), - syn::Path { - global: true, - segments: vec![ - "values".into(), - "computed".into(), - "ToComputedValue".into(), - "ComputedValue".into(), - ], - }, - ) - }).collect(), - .. Default::default() - }), - }); - - let to_body = match_body(&input, |field| { + let (impl_generics, ty_generics, where_clause, computed_value_type) = + cg::fmap_trait_parts( + &input, + &["values", "computed", "ToComputedValue"], + "ComputedValue", + ); + + let to_body = cg::fmap_match(&input, BindStyle::Ref, |field| { quote!(::values::computed::ToComputedValue::to_computed_value(#field, context)) }); - let from_body = match_body(&input, |field| { + let from_body = cg::fmap_match(&input, BindStyle::Ref, |field| { quote!(::values::computed::ToComputedValue::from_computed_value(#field)) }); @@ -69,74 +44,3 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { } } } - -fn match_body<F>(input: &syn::DeriveInput, f: F) -> quote::Tokens - where F: Fn(&synstructure::BindingInfo) -> quote::Tokens, -{ - let by_ref = synstructure::BindStyle::Ref.into(); - let by_value = synstructure::BindStyle::Move.into(); - - synstructure::each_variant(&input, &by_ref, |fields, variant| { - let name = if let syn::Body::Enum(_) = input.body { - format!("{}::{}", input.ident, variant.ident).into() - } else { - variant.ident.clone() - }; - let (computed_value, computed_fields) = synstructure::match_pattern(&name, &variant.data, &by_value); - let fields_pairs = fields.iter().zip(computed_fields.iter()); - let mut computations = quote!(); - computations.append_all(fields_pairs.map(|(field, computed_field)| { - let expr = f(field); - quote!(let #computed_field = #expr;) - })); - Some(quote!( - #computations - #computed_value - )) - }) -} - -/// `#ty: ::values::computed::ToComputedValue<ComputedValue = #computed_value,>` -fn where_predicate(ty: syn::Ty, computed_value: Option<syn::Ty>) -> syn::WherePredicate { - syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate { - bound_lifetimes: vec![], - bounded_ty: ty, - bounds: vec![syn::TyParamBound::Trait( - syn::PolyTraitRef { - bound_lifetimes: vec![], - trait_ref: trait_ref(computed_value), - }, - syn::TraitBoundModifier::None - )], - }) -} - -/// `::values::computed::ToComputedValue<ComputedValue = #computed_value,>` -fn trait_ref(computed_value: Option<syn::Ty>) -> syn::Path { - syn::Path { - global: true, - segments: vec![ - "values".into(), - "computed".into(), - syn::PathSegment { - ident: "ToComputedValue".into(), - parameters: syn::PathParameters::AngleBracketed( - syn::AngleBracketedParameterData { - bindings: trait_bindings(computed_value), - .. Default::default() - } - ), - } - ], - } -} - -/// `ComputedValue = #computed_value,` -fn trait_bindings(computed_value: Option<syn::Ty>) -> Vec<syn::TypeBinding> { - computed_value.into_iter().map(|ty| { - syn::TypeBinding { - ident: "ComputedValue".into(), - ty: ty, - } - }).collect() -} diff --git a/components/style_derive/to_css.rs b/components/style_derive/to_css.rs index 2dbf8731e45..fbbccb5a493 100644 --- a/components/style_derive/to_css.rs +++ b/components/style_derive/to_css.rs @@ -2,17 +2,16 @@ * 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 cg; use quote; use syn; use synstructure; pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let name = &input.ident; - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let mut where_clause = where_clause.clone(); - for param in &input.generics.ty_params { - where_clause.predicates.push(where_predicate(syn::Ty::Path(None, param.ident.clone().into()))) - } + let trait_path = &["style_traits", "ToCss"]; + let (impl_generics, ty_generics, mut where_clause) = + cg::trait_parts(&input, trait_path); let style = synstructure::BindStyle::Ref.into(); let match_body = synstructure::each_variant(&input, &style, |bindings, variant| { @@ -61,8 +60,10 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let mut expr = if !bindings.is_empty() { let mut expr = quote! {}; for binding in bindings { - if has_free_params(&binding.field.ty, &input.generics.ty_params) { - where_clause.predicates.push(where_predicate(binding.field.ty.clone())); + if cg::is_parameterized(&binding.field.ty, &input.generics.ty_params) { + where_clause.predicates.push( + cg::where_predicate(binding.field.ty.clone(), trait_path), + ); } expr = quote! { #expr @@ -106,49 +107,6 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { } } -/// Returns whether `ty` is parameterized by any parameter from `params`. -fn has_free_params(ty: &syn::Ty, params: &[syn::TyParam]) -> bool { - use syn::visit::Visitor; - - struct HasFreeParams<'a> { - params: &'a [syn::TyParam], - has_free: bool, - } - - impl<'a> Visitor for HasFreeParams<'a> { - fn visit_path(&mut self, path: &syn::Path) { - if !path.global && path.segments.len() == 1 { - if self.params.iter().any(|param| param.ident == path.segments[0].ident) { - self.has_free = true; - } - } - syn::visit::walk_path(self, path); - } - } - - let mut visitor = HasFreeParams { params: params, has_free: false }; - visitor.visit_ty(ty); - visitor.has_free -} - -/// `#ty: ::style_traits::ToCss` -fn where_predicate(ty: syn::Ty) -> syn::WherePredicate { - syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate { - bound_lifetimes: vec![], - bounded_ty: ty, - bounds: vec![syn::TyParamBound::Trait( - syn::PolyTraitRef { - bound_lifetimes: vec![], - trait_ref: syn::Path { - global: true, - segments: vec!["style_traits".into(), "ToCss".into()], - }, - }, - syn::TraitBoundModifier::None - )], - }) -} - /// Transforms "FooBar" to "foo-bar". /// /// If the first Camel segment is "Moz" or "Webkit", the result string |