I'm trying to create two different versions of the same function, only one of which will be compiled. As an example:
#[cfg(debug_assertions)]
fn do_something(x: usize) -> usize {
x + 1
}
#[cfg(not(debug_assertions))]
fn do_something() -> usize {
0
}
This works fine and I can also call the correct version of do_something if I know which one I'm calling (In practice, the functions will do the exact same thing, the debug one just requires more info for some validation). So I can create two corresponding main functions:
#[cfg(debug_assertions)]
fn main() {
do_something(0);
}
#[cfg(not(debug_assertions))]
fn main() {
do_something();
}
But this is very clumsy, and I want to have only one version of the code that doesn't depend on debug_assertions. I'd like to do something like:
macro_rules! call {
($func:ident, $optional_arg:expr) => {{
if cfg!(debug_assertions) {
$func($optional_arg);
} else {
$func();
}
}};
}
fn main() {
call!(do_something, 0);
}
and then re-use the macro wherever I call this function, or similar ones. But this doesn't compile:
--> main.rs:16:13
|
2 | fn do_something(x: usize) -> usize {
| ---------------------------------- defined here
...
16 | $func();
| ^^^^^-- supplied 0 arguments
| |
| expected 1 argument
...
22 | call!(do_something, 0);
| ----------------------- in this macro invocation
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
I don't understand why I get the error, since the wrong function call shouldn't even be compiled.
The error can be fixed by forcing the functions to have the same signature and simply ignoring the unnecessary argument in the release version, but that doesn't seem like the right way to go.
What would you do in this situation? Why doesn't the macro example compile?
From the reference :
cfg!, unlike #[cfg], does not remove any code and only evaluates
to true or false. For example, all blocks in an if/else expression
need to be valid when cfg! is used for the condition, regardless of
what cfg! is evaluating
Flags will be evaluated in compile time but you are doing this check at runtime. You need to use attributes to avoid the problem:
macro_rules! call {
($func:ident, $optional_arg:expr) => {{
#[cfg(debug_assertions)]
$func($optional_arg);
#[cfg(not(debug_assertions))]
$func();
}};
}
Related
I'm implementing a crate that has the purpose of wrapping some user code and make sure it is called in a certain context. I can summarize my workspace this way:
A "user_code" crate:
This contains a single "user" function, which I would have no control over. Notice that it returns a u32.
pub fn addition(a: u32, b: u32) -> u32 {
a + b
}
A "wrapper" crate:
This contains a macro_rules. This macro creates some modules and a caller function, which will call the user code seen above. This is a highly simplified version. Notice that the return value of addition is ignored.
#[macro_export]
macro_rules! macro_wrapper {
() => {
pub mod my_user_code {
use wrapper::*;
use user_code::*;
pub mod addition {
use wrapper::*;
use super::*;
pub fn caller(a: u32, b: u32) {
addition(a, b);
}
}
}
};
}
An "example" crate:
Here I simply call the wrapper macro, in order to form the modules and functions I need and then use in the main function.
#![deny(unused_results)]
use wrapper::macro_wrapper;
macro_wrapper! {
}
fn main() {
my_user_code::addition::caller(2,3);
println!("Hello, world!");
}
This might seem like super strange code (it is) but it's a very simplified example of a legit project :)
My goal now is to make sure that this code doesn't compile because the return value of addition is not used - it was forgotten. The lint #![deny(unused_results)] seems to achieve exactly what I want.
However, this works only if, instead of use wrapper::macro_wrapper; I have the macro directly defined in the main.rs. In that case I get:
error: unused result of type `u32`
--> example\src\main.rs:14:21
|
14 | addition(a, b);
| ^^^^^^^^^^^^^^^
...
21 | / macro_wrapper! {
22 | |
23 | | }
| |_- in this macro invocation
|
note: the lint level is defined here
--> example\src\main.rs:1:9
|
1 | #![deny(unused_results)]
| ^^^^^^^^^^^^^^
= note: this error originates in the macro `macro_wrapper` (in Nightly builds, run with -Z macro-backtrace for more info)
If the macro is defined in its crate "wrapper", the code compiles and runs just fine without any error. This is not the result I expect.
What am I missing here? Thank you in advance for reading!
The unused_results lint doesn't get fired for macro expansions for external macros. This is by design, because this lint can be very noisy, and you can't control the expansion of external macros.
If you need that, your best bet is to mark your function as #[must_use], then #![deny(unused_must_use)]. Because the unused_must_use lint does get fired for external macros, it will work.
If you can't control the function definition, a neat trick you can use is to define a dummy function whom only job is to trigger the lint:
#[doc(hidden)]
#[must_use]
pub fn must_use<T>(v: T) -> T { v }
// In the macro...
pub fn caller(a: u32, b: u32) {
$crate::must_use(addition(a, b));
}
I've been tyring to define a different function for eacu unsigned type in Rust, and of course they have to have different names because Rust can't pick the right one by signature. So I'm trying to give them different names but I was unable to do so:
macro_rules! define_my_function {
($t:ty, $f_name:ident) => {
pub fn concat_idents!(my_function_, $ty)()(
stream: &mut T
) -> Result<$ty, ParseError> {
todo!()
}
}
}
define_my_function!(u8, name_for_u8);
Compiling playground v0.0.1 (/playground)
error: expected one of `(` or `<`, found `!`
--> src/lib.rs:3:29
|
3 | pub fn concat_idents!(my_function_, $ty)()(
| ^ expected one of `(` or `<`
...
11 | define_my_function!(u8, name_for_u8);
| ------------------------------------- in this macro invocation
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=9ccea3ddcc75bb2cfab14c52df7bc24f
It looks like this is impossible in Rust. What can I do then? Also I don't want to use concat_idents as it's nightly only
You can use the paste crate, that internally uses a procedural macro to create new identifiers:
macro_rules! define_my_function {
($t:ty) => {
::paste::paste! {
pub fn [<my_function_ $t>]() {
println!(stringify!($t));
}
}
}
}
define_my_function!(u8);
define_my_function!(u16);
fn main() {
my_function_u8();
my_function_u16();
}
Playground
Note that I had to slightly change the code you gave because it wasn't compiling.
From the documentation for std::concat_idents:
Also, as a general rule, macros are only allowed in item, statement or expression position. That means while you may use this macro for referring to existing variables, functions or modules etc, you cannot define a new one with it.
Unfortunately, it seems that at the time this is possible using a procedural macro, or by manually copy-pasting for each numeric type.
I'm trying to write a macro to switch between rayon's par_iter and std's iter depending on a build feature (possibly getting ahead of myself, as I've not read a lot on macros yet). A macro seems a bit better to deal with than a function here, since a function might need some relatively complex types to make this work; as well a macro might remain more flexible in the future if I wanted to add even more variations in build features pertaining to how to run iterators.
#[macro_export]
macro_rules! par_iter {
($($tokens:tt)*) => {
#[cfg(feature = "threaded")]
$($tokens)*.par_iter()
#[cfg(not(feature = "threaded"))]
$($tokens)*.iter()
}
}
I see the following error:
error: macro expansion ignores token `b_slice` and any following
--> src/util.rs:28:8
|
28 | $($tokens)*.iter();
| ^^^^^^^^^
|
::: src/counting.rs:219:9
|
219 | par_iter!(b_slice).map(WordCount::from)
| ------------------- help: you might be missing a semicolon here: `;`
| |
| caused by the macro expansion here
|
= note: the usage of `par_iter!` is likely invalid in expression context
While I have no idea about the first error, I'm curious why a ; is expected - how do I make it valid in expression context?
This essentially boils down to, that you aren't allowed to have attributes within expressions like that, e.g. that the following is invalid:
b_slice.iter()
#[cfg(not(feature = "threaded"))]
.map(|x| x)
.collect();
To fix the issue, you can assign them to a temporary variable, like this:
Note the double {{ and }}, which results in a block, such that the final expression is the value that block results in.
#[macro_export]
macro_rules! par_iter {
($($tokens:tt)*) => {{
#[cfg(feature = "threaded")]
let it = $($tokens)*.par_iter();
#[cfg(not(feature = "threaded"))]
let it = $($tokens)*.iter();
it
}};
}
Alternatively, you can also split it into two macros like this:
#[cfg(feature = "threaded")]
#[macro_export]
macro_rules! par_iter {
($($tokens:tt)*) => {
$($tokens)*.par_iter()
}
}
#[cfg(not(feature = "threaded"))]
#[macro_export]
macro_rules! par_iter {
($($tokens:tt)*) => {
$($tokens)*.iter()
}
}
I want to ensure the code style is consistent by requiring this:
fn calc() -> u32 {
return 1 + 1;
}
And forbidding this:
fn calc() -> u32 {
1 + 1
}
Is there any setting in Cargo.toml?
I don't believe this can be done with Cargo itself, but Clippy has a lint for exactly this.
To enable the lint, place the line #![deny(clippy::implicit_return)] at the top of your root file (usually main.rs or lib.rs). Now running cargo clippy should show an error if you use implicit returns. You'll probably also want to disable the lint that has the opposite warning: #![allow(clippy::needless_return)].
Example code:
#![deny(clippy::implicit_return)]
#![allow(clippy::needless_return)]
fn foo() -> u32 {
0
}
fn main() {
println!("{}", foo());
}
And the error after running cargo clippy:
error: missing return statement
--> src/main.rs:5:5
|
5 | 0
| ^ help: add `return` as shown: `return 0`
|
note: lint level defined here
--> src/main.rs:1:9
|
1 | #![deny(clippy::implicit_return)]
| ^^^^^^^^^^^^^^^^^^^^^^^
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return
I started grouping code for one of my projects into module files. I encountered a lot of warnings about unused code for functions in those modules, but the functions are actually used (privately within the module).
An example from my project:
// ...
// Line 46:
fn calc_p(word: &str, dict: &Dictionary) -> f32
{
if !dict.contains_key(word) {
return 0.0;
}
let total: u32 = dict.values().sum();
dict[word] as f32 / total as f32
}
...
But at line 13 in the same file, same module the function is clearly used:
// ...
pub fn suggest_corrections(to_be_corrected: &str, dict: &Dictionary) -> Vec<(f32, String)>
{
let candidates = create_candidates(to_be_corrected, dict);
let mut weighted_candidates = candidates
.into_iter()
.map(|w| (calc_p(&w, dict), w)) // Line 13 - calc_p used here
.collect::<Vec<_>>();
weighted_candidates.sort_by(|a, b| b.partial_cmp(a).unwrap());
weighted_candidates
}
// ...
Yet I get the compiler warning:
warning: function is never used: `calc_p`, #[warn(dead_code)] on by default
--> src/spellcheck/corrections.rs:46:1
|
46 | fn calc_p(word: &str, dict: &Dictionary) -> f32
| _^ starting here...
47 | | {
48 | | if !dict.contains_key(word) {
49 | | return 0.0;
50 | | }
51 | |
52 | | let total: u32 = dict.values().sum();
53 | | dict[word] as f32 / total as f32
54 | | }
| |_^ ...ending here
I thought maybe it's because the module corrections is not public, but I also marked the module as public and still get the same warning.
I tried to reproduce the behaviour using the playground, but if the module is defined in the same file it seems to work. The warnings also happen for me during a TravisCI build.
Why is the function marked as unused although it's actually used in the same file in the same module?
I'm using Rust 1.15 / 1.16.
Why is the function marked as unused although it's actually used in the same file in the same module?
Because unused code is a transitive calculation, and the code that calls that function cannot be called from outside the crate. The compiler is correct here.
The first error I see is:
warning: static item is never used: `ALPHABET`, #[warn(dead_code)] on by default
--> src/spellcheck/edits.rs:3:1
That's defined as:
src/spellcheck/edits.rs
static ALPHABET : &'static str = "abcdefghijklmnopqrstuvwxyz";
So it's not public, and can only be used from inside the module.
It's called from replaces and inserts. Both of those are used from edits1, a public function. Is the module containing it (edits) public?
src/spellcheck/mod.rs
mod edits;
pub mod corrections;
pub mod dictionary;
Nope, it is not. So where is edits1 called from? kodecheck_spellcheck::spellcheck::corrections::create_candidates, a non-public function. This is called by suggest_corrections, a public function, inside the public module corrections.
Let's look up the tree...
src/lib-spellcheck.rs
// #FIXME do we really need this here or move to sub-modules?
#[macro_use]
extern crate nom;
extern crate regex;
mod spellcheck;
Ah. For whatever reason, you've decided to introduce a completely nested private module spellcheck inside the crate (which is why the full path earlier is kodecheck_spellcheck::spellcheck::corrections::create_candidates).
From this, we can see that kodecheck_spellcheck::spellcheck cannot be accessed from outside the crate; it's not pub.
Let's create an example that uses the crate. This the the best way to see if it's true and would have been easy for you to test yourself:
examples/foo.rs
extern crate kodecheck_spellcheck;
fn main() {
kodecheck_spellcheck::spellcheck::corrections::create_candidates();
}
Compiling this has the error:
error: module `spellcheck` is private
--> examples/foo.rs:4:5
|
4 | kodecheck_spellcheck::spellcheck::corrections::create_candidates();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
We could also create a MCVE:
mod spellcheck {
mod edits {
static ALPHABET: &'static str = "";
pub fn edits1() {
println!("{}", ALPHABET);
}
}
pub mod corrections {
pub fn create_candidates() {
::spellcheck::edits::edits1();
}
}
}
fn main() {}
Note that this differs from your example because main is empty. Your library crate doesn't have a mainmethod that calls anything. You could also explicitly specify that it's a library crate, but this is less well-known:
#![crate_type="lib"]
mod spellcheck {
mod edits {
static ALPHABET: &'static str = "";
pub fn edits1() {
println!("{}", ALPHABET);
}
}
pub mod corrections {
pub fn create_candidates() {
::spellcheck::edits::edits1();
}
}
}
Because there's a private module where all the code is, nothing outside this crate can call anything inside the crate. Therefore every method is unreachable.
To fix it, I'd suggest combining src/spellcheck/mod.rs into src/lib-spellcheck.rs. You could also just make the module public, but I see no reason to have the extra module.
I also see no reason to rename src/lib.rs to src/lib-spellcheck.rs; it's far more idiomatic to just leave it lib.rs.
Additionally, you should go ahead and become comfortable with Rust style. Braces go on the same line as the signature:
fn calc_p(word: &str, dict: &Dictionary) -> f32 {
// ...
Tools like rustfmt will help you apply the proper style.