mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
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 -->
This commit is contained in:
commit
e629f8da7b
9 changed files with 289 additions and 483 deletions
|
@ -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,
|
||||
)],
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
219
components/style_derive/cg.rs
Normal file
219
components/style_derive/cg.rs
Normal file
|
@ -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,
|
||||
)],
|
||||
})
|
||||
}
|
|
@ -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,
|
||||
)],
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
)],
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 (impl_generics, ty_generics, where_clause, animated_value_type) =
|
||||
cg::fmap_trait_parts(
|
||||
&input,
|
||||
&["values", "animated", "ToAnimatedValue"],
|
||||
"AnimatedValue",
|
||||
);
|
||||
|
||||
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 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()
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
)],
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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 (impl_generics, ty_generics, where_clause, computed_value_type) =
|
||||
cg::fmap_trait_parts(
|
||||
&input,
|
||||
&["values", "computed", "ToComputedValue"],
|
||||
"ComputedValue",
|
||||
);
|
||||
|
||||
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 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()
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue