Expand description
A crate helping with structuring the library crate of a proc-macro package.
The major of this crate is macro proc_macro_api!
,
which can export functions in submodules of a proc-macro crate as
the Application Programing Interfaces (APIs) of that proc-macro crate.
For example, assuming sub
is a submodule of the root of
a proc-macro crate and has a function,
pub fn proc_fn(input: TokenStream) -> TokenStream
, in order to export
proc_fn
as a function-like macro, proc_macro_api!
can be used in the
root of the crate like:
proc_macro_api! {
sub::{
#[proc_macro]
proc_fn,
},
}
Then, a function-like macro, proc_fn!()
, is available from that
proc-macro crate.
The macro should be used at somewhere that the proc-macro attributes
(i.e., #[proc_macro]
, #[proc_macro_attribute]
, etc.) are allowed.
§Input
Syntax
Input:
PathTreeListPathTreeList:
PathTreeWithAttr? (,
PathTreeWithAttr? )*PathTreeWithAttr:
OuterAttribute*
PathTreePathTree:
( SimplePath?::
)?{
PathTreeList}
| SimplePath (as
( IDENTIFIER |_
) )?
proc_macro_api!
requires paths with proc-macro attributes as
its input. The syntax of the input paths is like the path syntax
of use
declarations, but allows attribute and disallows
asterisk (i.e., *
).
§Paths
All the input paths should be either a path of a function or a path renamed with the underscore alias.
When a path is of a function and isn’t renamed with the underscore alias, a proc-macro attribute should be applied to the path, and the function should have a signature required by the proc-macro attribute.
When a path is renamed with the underscore alias, it is not required to be a path of a function, and not required to be annotated with proc-macro attributes. The path is only required to be syntactically valid.
§Brace syntax and path groups
Braces can be used for grouping paths with a common prefix.
When some paths are grouped by a pair of curly braces, they compose a path group.
Braces can be nested, and nested braces create subgroups of paths.
For example, in the following code, there is a path,
group_a::subgroup_of_a::path_of_fn
. The path is renamed with the
underscore alias, and belongs to path group group_a
and subgroup_of_a
.
proc_macro_api! {
group_a::{
subgroup_of_a::{
path_of_fn as _,
},
},
}
§Attributes
Attributes can be applied to single paths and path groups.
Input attributes are classed into two types:
- Global. When a global attribute is applied to a path group, it is applied to all the paths in that group. That is, global attributes inside curly braces will be appended after the global attributes from the outside.
- Local. For each path in a path group, inside the curly braces
of that group,
- if some local attributes are applied to the path, all the local attributes applied to the group won’t be applied to the path;
- if no local attribute is applied to the path, all the local attributes applied to the group will be applied to the path.
- That is, local attributes inside curly braces will override the local attributes from the outside.
After being parsed by the macro, for the input attributes applied to an input path, all the global attributes will always be placed before all the local attributes.
Only proc-macro attributes are local, and all other attributes are global.
§Attribute aliases
Proc-macro attributes have aliases in the input scope:
#[proc_macro]
=>#[fn]
#[proc_macro_attribute]
=>#[at]
#[proc_macro_derive]
=>#[dr]
If there is an imported attribute macro having the same name as one
of the aliases, in order to use it in the input, it will need
to be renamed (e.g., rename it by using use
declaration).
§Expansion
When a path is not renamed with the underscore alias, it will be
expanded to a pub
function annotated with all the input attributes
that are applied to that path.
- If the path doesn’t have an alias, the expanded function will have the same name as the name of the function in the path.
- If the path has an alias, the expanded function will have the same name as the alias.
The expanded function will and only will directly call the function in that path, with the arguments input to the expanded function.
It is recommended to annotate the functions in input paths with
#[inline(always)]
.
When a path is renamed with the underscore alias, it will be expanded to empty.
§Examples
// This example can be found in the examples of the package.
// in the crate root
extern crate proc_macro;
#[no_link]
extern crate proc_macro_api;
use proc_macro_api::proc_macro_api;
mod mod_a {
use proc_macro::TokenStream;
pub fn an_fn_api(_input: TokenStream) -> TokenStream {
TokenStream::new()
}
pub mod mod_b {
use proc_macro::TokenStream;
pub fn an_attr_api(_args: TokenStream, _item: TokenStream) -> TokenStream {
TokenStream::new()
}
pub fn a_derive_api(_item: TokenStream) -> TokenStream {
TokenStream::new()
}
}
}
proc_macro_api! {
// a path group
mod_a::{
// use an alias of the proc-macro attributes
#[fn] an_fn_api,
// a path subgroup
#[allow(unused)] // global attribute
#[proc_macro_attribute] // local attribute
mod_b::{
// #[allow(unused)]
/// `#[doc]` is global.
/// This API is renamed `the_attr_api`.
// #[proc_macro_attribute]
an_attr_api as the_attr_api,
// #[allow(unused)]
#[dr(Something)] a_derive_api,
// syntactically valid
nonexistent_api as _,
},
},
// syntactically valid
::nonexistent_mod::nonexistent_api as _,
}
// It will expand to three `pub` functions in the crate root, named
// `an_fn_api`, `the_attr_api`, and `a_derive_api`, respectively.
§Depth of recursion
This section is provided as reference for errors about recursion depth.
§Path recursion depth
For an input path, the number of the recursive steps for parsing it depends on the number of the segments in the path, the number of the groups it belongs to, the number of the attributes applied to the path, and the number of the attributes applied to the groups it belongs to.
Let N be the number of the segments of the path.
Let G be the number of the groups the path belongs to.
Let A be the number of the attributes applied to the groups
the path belongs to.
Let B be the number of the attributes that are applied directly
to the path but not to the groups the path belongs to.
Let d be the recursion depth of the path.
When there is no error in the input:
max { A + B, N + G } + 2 G + 7 ≤
d ≤ A + B + N + 4 G + 8 .
§Empty group recursion depth
When a group doesn’t contain any paths or path groups, it is empty.
For an empty group, it can be treated as a path that ends with curly braces, where G doesn’t include the last empty group and N includes the last empty curly brace pair.
Let demp be the recursion depth of the empty group.
When there is no error in the input:
max { A + B, N + G } + 2 G + 5 ≤
demp ≤ A + B + N + 4 G + 6 .
§Macro call recursion depth
When calling proc_macro_api!
, the recursion depth of the macro call
depends on the maximum recursion depth of all the input paths.
Let dp be the recursion depth of input path p,
where input paths include empty groups.
Let D be the recursion depth of the macro call.
D = max ( { dp | p is an input path, where input paths include empty groups } ∪ { 1 } ) .
Note: When counting the recursion depth, the distinction between paths is not according to their segments, but to their appearances. That is, for example, in the input of
proc_macro_api!(a as _, a as _)
, there are two paths (i.e., the firsta
and the seconda
), instead of one.
§Optional features
deny_shadow
(enabled by default) - A feature for debugging. Deny the shadowing of proc-macro attributes. The feature will check whether a single path or a path group is annotated with multiple proc-macro attributes, and will generate a compile-error if it does.deny_override
- Deny the overriding of local attributes.deny_append
- Deny the appending of global attributes.deny_group_attr
- Deny the applying of attributes to path groups.auto_transform
- Transform the inputTokenStream
into the input of the api-function, and transform the output of the api-function into the outputTokenStream
, by usingFrom
. It is useful when exporting some functions that, for example, requireproc_macro2::TokenStream
as their input, and output values ofproc_macro2::TokenStream
.
Macros§
- proc_
macro_ api - See the crate documentation.