Avoid duplicating use statements at beginning of doctests - rust

When writing doctests for methods on a struct or trait or functions in a file, etc. I often find myself putting the same use my_crate::{MyStruct, MyTrait, Etc} at the beginning of each doctest. Is there any way to avoid this duplication, like some way I could define those use statement just once for the whole module?

If you keep finding the same group of items gets imported over and over again, you may want to consider creating a prelude module. The core idea is that you simply re-export those key items in that module so anyone using your crate can do use your_crate::prelude::*; to import all of them as a group.
One common use cases for this is if you have a lot of traits that are frequently used. When you provide the most common traits as a group, your users don't need to spend figuring out which traits provide which methods. You can also choose to add structs/enums/unions, but I wouldn't recommend it. Unlike traits, types are almost always referred to explicitly and are much easier to find.
For example, here is what rayon's prelude module looks like.
//! The rayon prelude imports the various `ParallelIterator` traits.
//! The intention is that one can include `use rayon::prelude::*` and
//! have easy access to the various traits and methods you will need.
pub use crate::iter::FromParallelIterator;
pub use crate::iter::IndexedParallelIterator;
pub use crate::iter::IntoParallelIterator;
pub use crate::iter::IntoParallelRefIterator;
pub use crate::iter::IntoParallelRefMutIterator;
pub use crate::iter::ParallelBridge;
pub use crate::iter::ParallelDrainFull;
pub use crate::iter::ParallelDrainRange;
pub use crate::iter::ParallelExtend;
pub use crate::iter::ParallelIterator;
pub use crate::slice::ParallelSlice;
pub use crate::slice::ParallelSliceMut;
pub use crate::str::ParallelString;

Related

How to hide trait implementation in Rust

I have a project with its own error type, which is exposed outside of crate. Lets call it MyErrorType. The project itself internally depends on another crate with its own error type. Lets call it ForeignErrorType.
In order to simplify code and make it more readable I've created following implementation of From trait:
impl From<ForeignErrorType> for MyErrorType {
...
}
This allows to use question mark operator, ?, when dealing with foreign error types without a necessity to convert them in place.
The issue is that the mentioned trait implementation is exposed outside of my crate. I don't want the users of my crate to accidentally rely on the conversion possibility from ForeignErrorType to MyErrorType.
What I've tried so far: Have put the mentioned trait implementation into module with pub(crate) visibility. This surprisingly hides all structs defined in such module, but leaves trait implementation exposed.
Is there way to keep my From implementation private and not to expose it outside of crate?
Probably I'm trying to achieve error handling benefits in a non‑idiomatic way. If this is true, what's the proper way to be able to use ? operator on foreign error types without exposing them?
Is there way to keep my From implementation private and not to expose it outside of crate?
No. Trait implementations have no scope.
What you can do instead in this case is write a function with the same contents as your From implementation would have had, and apply it with Result::map_err before ?.
pub(crate) fn foreign_err(e: ForeignErrorType) -> MyErrorType {
todo!()
}
...
let foo = their_function().map_err(foreign_err)?;
This has to be done at every ? usage, but there is no way to have an implicit conversion that is scoped to a crate or module, so that's the best you can have.

How to automatically #derive(Something) on every struct(possibly with filtering)?

Is there a way to get the Rust compiler to add derives on all structs, possibly with some kind of matching, like only structs in X crate, or maybe recursively apply #derives? I would rather not vendor those crates because it'd be a lot of work to keep them up to date.
No, the Rust compiler does not provide such a facility.
You can't derive traits for types outside of your own crate. So you have two options:
Submit a PR to the crate in question, to add the implementations. Many projects will accept changes that implement common traits like serde::Serialize etc, provided they are feature-gated
Use wrapper types and implement the traits there. e.g. if the type in question is Uuid from the uuid crate:
pub struct MyUuid(uuid::Uuid);
impl MyTrait for MyUuid {
// etc
}
Note that you can't derive traits that need to know the fields of third party types because the tokens will not be available.

Avoiding pubs in Rust

I've just split my program into an executable and a large file full of struct definitions (structs.rs).
In order to use the structs and their fields for the main executable, I have to prepend each struct definition, and every field definition with pub.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Foo {
pub bar: u8,
pub baz: [u8; 4]
}
This reduces readability.
Is there a way of avoiding all of these pubs?
Or should I be using another way of decomposing my program into multiple files?
This is expected. Modules and crates are a privacy boundary in Rust. The default privacy level for structs and their fields is "same module and its submodules", so parent modules and sibling modules need to have a permission to touch struct's fields.
In Rust structs typically have only a few fields, but the fields may have important invariants to uphold. For example, if Vec.len was public, you could cause unsafe out of bounds access. As a precaution, Rust requires programmers to think through whether they can allow access to each field.
It's unusual to have thousands of structs or structs with thousands of fields, unless they're mirroring some external data definition. If that's the case, consider auto-generating struct definitions with a macro or build.rs.

How to suppress the warning for "drop_with_repr_extern" at a fine granularity?

I am currently experimenting with multi-threading code, and its performance is affected by whether two data members share the same cache line or not.
In order to avoid false-sharing, I need to specify the layout of the struct without the Rust compiler interfering, and thus I use repr(C). However, this same struct also implements Drop, and therefore the compiler warns about the "incompatibility" of repr(C) and Drop, which I care naught for.
However, attempting to silence this futile warning has proven beyond me.
Here is a reduced example:
#[repr(C)]
#[derive(Default, Debug)]
struct Simple<T> {
item: T,
}
impl<T> Drop for Simple<T> {
fn drop(&mut self) {}
}
fn main() {
println!("{:?}", Simple::<u32>::default());
}
which emits #[warn(drop_with_repr_extern)].
I have tried specifying #[allow(drop_with_repr_extern)]:
at struct
at impl Drop
at mod
and neither worked. Only the crate-level suppression worked, which is rather heavy-handed.
Which leads us to: is there a more granular way of suppressing this warning?
Note: remarks on a better way to ensure that two data members are spread over different cache lines are welcome; however they will not constitute answers on their own.
The reason is near the end of rustc_lint/builtin.rs:
The lint does not walk the crate, instead using ctx.tcx.lang_items.drop_trait() to look up all Drop trait implementations within the crate. The annotations are only picked up while walking the crate. I've stumbled upon the same problem in this question. So unless someone changes the lint to actually walk the crate and pick up Drop impls as it goes, you need to annotate the whole crate.

Is it required to import a trait whenever it is used?

I want to be able to have a trait which I can implement multiple times but not need to explicitly import it each time when using the library.
I have a lib.rs file which looks like this:
pub mod learning {
pub mod lin_reg;
pub trait Model<T,U> {
fn predict(&self, data:T) -> U;
fn train(&mut self, data:T, value:U);
}
}
And then I implement this Model trait in each of my models (like the Linear Regression model).
Now if the user wants to use the linear regression model they will need to do the following:
use ...::learning::lin_reg::LinRegressor;
use ...::learning::Model;
let model = LinRegressor:new();
model.train(...)
I want to be able to remove the need to import the Model trait each time. Is it possible to do this? Will I need to restructure my library?
Yes, it is always required that the end-user has explicitly declared that a trait is to be used. You can see examples of this in the standard library, as the std::io::Read trait is not available by default and must be used.
You can also follow the IO modules lead here, as it defines a prelude. This is a module called prelude which re-exports common traits and structs.
There's even a prelude for the entire standard library. The only difference is that the compiler automatically adds this for you, unless you use the no_std feature.
You can do the same for your crate, if you expect that everyone will want to use certain traits if they use it at all.
A bit of editorial, but I really prefer this style. As an end-user, I can have a very good sense of what it is that I am importing and relying on. This helps me, the programmer, keep track of my dependencies and make sure that my code isn't gathering "secret" dependencies that ultimately decrease the organization of my code.

Resources