Skip to main content

batch_impl/
lib.rs

1#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))]
2#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/tutorial.md"))]
3// The library uses no unsafe; missing docs are rejected as errors (only for pub items;
4// internal pub(crate) is exempt).
5#![forbid(unsafe_code)]
6#![deny(missing_docs)]
7// The MSVC linker prints "creating library ... and object ..." to stdout, which rustc
8// treats as linker_messages warnings; these are harmless Windows link-product notices,
9// suppressed globally.
10#![allow(linker_messages)]
11// The `delimiter!` macro is defined at the top of preprocess and imported into the crate
12// root via `#[macro_use]`; textual scope requires its declaration to precede all users
13// (fuzz / parse / this module).
14#[macro_use]
15pub(crate) mod preprocess;
16#[cfg(test)]
17mod testing;
18use syn::{ItemTrait, parse_macro_input};
19
20mod analyze;
21mod apply;
22mod ast;
23mod codegen;
24mod entry;
25mod parse;
26mod util;
27
28pub(crate) use analyze::TraitBounds;
29pub(crate) use entry::{expand_attr_macro, expand_batch_trait};
30
31/// Attribute macro that generates `impl` blocks for a trait in batch.
32///
33/// Annotate a trait definition with `#[batch_impl(...)]`; every impl-spec in the macro
34/// arguments generates a corresponding `impl` block for that trait.
35///
36/// ## Syntax
37///
38/// ```text
39/// #[batch_impl( impl-spec [, impl-spec]* [{ body }]? )]
40/// ```
41///
42/// An impl-spec has three parts (the tail of each part may be omitted):
43/// - `<impl generics>` — generic params of the `impl` block
44/// - `Trait name<trait generics>` — the trait's generic args and associated type bindings
45/// - target type — wrapped in `[]` for a parallel list, `^`/`-` for generic application
46///
47/// ## Examples
48///
49/// ```
50/// # use batch_impl::batch_impl;
51/// #[batch_impl(usize, isize)]
52/// trait Numeric {}
53///
54/// #[batch_impl(<T> Vec<T>)]
55/// trait Collection {}
56///
57/// #[batch_impl(<T> FromValue<T> [i32 { fn wrap(_: T) -> Self { 0 }}, u32 #wrap{0}] )]
58/// trait FromValue<T> { fn wrap(val: T) -> Self; }
59///
60/// // #name{body} also supports const and type items
61/// #[batch_impl(usize #MY_CONST{42})]
62/// trait HasConst { const MY_CONST: usize; }
63///
64/// ```
65#[proc_macro_attribute]
66pub fn batch_impl(
67    attr: proc_macro::TokenStream, item: proc_macro::TokenStream,
68) -> proc_macro::TokenStream {
69    let trait_item = parse_macro_input!(item as ItemTrait);
70    expand_attr_macro(attr.into(), trait_item, true)
71        .map(proc_macro::TokenStream::from)
72        .unwrap_or_else(Into::into)
73}
74
75#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/batch_impl_only.md"))]
76#[proc_macro_attribute]
77pub fn batch_impl_only(
78    attr: proc_macro::TokenStream, item: proc_macro::TokenStream,
79) -> proc_macro::TokenStream {
80    let trait_item = parse_macro_input!(item as ItemTrait);
81    expand_attr_macro(attr.into(), trait_item, false)
82        .map(proc_macro::TokenStream::from)
83        .unwrap_or_else(Into::into)
84}
85
86#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/batch_trait.md"))]
87#[proc_macro]
88pub fn batch_trait(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
89    expand_batch_trait(input).unwrap_or_else(Into::into)
90}
91
92#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/batch_preprocess_test.md"))]
93#[proc_macro]
94pub fn batch_preprocess_test(
95    input: proc_macro::TokenStream,
96) -> proc_macro::TokenStream {
97    entry::preprocess_test(input.into())
98        .map(proc_macro::TokenStream::from)
99        .unwrap_or_else(Into::into)
100}
101
102// ============================================================
103// Documentation placeholders for the DSL directive / macro-meta layers.
104//
105// The `#` directives and `@` constants live inside macro arguments, so IDE
106// hover and docs.rs cannot reach them. Each placeholder below is a public
107// no-op function whose doc block documents one directive — a hoverable,
108// searchable rustdoc entry. Never call these functions.
109// ============================================================
110
111#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/directive_delegate.md"))]
112#[proc_macro]
113pub fn batch_impl_delegate(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
114    proc_macro::TokenStream::new()
115}
116
117#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/directive_fill.md"))]
118#[proc_macro]
119pub fn batch_impl_fill(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
120    proc_macro::TokenStream::new()
121}
122
123#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/directive_blanket.md"))]
124#[proc_macro]
125pub fn batch_impl_blanket(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
126    proc_macro::TokenStream::new()
127}
128
129#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/directive_name.md"))]
130#[proc_macro]
131pub fn batch_impl_name(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
132    proc_macro::TokenStream::new()
133}
134
135#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/directive_open.md"))]
136#[proc_macro]
137pub fn batch_impl_open(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
138    proc_macro::TokenStream::new()
139}
140
141#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/directive_consts.md"))]
142#[proc_macro]
143pub fn batch_impl_consts(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
144    proc_macro::TokenStream::new()
145}