Comments (3)
@mystor has a promising implementation in abomonation_derive which he plans to factor into a separate crate. I will keep this ticket open until we have something to point people to. Thanks Michael!
from syn.
Just one remark though: @mystor's implementation currently only allows bindings to be named __binding_{i}
where i
starts at 0.
In order to implement something like PartialEq
you need two match
es like that:
fn eq(&self, __arg_0: &Foo<T>) -> bool {
match *__arg_0 {
Foo { foo: ref __self_1_0, bar: ref __self_1_1 } =>
match *self {
Foo { foo: ref __self_0_0, bar: ref __self_0_1 } =>
true && (*__self_0_0) == (*__self_1_0) &&
(*__self_0_1) == (*__self_1_1),
},
}
}
(this is what derive(PartialEq)
actually generates)
It would be nice if such a helper allowed for a custom placeholder name.
from syn.
Firstly, I split my first implementation into its own crate, you can find it here: https://github.com/mystor/synstructure or on crates.io.
@mcarton: I don't currently have support for that, but you can kinda do it yourself, by generating your own let
bindings in the outer scope, so you would generate code which looks something like:
fn eq(&self, __arg_0: &Foo<T>) -> bool {
match *__arg_0 {
Foo { foo: ref __binding_0, bar: ref __binding_1 } => {
let __self_1_0 = __binding_0;
let __self_1_1 = __binding_1;
match *self {
Foo { foo: ref __binding_0, bar: ref __binding_1 } =>
true && (*__binding_0) == (*__self_1_0) &&
(*__binding_1) == (*__self_1_1),
}
}
}
}
I'll admit that that is pretty gross though. I don't really want to add a ton of arguments to these methods because that feels like it will clutter up the interface. It might be easier to just add some sort of helper method which just "renames" the bindings for you with let bindings (I can't imagine those have any performance overhead after optimization). If such a method existed, an eq derive would look something like the following (I haven't tested this, so no promises that I didn't screw something up):
fn derive_partialeq(input: TokenStream) -> TokenStream {
let source = input.to_string();
let mut ast = syn::parse_macro_input(&source).unwrap();
// We need to copy the AST for the inner body, because match_substructs
// takes a mutable reference. It's kinda gross, and optimized for the case
// where we want to be able to remove attributes from within the callback.
// I might change this in the future.
let mut ast2 = ast.clone();
let body = match_substructs(&mut ast, bind, |outer_bis| {
let (renaming, outer_bis) = rename_bindings(outer_bis, "outer");
let inner_body = match_substructs(&mut ast, bind, |inner_bis| {
let mut zipped = outer_bis.into_iter().zip(inner_bis.into_iter());
let eqs = zipped.map(|(x, y)| quote!((#x == #y)));
quote!(true #(&& #eqs)*)
})
quote!{
#renaming
match *self { #inner_body }
}
}):
let name = &ast.ident;
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
let result = quote! {
#ast
impl #impl_generics PartialEq for #name #ty_generics #where_clause {
fn eq(&self, __arg_0: &Self) -> bool {
match *__arg_0 { #body }
}
}
};
result.to_string().parse().unwrap()
}
from syn.
Related Issues (20)
- Parsing keywords in `Meta`-path positions fails with syn v2 HOT 4
- Can't parse `DeriveInput` containing an expression-position macro invocation without `full` feature HOT 1
- [Question/Bug] Raw strings in function HOT 3
- Mention 5036fd9c6e9b89809f93a6ffa17ac6663652baed in release notes for 2.0.9
- `parse_nested_meta` docs: mention that error will be returned if closure doesn't parse non-path parts
- cannot find macro `compile_error` in this scope
- Attribute of assign expr HOT 2
- Make syn::meta::parse_nested_meta public?
- `Ident::as_str()` method? HOT 2
- Parsing expression `a.0.1` doesn't have the right spans
- Parse "return type notation"
- Parse non-lifetime binders
- Syn 2.0 doesn't causes problems when parsing keywords in attributes HOT 1
- Add `parse_macro_input2` for `proc_macro2::TokenStream` HOT 1
- Incorrect line column information when parsing from string HOT 2
- Why is Spanned sealed?
- "unexpected token" error even when all input has been parsed HOT 4
- dump_syntax doesn't give span info for lex errors
- How to avoid from the specific error when parsing nested meta? HOT 3
- Add `parse2_macro_input` (or equivalent) parsing macro using `syn::parse2` instead of `syn::parse` HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from syn.