Introduce style_derive::cg

This commit is contained in:
Anthony Ramine 2017-08-23 10:59:26 +02:00
parent 1c9c0334ba
commit f275895028
9 changed files with 289 additions and 483 deletions

View file

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