mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Opt out of bounds on type params for #[derive(ToAnimatedZero)]
This commit is contained in:
parent
6f7425059c
commit
ba12a344c6
4 changed files with 29 additions and 157 deletions
|
@ -35,6 +35,7 @@ pub struct SVGPaint<ColorType, 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))]
|
#[distance(no_bound(UrlPaintServer))]
|
||||||
|
#[zero(no_bound(UrlPaintServer))]
|
||||||
pub enum SVGPaintKind<ColorType, UrlPaintServer> {
|
pub enum SVGPaintKind<ColorType, UrlPaintServer> {
|
||||||
/// `none`
|
/// `none`
|
||||||
#[animation(error)]
|
#[animation(error)]
|
||||||
|
|
|
@ -3,83 +3,14 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use darling::{FromDeriveInput, FromField, FromVariant};
|
use darling::{FromDeriveInput, FromField, FromVariant};
|
||||||
use quote::{ToTokens, Tokens};
|
use quote::Tokens;
|
||||||
use std::collections::HashSet;
|
|
||||||
use syn::{self, AngleBracketedGenericArguments, Binding, DeriveInput, Field};
|
use syn::{self, AngleBracketedGenericArguments, Binding, DeriveInput, Field};
|
||||||
use syn::{GenericArgument, GenericParam, Ident, ImplGenerics, Path};
|
use syn::{GenericArgument, GenericParam, Ident, Path};
|
||||||
use syn::{PathArguments, PathSegment, QSelf, Type, TypeArray, TypeGenerics};
|
use syn::{PathArguments, PathSegment, QSelf, Type, TypeArray};
|
||||||
use syn::{TypeParam, TypeParen, TypePath, TypeSlice, TypeTuple};
|
use syn::{TypeParam, TypeParen, TypePath, TypeSlice, TypeTuple};
|
||||||
use syn::{Variant, WherePredicate};
|
use syn::{Variant, WherePredicate};
|
||||||
use syn::visit::{self, Visit};
|
|
||||||
use synstructure::{self, BindingInfo, BindStyle, VariantAst, VariantInfo};
|
use synstructure::{self, BindingInfo, BindStyle, VariantAst, VariantInfo};
|
||||||
|
|
||||||
pub struct WhereClause<'input, 'path> {
|
|
||||||
pub inner: Option<syn::WhereClause>,
|
|
||||||
pub params: Vec<&'input TypeParam>,
|
|
||||||
trait_path: &'path Path,
|
|
||||||
trait_output: Option<Ident>,
|
|
||||||
bounded_types: HashSet<Type>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'input, 'path> ToTokens for WhereClause<'input, 'path> {
|
|
||||||
fn to_tokens(&self, tokens: &mut Tokens) {
|
|
||||||
self.inner.to_tokens(tokens);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'input, 'path> WhereClause<'input, 'path> {
|
|
||||||
pub fn add_trait_bound(&mut self, ty: &Type) {
|
|
||||||
let trait_path = self.trait_path;
|
|
||||||
let mut found = self.trait_output.map(|_| HashSet::new());
|
|
||||||
if self.bounded_types.contains(&ty) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if !is_parameterized(&ty, &self.params, found.as_mut()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.bounded_types.insert(ty.clone());
|
|
||||||
|
|
||||||
let output = if let Some(output) = self.trait_output {
|
|
||||||
output
|
|
||||||
} else {
|
|
||||||
add_predicate(&mut self.inner, where_predicate(ty.clone(), trait_path, None));
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Type::Path(syn::TypePath { ref path, .. }) = *ty {
|
|
||||||
if path_to_ident(path).is_some() {
|
|
||||||
add_predicate(&mut self.inner, where_predicate(ty.clone(), trait_path, None));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let output_type = map_type_params(ty, &self.params, &mut |ident| {
|
|
||||||
parse_quote!(<#ident as ::#trait_path>::#output)
|
|
||||||
});
|
|
||||||
|
|
||||||
let pred = where_predicate(
|
|
||||||
ty.clone(),
|
|
||||||
trait_path,
|
|
||||||
Some((output, output_type)),
|
|
||||||
);
|
|
||||||
|
|
||||||
add_predicate(&mut self.inner, pred);
|
|
||||||
|
|
||||||
if let Some(found) = found {
|
|
||||||
for ident in found {
|
|
||||||
let ty = Type::Path(syn::TypePath { qself: None, path: ident.into() });
|
|
||||||
if !self.bounded_types.contains(&ty) {
|
|
||||||
self.bounded_types.insert(ty.clone());
|
|
||||||
add_predicate(
|
|
||||||
&mut self.inner,
|
|
||||||
where_predicate(ty, trait_path, None),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_predicate(
|
pub fn add_predicate(
|
||||||
where_clause: &mut Option<syn::WhereClause>,
|
where_clause: &mut Option<syn::WhereClause>,
|
||||||
pred: WherePredicate,
|
pred: WherePredicate,
|
||||||
|
@ -139,36 +70,6 @@ pub fn fmap_trait_output(
|
||||||
segment.into()
|
segment.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_parameterized(
|
|
||||||
ty: &Type,
|
|
||||||
params: &[&TypeParam],
|
|
||||||
found: Option<&mut HashSet<Ident>>,
|
|
||||||
) -> bool {
|
|
||||||
struct IsParameterized<'a, 'b> {
|
|
||||||
params: &'a [&'a TypeParam],
|
|
||||||
has_free: bool,
|
|
||||||
found: Option<&'b mut HashSet<Ident>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b, 'ast> Visit<'ast> for IsParameterized<'a, 'b> {
|
|
||||||
fn visit_path(&mut self, path: &'ast Path) {
|
|
||||||
if let Some(ident) = path_to_ident(path) {
|
|
||||||
if self.params.iter().any(|param| param.ident == ident) {
|
|
||||||
self.has_free = true;
|
|
||||||
if let Some(ref mut found) = self.found {
|
|
||||||
found.insert(ident.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
visit::visit_path(self, path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut visitor = IsParameterized { params, has_free: false, found };
|
|
||||||
visitor.visit_type(ty);
|
|
||||||
visitor.has_free
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn map_type_params<F>(ty: &Type, params: &[&TypeParam], f: &mut F) -> Type
|
pub fn map_type_params<F>(ty: &Type, params: &[&TypeParam], f: &mut F) -> Type
|
||||||
where
|
where
|
||||||
F: FnMut(&Ident) -> Type,
|
F: FnMut(&Ident) -> Type,
|
||||||
|
@ -314,33 +215,6 @@ pub fn ref_pattern<'a>(
|
||||||
(v.pat(), v.bindings().iter().cloned().collect())
|
(v.pat(), v.bindings().iter().cloned().collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trait_parts<'input, 'path>(
|
|
||||||
input: &'input DeriveInput,
|
|
||||||
trait_path: &'path Path,
|
|
||||||
) -> (ImplGenerics<'input>, TypeGenerics<'input>, WhereClause<'input, 'path>) {
|
|
||||||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
|
||||||
let where_clause = WhereClause {
|
|
||||||
inner: where_clause.cloned(),
|
|
||||||
params: input.generics.type_params().into_iter().collect::<Vec<&TypeParam>>(),
|
|
||||||
trait_path,
|
|
||||||
trait_output: None,
|
|
||||||
bounded_types: HashSet::new()
|
|
||||||
};
|
|
||||||
(impl_generics, ty_generics, where_clause)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn trait_ref(path: &Path, output: Option<(Ident, Type)>) -> Path {
|
|
||||||
let segments = path.segments.iter().collect::<Vec<&PathSegment>>();
|
|
||||||
let (name, parent) = segments.split_last().unwrap();
|
|
||||||
|
|
||||||
let last_segment: PathSegment = if let Some((param, ty)) = output {
|
|
||||||
parse_quote!(#name<#param = #ty>)
|
|
||||||
} else {
|
|
||||||
parse_quote!(#name)
|
|
||||||
};
|
|
||||||
parse_quote!(::#(#parent::)*#last_segment)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn value<'a>(
|
pub fn value<'a>(
|
||||||
variant: &'a VariantInfo,
|
variant: &'a VariantInfo,
|
||||||
prefix: &str,
|
prefix: &str,
|
||||||
|
@ -351,15 +225,6 @@ pub fn value<'a>(
|
||||||
(v.pat(), v.bindings().iter().cloned().collect())
|
(v.pat(), v.bindings().iter().cloned().collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn where_predicate(
|
|
||||||
bounded_ty: Type,
|
|
||||||
trait_path: &Path,
|
|
||||||
trait_output: Option<(Ident, Type)>,
|
|
||||||
) -> WherePredicate {
|
|
||||||
let trait_ref = trait_ref(trait_path, trait_output);
|
|
||||||
parse_quote!(#bounded_ty: #trait_ref)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Transforms "FooBar" to "foo-bar".
|
/// Transforms "FooBar" to "foo-bar".
|
||||||
///
|
///
|
||||||
/// If the first Camel segment is "Moz", "Webkit", or "Servo", the result string
|
/// If the first Camel segment is "Moz", "Webkit", or "Servo", the result string
|
||||||
|
|
|
@ -45,7 +45,7 @@ pub fn derive_parse(stream: TokenStream) -> TokenStream {
|
||||||
parse::derive(input).into()
|
parse::derive(input).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(ToAnimatedZero, attributes(animation))]
|
#[proc_macro_derive(ToAnimatedZero, attributes(animation, zero))]
|
||||||
pub fn derive_to_animated_zero(stream: TokenStream) -> TokenStream {
|
pub fn derive_to_animated_zero(stream: TokenStream) -> TokenStream {
|
||||||
let input = syn::parse(stream).unwrap();
|
let input = syn::parse(stream).unwrap();
|
||||||
to_animated_zero::derive(input).into()
|
to_animated_zero::derive(input).into()
|
||||||
|
|
|
@ -4,18 +4,25 @@
|
||||||
|
|
||||||
use animate::{AnimationVariantAttrs, AnimationFieldAttrs};
|
use animate::{AnimationVariantAttrs, AnimationFieldAttrs};
|
||||||
use cg;
|
use cg;
|
||||||
|
use darling::util::IdentList;
|
||||||
use quote;
|
use quote;
|
||||||
use syn;
|
use syn;
|
||||||
use synstructure;
|
use synstructure;
|
||||||
|
|
||||||
pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
pub fn derive(mut input: syn::DeriveInput) -> quote::Tokens {
|
||||||
let name = &input.ident;
|
let input_attrs = cg::parse_input_attrs::<ZeroInputAttrs>(&input);
|
||||||
let trait_path = parse_quote!(values::animated::ToAnimatedZero);
|
let no_bound = input_attrs.no_bound.unwrap_or_default();
|
||||||
let (impl_generics, ty_generics, mut where_clause) =
|
let mut where_clause = input.generics.where_clause.take();
|
||||||
cg::trait_parts(&input, &trait_path);
|
for param in input.generics.type_params() {
|
||||||
|
if !no_bound.contains(¶m.ident) {
|
||||||
|
cg::add_predicate(
|
||||||
|
&mut where_clause,
|
||||||
|
parse_quote!(#param: ::values::animated::ToAnimatedZero),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let s = synstructure::Structure::new(&input);
|
let to_body = synstructure::Structure::new(&input).each_variant(|variant| {
|
||||||
let to_body = s.each_variant(|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 {
|
||||||
return Some(quote! { Err(()) });
|
return Some(quote! { Err(()) });
|
||||||
|
@ -26,21 +33,10 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
||||||
computations.append_all(bindings_pairs.map(|(binding, mapped_binding)| {
|
computations.append_all(bindings_pairs.map(|(binding, mapped_binding)| {
|
||||||
let field_attrs = cg::parse_field_attrs::<AnimationFieldAttrs>(&binding.ast());
|
let field_attrs = cg::parse_field_attrs::<AnimationFieldAttrs>(&binding.ast());
|
||||||
if field_attrs.constant {
|
if field_attrs.constant {
|
||||||
if cg::is_parameterized(&binding.ast().ty, &where_clause.params, None) {
|
|
||||||
cg::add_predicate(
|
|
||||||
&mut where_clause.inner,
|
|
||||||
cg::where_predicate(
|
|
||||||
binding.ast().ty.clone(),
|
|
||||||
&parse_quote!(std::clone::Clone),
|
|
||||||
None,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
quote! {
|
quote! {
|
||||||
let #mapped_binding = ::std::clone::Clone::clone(#binding);
|
let #mapped_binding = ::std::clone::Clone::clone(#binding);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
where_clause.add_trait_bound(&binding.ast().ty);
|
|
||||||
quote! {
|
quote! {
|
||||||
let #mapped_binding =
|
let #mapped_binding =
|
||||||
::values::animated::ToAnimatedZero::to_animated_zero(#binding)?;
|
::values::animated::ToAnimatedZero::to_animated_zero(#binding)?;
|
||||||
|
@ -50,6 +46,10 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
||||||
computations.append_all(quote! { Ok(#mapped) });
|
computations.append_all(quote! { Ok(#mapped) });
|
||||||
Some(computations)
|
Some(computations)
|
||||||
});
|
});
|
||||||
|
input.generics.where_clause = where_clause;
|
||||||
|
|
||||||
|
let name = &input.ident;
|
||||||
|
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
impl #impl_generics ::values::animated::ToAnimatedZero for #name #ty_generics #where_clause {
|
impl #impl_generics ::values::animated::ToAnimatedZero for #name #ty_generics #where_clause {
|
||||||
|
@ -63,3 +63,9 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[darling(attributes(zero), default)]
|
||||||
|
#[derive(Default, FromDeriveInput)]
|
||||||
|
struct ZeroInputAttrs {
|
||||||
|
no_bound: Option<IdentList>,
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue