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