Skip to main content

derive_deftly_macros/
macros.rs

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