I have written my own procedural macro My_Proc_Macro
so I can do things like:
#[derive(My_Proc_Macro)
pub struct/enum Ident {
...
}
Now, consider a generic case:
#[derive(My_Proc_Macro)
pub struct/enum Ident<T> {
...
}
In the case of T: My_Porc_Macro
, I want My_Proc_Macro to generate code for Ident<T>
In the case T does not satisfy My_Proc_Macro
, I want My_Proc_Macro to no-op on Ident<T>
How do I do this in a procedural macro ?
Aside: I believe this is possible given the behaviour of Clone
on types T depending on whether T: Clone
As posed, this isn't possible. The only thing a procedural macro knows about T
is that it is a type parameter called T
, as part of the syntax tree of the item (in this case, the struct or enum Ident
) it's processing. The macro implementation isn't provided with any information about the rest of the program, such as where Ident
is used or what types populate T
.
However, if you take macro processing out of the picture for a second, I think what you want may be possible in ordinary Rust. And, if it is, then you can generate that Rust from within your macro processor.
Consider the following:
pub struct Ident<T> {
some_field: T,
}
impl<T> My_Proc_Macro for Ident<T>
where T: My_Proc_Macro {
// ...
}
This will provide an implementation of the My_Proc_Macro
trait for Ident<T>
corresponding to every type T
that, itself, also implements My_Proc_Macro
, and for no other types. At first glance, this seems to be to be what you described (edit: and as @quinedot says, this is how Clone
and other deriveable types are implemented); is there a way in which it's not?
2 Likes
(I probably won't be able to answer your actual question, but)
What do you mean by "satisfy My_Proc_Macro
?
Pre-submit edit: Oh, reading the above reply (posted while I was writing) maybe "My_Proc_Macro
" is (also) a trait, ok.
That's simply just something along the lines of
impl<X, Y, Z> Clone for Struct<X, Y, Z>
where
X: Clone,
Y: Clone,
Z: Clone,
(and not macro magic).
2 Likes
@derspiny @quinedot
-
I think I have this solved now.
-
I made a mistake in my original post. Instead of writing My_Proc_Macro
, I would have written My_Trait
, which has two parts: a Rust Trait and a Procedural macro -- much like Clone
it self -- both a Rust Trait AND a procedural macro.
-
The solution is that my procedural macro, instead of generating
impl <...> My_Trait for Foo<A, B, C> { ... }
it needs to generate
impl <A: My_Trait + ..., B: My_Trait + ..., C: My_Trait + ...> My_Trait for Foo<A, B, C> {
...
}
then the generated code is used when all generic arguments satisfy My_Trait
and no-ops when anyone of them fails to satisfy the My_Trait
- Sorry for the confusion, my use of
My_Proc_Macro
instead of My_Trait
made it hard to infer it was two things (proc macro & trait) sharing a single name (like Clone
).
1 Like
Yeah I don't know if it was much of a mistake really, the phrasing of "satisfy [my macro]" just threw me off initially
. Should have taken 2 seconds to think about what #[derive(...)]
meant beyond the name within.
1 Like