mirror of
https://github.com/servo/servo.git
synced 2025-08-05 05:30:08 +01:00
Auto merge of #17356 - servo:derive-all-the-things, r=SimonSapin
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 -->
This commit is contained in:
commit
2b02a444ea
2 changed files with 36 additions and 8 deletions
|
@ -11,5 +11,5 @@ proc-macro = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
quote = "0.3"
|
quote = "0.3"
|
||||||
syn = "0.11"
|
syn = { version = "0.11", features = ["visit"] }
|
||||||
synstructure = "0.5.2"
|
synstructure = "0.5.2"
|
||||||
|
|
|
@ -17,18 +17,17 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
||||||
let style = synstructure::BindStyle::Ref.into();
|
let style = synstructure::BindStyle::Ref.into();
|
||||||
let match_body = synstructure::each_variant(&input, &style, |bindings, variant| {
|
let match_body = synstructure::each_variant(&input, &style, |bindings, variant| {
|
||||||
let mut identifier = to_css_identifier(variant.ident.as_ref());
|
let mut identifier = to_css_identifier(variant.ident.as_ref());
|
||||||
let mut expr = if bindings.is_empty() {
|
let mut expr = if let Some((first, rest)) = bindings.split_first() {
|
||||||
quote! {
|
if has_free_params(&first.field.ty, &input.generics.ty_params) {
|
||||||
::std::fmt::Write::write_str(dest, #identifier)
|
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! {
|
let mut expr = quote! {
|
||||||
::style_traits::ToCss::to_css(#first, dest)
|
::style_traits::ToCss::to_css(#first, dest)
|
||||||
};
|
};
|
||||||
for binding in rest {
|
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 = quote! {
|
||||||
#expr?;
|
#expr?;
|
||||||
::std::fmt::Write::write_str(dest, " ")?;
|
::std::fmt::Write::write_str(dest, " ")?;
|
||||||
|
@ -36,6 +35,10 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
expr
|
expr
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
::std::fmt::Write::write_str(dest, #identifier)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let mut css_attrs = variant.attrs.iter().filter(|attr| attr.name() == "css");
|
let mut css_attrs = variant.attrs.iter().filter(|attr| attr.name() == "css");
|
||||||
let is_function = css_attrs.next().map_or(false, |attr| {
|
let is_function = css_attrs.next().map_or(false, |attr| {
|
||||||
|
@ -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`
|
/// `#ty: ::style_traits::ToCss`
|
||||||
fn where_predicate(ty: syn::Ty) -> syn::WherePredicate {
|
fn where_predicate(ty: syn::Ty) -> syn::WherePredicate {
|
||||||
syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate {
|
syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue