-
-
Notifications
You must be signed in to change notification settings - Fork 313
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement combine_substructure helper #27
Comments
@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! |
Just one remark though: @mystor's implementation currently only allows bindings to be named 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 It would be nice if such a helper allowed for a custom placeholder name. |
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 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()
} |
Based on the one from libsyntax.
The text was updated successfully, but these errors were encountered: