Using a custom derive macro "standalone" to create impls for my trait

Let's assume I implemented a new trait, and I created a custom derive macro that works for structs and enums. I would like to write impls for all the datatypes the standard library, but I'd like to have them derived by my macro. How is this done?

Basically, something like

#[derive(MyTrait, u8)]

In principle this should be possible since my macro doesn't do anything else than creating the TokenStream that contains the quoted impl MyTrait for u8. But I don't know how I can call my macro with the correct DeriveInput. Given a type like u8, how do I get the DeriveInput? Is there a way in macros to "look up the definition" and convert it to DeriveInput?

In the case of u8 there is no suitable DeriveInput since u8 is not defined anywhere in source code, but built into the compiler.

You could also provide a function-like macro version (i.e. #[proc_macro] instead of #[proc_macro_derive(MyTrait)]) of your derive macro. Then call that and provide the full definition of the struct or enum. You would probably only expect this to work for structs or enums anyways (because that’s what derive-macros have to be able to handle), and only if it isn’t non_exhaustive and all the fields are public. In that case, it should work, you’d call it e.g. like

name_of_my_macro! {
    pub enum Option<T> {
        None,
        Some(T),
    }
}

Looking up the definition of a type with a macro is unfortunately not possible. You can find the definition of a standard library type yourself e.g. with the [src] buttons in the standard library docs.

1 Like

Ah true, then let's take Option<T> or some enum as an example.

Ah that's a shame :frowning: in Haskell you can achieve such effects with standalone deriving clauses. Copying all the definitions by hand seems error prone. Is it maybe possible to pass a crate (such as std) or file to a macro? Then I could filter through it and search for all datatype definitions.

AFAIK, Haskell doesn’t even support something like custom derive macros at all. OTOH, template Haskell does allow looking up of definitions, IIRC, so that’s a fair point.

(GHC) Haskell's deriving machinery is definitely more advanced than Rust's in some respects, enabled by closer integration with the compiler: deriving is a language-level construct, so GHC can leverage information from type inference etc. in translating it, whereas proc macros in Rust have to run to completion before type checking even begins, operate on the level of syntax, and only get access to the tokens you explicitly pass them. I would love something like GeneralizedNewtypeDeriving or even DerivingVia for Rust, but it's just not possible with proc macros alone afaict, and standalone deriving is in the same category.

Then maybe the best we can do is something like doctest does: Scan through source files. Ideally I'd do something like

let all_structs_in_crate = files_in_crate!(std)
    .iter()
    .flat_map(|file| file.items)
    .filter_map(|item| match item {
        Struct(struct_item) => Some(my_proc_macro(struct_item)),
        _ => None,
    })

quote! {
    #(all_structs_in_crate)*
}

I have my_proc_macro. I'm lacking a macro that does vaguely something like files_in_crate.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.