Define function name from input to Rust macro [duplicate] - rust

This question already has answers here:
Is it possible to declare variables procedurally using Rust macros?
(4 answers)
Closed 5 years ago.
When using a macro that defines a function, is it possible to add a prefix to the function?
macro_rules! my_test {
($id:ident, $arg:expr) => {
#[test]
fn $id() {
my_test_impl(stringify!($id), $arg);
}
}
}
For example, fn my_test_$id() {
I'm defining tests using an identifier which may begin with numbers, and I would like to use a common prefix.

Currently this is not supported in stable.
However there is a feature in nightly called concat_idents:
concat_idents!(my_test_, $id)
See
Rust docs
Issue
Update: it seems there aren't near-term plans to add this into stable releases, see issue.

[...] is it possible to add a prefix to the function?
No. Really, really no. Super totally not at all even in the slightest.
I would like to have use a common prefix.
Put them all in a mod instead.

As mentioned, you should use submodules for this, but remember that macros can create submodules, submodules can be nested allowing their names to overlap, submodules can provide impls, and the tests submodule is not magic.
I once submitted a pull request that avoids numerous "boiler plate names" by refactoring the code using these tricks, although the #[no_mangle] exports make it harder.

Related

What's the proper way to import mods in other files in Rust?

I am writing a Rust project and I want to use multiple mods. The src directory has files:main.rs, default.rs, difficult.rs.
The default.rs has:
pub struct Info {...}
pub fn f(...) {...}
and adding mod default, I can directly use default::Info and default::f.
But I want to use Info in difficult.rs and I add mod default into difficult.rs, then it gets error which says that default is not found.
How should I fix this?
How should I fix this?
You might want to read the book? The solution is at section 7.4. Rust is not a language which is easy to learn, and learning rust by osmosis or random walking tends to be a frustrating and unsuccessful endeavour.
I would very strongly recommend reading the book cover to cover at least once.
Anyway use is how you "import" things into the local scope.
mod is how you declare a module. If you use mod multiple times for the same file, you're essentially creating copies of the modules, which the compiler will see as two unrelated modules with unrelated types.

Why duplicate function names in mod.rs as another .rs file?

For example, have module within /xyz/ sub-directory. Inside the directory are two files, mod.rs and network.rs say.
Why do mod.rs and network.rs have the same function names, but different code within the functions? Is there any reason for this? I thought mod.rs was just basically a defintions file to declare a module, and specify which other .rs files within the sub-directory should be treated as their own creates / modules.
Any help?
It sounds like you are referring to a design decision made by a specific crate. You are correct in assuming there is no special consideration given by the compiler to function/type/ident names in separate files/modules.
That being said it seems likely that what you are referring to might be using conditional compilation. Conditional compilation lets the compiler decide if a given piece of code is compiled or not. You will usually see this used to handle which implementation of a function is used when compiling code on different operating systems since it is often it too inefficient or simply impossible to check at runtime. Some library authors might also decide to add an implementation that it can fallback to instead of throwing a hard error.
Here is a quick example of why xyz might want to have 3 different implementations of foobar.
// xyz/mod.rs
mod windows;
mod unix;
// If this crate is compiled on windows re-export the contents of windows.rs
#[cfg(windows)]
pub use windows::*;
// If this crate is compiled on unix/linux re-export the contents of unix.rs
#[cfg(unix)]
pub use unix::*;
// If not on either windows or unix provide a default implementation to use instead
#[cfg(not(any(windows, unix)))]
pub fn foobar() -> i32 {
panic!("This function is unsupported on the current os")
}

How do you define a derive macro crate as a dependency and re-export the procedural macro code

In the Book:
"The two crates will need to be published separately, and programmers
using these crates will need to add both as dependencies and bring
them both into scope. We could instead have the hello_macro crate use
hello_macro_derive as a dependency and re-export the procedural macro
code. However, the way we’ve structured the project makes it possible
for programmers to use hello_macro even if they don’t want the derive
functionality."
Assuming the user will always want the derive functionality, how do you do as suggested and have the hello_macro crate use hello_macro_derive as a dependency and re-export the procedural macro code, with one use and one dependency instead of two each?
[dependencies]
hello_macro = { path = "../hello_macro" }
hello_macro_derive = { path = "../hello_macro/hello_macro_derive" }
use hello_macro::HelloMacro;
use hello_macro_derive::HelloMacro
#[derive(HelloMacro)]
struct Pancakes;

How is it possible to keep Rust module documentation in separate Markdown files?

This section of the Rust book seems to imply that it is possible to keep Rust documentation in separate .md files, but it does not say how these .md files can then be included back. How does this work?
The syntax for putting Rust module documentation in separate Markdown files is:
#![doc = include_str!("path/to/some-documentation.md")]
/* content of the module */
This is supported since stable Rust 1.54.0.
On old nightly compilers from 1.50.0-nightly through 1.53.0-nightly, an unstable feature is required in order for the above to be available.
#![feature(extended_key_value_attributes)]
#![doc = include_str!("path/to/some-documentation.md")]
On nightly compilers 1.24.0-nightly through 1.53.0-nightly, the following alternative syntax is available, but has since been removed.
#![feature(external_doc)]
#![doc(include = "path/to/some-documentation.md")]
It doesn't. That section on describing the functionality of rustdoc is saying that it can process individual .md files. The third paragraph touches on this:
Documentation can be generated in two ways: from source code, and from standalone Markdown files.
Insofar as I am aware, there is no extant way to put code documentation in external files. It would be theoretically possible to do so using a procedural derive macro, but I'm not aware of any crate that actually does this.
In stable Rust, you can mimic the unstable external-doc feature through clever macros.
An easy way to do this is to use the doc-comment crate:
#[macro_use]
extern crate doc_comment;
// If you want to test examples in your README file.
doctest!("../README.md");
// If you want to document an item:
doc_comment!(include_str!("another_file.md"), pub struct Foo {});
You can see a complicated version of this in my crate SNAFU, where I use it for the user's guide.
The "by-hand" version involves passing the thing to be documented along with the included markdown:
macro_rules! inner {
($text:expr, $($rest: tt)*) => {
#[doc = $text]
$($rest)*
};
}
inner! {
include_str!("/etc/hosts"),
mod dummy {}
}
See also:
Is it possible to emit Rust attributes from within macros?
How to embed a Rust macro variable into documentation?
Generating documentation in macros

How to document macros from a Rust compiler plugin?

I notice that compiler plugins frequently provide macros that the documentation wont even mention. They're registered and created programmatically rather than being defined in a syntax rustdoc recognizes. Naturally, no documentation can be shown.
I'm looking for a way to get around that, some way of generating documentation for a macro that doesn't exist in the crate at compile time.
I notice the syntax crate could benefit from such a thing as well. quote_item, for instance, is completely undocumented. I can't even find the code that registers it.
One possibility is to do what the compiler does: create an empty macro_rules! macro and attach documentation to that. E.g. if a crate defines foo that takes a single expression, then write something like
/// Documentation
#[macro_export]
macro_rules! foo {
($e: expr) => ({ /* syntax extension */ })
}
I notice the syntax crate could benefit from such a thing as well. quote_item, for instance, is completely undocumented. I can't even find the code that registers it.
You can search the Rust source for quote_item, which is helpful for two reasons: it gives some examples, and also allows you to track down the definition. The latter is easier using Rust's DXR instance which can search for things with quotes (i.e. can find strings), and includes various source code navigation tricks (like jump-to-definition).

Resources