Generating documentation in macros - macros

I have a couple of macros to reduce boilerplate when defining certain tuple-structs of the form:
macro_rules! new_type (($name:ident, $bytes:expr) => (
pub struct $name(pub [u8; $bytes]);
// some common operations on $name
));
However, I would also like to document these new structs. The best thing would be if I could write my documentation right before my macro invocation.
/// A certain type
new_type!(CertainType, 42);
However, Rust won't generate documentation for CertainType when this happens.
Another (not as flexible) alternative would be to do something like:
macro_rules! new_type (($name:ident, $bytes:expr) => (
/// Some more generic documentation for $name
pub struct $name(pub [u8; $bytes]);
// some common operations on $name
));
However, when doing that the Rust macro system doesn't expand the token $name in the documentation comment. The only alternative left is to write very generic documentation in the macro, but that would lead to my library being a lot worse documented than it could be.
What are your recommendations for handling this? The best solution for me would be to be able to write specific documentation for each macro invocation, but if that's not possible I would be grateful for hints on how to expand tokens in documentation comments.

It is possible to capture doc comments in macro invocations. It is not widely-known, but Rust documentation is actually represented as a special kind of attribute on an item. For example:
/// Some documentation comment
pub fn function() {}
// is equivalent to
#[doc="Some documentation comment"]
pub fn function() {}
And it is possible to capture attributes in macros. There are already several macros which use this ability, the most used probably being bitflags!:
macro_rules! bitflags {
(
$(#[$outer:meta])*
pub struct $BitFlags:ident: $T:ty {
$(
$(#[$inner:ident $($args:tt)*])*
const $Flag:ident = $value:expr;
)+
}
) => { /* ... */ };
// ...
}
Note the $(#[$outer:meta])* and $(#[$inner:meta])* parts of the pattern. These capture all attributes placed before the respective item in the pattern. If you write a doc comment there, it will be converted to the doc attribute and will be passed to rustdoc, as usual.
The following is an example from the quick_error crate which also uses this approach:
quick_error! {
#[derive(Debug)]
pub enum SomeError {
/// IO Error
Io(err: io::Error) {}
/// Arbitrary system error
Sys(errno: nix::Errno) {}
}
}
It does work β€” here is an example of the structure generated by quick_error macro, and here is its definition.

Related

Is it possible for a macro to turn an identifier lowercase? [duplicate]

This question already has answers here:
Is it possible to modify the case of a token inside of a macro?
(2 answers)
Closed 2 years ago.
Is it possible to generate a symbol or identifier in a Rust macro
from a string? Or to perform string-like operations on a identifier?
I wanted to generate a method given a symbol, but need to downcase it to
obtain the method name.
get!(B);
// should expand to
fn b() -> B {
// method body
}
It's easy to get close...
macro_rules! get {
($kind:ident, $method:ident)
=>
{
fn $method() -> $kind {
// method body
}
}
}
get!(B, b)
But dissatisfying.
I just wrote a procedural macro (casey) to do this.
#![feature(proc_macro_hygiene)]
use casey::lower;
lower!(B); // would render as `b`
Update
proc_macro_hygiene is stable as of rust 1.45.0, so no longer requires nightly.
The previous answers are all correct; standard declarative macros can't do this, and you can drop to procedural macros instead. However, a simpler alternative to procedural macros (especially if, like myself, that's an area of the language you haven't delved into yet) is dtolnay's paste crate.
An example from those docs:
use paste::paste;
paste! {
// Defines a const called `QRST`.
const [<Q R S T>]: &str = "success!";
}
fn main() {
assert_eq!(
paste! { [<Q R S T>].len() },
8,
);
}
Case conversion is also supported, e.g. [<ld_ $reg:lower _expr>]
No, there isn't a macro that can perform this sort of string manipulation on identifiers.
It is possible to create such a macro in the compiler, but it doesn't seem to be a popular need; today only the experimental concat_idents! comes anything close to this (i.e. string-like operations for identifiers).
Your workaround is currently the only available solution.

Cannot find macro in this scope [duplicate]

I have two modules in separate files within the same crate, where the crate has macro_rules enabled. I want to use the macros defined in one module in another module.
// macros.rs
#[macro_export] // or not? is ineffectual for this, afaik
macro_rules! my_macro(...)
// something.rs
use macros;
// use macros::my_macro; <-- unresolved import (for obvious reasons)
my_macro!() // <-- how?
I currently hit the compiler error "macro undefined: 'my_macro'"... which makes sense; the macro system runs before the module system. How do I work around that?
Macros within the same crate
New method (since Rust 1.32, 2019-01-17)
foo::bar!(); // works
mod foo {
macro_rules! bar {
() => ()
}
pub(crate) use bar; // <-- the trick
}
foo::bar!(); // works
With the pub use, the macro can be used and imported like any other item. And unlike the older method, this does not rely on source code order, so you can use the macro before (source code order) it has been defined.
Old method
bar!(); // Does not work! Relies on source code order!
#[macro_use]
mod foo {
macro_rules! bar {
() => ()
}
}
bar!(); // works
If you want to use the macro in the same crate, the module your macro is defined in needs the attribute #[macro_use]. Note that macros can only be used after they have been defined!
Macros across crates
Crate util
#[macro_export]
macro_rules! foo {
() => ()
}
Crate user
use util::foo;
foo!();
Note that with this method, macros always live at the top-level of a crate! So even if foo would be inside a mod bar {}, the user crate would still have to write use util::foo; and not use util::bar::foo;. By using pub use, you can export a macro from a module of your crate (in addition to it being exported at the root).
Before Rust 2018, you had to import macro from other crates by adding the attribute #[macro_use] to the extern crate util; statement. That would import all macros from util. This syntax should not be necessary anymore.
Alternative approach as of 1.32.0 (2018 edition)
Note that while the instructions from #lukas-kalbertodt are still up to date and work well, the idea of having to remember special namespacing rules for macros can be annoying for some people.
EDIT: it turns out their answer has been updated to include my suggestion, with no credit mention whatsoever πŸ˜•
On the 2018 edition and onwards, since the version 1.32.0 of Rust, there is another approach which works as well, and which has the benefit, imho, of making it easier to teach (e.g., it renders #[macro_use] obsolete). The key idea is the following:
A re-exported macro behaves as any other item (function, type, constant, etc.): it is namespaced within the module where the re-export occurs.
It can then be referred to with a fully qualified path.
It can also be locally used / brought into scope so as to refer to it in an unqualified fashion.
Example
macro_rules! macro_name { ... }
pub(crate) use macro_name; // Now classic paths Just Workβ„’
And that's it. Quite simple, huh?
Feel free to keep reading, but only if you are not scared of information overload ;) I'll try to detail why, how and when exactly does this work.
More detailed explanation
In order to re-export (pub(...) use ...) a macro, we need to refer to it! That's where the rules from the original answer are useful: a macro can always be named within the very module where the macro definition occurs, but only after that definition.
macro_rules! my_macro { ... }
my_macro!(...); // OK
// Not OK
my_macro!(...); /* Error, no `my_macro` in scope! */
macro_rules! my_macro { ... }
Based on that, we can re-export a macro after the definition; the re-exported name, then, in and of itself, is location agnostic, as all the other global items in Rust πŸ™‚
In the same fashion that we can do:
struct Foo {}
fn main() {
let _: Foo;
}
We can also do:
fn main() {
let _: A;
}
struct Foo {}
use Foo as A;
The same applies to other items, such as functions, but also to macros!
fn main() {
a!();
}
macro_rules! foo { ... } // foo is only nameable *from now on*
use foo as a; // but `a` is now visible all around the module scope!
And it turns out that we can write use foo as foo;, or the common use foo; shorthand, and it still works.
The only question remaining is: pub(crate) or pub?
For #[macro_export]-ed macros, you can use whatever privacy you want; usually pub.
For the other macro_rules! macros, you cannot go above pub(crate).
Detailed examples
For a non-#[macro_export]ed macro
mod foo {
use super::example::my_macro;
my_macro!(...); // OK
}
mod example {
macro_rules! my_macro { ... }
pub(crate) use my_macro;
}
example::my_macro!(...); // OK
For a #[macro_export]-ed macro
Applying #[macro_export] on a macro definition makes it visible after the very module where it is defined (so as to be consistent with the behavior of non-#[macro_export]ed macros), but it also puts the macro at the root of the crate (where the macro is defined), in an absolute path fashion.
This means that a pub use macro_name; right after the macro definition, or a pub use crate::macro_name; in any module of that crate will work.
Note: in order for the re-export not to collide with the "exported at the root of the crate" mechanic, it cannot be done at the root of the crate itself.
pub mod example {
#[macro_export] // macro nameable at `crate::my_macro`
macro_rules! my_macro { ... }
pub use my_macro; // macro nameable at `crate::example::my_macro`
}
pub mod foo {
pub use crate::my_macro; // macro nameable at `crate::foo::my_macro`
}
When using the pub / pub(crate) use macro_name;, be aware that given how namespaces work in Rust, you may also be re-exporting constants / functions or types / modules. This also causes problems with globally available macros such as #[test], #[allow(...)], #[warn(...)], etc.
In order to solve these issues, remember you can rename an item when re-exporting it:
macro_rules! __test__ { ... }
pub(crate) use __test__ as test; // OK
macro_rules! __warn__ { ... }
pub(crate) use __warn__ as warn; // OK
Also, some false positive lints may fire:
from the trigger-happy clippy tool, when this trick is done in any fashion;
from rustc itself, when this is done on a macro_rules! definition that happens inside a function's body: https://github.com/rust-lang/rust/issues/78894
This answer is outdated as of Rust 1.1.0-stable.
You need to add #![macro_escape] at the top of macros.rs and include it using mod macros; as mentioned in the Macros Guide.
$ cat macros.rs
#![macro_escape]
#[macro_export]
macro_rules! my_macro {
() => { println!("hi"); }
}
$ cat something.rs
#![feature(macro_rules)]
mod macros;
fn main() {
my_macro!();
}
$ rustc something.rs
$ ./something
hi
For future reference,
$ rustc -v
rustc 0.13.0-dev (2790505c1 2014-11-03 14:17:26 +0000)
Adding #![macro_use] to the top of your file containing macros will cause all macros to be pulled into main.rs.
For example, let's assume this file is called node.rs:
#![macro_use]
macro_rules! test {
() => { println!("Nuts"); }
}
macro_rules! best {
() => { println!("Run"); }
}
pub fn fun_times() {
println!("Is it really?");
}
Your main.rs would look sometime like the following:
mod node; //We're using node.rs
mod toad; //Also using toad.rs
fn main() {
test!();
best!();
toad::a_thing();
}
Finally let's say you have a file called toad.rs that also requires these macros:
use node; //Notice this is 'use' not 'mod'
pub fn a_thing() {
test!();
node::fun_times();
}
Notice that once files are pulled into main.rs with mod, the rest of your files have access to them through the use keyword.
I have came across the same problem in Rust 1.44.1, and this solution works for later versions (known working for Rust 1.7).
Say you have a new project as:
src/
main.rs
memory.rs
chunk.rs
In main.rs, you need to annotate that you are importing macros from the source, otherwise, it will not do for you.
#[macro_use]
mod memory;
mod chunk;
fn main() {
println!("Hello, world!");
}
So in memory.rs you can define the macros, and you don't need annotations:
macro_rules! grow_capacity {
( $x:expr ) => {
{
if $x < 8 { 8 } else { $x * 2 }
}
};
}
Finally you can use it in chunk.rs, and you don't need to include the macro here, because it's done in main.rs:
grow_capacity!(8);
The upvoted answer caused confusion for me, with this doc by example, it would be helpful too.
Note: This solution does work, but do note as #ineiti highlighted in the comments, the order u declare the mods in the main.rs/lib.rs matters, all mods declared after the macros mod declaration try to invoke the macro will fail.

Documenting a function created with a macro in Rust [duplicate]

This question already has an answer here:
Generating documentation in macros
(1 answer)
Closed 6 years ago.
I tried to do
#![deny(missing_docs)]
in Rust. And I found that /// comments are just ignored when a function is created with a macro like this:
/// docs
py_module_initializer!(libx, initlibx PyInit_libx |py, m| {
Ok(())
});
with:
error: missing documentation for a function
113 | py_module_initializer!(libx initlibx PyInit_libx |py, m| {
| ^
I thought a macro will just add a function definition after ///. What is wrong here?
Your doc comment refers to the macro invocation, which is useless in your case. To document the generated functions you have to write the doc comment into the macro definition or change your macro to also accept doc comments. Let's take a look at this:
#![deny(missing_docs)]
//! crate docs
macro_rules! gen_fn {
($name:ident) => {
/// generic doc comment... not very useful
pub fn $name() {}
}
}
gen_fn!(a);
gen_fn!(b);
This works, but it's not the best solution, because doc comments are the same for all generated functions. If you want to document each generated function, you have to change the macro:
macro_rules! gen_fn {
($(#[$attr:meta])* => $name:ident) => {
$(#[$attr])*
pub fn $name() {}
}
}
gen_fn!{
/// Doc comment for a
=> a
}
This works, because doc comments are converted to the #[doc(...)] attribute internally. You can find more information about that here.

Equivalent of __func__ or __FUNCTION__ in Rust?

In C and C++ you can get the name of the currently executing function through the __func__ macro with C99 & C++11 and ___FUNCTION___ for MSVC.
Is there an equivalent of this in Rust?
Example of __func__ in C:
#include "stdio.h"
void funny_hello() {
printf ("Hello from %s\n", __func__);
}
int main() {
funny_hello();
}
Outputs Hello from funny_hello.
You can hack one together with std::any::type_name.
macro_rules! function {
() => {{
fn f() {}
fn type_name_of<T>(_: T) -> &'static str {
std::any::type_name::<T>()
}
let name = type_name_of(f);
&name[..name.len() - 3]
}}
}
Note that this gives a full pathname, so my::path::my_func instead of just my_func. A demo is available.
There was an RFC about this, but it was never agreed upon or implemented.
The rationale for its absence:
"In general I don't think any of us have given an inordinate amount of
thought to these "debugging related" macros in terms of long term
stability. Most of them seem fairly harmless, but committing to
provide all of them for all Rust programs forever is a strong
commitment to make. We may want to briefly consider the story of these
macros in conjunction with considering adding this new macro."
Maybe Rust will have something comparable in the future,
but for now you will need to rely on your own tagging.
side note: __FUNCTION__ is non standard, __func__ exists in C99 / C++11.
Adding to Veedrac's answer, you can get the function's name without its full path by adding this:
macro_rules! function {
() => {{
fn f() {}
fn type_name_of<T>(_: T) -> &'static str {
std::any::type_name::<T>()
}
let name = type_name_of(f);
// Find and cut the rest of the path
match &name[..name.len() - 3].rfind(':') {
Some(pos) => &name[pos + 1..name.len() - 3],
None => &name[..name.len() - 3],
}
}};
}
You will get my_func instead of my::path::my_func for example.
It appears that function_name crate will do this.
https://docs.rs/function_name/latest/function_name/
The example from the docs is
use ::function_name::named;
#[named]
fn my_super_duper_function ()
{
assert_eq!(
function_name!(),
"my_super_duper_function",
);
}
I am not involved with the project and have not actually tried it yet.
While there's a lack of official support, there's the stdext crate (also mentioned in the RFC issue) that makes it easy to use.
use stdext::function_name;
fn foo() {
println!("{}", function_name!());
}
This includes module/trait names, like ::module::Trait::function if any.
If you only care about the name and not its entire path, you could do something like this for trait methods (keep in mind that there is runtime overhead for this, you may want to limit it with, e.g. OnceCell):
let fn_name = function_name!()
.rsplit_once(':')
.expect("could not parse function name")
.1;

Building an enum inside a macro

Is it possible to build an enum inside a Rust macro using fields that are defined as macro parameters? I've tried this:
macro_rules! build {
($($case:ty),*) => { enum Test { $($case),* } };
}
fn main() {
build!{ Foo(i32), Bar(i32, i32) };
}
But it fails with error: expected ident, found 'Foo(i32)'
Note that if the fields are defined inside the enum, there is no problem:
macro_rules! build {
($($case:ty),*) => { enum Test { Foo(i32), Bar(i32, i32) } };
}
fn main() {
build!{ Foo(i32), Bar(i32, i32) };
}
It also works if my macro only accepts simple fields:
macro_rules! build {
($($case:ident),*) => { enum Test { $($case),* } };
}
fn main() {
build!{ Foo, Bar };
}
But I've been unable to get it to work in the general case.
It's absolutely possible, but you're conflating totally unrelated concepts.
Something like $case:ty does not mean $case is something which looks like a type, it means $case is literally a type. Enums are not made up of a sequence of types; they're made up of a sequence of variants which are an identifier followed (optionally) by a tuple structure body, a record structure body, or a tag value.
The parser doesn't care if the type you give it happens to coincidentally look like a valid variant, it's simply not expecting a type, and will refuse to parse one in that position.
What you need is to use something like $case:variant. Unfortunately for you, no such matcher exists. The only way to do something like this is to manually parse it using a recursive incremental parser and that is so out of scope of an SO question it's not funny. If you want to learn more, try the chapter on incremental TT munchers in the Little Book of Rust Macros as a starting point.
However, you don't appear to actually do anything with the cases. You're just blindly substituting them. In that case, you can just cheat and not bother with trying to match anything coherent:
macro_rules! build {
($($body:tt)*) => {
as_item! {
enum Test { $($body)* }
}
};
}
macro_rules! as_item {
($i:item) => { $i };
}
fn main() {
build!{ Foo, Bar };
}
(Incidentally, that as_item! thing is explained in the section on AST coercion (a.k.a. "the reparse trick").)
This just grabs everything provided as input to build!, and shoves it into the body of an enum without caring what it looks like.
If you were trying to do something meaningful with the variants, well, you're going to have to be more specific about what you're actually trying to accomplish, as the best advice of how to proceed varies wildly depending on the answer.