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