# Implementation approach - how does this work?
**You do not need to understand this in order to use derive-adhoc.**
Also, you should not rely on the details here.
They don't form part of the public interface.
## Introduction
It is widely understood that proc macro invocations
cannot communicate with each other.
(Some people have tried sneaking round the back with disk files etc.
but this can break due to incremental and concurrent compilation.)
But, a proc macro can *define a `macro_rules` macro*.
Then, later proc macros can invoke that macro.
The expansion can even invoke further macros.
In this way, a proc macro invocation *can* communicate with
subsequent proc macro invocations.
(This trick is also used by
[`ambassador`](https://crates.io/crates/ambassador).)
There is a further complication.
One macro X cannot peer into and dismantle
the expansion of another macro Y.
(This is necessary for soundness, when macros can generate `unsafe`.)
So we must sometimes define macros that apply other macros
(whose name is supplied as an argument)
to what is conceptually the first macro's output.
## Implementation approach - truly ad-hoc macros
### 1. `#[derive(Adhoc)]` proc macro for saving struct definitions
Implemented in `capture.rs::derive_adhoc_derive_macro`.
When applied to (e.g.) `pub struct StructName`, generates this
```rust,ignore
macro_rules! derive_adhoc_driver_StructName { {
{ $($template:tt)* }
{ ($orig_dollar:tt) $(future:tt)* }
$($tpassthrough:tt)*
} => {
derive_adhoc_expand!{
{ pub struct StructName { /* original struct definition */ } }
{ }
{ $($template)* }
{ $($tpassthrough)* }
}
} }
```
(The extra `{ }` parts after the driver and template
include space for future expansion.)
In the `pub struct` part every `$` is replaced with `$orig_dollar`,
to use the `$` passed in at the invocation site.
### 2. `derive_adhoc!` function-like proc macro for applying to a template
Implemented in `invocation.rs::derive_adhoc_func_macro`.
When applied like this
```rust,ignore
derive_adhoc!{
StructName TOPTIONS...:
TEMPLATE...
}
```
Expands to
```rust,ignore
derive_adhoc_driver_StructName! {
{ TEMPLATE... }
{ ($) }
crate; [TOPTIONS...]
}
```
### 3. Function-like proc macro to do the actual expansion
Implemented in `expand.rs::derive_adhoc_expand_func_macro`.
The result of expanding the above is this:
```rust,ignore
derive_adhoc_expand!{
{ pub struct StructName { /* original struct definition */ } }
{ }
{ TEMPLATE... }
{ crate; [TOPTIONS...] /*no template name*/; }
}
```
`derive_adhoc_expand` parses `pub struct StructName`,
and implements a bespoke template expander,
whose template syntax resembles the expansion syntax from `macro_rules`.
`crate` is just used as the expansion for `${crate}`.
(For an ad-hoc template, the local crate is correct.)
## Implementation approach - reusable template macros
## 1. `define_derive_adhoc!` macro for defining a reuseable template
Implemented in `definition.rs::define_derive_adhoc_func_macro`.
When used like this
```rust,ignore
define_derive_adhoc! {
MyMacro TOPTIONS... =
TEMPLATE...
}
```
Expands to
```rust,ignore
macro_rules! derive_adhoc_template_Template { {
{ $($driver:tt)* }
$( [ $($aoptions:tt)* ] )?
{ $($future:tt)* }
$($dpassthrough:tt)*
} => {
derive_adhoc_expand! {
{ $($driver)* }
$( [ $(aoptions)* ] )?
{ $($dpassthrough)* }
{ TEMPLATE... }
{ $crate; [TOPTIONS...] Template; }
}
} }
```
Except, every `$` in the TEMPLATE is replaced with `$orig_dollar`.
This is because a `macro_rules!` template
is not capable of generating a
literal in the expansion `$`.
(With the still-unstable
[`decl_macro`](https://github.com/rust-lang/rust/issues/83527)
feature, `$$` does this.)
The template expansion engine treats `$orig_dollar` as just a single `$`.
(Again, the extra `{ }` parts after the driver and template
include space for future expansion.)
## 2. `#[derive_adhoc(Template)]`, implemented in `#[derive(Adhoc)]`
Template reuse is also implemented in `capture.rs::derive_adhoc_derive_macro`.
This
```rust,ignore
#[derive(Adhoc)]
#[derive_adhoc(Template[AOPTIONS,...])]
pub struct StructName { ... }
```
Generates (in addition to the `derive_adhoc_driver_StructName` definition)
```rust,ignore
derive_adhoc_template_Template! {
{ #[derive_adhoc(Template)] struct StructName { ... } }
[1 0 AOPTIONS] // but only if AOPTIONS is nonempty
{ }
}
```
The literal `$` is there to work around a limitation in `macro_rules!`,
see above.
## 3. Actual expansion
The call to `derive_adhoc_template_Template!`
is expanded according to the `macro_rules!` definition,
resulting in a call to `derive_adhoc_expand`:
```rust,ignore
derive_adhoc_expand!{
{ pub struct StructName { /* original struct definition */ } }
[1 0 AOPTIONS] // but only if AOPTIONS is nonempty
{ }
{ TEMPLATE... }
{ $crate; [TOPTIONS...] Template; }
}
```