Opt out of bounds on type params for #[derive(ComputeSquaredDistance)]

This commit is contained in:
Anthony Ramine 2018-03-11 14:53:33 +01:00
parent 5cc2d7c4b3
commit 6f7425059c
2 changed files with 70 additions and 35 deletions

View file

@ -18,6 +18,7 @@ use values::distance::{ComputeSquaredDistance, SquaredDistance};
#[animate(no_bound(UrlPaintServer))] #[animate(no_bound(UrlPaintServer))]
#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq)] #[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq)]
#[derive(ToAnimatedValue, ToComputedValue, ToCss)] #[derive(ToAnimatedValue, ToComputedValue, ToCss)]
#[distance(no_bound(UrlPaintServer))]
pub struct SVGPaint<ColorType, UrlPaintServer> { pub struct SVGPaint<ColorType, UrlPaintServer> {
/// The paint source /// The paint source
pub kind: SVGPaintKind<ColorType, UrlPaintServer>, pub kind: SVGPaintKind<ColorType, UrlPaintServer>,
@ -33,6 +34,7 @@ pub struct SVGPaint<ColorType, UrlPaintServer> {
#[animate(no_bound(UrlPaintServer))] #[animate(no_bound(UrlPaintServer))]
#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq)] #[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq)]
#[derive(ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)] #[derive(ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)]
#[distance(no_bound(UrlPaintServer))]
pub enum SVGPaintKind<ColorType, UrlPaintServer> { pub enum SVGPaintKind<ColorType, UrlPaintServer> {
/// `none` /// `none`
#[animation(error)] #[animation(error)]
@ -205,7 +207,11 @@ pub enum SVGLength<LengthType> {
pub enum SVGStrokeDashArray<LengthType> { pub enum SVGStrokeDashArray<LengthType> {
/// `[ <length> | <percentage> | <number> ]#` /// `[ <length> | <percentage> | <number> ]#`
#[css(comma)] #[css(comma)]
Values(#[css(if_empty = "none", iterable)] Vec<LengthType>), Values(
#[css(if_empty = "none", iterable)]
#[distance(field_bound)]
Vec<LengthType>,
),
/// `context-value` /// `context-value`
ContextValue, ContextValue,
} }

View file

@ -4,21 +4,29 @@
use animate::AnimationVariantAttrs; use animate::AnimationVariantAttrs;
use cg; use cg;
use darling::util::IdentList;
use quote::Tokens; use quote::Tokens;
use syn::{DeriveInput, Path}; use syn::{DeriveInput, Path};
use synstructure; use synstructure;
pub fn derive(input: DeriveInput) -> Tokens { pub fn derive(mut input: DeriveInput) -> Tokens {
let name = &input.ident;
let trait_path = parse_quote!(values::distance::ComputeSquaredDistance);
let (impl_generics, ty_generics, mut where_clause) =
cg::trait_parts(&input, &trait_path);
let input_attrs = cg::parse_input_attrs::<DistanceInputAttrs>(&input); let input_attrs = cg::parse_input_attrs::<DistanceInputAttrs>(&input);
let no_bound = input_attrs.no_bound.unwrap_or_default();
let mut where_clause = input.generics.where_clause.take();
for param in input.generics.type_params() {
if !no_bound.contains(&param.ident) {
cg::add_predicate(
&mut where_clause,
parse_quote!(#param: ::values::distance::ComputeSquaredDistance),
);
}
}
let (mut match_body, append_error_clause) = {
let s = synstructure::Structure::new(&input); let s = synstructure::Structure::new(&input);
let mut append_error_clause = s.variants().len() > 1; let mut append_error_clause = s.variants().len() > 1;
let mut match_body = s.variants().iter().fold(quote!(), |body, variant| { let match_body = s.variants().iter().fold(quote!(), |body, variant| {
let attrs = cg::parse_variant_attrs::<AnimationVariantAttrs>(&variant.ast()); let attrs = cg::parse_variant_attrs::<AnimationVariantAttrs>(&variant.ast());
if attrs.error { if attrs.error {
append_error_clause = true; append_error_clause = true;
@ -32,7 +40,14 @@ pub fn derive(input: DeriveInput) -> Tokens {
} else { } else {
let mut sum = quote!(); let mut sum = quote!();
sum.append_separated(this_info.iter().zip(&other_info).map(|(this, other)| { sum.append_separated(this_info.iter().zip(&other_info).map(|(this, other)| {
where_clause.add_trait_bound(&this.ast().ty); let field_attrs = cg::parse_field_attrs::<DistanceFieldAttrs>(&this.ast());
if field_attrs.field_bound {
let ty = &this.ast().ty;
cg::add_predicate(
&mut where_clause,
parse_quote!(#ty: ::values::distance::ComputeSquaredDistance),
);
}
quote! { quote! {
::values::distance::ComputeSquaredDistance::compute_squared_distance(#this, #other)? ::values::distance::ComputeSquaredDistance::compute_squared_distance(#this, #other)?
} }
@ -47,6 +62,10 @@ pub fn derive(input: DeriveInput) -> Tokens {
} }
}); });
(match_body, append_error_clause)
};
input.generics.where_clause = where_clause;
if append_error_clause { if append_error_clause {
if let Some(fallback) = input_attrs.fallback { if let Some(fallback) = input_attrs.fallback {
match_body.append_all(quote! { match_body.append_all(quote! {
@ -57,6 +76,9 @@ pub fn derive(input: DeriveInput) -> Tokens {
} }
} }
let name = &input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
quote! { quote! {
impl #impl_generics ::values::distance::ComputeSquaredDistance for #name #ty_generics #where_clause { impl #impl_generics ::values::distance::ComputeSquaredDistance for #name #ty_generics #where_clause {
#[allow(unused_variables, unused_imports)] #[allow(unused_variables, unused_imports)]
@ -77,4 +99,11 @@ pub fn derive(input: DeriveInput) -> Tokens {
#[derive(Default, FromDeriveInput)] #[derive(Default, FromDeriveInput)]
struct DistanceInputAttrs { struct DistanceInputAttrs {
fallback: Option<Path>, fallback: Option<Path>,
no_bound: Option<IdentList>,
}
#[darling(attributes(distance), default)]
#[derive(Default, FromField)]
struct DistanceFieldAttrs {
field_bound: bool,
} }