avoid conflicting use paths, in rust - 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.

Related

Difference between "pub use" and "pub mod"?

Suppose I have this file hierarchy in a Rust package:
src/...
src/m1/mod.rs
src/m1/path/m2.rs
What would be the practical difference between having the line:
pub mod path::m2;
in my file m1/mod.rs, versus having the line:
pub use path::m2;
Trying to refresh my understanding of Rust after a time away, so this isn't my first learning cycle. (Of course, for other readers it may be.) I'm saying this because I'm not asking for a general explanation of the differences between use and mod. My unclarity is specific to the two directives above. It seems like they would both serve to make the module in file src/m1/path/m2.rs available to the module m1 and to anything else that imported it (because of the pub prefix on both directives). Is that right? Would these be perfect aliases, or would there be some differences? Is either idiom preferable to the other?
mod foo; is akin to copying and pasting a module into the current scope. That is, if the current scope can find module foo at its own "top level" — basically, if there's a file foo.rs or a folder foo in the same directory — then mod foo; basically gets transformed into mod foo { /* contents of foo */ }. Note that the syntax for mod requires that the thing after mod be an identifier, not an arbitrary path (so mod path::m2; would be illegal). I can only assume that modules that could be brought into scope aren't automatically brought into scope in order to limit the amount of work the compiler has to do when resolving names.
Meanwhile, once a container of items — whether that be a module, type, trait, etc — has been made available in the current scope, shortcuts to its items can be created with use path::to::item. If containers of items were ordinary variables, this would be akin to something like let item = path.to.item, if that were legal.
I'll edit this answer later to give a fuller explanation. But, with help from the comments and other answer posted here, plus some experimentation, I think I've come to a better understanding of these directives. There may be circumstances where one could use either pub use or pub mod, though they'd be contrived and in any case where both could work one should prefer the former (see third point below). The key differences are:
pub use is followed by a path (a bare identifier m2 would be the same as self::m2). pub mod is only followed by an identifier.
pub mod m2; in main.rs or lib.rs would include the contents of file ./m2.rs (or ./m2/mod.rs). If the line pub mod m2; is instead in a file path/m1.rs (or path/m1/mod.rs) then the included file would instead be path/m1/m2.rs (or path/m1/m2/mod.rs).
(You could include a module from another location using mod m2 { include!("path/m2.rs") } but this isn't idiomatic. I've also seen some attribute tricks that affect the location of the loaded module. But generally things work as described in the previous paragraph.)
The use directive doesn't request/order the compilation of any additional files. A mod directive is needed to do that.
(In fact the additional files aren't compiled separately, but merged into the source file where the mod directive occurs. Only the files that are crate roots (plus whatever is merged into them) get compiled.)
If one file in your crate had a pub mod m2; line, then another file could conceivably have a choice of also using pub mod or pub use. Subject to the constraints imposed by point 1 above.
But if you were in such circumstances, you wouldn't want to use the mod directive, as that would merge the relevant code into your source tree a second time. Perhaps the compiler might eventually undo the duplication, but what would you gain by hoping for that?
There's also this statement from the "Separating Modules into Different Files" chapter in the book:
Note that you only need to load the contents of a file using a mod declaration once somewhere in your module tree. Once the compiler knows the file is part of the project (and knows where in the module tree the code resides because of where you’ve put the mod statement), other files in your project should refer to the code in that file using a path to where it was declared...

Rust - Use module in a parent directory

I have a file structure looking somewhat like the following:
src/
--clients/
----queue_client/
------mod.rs
--data_evaluator/
----data_evaluator.rs
In data_evaluator, I want to use the queue_client module, but when I do mod queue_client in data_evaluator.rs- I get the following error - File not found for module queue_client. It only finds the module if I move it into the data_evaluator folder.
My question is, how do I correctly use modules that are outside of the consumer code's directory? Apologies if there is an easy way to do this, I did try searching for quite a while and couldn't find a way.
You seem to be a bit confused.
In Rust, you build the module tree.
You use mod to register a module as a submodule of your current module.
You use use to use a module within your current module.
This article may clear some things up: http://www.sheshbabu.com/posts/rust-module-system/
Aside from that, to use a module that's higher in the tree than your current module, you use crate to get to the root of your module tree.
So in your case, crate::clients::queue_client.

Rust: Cannot access functions in subdirectories [duplicate]

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.

Is there a problem with naming a crate containing the string ".rs"?

Could there be any future problem in naming a dependency .rs for example,
[dependencies]
gccjit.rs = { git = "https://github.com/swgillespie/gccjit.rs.git" }
In the above code, I use .rs for something which is not a Rust source code file. Is that not ideal or is it okay because it would be easier to default to the same name as the repository?
If an object is named .rs it could maybe be automatically recognized as Rust source code but in this case it is not.
Yes, there is a problem. Do not do this.
How you could have determined this for yourself
Try to use the code that you've proposed, you'll see:
$ cargo build
error: failed to parse manifest at `.../Cargo.toml`
Caused by:
could not parse input as TOML
Caused by:
expected an equals, found a period at line 9
You could have also attempted to create a package with the same name. You would have then seen:
$ cargo new 'gccjit.rs.git'
error: Invalid character `.` in crate name: `gccjit.rs.git`
use --name to override crate name
Who controls crate names
You don't get to control the name of an imported crate that way; the crate determines it and it's already picked one:
[package]
name = "gccjit"
If you want to rename an existing package on import, you have to use the package key to match the real name:
some_name = { package = "gccjit", git = "https://github.com/swgillespie/gccjit.rs.git" }
See How to idiomatically alias a crate in Rust 2018? for more.
To use a period in the name, you can seemingly use a string key (although I think this is a bug):
"gcc.jit" = { package = "gccjit", git = "https://github.com/swgillespie/gccjit.rs.git" }
However, a package name has to be a valid Rust identifier, which periods are not. If you do this, there's no way to use the package.
It's redundant anyway
More opinion based, such a name is completely pointless. You don't need to say "rs" or "rust" in the name because of course it's Rust code. If it wasn't, you couldn't use it as a dependency in the first place.
We don't call our packages "computer-source-code-awesome-tool" for the same reason — that much is implied.
Package names are different from source control
Cargo and Rust don't care what the name of your source control repository is. It's separate from the package name. While it's better to have them be somewhat similar, there's no real reason they have to be whatsoever related.
Package names are different from library names
This is a feature with a very small number of uses, but the name of your package (a.k.a. name of the crate on Crates.io) can be different from the name of your library (what is imported into the code).
Piston is the biggest "offender" of this that I know of:
[package]
name = "piston2d-graphics"
version = "0.30.0"
[lib]
name = "graphics"
Please do not use this as it's simply maddening to attempt to debug.

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