Rust: Cannot access functions in subdirectories [duplicate] - rust

This question already has an answer here:
Can't understand Rust module system
(1 answer)
Closed 2 years ago.
I am learning rust and am going through the book and have run into a question. Is it possible to access files within a folder? I am currently having issues with this.
Here is a project which demonstrates the issue: https://github.com/joemspalding/rust-stack-overflow-file-example/tree/master/src
In this project, I can successfully import functions from a different file, however, trying to access a file from a different folder is where I lose understanding syntactically. I feel I've tried nearly every combination of
mod foo;
mod foo::bar;
use foo;
use foo::bar;
Currently, running cargo run produces the following compile time error
Compiling my-project v0.1.0 (J:\Projects\rust\the_book\ch7\my-project)
error[E0432]: unresolved import `foo`
--> src\main.rs:1:5
|
1 | use foo::bar;
| ^^^ use of undeclared type or module `foo`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0432`.
error: could not compile `my-project`.
To learn more, run the command again with --verbose.
I've been reading into this for hours and all of the resources I can find have great examples of reading code from a file on the same level, but not on reading code through folders.
Another common line I've seen is with the use of folder/mod.rs This seems unstylistic of rust after an update in 2018 and I'd like to avoid it if possible.

You must use mod.rs. It is the preferred option in rust 2018 and above. Module definitions aren't file paths and shouldn't be treated as such. Think of them more as C++ namespaces.
You could also choose to rename your mod.rs to match the name of the folder it is in (Ex: example_a/mod.rs -> example_a/example_a.rs). However I almost never this done and I find its much easier to navigate code with mod.rs.
If your mod.rs doesn't have any useful code, maybe you don't need a submodule.
A mod.rs should have code which relates to its sub modules. If it is only a couple lines long, you may want to skip adding the folder entirely since it doesn't sound like it has any purpose in your specific use case. This isn't like the empty __init__.py files of python 2.

Related

avoid conflicting use paths, in rust

I have a module csv and am trying to use the external csv library (use csv::ReaderBuilder;). I am getting a conflict.
Minimal code that exhibits the error
mod csv {
use ::csv::ReaderBuilder;
}
Error message
--> src/csv.rs:4:5
|
4 | use csv::ReaderBuilder;
| ^^^ help: a similar path exists: `crate::csv`
|
= note: `use` statements changed in Rust 2018; read more at <https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-clarity.html>
My question is how do I avoid such conflicts?
When creating a module, knowing the name of all modules that I may use via use seems un-reasonable. What am I doing wrong? I could name all my modules starting with my_, but this is ugly, and almost not the best solution.
Sorry if some of my terminology is wrong, I am new to rust.
You can disambiguate these where you use them. A leading crate path element indicates that the module belongs to the current crate. A leading empty path element indicates that the module belongs to the namespace root, much like a leading / character makes a filesystem path absolute.
use ::csv::Foo; // Uses Foo from the external csv crate
use crate::csv::Foo; // Uses Foo from the csv module of the current crate
It seems that I did not add the dependency to the Cargo.toml file.
On farther inspection, I see that the error message explains. However, I was confused by the help. It assumes that there is a syntax error in the use command.
In future I need to realise that the help part is a suggestion, not a description of the problem.

run specific .rs file

quick introduction, I came from python I have studied it by myself, and now I'm trying to learn Rust. I find it a bit confusing.
I have a main.rs file and other .rs files in the src directory just to have cleaner and organized code, as each of these other files do specific tasks and the main.rs just put all together with a simple CLI.
I just wanna test a single of these .rs file, or even a single fn inside to check if the result is what I am expecting.
How can I do that? It's simple, it's stupid, but I have read around and found nothing that could help me in the end.
I read this, where it talks about making a tests folder and then using cargo test, I've done it, but it still runs the src/main.rs instead of what I have put in tests. BTW I'm using CLion with the Rust plugin.
Sorry if this is somewhat a duplicate, I looked around but I didn't found an answer.
This funcitonality is not really part of Rust itself, but there are some crates that do it. The one I'm most familiar with is rust-script. It works with a hashbang like #!/usr/bin/env rust-script at the top of your script, then run it with ./script.rs. You can even specify dependencies in the script which get parsed out of some special comments.
Edit: Sorry yes - it looks like you're trying to write/run tests. The page you linked in the book should cover what you're trying to do. I'm not sure what you mean by "it still runs the src/main.rs instead of what I have put in tests". Do you have mod tests in main.rs as well?
you can compile any .rs file using rustc your_file.rs command as long as the file contains main() function. rustc will fail if there isn't main function:
error[E0601]: `main` function not found in crate `abc`
--> abc.rs:5:2
|
5 | }
| ^ consider adding a `main` function to `abc.rs`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0601`.
but you can skip this by marking the file as library crate instead of bin:
rustc you_file.rs --crate-type=lib

How can I have a shared Clippy configuration for all the crates in a workspace?

I have an application split into several crates. I want to deny or allow a specific lint in all crates. For example:
#![deny(clippy::print_stdout)]
It seems I have to add this to lib.rs in each of the crates.
There is an ticket with Cargo to allow configuring this somehow, but it has been open for several years with no clear conclusion.
Is there a workaround to avoid having these allow/deny/warn lines duplicated per crate?
One idea I had was to include! the lines by creating a clippy_config.rs at the workspace root, then in each crate's lib.rs adding
include!("../../clippy_config.rs");
However this fails with
error: an inner attribute is not permitted in this context
--> app/src/../../clippy_config.rs:1:1
|
1 | #![deny(clippy::print_stdout)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
My other thought to use a macro also does not work for much the same reason.
Is there a simple way to do this, except writing an external script to modify the Rust files to automate the duplication? (as mentioned in this comment describing Embark Studio's setup).
Clippy offers 3 configuration modes:
Attributes: #[deny(clippy::print_stdout)]
Flags: -Dclippy::print-stdout
Configuration file: clippy.toml, though restricted to a subset of configurable lints.
For project-wide configuration, across crates, the configuration file is the best option if it works.
Otherwise, the second best (hacky) option is to use flags indirectly. That is, rather than specifying RUSTFLAGS=-Dclippy::print-stdout in front of your compiler invocation, you can let Cargo do it, and configure Cargo project-wide.
At the root of your project, create a .cargo/config.toml file with the following content:
[build]
rustflags = ["-Dclippy::print-stdout"]
Cargo will then pass this flag to clippy when it invokes it.
Note: in a workspace setting, .cargo/config.toml in individual crate folders is ignored when invoking Cargo from the root of the workspace, so best place this in the .cargo at the root.

Why does this work with #[cfg(tests)] but not without?

Recently, I've been playing with Rust and gRPC using the Tonic libraries. I started looking at how to create a custom Codec and I'm scratching my head over this...
Starting with this chunk of code, I copied the MockEncoder & MockDecoder and added all the same imports used here in the test module:
https://github.com/hyperium/tonic/blob/master/tonic/src/codec/prost.rs#L133-L158
Then I got stuck on this error:
no method named `bytes` found for mutable reference `&mut tonic::codec::DecodeBuf<'_>` in the current scope
method not found in `&mut tonic::codec::DecodeBuf<'_>`rustc(E0599)
codec.rs(55, 37): method not found in `&mut tonic::codec::DecodeBuf<'_>`
The error is complaining about let out = Vec::from(buf.bytes()); because DecodeBuf doesn't implement a bytes method.
Now, for some reason, if I wrap this code I copied in a module with #[cfg(tests)] (similar to how this originally appeared in Tonic) this error goes away. I can compile and run tests without any errors.
Curious, what is #[cfg(tests)] doing that makes buf.bytes() compile and is there something I can import in order to move MockDecoder outside of this test config?
The option is #[cfg(test)] (singular), not #[cfg(tests)] (plural). This is probably not failing because it's not being compiled or run at all, since the option is never set.

Multiple Rust source files for cargo

If I have multiple .rs files in the src directory of a Cargo package, what are the rules for visibility, importing, etc.?
Currently, any extra (i.e. not the file that is explicitly identified as the source for the executable in Cargo.toml) files are ignored.
What do I need to do to fix this?
There is nothing special about Cargo at all in this way. It’s all the perfectly normal Rust module system. If Cargo will be compiling src/lib.rs, that’s more or less equivalent to having executed rustc --crate-type lib src/lib.rs (there are more command line arguments in practice, but that’s the basics of it).
Other files are then used with mod, use and so forth. Files are not automatically imported or anything like that. This part is not documented very clearly yet; a couple of things that show briefly how to achieve things are http://rustbyexample.com/mod/split.html and http://doc.rust-lang.org/reference.html#modules, but any non-trivial code base will use them and so you can pick just about any code base to look at for examples.
It's hard to say what you're getting tripped up on from the info you shared. Here are three seemingly trivial things that I still had to refer to the documentaton to figure out:
First of all,
mod foo;
looks like a declaration, but it without arguments it is actually something like an include. So you use the same keyword both for declaring and including modules, i.e. there is no using:: keyword.
Second, modules themselves can be public or private. If you didn't add a pub keyword both on the function in question AND on the containing module, that may be tripping you up.
pub mod foo {pub fn bar();}
Third, there seems to be an implicit module added at the top of every file. This is confusing; the reference manual talks about a strict separation between file paths and names, and the module paths in your code, but that abstraction seems to be leaky here.
Note, Rust is still pre-1.0 (0.12) at the time of writing, at the module system and file paths are relatively high level, so don't be surprised if what I said may already wrong by the time you read this.
Files are implicitly included from your rust code.
For instance, if a file src/foo.rs pointed by path in a [lib] or [[bin]] section of your Cargo.toml contains:
mod bar;
It tells cargo to build src/bar.rs too, and include it.

Resources