Auto merge of #20022 - Eijebong:syn, r=nox

Update syn, quote and synstructure

Right now they're duplicated because we need a new serde release (ping @dtolnay), a new cssparser release (ping @SimonSapin) and a new release of html5ever with https://github.com/servo/html5ever/pull/336

<!-- 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/20022)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-02-13 11:15:54 -05:00 committed by GitHub
commit 6cb78057bb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 440 additions and 457 deletions

100
Cargo.lock generated
View file

@ -567,32 +567,31 @@ dependencies = [
[[package]]
name = "darling"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"darling_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"darling_macro 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"darling_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"darling_macro 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "darling_core"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ident_case 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "darling_macro"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"darling_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
"darling_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -642,8 +641,8 @@ dependencies = [
name = "deny_public_fields"
version = "0.0.1"
dependencies = [
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
"synstructure 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)",
"synstructure 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -703,8 +702,8 @@ version = "0.0.1"
name = "domobject_derive"
version = "0.0.1"
dependencies = [
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1298,9 +1297,9 @@ dependencies = [
name = "jstraceable_derive"
version = "0.0.1"
dependencies = [
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
"synstructure 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)",
"synstructure 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1564,9 +1563,9 @@ dependencies = [
name = "malloc_size_of_derive"
version = "0.0.1"
dependencies = [
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
"synstructure 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)",
"synstructure 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -2122,6 +2121,14 @@ name = "precomputed-hash"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "proc-macro2"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "procedural-masquerade"
version = "0.1.2"
@ -2175,6 +2182,14 @@ name = "quote"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "quote"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.3.15"
@ -2916,10 +2931,10 @@ dependencies = [
name = "style_derive"
version = "0.0.1"
dependencies = [
"darling 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
"synstructure 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"darling 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)",
"synstructure 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -2996,6 +3011,16 @@ dependencies = [
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "0.12.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "synom"
version = "0.11.3"
@ -3006,11 +3031,13 @@ dependencies = [
[[package]]
name = "synstructure"
version = "0.5.2"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -3170,6 +3197,11 @@ name = "unicode-xid"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unreachable"
version = "0.1.1"
@ -3543,9 +3575,9 @@ dependencies = [
"checksum core-text 9.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bd581c37283d0c23311d179aefbb891f2324ee0405da58a26e8594ab76e5748"
"checksum cssparser 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8a807ac3ab7a217829c2a3b65732b926b2befe6a35f33b4bf8b503692430f223"
"checksum cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "079adec4af52bb5275eadd004292028c79eb3c5f5b4ee8086a36d4197032f6df"
"checksum darling 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9861a8495606435477df581bc858ccf15a3469747edf175b94a4704fd9aaedac"
"checksum darling_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1486a8b00b45062c997f767738178b43219133dd0c8c826cb811e60563810821"
"checksum darling_macro 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a86ec160aa0c3dd492dd4a14ec8104ad8f1a9400a820624db857998cc1f80f9"
"checksum darling 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d3effd06d4057f275cb7858889f4952920bab78dd8ff0f6e7dfe0c8d2e67ed89"
"checksum darling_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "167dd3e235c2f1da16a635c282630452cdf49191eb05711de1bcd1d3d5068c00"
"checksum darling_macro 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c53edaba455f6073a10c27c72440860eb3f60444f8c8660a391032eeae744d82"
"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
"checksum dbus 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4aee01fb76ada3e5e7ca642ea6664ebf7308a810739ca2aca44909a1191ac254"
"checksum debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a032eac705ca39214d169f83e3d3da290af06d8d1d344d1baad2fd002dca4b3"
@ -3671,8 +3703,10 @@ dependencies = [
"checksum plane-split 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2adb8d1523b2ddcd98275613e9bc04eef75b47a39e252e63733a3218ae3c1b7"
"checksum png 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f0b0cabbbd20c2d7f06dbf015e06aad59b6ca3d9ed14848783e98af9aaf19925"
"checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
"checksum proc-macro2 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d1cb7aaaa4bf022ec2b14ff2f2ba1643a22f3cee88df014a85e14b392282c61d"
"checksum procedural-masquerade 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c93cdc1fb30af9ddf3debc4afbdb0f35126cbd99daa229dd76cdd5349b41d989"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408"
"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
"checksum rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b614fe08b6665cb9a231d07ac1364b0ef3cb3698f1239ee0c4c3a88a524f54c8"
"checksum rayon-core 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2c21a92a5dca958fb030787c1158446c6deb7f976399b72fa8074603f169e2a"
@ -3720,8 +3754,9 @@ dependencies = [
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
"checksum swapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e454d048db5527d000bfddb77bd072bbf3a1e2ae785f16d9bd116e07c2ab45eb"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum syn 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9e1c669ed757c0ebd04337f6a5bb972d05e0c08fe2540dd3ee3dd9e4daf1604c"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
"checksum synstructure 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cf318c34a2f8381a4f3d4db2c91b45bca2b1cd8cbe56caced900647be164800c"
"checksum synstructure 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "010366096045d8250555904c58da03377289e7f4b2ce7a5b1027e2b532f41000"
"checksum tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
@ -3743,6 +3778,7 @@ dependencies = [
"checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946"
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91"
"checksum url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa35e768d4daf1d85733418a49fb42e10d7f633e394fccab4ab7aba897053fe2"
"checksum url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e7d099f1ee52f823d4bdd60c93c3602043c728f5db3b97bdb548467f7bddea"

View file

@ -10,5 +10,5 @@ path = "lib.rs"
proc-macro = true
[dependencies]
syn = "0.11"
synstructure = "0.5"
syn = "0.12.12"
synstructure = "0.7"

View file

@ -4,24 +4,22 @@
extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate synstructure;
#[proc_macro_derive(DenyPublicFields)]
pub fn expand_token_stream(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
expand_string(&input.to_string()).parse().unwrap()
}
use std::str::FromStr;
fn expand_string(input: &str) -> String {
let type_ = syn::parse_macro_input(input).unwrap();
decl_derive!([DenyPublicFields] => deny_public_fields_derive);
let style = synstructure::BindStyle::Ref.into();
synstructure::each_field(&type_, &style, |binding| {
if binding.field.vis != syn::Visibility::Inherited {
fn deny_public_fields_derive(s: synstructure::Structure) -> proc_macro::TokenStream {
s.each(|binding| {
if binding.ast().vis != syn::Visibility::Inherited {
panic!("Field `{}` should not be public",
binding.field.ident.as_ref().unwrap_or(&binding.ident));
binding.ast().ident.as_ref().unwrap_or(&binding.binding));
}
"".to_owned()
});
"".to_owned()
proc_macro::TokenStream::from_str("").unwrap()
}

View file

@ -10,5 +10,5 @@ path = "lib.rs"
proc-macro = true
[dependencies]
syn = "0.11"
quote = "0.3.15"
syn = "0.12.12"
quote = "0.4.2"

View file

@ -2,20 +2,21 @@
* 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/. */
#![recursion_limit = "128"]
extern crate proc_macro;
#[macro_use] extern crate quote;
extern crate syn;
#[macro_use] extern crate syn;
#[proc_macro_derive(DomObject)]
pub fn expand_token_stream(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
expand_string(&input.to_string()).parse().unwrap()
let input = syn::parse(input).unwrap();
expand_dom_object(input).into()
}
fn expand_string(input: &str) -> String {
let type_ = syn::parse_macro_input(input).unwrap();
let fields = if let syn::Body::Struct(syn::VariantData::Struct(ref fields)) = type_.body {
fields
fn expand_dom_object(input: syn::DeriveInput) -> quote::Tokens {
let fields = if let syn::Data::Struct(syn::DataStruct { ref fields, .. }) = input.data {
fields.iter().collect::<Vec<&syn::Field>>()
} else {
panic!("#[derive(DomObject)] should only be applied on proper structs")
};
@ -23,6 +24,7 @@ fn expand_string(input: &str) -> String {
let (first_field, fields) = fields
.split_first()
.expect("#[derive(DomObject)] should not be applied on empty structs");
let first_field_name = first_field.ident.as_ref().unwrap();
let mut field_types = vec![];
for field in fields {
@ -31,9 +33,8 @@ fn expand_string(input: &str) -> String {
}
}
let name = &type_.ident;
let (impl_generics, ty_generics, where_clause) = type_.generics.split_for_impl();
let name = &input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let mut items = quote! {
impl #impl_generics ::js::conversions::ToJSValConvertible for #name #ty_generics #where_clause {
#[allow(unsafe_code)]
@ -60,7 +61,7 @@ fn expand_string(input: &str) -> String {
};
let mut params = quote::Tokens::new();
params.append_separated(type_.generics.ty_params.iter().map(|param| &param.ident), ", ");
params.append_separated(input.generics.type_params().map(|param| param.ident), ", ");
// For each field in the struct, we implement ShouldNotImplDomObject for a
// pair of all the type parameters of the DomObject and and the field type.
@ -72,33 +73,21 @@ fn expand_string(input: &str) -> String {
}
}));
let bound = syn::TyParamBound::Trait(
syn::PolyTraitRef {
bound_lifetimes: vec![],
trait_ref: syn::parse_path("::dom::bindings::reflector::DomObject").unwrap(),
},
syn::TraitBoundModifier::None
);
let mut generics = input.generics.clone();
generics.params.push(parse_quote!(__T: ::dom::bindings::reflector::DomObject));
let mut generics = type_.generics.clone();
generics.ty_params.push(syn::TyParam {
attrs: vec![],
ident: "__T".into(),
bounds: vec![bound],
default: None,
});
let (impl_generics, _, where_clause) = generics.split_for_impl();
items.append(quote! {
items.append_all(quote! {
trait ShouldNotImplDomObject {}
impl #impl_generics ShouldNotImplDomObject for ((#params), __T) #where_clause {}
}.as_str());
});
let dummy_const = syn::Ident::new(format!("_IMPL_DOMOBJECT_FOR_{}", name));
let dummy_const = syn::Ident::from(format!("_IMPL_DOMOBJECT_FOR_{}", name));
let tokens = quote! {
#[allow(non_upper_case_globals)]
const #dummy_const: () = { #items };
};
tokens.to_string()
tokens
}

View file

@ -10,6 +10,6 @@ path = "lib.rs"
proc-macro = true
[dependencies]
quote = "0.3.15"
syn = "0.11"
synstructure = "0.5"
quote = "0.4.2"
syn = "0.12.12"
synstructure = "0.7"

View file

@ -2,39 +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/. */
extern crate proc_macro;
#[macro_use] extern crate quote;
extern crate syn;
extern crate synstructure;
#[macro_use] extern crate syn;
#[macro_use] extern crate synstructure;
#[proc_macro_derive(JSTraceable)]
pub fn expand_token_stream(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
expand_string(&input.to_string()).parse().unwrap()
}
decl_derive!([JSTraceable] => js_traceable_derive);
fn expand_string(input: &str) -> String {
let mut type_ = syn::parse_macro_input(input).unwrap();
let style = synstructure::BindStyle::Ref.into();
let match_body = synstructure::each_field(&mut type_, &style, |binding| {
Some(quote! { #binding.trace(tracer); })
fn js_traceable_derive(s: synstructure::Structure) -> quote::Tokens {
let match_body = s.each(|binding| {
Some(quote!(#binding.trace(tracer);))
});
let name = &type_.ident;
let (impl_generics, ty_generics, where_clause) = type_.generics.split_for_impl();
let mut where_clause = where_clause.clone();
for param in &type_.generics.ty_params {
where_clause.predicates.push(syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate {
bound_lifetimes: Vec::new(),
bounded_ty: syn::Ty::Path(None, param.ident.clone().into()),
bounds: vec![syn::TyParamBound::Trait(
syn::PolyTraitRef {
bound_lifetimes: Vec::new(),
trait_ref: syn::parse_path("::dom::bindings::trace::JSTraceable").unwrap(),
},
syn::TraitBoundModifier::None
)],
}))
let ast = s.ast();
let name = ast.ident;
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
let mut where_clause = where_clause.unwrap_or(&parse_quote!(where)).clone();
for param in ast.generics.type_params() {
let ident = param.ident;
where_clause.predicates.push(parse_quote!(#ident: ::dom::bindings::trace::JSTraceable))
}
let tokens = quote! {
@ -51,5 +36,5 @@ fn expand_string(input: &str) -> String {
}
};
tokens.to_string()
tokens
}

View file

@ -10,6 +10,6 @@ path = "lib.rs"
proc-macro = true
[dependencies]
quote = "0.3.15"
syn = "0.11"
synstructure = "0.5"
quote = "0.4.2"
syn = { version = "0.12.12", features = ["full"] }
synstructure = "0.7"

View file

@ -10,36 +10,35 @@
//! A crate for deriving the MallocSizeOf trait.
#[cfg(not(test))] extern crate proc_macro;
#[macro_use] extern crate quote;
extern crate syn;
extern crate synstructure;
#[macro_use] extern crate syn;
#[cfg(not(test))]
#[proc_macro_derive(MallocSizeOf, attributes(ignore_malloc_size_of))]
pub fn expand_token_stream(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
expand_string(&input.to_string()).parse().unwrap()
}
#[macro_use] extern crate synstructure;
fn expand_string(input: &str) -> String {
let mut type_ = syn::parse_macro_input(input).unwrap();
#[cfg(test)]
extern crate synstructure;
let style = synstructure::BindStyle::Ref.into();
let match_body = synstructure::each_field(&mut type_, &style, |binding| {
let ignore = binding.field.attrs.iter().any(|attr| match attr.value {
syn::MetaItem::Word(ref ident) |
syn::MetaItem::List(ref ident, _) if ident == "ignore_malloc_size_of" => {
#[cfg(not(test))]
decl_derive!([MallocSizeOf, attributes(ignore_malloc_size_of)] => malloc_size_of_derive);
fn malloc_size_of_derive(s: synstructure::Structure) -> quote::Tokens {
let match_body = s.each(|binding| {
let ignore = binding.ast().attrs.iter().any(|attr| match attr.interpret_meta().unwrap() {
syn::Meta::Word(ref ident) |
syn::Meta::List(syn::MetaList { ref ident, .. }) if ident == "ignore_malloc_size_of" => {
panic!("#[ignore_malloc_size_of] should have an explanation, \
e.g. #[ignore_malloc_size_of = \"because reasons\"]");
}
syn::MetaItem::NameValue(ref ident, _) if ident == "ignore_malloc_size_of" => {
syn::Meta::NameValue(syn::MetaNameValue { ref ident, .. }) if ident == "ignore_malloc_size_of" => {
true
}
_ => false,
});
if ignore {
None
} else if let syn::Ty::Array(..) = binding.field.ty {
} else if let syn::Type::Array(..) = binding.ast().ty {
Some(quote! {
for item in #binding.iter() {
sum += ::malloc_size_of::MallocSizeOf::size_of(item, ops);
@ -52,21 +51,13 @@ fn expand_string(input: &str) -> String {
}
});
let name = &type_.ident;
let (impl_generics, ty_generics, where_clause) = type_.generics.split_for_impl();
let mut where_clause = where_clause.clone();
for param in &type_.generics.ty_params {
where_clause.predicates.push(syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate {
bound_lifetimes: Vec::new(),
bounded_ty: syn::Ty::Path(None, param.ident.clone().into()),
bounds: vec![syn::TyParamBound::Trait(
syn::PolyTraitRef {
bound_lifetimes: Vec::new(),
trait_ref: syn::parse_path("::malloc_size_of::MallocSizeOf").unwrap(),
},
syn::TraitBoundModifier::None
)],
}))
let ast = s.ast();
let name = &ast.ident;
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
let mut where_clause = where_clause.unwrap_or(&parse_quote!(where)).clone();
for param in ast.generics.type_params() {
let ident = param.ident;
where_clause.predicates.push(parse_quote!(#ident: ::malloc_size_of::MallocSizeOf));
}
let tokens = quote! {
@ -83,13 +74,16 @@ fn expand_string(input: &str) -> String {
}
};
tokens.to_string()
tokens
}
#[test]
fn test_struct() {
let mut source = "struct Foo<T> { bar: Bar, baz: T, #[ignore_malloc_size_of = \"\"] z: Arc<T> }";
let mut expanded = expand_string(source);
let source =
syn::parse_str("struct Foo<T> { bar: Bar, baz: T, #[ignore_malloc_size_of = \"\"] z: Arc<T> }").unwrap();
let source = synstructure::Structure::new(&source);
let expanded = malloc_size_of_derive(source).to_string();
let mut no_space = expanded.replace(" ", "");
macro_rules! match_count {
($e: expr, $count: expr) => {
@ -103,8 +97,9 @@ fn test_struct() {
match_count!("impl<T> ::malloc_size_of::MallocSizeOf for Foo<T> where T: ::malloc_size_of::MallocSizeOf {", 1);
match_count!("sum += ::malloc_size_of::MallocSizeOf::size_of(", 2);
source = "struct Bar([Baz; 3]);";
expanded = expand_string(source);
let source = syn::parse_str("struct Bar([Baz; 3]);").unwrap();
let source = synstructure::Structure::new(&source);
let expanded = malloc_size_of_derive(source).to_string();
no_space = expanded.replace(" ", "");
match_count!("for item in", 1);
}
@ -112,6 +107,7 @@ fn test_struct() {
#[should_panic(expected = "should have an explanation")]
#[test]
fn test_no_reason() {
expand_string("struct A { #[ignore_malloc_size_of] b: C }");
let input = syn::parse_str("struct A { #[ignore_malloc_size_of] b: C }").unwrap();
malloc_size_of_derive(synstructure::Structure::new(&input));
}

View file

@ -10,7 +10,7 @@ path = "lib.rs"
proc-macro = true
[dependencies]
darling = "0.2"
quote = "0.3.15"
syn = { version = "0.11", features = ["visit"] }
synstructure = "0.5.2"
darling = "0.3"
quote = "0.4.2"
syn = { version = "0.12.12", features = ["visit"] }
synstructure = "0.7"

View file

@ -5,41 +5,41 @@
use cg;
use quote::Tokens;
use syn::{DeriveInput, Path};
use synstructure;
pub fn derive(input: DeriveInput) -> Tokens {
let name = &input.ident;
let trait_path = &["values", "animated", "Animate"];
let trait_path = parse_quote!(values::animated::Animate);
let (impl_generics, ty_generics, mut where_clause) =
cg::trait_parts(&input, trait_path);
cg::trait_parts(&input, &trait_path);
let input_attrs = cg::parse_input_attrs::<AnimateInputAttrs>(&input);
let variants = cg::variants(&input);
let mut match_body = quote!();
let mut append_error_clause = variants.len() > 1;
match_body.append_all(variants.iter().flat_map(|variant| {
let variant_attrs = cg::parse_variant_attrs::<AnimationVariantAttrs>(variant);
let s = synstructure::Structure::new(&input);
let mut append_error_clause = s.variants().len() > 1;
let mut match_body = s.variants().iter().fold(quote!(), |body, variant| {
let variant_attrs = cg::parse_variant_attrs::<AnimationVariantAttrs>(&variant.ast());
if variant_attrs.error {
append_error_clause = true;
return None;
return body;
}
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 (this_pattern, this_info) = cg::ref_pattern(&variant, "this");
let (other_pattern, other_info) = cg::ref_pattern(&variant, "other");
let (result_value, result_info) = cg::value(&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))| {
let field_attrs = cg::parse_field_attrs::<AnimationFieldAttrs>(&result.field);
let field_attrs = cg::parse_field_attrs::<AnimationFieldAttrs>(&result.ast());
if field_attrs.constant {
if cg::is_parameterized(&result.field.ty, where_clause.params, None) {
where_clause.inner.predicates.push(cg::where_predicate(
result.field.ty.clone(),
&["std", "cmp", "PartialEq"],
if cg::is_parameterized(&result.ast().ty, &where_clause.params, None) {
where_clause.add_predicate(cg::where_predicate(
result.ast().ty.clone(),
&parse_quote!(std::cmp::PartialEq),
None,
));
where_clause.inner.predicates.push(cg::where_predicate(
result.field.ty.clone(),
&["std", "clone", "Clone"],
where_clause.add_predicate(cg::where_predicate(
result.ast().ty.clone(),
&parse_quote!(std::clone::Clone),
None,
));
}
@ -50,28 +50,29 @@ pub fn derive(input: DeriveInput) -> Tokens {
let #result = ::std::clone::Clone::clone(#this);
}
} else {
where_clause.add_trait_bound(&result.field.ty);
where_clause.add_trait_bound(&result.ast().ty);
quote! {
let #result =
::values::animated::Animate::animate(#this, #other, procedure)?;
}
}
}));
Some(quote! {
quote! {
#body
(&#this_pattern, &#other_pattern) => {
#computations
Ok(#result_value)
}
})
}));
}
});
if append_error_clause {
if let Some(fallback) = input_attrs.fallback {
match_body.append(quote! {
match_body.append_all(quote! {
(this, other) => #fallback(this, other, procedure)
});
} else {
match_body.append(quote! { _ => Err(()) });
match_body.append_all(quote! { _ => Err(()) });
}
}

View file

@ -4,22 +4,21 @@
use darling::{FromDeriveInput, FromField, FromVariant};
use quote::{ToTokens, Tokens};
use std::borrow::Cow;
use std::collections::HashSet;
use std::iter;
use syn::{self, AngleBracketedParameterData, Body, DeriveInput, Field, Ident};
use syn::{ImplGenerics, Path, PathParameters, PathSegment, PolyTraitRef};
use syn::{QSelf, TraitBoundModifier, Ty, TyGenerics, TyParam, TyParamBound};
use syn::{TypeBinding, Variant, WhereBoundPredicate, WherePredicate};
use syn::visit::{self, Visitor};
use synstructure::{self, BindOpts, BindStyle, BindingInfo};
use syn::{self, DeriveInput, Field, Ident};
use syn::{ImplGenerics, Path, PathArguments, PathSegment, AngleBracketedGenericArguments, GenericParam};
use syn::{QSelf, Type, TypeGenerics, TypeParam};
use syn::{TypeSlice, TypeArray, TypeTuple, TypePath, TypeParen};
use syn::{Variant, WherePredicate, GenericArgument, Binding};
use syn::visit::{self, Visit};
use synstructure::{self, BindingInfo, BindStyle, VariantAst, VariantInfo};
pub struct WhereClause<'input, 'path> {
pub inner: syn::WhereClause,
pub params: &'input [TyParam],
trait_path: &'path [&'path str],
trait_output: Option<&'path str>,
bounded_types: HashSet<Ty>,
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> {
@ -29,14 +28,13 @@ impl<'input, 'path> ToTokens for WhereClause<'input, 'path> {
}
impl<'input, 'path> WhereClause<'input, 'path> {
pub fn add_trait_bound(&mut self, ty: &Ty) {
pub fn add_trait_bound(&mut self, ty: &Type) {
let trait_path = self.trait_path;
let params = self.params;
let mut found = self.trait_output.map(|_| HashSet::new());
if self.bounded_types.contains(&ty) {
return;
}
if !is_parameterized(&ty, params, found.as_mut()) {
if !is_parameterized(&ty, &self.params, found.as_mut()) {
return;
}
self.bounded_types.insert(ty.clone());
@ -44,19 +42,19 @@ impl<'input, 'path> WhereClause<'input, 'path> {
let output = if let Some(output) = self.trait_output {
output
} else {
self.inner.predicates.push(where_predicate(ty.clone(), trait_path, None));
self.add_predicate(where_predicate(ty.clone(), trait_path, None));
return;
};
if let Ty::Path(None, ref path) = *ty {
if let Type::Path(syn::TypePath { ref path, .. }) = *ty {
if path_to_ident(path).is_some() {
self.inner.predicates.push(where_predicate(ty.clone(), trait_path, None));
self.add_predicate(where_predicate(ty.clone(), trait_path, None));
return;
}
}
let output_type = map_type_params(ty, params, &mut |ident| {
let ty = Ty::Path(None, ident.clone().into());
let output_type = map_type_params(ty, &self.params, &mut |ident| {
let ty = Type::Path(syn::TypePath { qself: None, path: ident.clone().into() });
fmap_output_type(ty, trait_path, output)
});
@ -66,20 +64,29 @@ impl<'input, 'path> WhereClause<'input, 'path> {
Some((output, output_type)),
);
self.inner.predicates.push(pred);
self.add_predicate(pred);
if let Some(found) = found {
for ident in found {
let ty = Ty::Path(None, ident.into());
let ty = Type::Path(syn::TypePath { qself: None, path: ident.into() });
if !self.bounded_types.contains(&ty) {
self.bounded_types.insert(ty.clone());
self.inner.predicates.push(
self.add_predicate(
where_predicate(ty, trait_path, None),
);
};
}
}
}
pub fn add_predicate(&mut self, pred: WherePredicate) {
if let Some(ref mut inner) = self.inner {
inner.predicates.push(pred);
} else {
self.inner = Some(parse_quote!(where));
self.add_predicate(pred);
}
}
}
pub fn fmap_match<F>(
@ -90,71 +97,77 @@ pub fn fmap_match<F>(
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 s = synstructure::Structure::new(input);
s.variants_mut().iter_mut().for_each(|v| { v.bind_with(|_| bind_style); });
s.each_variant(|variant| {
let (mapped, mapped_fields) = value(variant, "mapped");
let fields_pairs = variant.bindings().into_iter().zip(mapped_fields);
let mut computations = quote!();
computations.append_all(fields_pairs.map(|(field, mapped_field)| {
let expr = f(field);
let expr = f(field.clone());
quote! { let #mapped_field = #expr; }
}));
computations.append(mapped);
computations.append_all(mapped);
Some(computations)
})
}
fn fmap_output_type(
ty: Ty,
trait_path: &[&str],
trait_output: &str,
) -> Ty {
Ty::Path(
Some(QSelf {
ty: Box::new(ty),
position: trait_path.len(),
}),
path(trait_path.iter().chain(iter::once(&trait_output))),
)
ty: Type,
trait_path: &Path,
trait_output: Ident,
) -> Type {
parse_quote!(<#ty as ::#trait_path>::#trait_output)
}
pub fn fmap_trait_parts<'input, 'path>(
input: &'input DeriveInput,
trait_path: &'path [&'path str],
trait_output: &'path str,
) -> (ImplGenerics<'input>, TyGenerics<'input>, WhereClause<'input, 'path>, Path) {
trait_path: &'path Path,
trait_output: Ident,
) -> (ImplGenerics<'input>, TypeGenerics<'input>, WhereClause<'input, 'path>, Path) {
let (impl_generics, ty_generics, mut where_clause) = trait_parts(input, trait_path);
where_clause.trait_output = Some(trait_output);
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| {
fmap_output_type(
Ty::Path(None, ty.ident.clone().into()),
trait_path,
trait_output,
)
arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
args: input.generics.params.iter().map(|arg| {
match arg {
&GenericParam::Lifetime(ref data) => GenericArgument::Lifetime(data.lifetime.clone()),
&GenericParam::Type(ref data) => {
let ident = data.ident;
GenericArgument::Type(
fmap_output_type(
parse_quote!(#ident),
trait_path,
trait_output
)
)
},
ref arg => panic!("arguments {:?} cannot be mapped yet", arg)
}
}).collect(),
.. Default::default()
}),
}.into();
(impl_generics, ty_generics, where_clause, output_ty)
colon2_token: Default::default(),
gt_token: Default::default(),
lt_token: Default::default(),
})
};
(impl_generics, ty_generics, where_clause, output_ty.into())
}
pub fn is_parameterized(
ty: &Ty,
params: &[TyParam],
ty: &Type,
params: &[&TypeParam],
found: Option<&mut HashSet<Ident>>,
) -> bool {
struct IsParameterized<'a, 'b> {
params: &'a [TyParam],
params: &'a [&'a TypeParam],
has_free: bool,
found: Option<&'b mut HashSet<Ident>>,
}
impl<'a, 'b> Visitor for IsParameterized<'a, 'b> {
fn visit_path(&mut self, path: &Path) {
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;
@ -163,100 +176,104 @@ pub fn is_parameterized(
}
}
}
visit::walk_path(self, path);
visit::visit_path(self, path);
}
}
let mut visitor = IsParameterized { params, has_free: false, found };
visitor.visit_ty(ty);
visitor.visit_type(ty);
visitor.has_free
}
pub fn map_type_params<F>(ty: &Ty, params: &[TyParam], f: &mut F) -> Ty
pub fn map_type_params<F>(ty: &Type, params: &[&TypeParam], f: &mut F) -> Type
where
F: FnMut(&Ident) -> Ty,
F: FnMut(&Ident) -> Type,
{
match *ty {
Ty::Slice(ref ty) => Ty::Slice(Box::new(map_type_params(ty, params, f))),
Ty::Array(ref ty, ref expr) => {
Ty::Array(Box::new(map_type_params(ty, params, f)), expr.clone())
Type::Slice(ref inner) => {
Type::from(TypeSlice { elem: Box::new(map_type_params(&inner.elem, params, f)), ..inner.clone() })
},
Ty::Never => Ty::Never,
Ty::Tup(ref items) => {
Ty::Tup(items.iter().map(|ty| map_type_params(ty, params, f)).collect())
Type::Array(ref inner) => { //ref ty, ref expr) => {
Type::from(TypeArray { elem: Box::new(map_type_params(&inner.elem, params, f)), ..inner.clone() })
},
Ty::Path(None, ref path) => {
ref ty @ Type::Never(_) => ty.clone(),
Type::Tuple(ref inner) => {
Type::from(
TypeTuple {
elems: inner.elems.iter().map(|ty| map_type_params(&ty, params, f)).collect(),
..inner.clone()
}
)
},
Type::Path(TypePath { qself: None, ref path }) => {
if let Some(ident) = path_to_ident(path) {
if params.iter().any(|param| param.ident == ident) {
return f(ident);
}
}
Ty::Path(None, map_type_params_in_path(path, params, f))
Type::from(TypePath { qself: None, path: map_type_params_in_path(path, params, f) })
}
Ty::Path(ref qself, ref path) => {
Ty::Path(
qself.as_ref().map(|qself| {
Type::Path(TypePath { ref qself, ref path }) => {
Type::from(TypePath {
qself: qself.as_ref().map(|qself| {
QSelf {
ty: Box::new(map_type_params(&qself.ty, params, f)),
position: qself.position,
..qself.clone()
}
}),
map_type_params_in_path(path, params, f),
)
path: map_type_params_in_path(path, params, f),
})
},
Type::Paren(ref inner) => {
Type::from(TypeParen { elem: Box::new(map_type_params(&inner.elem, params, f)), ..inner.clone() })
},
Ty::Paren(ref ty) => Ty::Paren(Box::new(map_type_params(ty, params, f))),
ref ty => panic!("type {:?} cannot be mapped yet", ty),
}
}
fn map_type_params_in_path<F>(path: &Path, params: &[TyParam], f: &mut F) -> Path
fn map_type_params_in_path<F>(path: &Path, params: &[&TypeParam], f: &mut F) -> Path
where
F: FnMut(&Ident) -> Ty,
F: FnMut(&Ident) -> Type,
{
Path {
global: path.global,
leading_colon: path.leading_colon,
segments: path.segments.iter().map(|segment| {
PathSegment {
ident: segment.ident.clone(),
parameters: match segment.parameters {
PathParameters::AngleBracketed(ref data) => {
PathParameters::AngleBracketed(AngleBracketedParameterData {
lifetimes: data.lifetimes.clone(),
types: data.types.iter().map(|ty| {
map_type_params(ty, params, f)
}).collect(),
bindings: data.bindings.iter().map(|binding| {
TypeBinding {
ident: binding.ident.clone(),
ty: map_type_params(&binding.ty, params, f),
arguments: match segment.arguments {
PathArguments::AngleBracketed(ref data) => {
PathArguments::AngleBracketed(AngleBracketedGenericArguments {
args: data.args.iter().map(|arg| {
match arg {
ty @ &GenericArgument::Lifetime(_) => ty.clone(),
&GenericArgument::Type(ref data) => {
GenericArgument::Type(map_type_params(data, params, f))
},
&GenericArgument::Binding(ref data) => GenericArgument::Binding(Binding {
ty: map_type_params(&data.ty, params, f),
..data.clone()
}),
ref arg => panic!("arguments {:?} cannot be mapped yet", arg)
}
}).collect(),
..data.clone()
})
},
ref arg @ PathArguments::None => arg.clone(),
ref parameters => {
panic!("parameters {:?} cannot be mapped yet", parameters)
},
}
},
}
}).collect(),
}
}
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(),
}
}
fn path_to_ident(path: &Path) -> Option<&Ident> {
match *path {
Path { global: false, ref segments } if segments.len() == 1 => {
if segments[0].parameters.is_empty() {
Path { leading_colon: None, ref segments } if segments.len() == 1 => {
if segments[0].arguments.is_empty() {
Some(&segments[0].ident)
} else {
None
@ -286,36 +303,41 @@ where
}
}
pub fn parse_variant_attrs<A>(variant: &Variant) -> A
pub fn parse_variant_attrs<A>(variant: &VariantAst) -> A
where
A: FromVariant,
{
match A::from_variant(variant) {
let v = Variant {
ident: *variant.ident,
attrs: variant.attrs.to_vec(),
fields: variant.fields.clone(),
discriminant: variant.discriminant.clone(),
};
match A::from_variant(&v) {
Ok(attrs) => attrs,
Err(e) => panic!("failed to parse variant attributes: {}", e),
}
}
pub fn ref_pattern<'a>(
name: &Ident,
variant: &'a Variant,
variant: &'a VariantInfo,
prefix: &str,
) -> (Tokens, Vec<BindingInfo<'a>>) {
synstructure::match_pattern(
&name,
&variant.data,
&BindOpts::with_prefix(BindStyle::Ref, prefix.to_owned()),
)
let mut v = variant.clone();
v.bind_with(|_| BindStyle::Ref);
v.bindings_mut().iter_mut().for_each(|b| { b.binding = Ident::from(format!("{}_{}", b.binding, prefix)) });
(v.pat(), v.bindings().iter().cloned().collect())
}
pub fn trait_parts<'input, 'path>(
input: &'input DeriveInput,
trait_path: &'path [&'path str],
) -> (ImplGenerics<'input>, TyGenerics<'input>, WhereClause<'input, 'path>) {
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.clone(),
params: &input.generics.ty_params,
inner: where_clause.cloned(),
params: input.generics.type_params().into_iter().collect::<Vec<&TypeParam>>(),
trait_path,
trait_output: None,
bounded_types: HashSet::new()
@ -323,88 +345,35 @@ pub fn trait_parts<'input, 'path>(
(impl_generics, ty_generics, where_clause)
}
fn 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()
}
)
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)
};
Path {
global: true,
segments: {
parent
.iter()
.cloned()
.map(Into::into)
.chain(iter::once(last_segment))
.collect()
},
}
parse_quote!(::#(#parent::)*#last_segment)
}
pub fn value<'a>(
name: &Ident,
variant: &'a Variant,
variant: &'a VariantInfo,
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()
},
}
let mut v = variant.clone();
v.bindings_mut().iter_mut().for_each(|b| { b.binding = Ident::from(format!("{}_{}", b.binding, prefix)) });
v.bind_with(|_| BindStyle::Move);
(v.pat(), v.bindings().iter().cloned().collect())
}
pub fn where_predicate(
bounded_ty: Ty,
trait_path: &[&str],
trait_output: Option<(&str, Ty)>,
bounded_ty: Type,
trait_path: &Path,
trait_output: Option<(Ident, Type)>,
) -> WherePredicate {
WherePredicate::BoundPredicate(WhereBoundPredicate {
bound_lifetimes: vec![],
bounded_ty,
bounds: vec![TyParamBound::Trait(
PolyTraitRef {
bound_lifetimes: vec![],
trait_ref: trait_ref(trait_path, trait_output),
},
TraitBoundModifier::None
)],
})
let trait_ref = trait_ref(trait_path, trait_output);
parse_quote!(#bounded_ty: #trait_ref)
}
/// Transforms "FooBar" to "foo-bar".

View file

@ -6,52 +6,54 @@ use animate::AnimationVariantAttrs;
use cg;
use quote::Tokens;
use syn::{DeriveInput, Path};
use synstructure;
pub fn derive(input: DeriveInput) -> Tokens {
let name = &input.ident;
let trait_path = &["values", "distance", "ComputeSquaredDistance"];
let trait_path = parse_quote!(values::distance::ComputeSquaredDistance);
let (impl_generics, ty_generics, mut where_clause) =
cg::trait_parts(&input, trait_path);
cg::trait_parts(&input, &trait_path);
let input_attrs = cg::parse_input_attrs::<DistanceInputAttrs>(&input);
let variants = cg::variants(&input);
let mut match_body = quote!();
let mut append_error_clause = variants.len() > 1;
match_body.append_all(variants.iter().map(|variant| {
let attrs = cg::parse_variant_attrs::<AnimationVariantAttrs>(variant);
let s = synstructure::Structure::new(&input);
let mut append_error_clause = s.variants().len() > 1;
let mut match_body = s.variants().iter().fold(quote!(), |body, variant| {
let attrs = cg::parse_variant_attrs::<AnimationVariantAttrs>(&variant.ast());
if attrs.error {
append_error_clause = true;
return None;
return body;
}
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 (this_pattern, this_info) = cg::ref_pattern(&variant, "this");
let (other_pattern, other_info) = cg::ref_pattern(&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.add_trait_bound(&this.field.ty);
where_clause.add_trait_bound(&this.ast().ty);
quote! {
::values::distance::ComputeSquaredDistance::compute_squared_distance(#this, #other)?
}
}), "+");
}), quote!(+));
sum
};
Some(quote! {
quote! {
#body
(&#this_pattern, &#other_pattern) => {
Ok(#sum)
}
})
}));
}
});
if append_error_clause {
if let Some(fallback) = input_attrs.fallback {
match_body.append(quote! {
match_body.append_all(quote! {
(this, other) => #fallback(this, other)
});
} else {
match_body.append(quote! { _ => Err(()) });
match_body.append_all(quote! { _ => Err(()) });
}
}

View file

@ -7,7 +7,7 @@
#[macro_use] extern crate darling;
extern crate proc_macro;
#[macro_use] extern crate quote;
extern crate syn;
#[macro_use] extern crate syn;
extern crate synstructure;
use proc_macro::TokenStream;
@ -23,42 +23,42 @@ mod to_css;
#[proc_macro_derive(Animate, attributes(animate, animation))]
pub fn derive_animate(stream: TokenStream) -> TokenStream {
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
animate::derive(input).to_string().parse().unwrap()
let input = syn::parse(stream).unwrap();
animate::derive(input).into()
}
#[proc_macro_derive(ComputeSquaredDistance, attributes(animation, distance))]
pub fn derive_compute_squared_distance(stream: TokenStream) -> TokenStream {
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
compute_squared_distance::derive(input).to_string().parse().unwrap()
let input = syn::parse(stream).unwrap();
compute_squared_distance::derive(input).into()
}
#[proc_macro_derive(ToAnimatedValue)]
pub fn derive_to_animated_value(stream: TokenStream) -> TokenStream {
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
to_animated_value::derive(input).to_string().parse().unwrap()
let input = syn::parse(stream).unwrap();
to_animated_value::derive(input).into()
}
#[proc_macro_derive(Parse, attributes(css))]
pub fn derive_parse(stream: TokenStream) -> TokenStream {
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
parse::derive(input).to_string().parse().unwrap()
let input = syn::parse(stream).unwrap();
parse::derive(input).into()
}
#[proc_macro_derive(ToAnimatedZero, attributes(animation))]
pub fn derive_to_animated_zero(stream: TokenStream) -> TokenStream {
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
to_animated_zero::derive(input).to_string().parse().unwrap()
let input = syn::parse(stream).unwrap();
to_animated_zero::derive(input).into()
}
#[proc_macro_derive(ToComputedValue, attributes(compute))]
pub fn derive_to_computed_value(stream: TokenStream) -> TokenStream {
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
to_computed_value::derive(input).to_string().parse().unwrap()
let input = syn::parse(stream).unwrap();
to_computed_value::derive(input).into()
}
#[proc_macro_derive(ToCss, attributes(css))]
pub fn derive_to_css(stream: TokenStream) -> TokenStream {
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
to_css::derive(input).to_string().parse().unwrap()
let input = syn::parse(stream).unwrap();
to_css::derive(input).into()
}

View file

@ -10,38 +10,40 @@ use to_css::CssVariantAttrs;
pub fn derive(input: DeriveInput) -> Tokens {
let name = &input.ident;
let s = synstructure::Structure::new(&input);
let mut match_body = quote! {};
let style = synstructure::BindStyle::Ref.into();
synstructure::each_variant(&input, &style, |bindings, variant| {
let match_body = s.variants().iter().fold(quote!(), |match_body, variant| {
let bindings = variant.bindings();
assert!(
bindings.is_empty(),
"Parse is only supported for single-variant enums for now"
);
let variant_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(variant);
let variant_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(&variant.ast());
let identifier = cg::to_css_identifier(
&variant_attrs.keyword.as_ref().unwrap_or(&variant.ident).as_ref(),
&variant_attrs.keyword.unwrap_or(variant.ast().ident.as_ref().into()),
);
let ident = &variant.ident;
let ident = &variant.ast().ident;
match_body = quote! {
let mut body = quote! {
#match_body
#identifier => Ok(#name::#ident),
};
let aliases = match variant_attrs.aliases {
Some(aliases) => aliases,
None => return,
None => return body,
};
for alias in aliases.split(",") {
match_body = quote! {
#match_body
body = quote! {
#body
#alias => Ok(#name::#ident),
};
}
body
});
let parse_trait_impl = quote! {

View file

@ -4,17 +4,17 @@
use cg;
use quote;
use syn;
use syn::{self, Ident};
use synstructure::BindStyle;
pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
let name = &input.ident;
let trait_path = &["values", "animated", "ToAnimatedValue"];
let trait_path = parse_quote!(values::animated::ToAnimatedValue);
let (impl_generics, ty_generics, mut where_clause, animated_value_type) =
cg::fmap_trait_parts(&input, trait_path, "AnimatedValue");
cg::fmap_trait_parts(&input, &trait_path, Ident::from("AnimatedValue"));
let to_body = cg::fmap_match(&input, BindStyle::Move, |binding| {
where_clause.add_trait_bound(&binding.field.ty);
where_clause.add_trait_bound(&binding.ast().ty);
quote!(::values::animated::ToAnimatedValue::to_animated_value(#binding))
});
let from_body = cg::fmap_match(&input, BindStyle::Move, |binding| {

View file

@ -6,31 +6,30 @@ use animate::{AnimationVariantAttrs, AnimationFieldAttrs};
use cg;
use quote;
use syn;
use synstructure::{self, BindStyle};
use synstructure;
pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
let name = &input.ident;
let trait_path = &["values", "animated", "ToAnimatedZero"];
let trait_path = parse_quote!(values::animated::ToAnimatedZero);
let (impl_generics, ty_generics, mut where_clause) =
cg::trait_parts(&input, trait_path);
cg::trait_parts(&input, &trait_path);
let bind_opts = BindStyle::Ref.into();
let to_body = synstructure::each_variant(&input, &bind_opts, |bindings, variant| {
let attrs = cg::parse_variant_attrs::<AnimationVariantAttrs>(variant);
let s = synstructure::Structure::new(&input);
let to_body = s.each_variant(|variant| {
let attrs = cg::parse_variant_attrs::<AnimationVariantAttrs>(&variant.ast());
if attrs.error {
return Some(quote! { Err(()) });
}
let name = cg::variant_ctor(&input, variant);
let (mapped, mapped_bindings) = cg::value(&name, variant, "mapped");
let bindings_pairs = bindings.into_iter().zip(mapped_bindings);
let (mapped, mapped_bindings) = cg::value(variant, "mapped");
let bindings_pairs = variant.bindings().into_iter().zip(mapped_bindings);
let mut computations = quote!();
computations.append_all(bindings_pairs.map(|(binding, mapped_binding)| {
let field_attrs = cg::parse_field_attrs::<AnimationFieldAttrs>(&binding.field);
let field_attrs = cg::parse_field_attrs::<AnimationFieldAttrs>(&binding.ast());
if field_attrs.constant {
if cg::is_parameterized(&binding.field.ty, where_clause.params, None) {
where_clause.inner.predicates.push(cg::where_predicate(
binding.field.ty.clone(),
&["std", "clone", "Clone"],
if cg::is_parameterized(&binding.ast().ty, &where_clause.params, None) {
where_clause.add_predicate(cg::where_predicate(
binding.ast().ty.clone(),
&parse_quote!(std::clone::Clone),
None,
));
}
@ -38,14 +37,14 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
let #mapped_binding = ::std::clone::Clone::clone(#binding);
}
} else {
where_clause.add_trait_bound(&binding.field.ty);
where_clause.add_trait_bound(&binding.ast().ty);
quote! {
let #mapped_binding =
::values::animated::ToAnimatedZero::to_animated_zero(#binding)?;
}
}
}));
computations.append(quote! { Ok(#mapped) });
computations.append_all(quote! { Ok(#mapped) });
Some(computations)
});

View file

@ -4,29 +4,29 @@
use cg;
use quote::Tokens;
use syn::DeriveInput;
use syn::{Ident, DeriveInput};
use synstructure::BindStyle;
pub fn derive(input: DeriveInput) -> Tokens {
let name = &input.ident;
let trait_path = &["values", "computed", "ToComputedValue"];
let trait_path = parse_quote!(values::computed::ToComputedValue);
let (impl_generics, ty_generics, mut where_clause, computed_value_type) =
cg::fmap_trait_parts(&input, trait_path, "ComputedValue");
cg::fmap_trait_parts(&input, &trait_path, Ident::from("ComputedValue"));
let to_body = cg::fmap_match(&input, BindStyle::Ref, |binding| {
let attrs = cg::parse_field_attrs::<ComputedValueAttrs>(&binding.field);
let attrs = cg::parse_field_attrs::<ComputedValueAttrs>(&binding.ast());
if attrs.clone {
if cg::is_parameterized(&binding.field.ty, where_clause.params, None) {
where_clause.inner.predicates.push(cg::where_predicate(
binding.field.ty.clone(),
&["std", "clone", "Clone"],
if cg::is_parameterized(&binding.ast().ty, &where_clause.params, None) {
where_clause.add_predicate(cg::where_predicate(
binding.ast().ty.clone(),
&parse_quote!(std::clone::Clone),
None,
));
}
quote! { ::std::clone::Clone::clone(#binding) }
} else {
if !attrs.ignore_bound {
where_clause.add_trait_bound(&binding.field.ty);
where_clause.add_trait_bound(&binding.ast().ty);
}
quote! {
::values::computed::ToComputedValue::to_computed_value(#binding, context)
@ -34,7 +34,7 @@ pub fn derive(input: DeriveInput) -> Tokens {
}
});
let from_body = cg::fmap_match(&input, BindStyle::Ref, |binding| {
let attrs = cg::parse_field_attrs::<ComputedValueAttrs>(&binding.field);
let attrs = cg::parse_field_attrs::<ComputedValueAttrs>(&binding.ast());
if attrs.clone {
quote! { ::std::clone::Clone::clone(#binding) }
} else {

View file

@ -5,20 +5,23 @@
use cg;
use darling::{Error, FromMetaItem};
use quote::Tokens;
use syn::{self, DeriveInput, Ident};
use syn::{self, Ident};
use synstructure;
pub fn derive(input: DeriveInput) -> Tokens {
pub fn derive(input: syn::DeriveInput) -> Tokens {
let name = &input.ident;
let trait_path = &["style_traits", "ToCss"];
let trait_path = parse_quote!(style_traits::ToCss);
let (impl_generics, ty_generics, mut where_clause) =
cg::trait_parts(&input, trait_path);
cg::trait_parts(&input, &trait_path);
let input_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
let style = synstructure::BindStyle::Ref.into();
let match_body = synstructure::each_variant(&input, &style, |bindings, variant| {
let identifier = cg::to_css_identifier(variant.ident.as_ref());
let variant_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(variant);
let s = synstructure::Structure::new(&input);
let match_body = s.each_variant(|variant| {
let bindings = variant.bindings();
let identifier = cg::to_css_identifier(variant.ast().ident.as_ref());
let ast = variant.ast();
let variant_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(&ast);
let separator = if variant_attrs.comma { ", " } else { " " };
if variant_attrs.dimension {
@ -49,9 +52,9 @@ pub fn derive(input: DeriveInput) -> Tokens {
};
} else {
for binding in bindings {
let attrs = cg::parse_field_attrs::<CssFieldAttrs>(&binding.field);
let attrs = cg::parse_field_attrs::<CssFieldAttrs>(&binding.ast());
if !attrs.ignore_bound {
where_clause.add_trait_bound(&binding.field.ty);
where_clause.add_trait_bound(&binding.ast().ty);
}
expr = quote! {
#expr
@ -107,7 +110,7 @@ pub fn derive(input: DeriveInput) -> Tokens {
};
if input_attrs.derive_debug {
impls.append(quote! {
impls.append_all(quote! {
impl #impl_generics ::std::fmt::Debug for #name #ty_generics #where_clause {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
::style_traits::ToCss::to_css(
@ -137,7 +140,7 @@ pub struct CssVariantAttrs {
pub iterable: bool,
pub comma: bool,
pub dimension: bool,
pub keyword: Option<Ident>,
pub keyword: Option<String>,
pub aliases: Option<String>,
}
@ -157,7 +160,7 @@ impl FromMetaItem for Function {
}
fn from_string(name: &str) -> Result<Self, Error> {
let name = syn::parse_ident(name).map_err(Error::custom)?;
let name = Ident::from(name);
Ok(Self { name: Some(name) })
}
}

View file

@ -39,6 +39,9 @@ packages = [
"bitflags",
"lazy_static",
"winapi",
"syn",
"quote",
"unicode-xid",
]
# Files that are ignored for all tidy and lint checks.
files = [