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#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/batch_preview.md"))]
103#[proc_macro]
104pub fn batch_preview(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
105    entry::preview(input.into())
106        .map(proc_macro::TokenStream::from)
107        .unwrap_or_else(Into::into)
108}
109
110// ============================================================
111// Documentation placeholders for the DSL directive / macro-meta layers.
112//
113// The `#` directives and `@` constants live inside macro arguments, so IDE
114// hover and docs.rs cannot reach them. Each placeholder below is a public
115// no-op function whose doc block documents one directive — a hoverable,
116// searchable rustdoc entry. Never call these functions.
117// ============================================================
118
119#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/directive_delegate.md"))]
120#[proc_macro]
121pub fn batch_impl_delegate(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
122    proc_macro::TokenStream::new()
123}
124
125#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/directive_fill.md"))]
126#[proc_macro]
127pub fn batch_impl_fill(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
128    proc_macro::TokenStream::new()
129}
130
131#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/directive_blanket.md"))]
132#[proc_macro]
133pub fn batch_impl_blanket(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
134    proc_macro::TokenStream::new()
135}
136
137#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/directive_name.md"))]
138#[proc_macro]
139pub fn batch_impl_name(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
140    proc_macro::TokenStream::new()
141}
142
143#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/directive_open.md"))]
144#[proc_macro]
145pub fn batch_impl_open(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
146    proc_macro::TokenStream::new()
147}
148
149#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/directive_consts.md"))]
150#[proc_macro]
151pub fn batch_impl_consts(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
152    proc_macro::TokenStream::new()
153}