derive_deftly_macros/
macros.rs

1#![allow(clippy::style, clippy::complexity)]
2#![doc=include_str!("README.md")]
3//
4// This is the actual proc-macro crate.
5//
6// All it exports (or can export) are the proc macros themselves.
7// Everything else that is `pub` could be written `pub(crate)`.
8
9mod prelude;
10
11pub(crate) use prelude::*;
12
13// Implementation - common parts
14#[macro_use]
15pub(crate) mod utils;
16#[macro_use]
17pub(crate) mod adviseable;
18pub(crate) mod framework;
19
20// Implementation - specific areas
21pub(crate) mod accum;
22pub(crate) mod approx_equal;
23pub(crate) mod boolean;
24pub(crate) mod dbg_allkw;
25pub(crate) mod expand;
26pub(crate) mod meta;
27pub(crate) mod options;
28pub(crate) mod paste;
29pub(crate) mod repeat;
30pub(crate) mod syntax;
31
32#[cfg_attr(not(feature = "beta"), path = "beta_disabled.rs")]
33pub(crate) mod beta;
34
35// Implementations of each proc-macros
36pub(crate) mod adhoc;
37pub(crate) mod define;
38pub(crate) mod derive;
39pub(crate) mod engine;
40pub(crate) mod semver;
41
42pub(crate) mod compat_syn_2;
43pub(crate) mod compat_syn_common;
44
45#[doc=include_str!("HACKING.md")]
46mod _doc_hacking {}
47
48#[doc=include_str!("NOTES.md")]
49mod _doc_notes {}
50
51/// Dummy of proc_macro for use when compiling outside of proc macro context
52#[cfg(not(proc_macro))]
53pub(crate) mod proc_macro {
54    pub(crate) use proc_macro2::TokenStream;
55}
56
57//========== `expect`, the `check` module (or dummy version) ==========
58
59// "expect" feature; module named check.rs for tab completion reasons
60#[cfg(feature = "expect")]
61mod check;
62#[cfg(not(feature = "expect"))]
63mod check {
64    use super::prelude::*;
65    #[derive(Debug, Clone, Copy, PartialEq)]
66    pub struct Target(Void);
67
68    impl FromStr for Target {
69        type Err = Void;
70        fn from_str(_: &str) -> Result<Self, Void> {
71            panic!("output syntax checking not supported, enable `expect` feature of `derive-deftly`")
72        }
73    }
74
75    pub fn check_expected_target_syntax(
76        _ctx: &framework::Context,
77        _output: &mut TokenStream,
78        target: DdOptVal<Target>,
79    ) {
80        void::unreachable(target.value.0)
81    }
82
83    pub fn check_expect_opcontext(
84        op: &DdOptVal<Target>,
85        _context: OpContext,
86    ) -> syn::Result<()> {
87        void::unreachable(op.value.0)
88    }
89}
90impl DdOptValDescribable for check::Target {
91    const DESCRIPTION: &'static str =
92        "expected output syntax (`expect` option)";
93}
94
95//========== actual macro entrypoints ==========
96
97/// Wraps an actual macro implementation function that uses a proc_macro2
98/// implementation to expose a proc_macro implementation instead.
99//
100// Clippy gives false positives for converting between proc_macro[2]::TokenStream.
101#[allow(clippy::useless_conversion)]
102fn wrap_macro_func<F>(
103    func: F,
104    input: proc_macro::TokenStream,
105) -> proc_macro::TokenStream
106where
107    F: FnOnce(
108        proc_macro2::TokenStream,
109    ) -> Result<proc_macro2::TokenStream, syn::Error>,
110{
111    let input = proc_macro2::TokenStream::from(input);
112    let output = func(input).unwrap_or_else(|e| e.into_compile_error());
113    proc_macro::TokenStream::from(output)
114}
115
116/// Template expansion engine, internal
117///
118/// <!-- @dd-navbar macros . -->
119/// <!-- this line automatically maintained by update-navbars --><nav style="text-align: right; margin-bottom: 12px;">[ <em>docs: <a href="index.html">crate top-level</a> | <a href="index.html#overall-toc">overall toc, <strong>macros</strong></a> | <a href="doc_reference/index.html">template etc. reference</a> | <a href="https://diziet.pages.torproject.net/rust-derive-deftly/latest/guide/">guide/tutorial</a></em> ]</nav>
120///
121/// Normally you do not need to mention this macro.
122///
123/// derive-deftly does its work by
124/// (defining and then) invoking various interrelated macros
125/// including `macro_rules` macros and proc macros.
126/// These ultimately end up calling this macro,
127/// which takes a template and a data structure,
128/// and expands the template for that data structure.
129///
130/// This macro's behvaiour is not currently stable or documented.
131/// If you invoke it yourself, you get to keep all the pieces.
132#[cfg_attr(proc_macro, proc_macro)]
133pub fn derive_deftly_engine(
134    input: proc_macro::TokenStream,
135) -> proc_macro::TokenStream {
136    wrap_macro_func(engine::derive_deftly_engine_func_macro, input)
137}
138
139/// Expand an ad-hoc template, on a data structure decorated `#[derive_deftly_adhoc]`
140///
141/// <!-- @dd-navbar macros . -->
142/// <!-- this line automatically maintained by update-navbars --><nav style="text-align: right; margin-bottom: 12px;">[ <em>docs: <a href="index.html">crate top-level</a> | <a href="index.html#overall-toc">overall toc, <strong>macros</strong></a> | <a href="doc_reference/index.html">template etc. reference</a> | <a href="https://diziet.pages.torproject.net/rust-derive-deftly/latest/guide/">guide/tutorial</a></em> ]</nav>
143///
144/// ```
145// We're in the macro crate, where the facade crate is not available.
146// So we must do some namespace-swizzling.
147/// # use derive_deftly_macros as derive_deftly;
148// `proc-macro-crate` says `Itself` so generates ::derive_deftly_engine,
149// which is wrong for a doctest.  Fudge that.  We must also make sure
150// we're not inside main here, so we must define a main.
151/// # use derive_deftly::derive_deftly_engine;
152/// # fn main(){}
153/// use derive_deftly::{Deftly, derive_deftly_adhoc};
154/// #[derive(Deftly)]
155/// #[derive_deftly_adhoc]
156/// struct DdtaStructureType { }
157///
158// Smoke and mirrors so we can use metasyntactic OPTIONS and TEMPLATE.
159/// # macro_rules! derive_deftly_adhoc { {
160/// #     $x:ident OPTIONS,..: TEMPLATE
161/// # } => { derive_deftly_macros::derive_deftly_adhoc! {
162/// #     $x expect items: fn x(){}
163/// # } } }
164/// derive_deftly_adhoc! {
165///     DdtaStructureType OPTIONS,..:
166///     TEMPLATE
167/// }
168/// ```
169///
170/// Expands the template `TEMPLATE` for the type `DdtaStructureType`,
171///
172/// `OPTIONS,..` is an optional comma-separated list of
173/// [expansion options](doc_reference/index.html#expansion-options).
174///
175/// The definition of `DdtaStructureType` must have been decorated
176/// with [`#[derive(Deftly)]`](crate::Deftly),
177/// and `#[derive_deftly_adhoc]`,
178/// and the resulting `derive_deftly_driver_TYPE` macro must be
179/// available in scope.
180///
181/// `derive_deftly_adhoc!` can be used in any context
182/// where the Rust language permits macro calls.
183/// For example, it can expand to expressions, statements,
184/// types, or patterns.
185#[cfg_attr(proc_macro, proc_macro)]
186pub fn derive_deftly_adhoc(
187    input: proc_macro::TokenStream,
188) -> proc_macro::TokenStream {
189    wrap_macro_func(adhoc::derive_deftly_adhoc, input)
190}
191
192/// Define a reuseable template
193///
194/// <!-- @dd-navbar macros . -->
195/// <!-- this line automatically maintained by update-navbars --><nav style="text-align: right; margin-bottom: 12px;">[ <em>docs: <a href="index.html">crate top-level</a> | <a href="index.html#overall-toc">overall toc, <strong>macros</strong></a> | <a href="doc_reference/index.html">template etc. reference</a> | <a href="https://diziet.pages.torproject.net/rust-derive-deftly/latest/guide/">guide/tutorial</a></em> ]</nav>
196///
197/// ```text
198/// define_derive_deftly! {
199///     [/// DOCS]
200///     [export] MyMacro OPTIONS,..:
201///     TEMPLATE
202/// }
203/// ```
204///
205/// Then, `MyMacro` can be used with
206/// [`#[derive(Deftly)]`](crate::Deftly)
207/// `#[derive_deftly(MyMacro)]`.
208///
209/// <span id="options-in-define">`OPTIONS,..`</span>
210/// is an optional comma-separated list of
211/// [expansion options](doc_reference/index.html#expansion-options),
212/// which will be applied whenever this template is expanded.
213///
214/// <span id="docs-in-define">`DOCS`</span>,
215/// if supplied, are used as the rustdocs
216/// for the captured template macro `derive_deftly_template_MyMacro`.
217/// derive-deftly will then also append a note about
218/// how to invoke the template.
219///
220/// ## Template definition macro `derive_deftly_template_MyMacro`
221///
222/// The template is made into a `macro_rules` macro
223/// named `derive_deftly_template_MyMacro`,
224/// which is referenced when the template is applied.
225///
226/// The template definition macro
227/// from `define_derive_deftly!`
228/// must be in scope at the point where you try to use it
229/// (with `#[derive(Deftly)] #[derive_deftly(MyMacro)]`).
230/// If the template definition is in another module,
231/// you may need to annotate that module with `#[macro_use]`.
232/// See the
233/// [documentation for `#[derive(Deftly)]`](derive.Deftly.html#scoping-and-ordering-within-the-same-crate).
234///
235/// ## Exporting a template for use by other crates
236///
237/// With `export MyMacro`, `define_derive_deftly!` exports the template
238/// for use by other crates.
239/// Then, it is referred to in other crates
240/// with `#[derive_ahdoc(this_crate::MyMacro)]`.
241///
242/// I.e., `export MyMacro` causes the `derive_deftly_template_MyMacro`
243/// pattern macro to be exported with `#[macro_export]`.
244///
245/// Note that a template is always exported at the crate top level,
246/// not in a sub-module,
247/// even if it is *defined* in a sub-module.
248/// Also, note that `export` does not have any effect on
249/// visibility of the template *within the same crate*.
250/// You may still need `#[macro_use]`.
251///
252/// ### You must re-export `derive_deftly`; semver implications
253///
254/// When exporting a template to other crates, you must also
255/// re-export `derive_deftly`,
256/// at the top level of your crate:
257///
258/// ```ignore
259/// #[doc(hidden)]
260/// pub use derive_deftly;
261/// ```
262/// This is used to find the template expansion engine,
263/// and will arrange that your template is expanded
264/// by the right version of derive-deftly.
265/// The template syntax is that for *your* version of `derive-deftly`,
266/// even if the depending crate uses a different version of derive-deftly.
267///
268/// You should *not* treat a breaking change
269/// to derive-deftly's template syntax
270/// (which is a major change to derive-deftly),
271/// nor a requirement to use a newer template feature,
272/// as a breaking changes in the API of your crate.
273/// (You *should* use `#[doc(hidden)]`, or other approaches,
274/// to discourage downstream crates from using
275/// the derive-deftly version you re-export.
276/// Such use would be outside the semver guarantees.)
277///
278/// You *should* call
279/// [`derive_deftly::template_export_semver_check!`](macro@template_export_semver_check)
280/// once in each crate that exports macros.
281/// This will notify you, by breaking your build,
282/// if you update to a derive-deftly version
283/// that has semver implications for other crates that use your macros.
284///
285/// Changes that would require a semver bump
286/// for all libraries that export templates,
287/// will be rare, and specially marked in the derive-deftly changelog.
288/// Search for sections with titles containing "template export semver".
289///
290/// ## Namespacing within a template
291///
292/// Within the template,
293/// items within your crate can be referred to with
294/// [`$crate`](doc_reference/index.html#x:crate).
295///
296/// For other items,
297/// including from the standard library e.g., `std::option::Option`,
298/// you may rely on the context which uses the template
299/// to have a reasonable namespace,
300/// or use a explicit paths starting with `std` or `::std` or `::core`
301/// or `$crate` (perhaps naming a re-export).
302///
303/// Overall, the situation is similar to defining
304/// an exported `macro_rules` macro.
305#[cfg_attr(proc_macro, proc_macro)]
306pub fn define_derive_deftly(
307    input: proc_macro::TokenStream,
308) -> proc_macro::TokenStream {
309    wrap_macro_func(define::define_derive_deftly_func_macro, input)
310}
311
312/// Perform ad-hoc templating driven by a data structure
313///
314/// <!-- @dd-navbar macros . -->
315/// <!-- this line automatically maintained by update-navbars --><nav style="text-align: right; margin-bottom: 12px;">[ <em>docs: <a href="index.html">crate top-level</a> | <a href="index.html#overall-toc">overall toc, <strong>macros</strong></a> | <a href="doc_reference/index.html">template etc. reference</a> | <a href="https://diziet.pages.torproject.net/rust-derive-deftly/latest/guide/">guide/tutorial</a></em> ]</nav>
316///
317/// This macro does two things:
318///
319///  1. If `#[derive_deftly(MyMacro)]` attributes are also specified,
320///     they are taken to refer to reuseable templates
321///     defined with
322///     [`define_derive_deftly!`](macro@crate::define_derive_deftly).
323///     Each such `MyMacro` is applied to the data structure.
324///
325///     <span id="expansion-options">You can specify
326///     [expansion options](doc_reference/index.html#expansion-options)
327///     for each such template application, by writing
328///     `#[derive_deftly(MyMacro[OPTIONS,..])]`, where
329///     `[OPTIONS,..]` is a comma-separated list of expansion options
330///     contained within `[ ]`.</span>
331///
332///  2. If `#[derive_deftly_adhoc]` is specified,
333///     captures the data structure definition,
334///     so that it can be used with calls to
335///     [`derive_deftly_adhoc!`](macro@crate::derive_deftly_adhoc).
336///
337/// ## `#[deftly]` attribute
338///
339/// The contents of `#[deftly]` attributes are made available
340/// to templates via the
341/// [`${Xmeta}`](doc_reference/index.html#tmeta-vmeta-fmeta--deftly-attributes)
342/// expansions.
343///
344/// If none of the template(s) recognise them,
345/// [it is an error](doc_reference/index.html#unrecognisedunused-deftly-attributes),
346/// (unless `#[derive_deftly_adhoc]` is specified).
347///
348/// `derive-deftly`
349/// [does not impose any namespacing](doc_reference/index.html#attribute-namespacing)
350/// within `#[deftly]`:
351///
352/// ## Scoping and ordering within the same crate
353///
354/// **Summary of required ordering**
355///
356///  1. `define_derive_deftly! { MyMacro = ... }`
357///  2. `#[derive(Deftly)] #[derive_deftly(MyMacro)] struct MyStruct { ... }`
358///  3. `derive_deftly_adhoc! { MyStruct: ... }`
359///
360/// Any reusable templates defined with
361/// `define_derive_deftly!` must lexically their precede
362/// uses with `#[derive(Deftly) #[derive_deftly(...)]`.
363///
364/// And, for one-off templates (`derive_deftly_adhoc!`),
365/// the data structure with its `#[derive(Deftly)]`
366/// must lexically precede
367/// the references in `derive_deftly_adhoc!`,
368/// so that the data structure definition macro
369/// is in scope.
370///
371/// In each case,
372/// if the definition is in another module
373/// in the same crate,
374/// the defining module's `mod` statement must come before
375/// the reference,
376/// and
377/// the `mod` statement will need `#[macro_use]`.
378/// So the placement and order of `mod` statements can matter.
379/// Alternatively, it is possible to use path-based scoping;
380/// there is
381/// [an example in the Guide](https://diziet.pages.torproject.net/rust-derive-deftly/latest/guide/templates-in-modules.html#path-scope).
382///
383/// ## Applying a template (derive-deftly macro) from another crate
384///
385/// `#[derive_deftly(some_crate::MyMacro)]`
386/// applies an exported template
387/// defined and exported by `some_crate`.
388///
389/// You can import a template from another crate,
390/// so you can apply it with an unqualified name,
391/// with `use`,
392/// but the `use` must refer to
393/// the actual pattern macro name `derive_deftly_template_MyMacro`:
394/// ```
395// See the doc comment for `derive_deftly_adhoc`.
396/// # use derive_deftly_macros as derive_deftly;
397/// # use derive_deftly::derive_deftly_engine;
398/// # fn main(){}
399// We can't make another crate.  Fake up the macro definition
400/// # derive_deftly::define_derive_deftly! { TheirMacro: }
401/// use derive_deftly::Deftly;
402// and don't really try to import it, then
403/// # #[cfg(any())]
404/// use other_crate::derive_deftly_template_TheirMacro;
405/// #[derive(Deftly)]
406/// #[derive_deftly(TheirMacro)]
407/// struct MyStruct { // ...
408/// # }
409/// ```
410///
411/// ## Captured data structure definition `derive_deftly_driver_TYPE`
412///
413/// With `#[derive_deftly_adhoc]`,
414/// the data structure is captured
415/// for use by
416/// [`derive_deftly_adhoc!`](macro@crate::derive_deftly_adhoc).
417///
418/// Specifically, by defining
419/// a `macro_rules` macro called `derive_deftly_driver_TYPE`,
420/// where `TYPE` is the name of the type
421/// that `#[derive(Deftly)]` is applied to.
422///
423///
424///
425/// ### Exporting the driver for downstream crates' templates
426///
427// Really, the documentation about this in `pub-a.rs` and `pub-b.rs`,
428// should be somewhere in our rustdoc output.
429// But I don't want to put it *here* because it would completely
430// dominate this macro documentation.
431// So for now just reference the source tree docs.
432// (We can't really easily provide even a link.)
433// I think this is such a minority feature,
434// that hiding the docs like this is OK.
435//
436/// To cause the macro embodying the driver struct to be exported,
437/// write:
438/// `#[derive_deftly_adhoc(export)]`.
439/// The driver can then be derived from in other crates,
440/// with `derive_deftly_adhoc! { exporting_crate::DriverStruct: ... }`.
441///
442/// #### Semver hazards
443///
444/// This is a tricky feature,
445/// which should only be used by experts
446/// who fully understand the implications.
447/// It effectively turns the body of the struct into a macro,
448/// with a brittle API
449/// and very limited support for namespacing or hygiene.
450///
451/// See `pub mod a_driver` in the example file `pub-a.rs`,
452/// in the source tree,
453/// for a fuller discussion of the implications,
454/// and some advice.
455///
456/// If you do this, you must **pin your derive-deftly** to a minor version,
457/// as you may need to treat *minor* version updates in derive-deftly
458/// as semver breaks for your crate.
459/// And every time you update, you must read the `CHANGELOG.md`,
460/// since there is nothing that will warn you automatically
461/// about breaking changes.
462//
463// This is the implementation of #[derive(Deftly)]
464#[cfg_attr(
465    proc_macro,
466    proc_macro_derive(
467        Deftly,
468        attributes(deftly, derive_deftly, derive_deftly_adhoc)
469    )
470)]
471pub fn derive_deftly(
472    input: proc_macro::TokenStream,
473) -> proc_macro::TokenStream {
474    wrap_macro_func(derive::derive_deftly, input)
475}
476
477/// Check semver compatibility, for a crate which exports macros
478///
479/// <!-- @dd-navbar macros . -->
480/// <!-- this line automatically maintained by update-navbars --><nav style="text-align: right; margin-bottom: 12px;">[ <em>docs: <a href="index.html">crate top-level</a> | <a href="index.html#overall-toc">overall toc, <strong>macros</strong></a> | <a href="doc_reference/index.html">template etc. reference</a> | <a href="https://diziet.pages.torproject.net/rust-derive-deftly/latest/guide/">guide/tutorial</a></em> ]</nav>
481///
482/// Causes a compilation error
483/// if and only if the specified version of `derive-deftly`
484/// is prior to the last *relevant change*,
485/// compared to the currently-running one.
486///
487/// A *relevant change* is one which has semver implications
488/// for the API of a crate which exports derive-deftly templates.
489///
490/// ## When and how to call this
491///
492/// If you export templates, with `define_derive_deftly! { export ... }`,
493/// call this macro too, once in your crate.
494///
495/// Pass it the version of `derive-deftly` that was current,
496/// when you last read the `derive-deftly` changelog
497/// and considered breaking changes.
498///
499/// (The argument must be a string literal, containing a
500/// 2- or 3-element version number.
501/// If the 3rd element is omitted, 0 is used.)
502///
503/// ## Guarantee
504///
505/// You can upgrade your derive-deftly version,
506/// even across a semver-breaking change to derive-deftly,
507/// without making any consequential update to your crate's own semver.
508///
509/// If a new version of derive-adhoc means *your* crate's
510/// API has semver-relevant changes, this macro will throw an error.
511/// (Of course that will only happen across semver-breaking
512/// updates of derive-deftly.)
513///
514/// (Exporting a *driver* struct for derivation in downstream crates,
515/// `#[derive_deftly_adhoc(export)]`, is not covered by this promise.)
516///
517/// ## Example
518///
519/// ```
520/// # use derive_deftly_macros as derive_deftly;
521/// derive_deftly::template_export_semver_check!("0.13.0");
522/// ```
523#[cfg_attr(proc_macro, proc_macro)]
524pub fn template_export_semver_check(
525    input: proc_macro::TokenStream,
526) -> proc_macro::TokenStream {
527    wrap_macro_func(semver::template_export_semver_check_func_macro, input)
528}