How to disable the "unused code must be used" warning from macro? - rust

I tried to add allow dead_code and unused_must_use:
#[allow(dead_code)]
#[allow(unused_must_use)]
#[implement(MyStruct)]
pub struct MyStructList(pub Rc<Vec<MyStruct>>);
But still got the warning, still new to rust, what does it mean to call drop ?
warning: unused return value of `Box::<T>::from_raw` that must be used
--> test.rs
|
| #[implement(MyStruct)]
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: call `drop(from_raw(ptr))` if you intend to drop the `Box`
= note: this warning originates in the attribute macro `implement` (in Nightly builds, run with -Z macro-backtrace for more info)

I had this issue once, with a macro of my own. At the end I fixed the macro, but while the bug was there I workarounded with this trick:
#[allow(unused_must_use)]
mod my_struct {
use super::*;
#[implement(MyStruct)]
pub struct MyStructList(pub Rc<Vec<MyStruct>>);
}
pub use my_struct::*;
This is similar to the solution by #Andrew, but the allow directive applies only to the inner private module, instead of to all your module.
You may need to add/fix the pub use below depending on the details of what your macro exactly does. You may prefer pub use my_struct::MyStructList;, for example, and have finer control of your exports.

Related

Equivalent of NonZeroU8 but instead of 0, use u8::MAX?

I want to be able to use Option<NonZeroU8> for its compact repr, but still be able to use 0.
Is there a way to use u8::MAX as the non-representable value instead of 0?
To truly get the niche optimization directly, you'd have to use the super unstable rustc_ attributes.
#![feature(rustc_attrs)]
#[rustc_layout_scalar_valid_range_start(0)]
#[rustc_layout_scalar_valid_range_end(254)]
struct NonMaxU8(u8);
fn main() {
dbg!(std::mem::size_of::<Option<NonMaxU8>>());
}
[src/main.rs:8] std::mem::size_of::<Option<NonMaxU8>>() = 1
I say "super unstable" because these attributes will never be stabilized, at least not in their current form. Using them without feature(rustc_attrs) will emit the following message:
error[E0658]: the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable niche optimizations in libcore and libstd and will never be stable
--> src/main.rs:3:1
|
3 | #[rustc_layout_scalar_valid_range_start(0)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
error[E0658]: the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable niche optimizations in libcore and libstd and will never be stable
--> src/main.rs:4:1
|
4 | #[rustc_layout_scalar_valid_range_end(254)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
There have been asks for compiler support for ranged integers, like the discussion here, but I don't think anything has been formally proposed as of yet.
There is the nonmax crate that provides this. See NonMaxU8 specifically. This works because it uses NonZeroU8 internally and does the appropriate conversion upon creation and the .get() method.
If you wanted a different variant, not just zero or max, you can easily make your own. The nonmax crate uses an XOR strategy to zero-out the non-representable value or use a modular arithmetic method like is suggested in the comments:
pub struct NonTenU8(NonZeroU8);
impl NonTenU8 {
const UNREPRESENTABLE: u8 = 10;
/// Creates a u8 value that cannot be ten.
pub fn new(value: u8) -> Option<Self> {
NonZeroU8::new(value ^ Self::UNREPRESENTABLE).map(Self)
// NonZeroU8::new(value.wrapping_sub(Self::UNREPRESENTABLE)).map(Self)
}
pub fn get(&self) -> u8 {
self.0.get() ^ Self::UNREPRESENTABLE
// self.0.get().wrapping_add(Self::UNREPRESENTABLE)
}
}

Missing Copy/Debug traits warnings when defining enum with `strum` traits in macro

I want to define an enum using a macro. The enum needs to implement the strum traits {Display, EnumIter, EnumString}. I also want to keep the warnings missing_copy_implementations, missing_debug_implementations on. I came up with the following snippet:
#![warn(
missing_copy_implementations,
missing_debug_implementations,
)]
macro_rules! define_fruits {
{$($fruit:ident -> $name:literal),* $(,)?} => {
#[derive(Display, EnumIter, EnumString, Clone, Copy, Debug)]
pub enum Fruits {
$(
#[strum(to_string = $name)]
$fruit,
)*
}
};
}
define_fruits! {
Apple -> "green",
Orange -> "orange",
}
The above works fine except I get the warnings:
|
4 | missing_copy_implementations,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this warning originates in the macro `define_fruits` (in Nightly builds, run with -Z macro-backtrace for more info)
and similar for missing_debug_implementations.
These warnings go away when I remove Display, EnumIter, EnumString from my enum. They also go away if I define the same enum outside of a macro.
I cannot seem to find a way to get rid of the warnings in the above scenario, can someone help?
TL/DR: the problem is with derive(EnumIter), which isn't compatible with these lints. I've opened the issue on strum repository asking for possible changes.
To see what really happens, let's try to cargo expand the current code. After some simplification and stubbing out the unnecessary parts, we can see the following structure:
///An iterator over the variants of [Self]
pub struct FruitsIter {
idx: usize,
back_idx: usize,
marker: PhantomData<()>,
}
This is a type you get when you call IntoEnumIterator::iter derived for your enum. There's no Copy or Debug implementation for this struct - they are neither derived nor explicitly added by strum, so the lint sees the violation and fires.
A hint on the problem source can be seen when looking at the exact error, as provided by cargo check (or at the eror highlighting from rust-analyzer):
warning: type could implement `Copy`; consider adding `impl Copy`
--> src/lib.rs:10:27
|
10 | #[derive(Display, EnumIter, EnumString, Clone, Copy, Debug)]
| ___________________________^
11 | | pub enum Fruits {
| |___________^
Note that the span of the "erroneous" code starts from the EnumIter - since that's the token which the FruitsIter's span is tied to, warning on the FruitsIter is shown as a warning on the derive(EnumIter). And indeed, if we drop this derive - warning disappears.
There's nothing you can do with this, I'm afraid, aside from explicitly allowing these lints for the whole module containing your enum. This is something that should probably be fixed by the strum maintainers.

How to use two traits with enum_dispatch?

I've tried:
#[enum_dispatch(BarTrait, BazTrait)]
pub enum Foo {
VariantZero,
...
}
It seems to ignore any traits after the first, silently.
This causes errors, as in this case the compiler doesn't seem to believe that Foo implements BazTrait.
Update: #kmdreko's code works properly so long as BazTrait is in the same crate as Foo.
When BazTrait is in a different crate, which also uses enum_dispatch, BazTrait is ignored and causes two errors of the form:
error[E0599]: no method named `baz` found for enum `Foo` in the current scope
--> src/main.rs:53:9
|
45 | enum Foo {
| -------- method `baz` not found for this
...
53 | foo.baz();
| ^^^ method not found in `Foo`
|
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `baz`, perhaps you need to implement it:
candidate #1: `mylib::BazTrait`
It is important to note that there is no error at either #[enum_dispatch(BarTrait, BazTrait)] or pub enum Foo {.
The #[enum_dispatch] attribute does not work across crates:
Unfortunately, procedural macros in Rust are limited in a few ways that will make what you're trying to achieve impossible - notably, they are run independently per-crate, so there's no way for information from one crate to affect an implementation in another.
From the author of enum_dispatch in an unrelated issue.

Rust says import is not used and can't find imported statements at the same time

I've got some structure I want to use Serde with. Like this one:
use serde::{Serialize, Deserialize};
#[derive(Serialize)]
struct GetLinkResponse {
error: String,
link: String,
}
But compiler says that:
Serialize import is not used
Serialize can't be found
error: cannot find derive macro `Serialize` in this scope
--> src/structs.rs:3:10
|
3 | #[derive(Serialize)]
| ^^^^^^^^^
warning: unused imports: `Deserialize`, `Serialize`
--> src/structs.rs:1:13
|
1 | use serde::{Serialize, Deserialize};
| ^^^^^^^^^ ^^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
I guess I'm not understanding something about how use works. Can somebody explain me what is my mistake here?
You're victim of the "magic" behind automatic trait implementation, i.e. procedural macros. Usually, people give the procedural macro that implements a trait the same name as the trait (because it's convenient). Here, there is the trait serde::Serialize, but there is also the procedural macro that automatically implements that trait serde::Serialize.
They don't conflict because they live in difference namespaces, and the compiler infers from the context if it's a macro or a trait.
In your situation, you forgot to add the derive feature, so there is no proc macro in serde. Thus, you're importing a trait without using it, and you try to use a proc macro that doesn't exist.
The solution is to use the serde's derive feature:
serde = { version = "1.0", features = ["derive"] }

How are mod & use supposed to work for traits in rust?

Consider the following contrived situation:
mod imported {
pub trait Imported {
fn hello(&self, x:int) -> int;
}
}
struct Hi;
impl imported::Imported for Hi {
fn hello(&self, x:int) -> int {
return x;
}
}
#[test]
fn test_thing() {
let value = Hi;
println!("{:?}", value.hello(10));
}
This won't compile, because the trait Imported is not in scope, so the method hello() cannot be invoked:
imports.rs:20:18: 20:33 error: type `imports::Hi` does not implement any method in scope named `hello`
imports.rs:20 println!("{:?}", value.hello(10));
^~~~~~~~~~~~~~~
If we put Imported in the current scope (ie. get rid of mod imported) this works fine, but like this, it does not.
Normally for this purpose you would use 'use' to bring the 'Imported' symbol into the local scope:
use imported::Imported;
However, in this case you cannot, because the symbol 'imported' does not yet exist at the beginning of the file:
imports.rs:2:5: 2:13 error: unresolved import. maybe a missing `extern crate imported`?
imports.rs:2 use imported::Imported;
^~~~~~~~
imports.rs:2:5: 2:23 error: failed to resolve import `imported::Imported`
imports.rs:2 use imported::Imported;
^~~~~~~~~~~~~~~~~~
And you cannot do it after the mod imported call, because:
imports.rs:8:1: 8:24 error: `use` and `extern crate` declarations must precede items
imports.rs:8 use imported::Imported;
^~~~~~~~~~~~~~~~~~~~~~~
To be fair this only occurs when you are implementing a trait and then trying to use that impl in the safe file, but it seems like this would actually be quite a common use case for testing.
You can work around it by structuring your code slightly differently and importing modules from some common parent, but this seems like an inherent limitation of the current system.
Am I missing something?
I think you have indeed missed something. Adding use imported::Imported; at the top of the file does work—I presume that this is not precisely what you tried to compile.
use statements, although written before the mod statements, are resolved after the mod, so there is no source order problem.
I presume that your error is in fact that your file imports.rs was not the crate root. Remember that a use statement takes an absolute path if you don't use super or self in it. To make it work in any place, you would need to write use self::imported::Imported;; assuming you were compiling a lib.rs containing mod imports;, you would have needed to use imports::imported::Imported, the absolute path to the trait.
(BTW, you can replace return x; at the end of the function with just x. Remember Rust's block value doctrine, whereby the last expression in a block is the value of the block.)

Resources