Skip to content

Commit

Permalink
Auto merge of #17356 - servo:derive-all-the-things, r=SimonSapin
Browse files Browse the repository at this point in the history
Minor improvements to #[derive(ToCss)]

<!-- 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/17356)
<!-- Reviewable:end -->
  • Loading branch information
bors-servo committed Jun 16, 2017
2 parents 2a856ed + b7c83ee commit 2b02a44
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 8 deletions.
2 changes: 1 addition & 1 deletion components/style_derive/Cargo.toml
Expand Up @@ -11,5 +11,5 @@ proc-macro = true

[dependencies]
quote = "0.3"
syn = "0.11"
syn = { version = "0.11", features = ["visit"] }
synstructure = "0.5.2"
42 changes: 35 additions & 7 deletions components/style_derive/to_css.rs
Expand Up @@ -17,25 +17,28 @@ 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 expr = if bindings.is_empty() {
quote! {
::std::fmt::Write::write_str(dest, #identifier)
let mut expr = if let Some((first, rest)) = bindings.split_first() {
if has_free_params(&first.field.ty, &input.generics.ty_params) {
where_clause.predicates.push(where_predicate(first.field.ty.clone()));
}
} else {
let (first, rest) = bindings.split_first().expect("unit variants are not yet supported");
where_clause.predicates.push(where_predicate(first.field.ty.clone()));
let mut expr = quote! {
::style_traits::ToCss::to_css(#first, dest)
};
for binding in rest {
where_clause.predicates.push(where_predicate(binding.field.ty.clone()));
if has_free_params(&binding.field.ty, &input.generics.ty_params) {
where_clause.predicates.push(where_predicate(binding.field.ty.clone()));
}
expr = quote! {
#expr?;
::std::fmt::Write::write_str(dest, " ")?;
::style_traits::ToCss::to_css(#binding, dest)
};
}
expr
} else {
quote! {
::std::fmt::Write::write_str(dest, #identifier)
}
};
let mut css_attrs = variant.attrs.iter().filter(|attr| attr.name() == "css");
let is_function = css_attrs.next().map_or(false, |attr| {
Expand Down Expand Up @@ -91,6 +94,31 @@ 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 {
Expand Down

0 comments on commit 2b02a44

Please sign in to comment.