mod.rs and nested modules in Rust - rust

I want to specify a generic trait Engine and provide two different implementations: Random and Dummy. I want to use following file structure:
src-
|-engine
|-mod.rs //contains Engine trait code
|-random.rs // contains first engine implementation
|-dummy.rs // contains second engine implementation
I have something like this in lib.rs:
pub mod engine {
// random moves engine
pub mod random;
pub mod dummy;
}
When I try to add use engine::Engine anywhere in my other modules, it can't be found:
error[E0432]: unresolved import `engine::Engine`

When you write curly braces in a mod item, that tells the compiler that the module's contents are within these braces, not in an external file. Thus, the compiler doesn't even look at engine/mod.rs. When you write a semicolon instead, the compiler will look for an external file.
What you need to do instead is put these lines in engine/mod.rs:
pub mod random;
pub mod dummy;
And in lib.rs, write:
pub mod engine;

Related

How *exactly* does rust look up modules?

What is the exact set of rules that rust uses to look up a module from a file?
Every explanation I have found online about modules says, "this is the purpose of modules, here is an example of one, ..." None give the complete, comprehensive, 100% accurate explanation for how rust looks up modules. Even the rust reference doesn't tell you whether both the crate root and the importing file need to declare mod! There is no simple ruleset I can use to tell whether it will work.
I'm looking for something I can follow, like:
Rust looks at the name, parsing :: like subdir::subdir::name
Rust looks to see if there is a file name.rs in the same directory and name/mod.rs
There is not allowed to be both a name.rs and a name/mod.rs.
Then, Rust...???
This is best explained starting from inline modules. Modules are arranged into a hierarchy from the crate root. Every crate, after some desugaring, looks something like this:
// root
pub mod a {
pub mod b {
pub const X: u8 = 1;
}
}
mod foo {
}
Referring to an item in the tree is pretty simple:
:: goes "down" a level
super:: goes "up" a level
crate:: goes to the root level
Examples for referring to X:
a::b::X from the crate root
crate::a::b::X from anywhere in the crate
super::a::b::X from within module foo
b::X from within module a
mod a; is really just syntax sugar for either of the following:
#[path = "foo.rs"]
mod foo;
// or
#[path = "foo/mod.rs"]
mod foo;
Which further desugar to:
mod foo {
include!("foo.rs");
}
// or
mod foo {
include!("foo/mod.rs");
}
If foo.rs (or foo/mod.rs) contains a mod bar; then the whole tree would look like:
mod foo {
mod bar {
// contents of `bar.rs` (or `foo/bar/mod.rs`)
}
// remaining contents of `foo.rs`
}
Please note that the usage of mod.rs, while still supported, is discouraged. Instead, it's recommended to use foo.rs for crate::foo and place any submodules of foo in the foo/ directory.
crate:: just always corresponds to the root being compiled at the time. If your crate is sufficiently complex or doesn't follow convention, then certain crate::... item paths can refer to different things in different files. But confusion is easily avoidable by following conventions.

In rust, how come with modules like rand, you dont include the child module?

In rust you can use a module by typing use rand::Rng
when you want to use it you type let x = rand::thread_rng().gen_range(0,100);
if thread_rng() is local to the Rng module then how come we dont type Rng::thread_rng().gen_range(0,100);
if I try something similar..
mod first{
pub mod second{
pub fn hello(){println!("hello");}
}
}
use first::second;
fn main(){
first::hello();
}
then I get an error saying it cant find hello in module first
if thread_rng() is local to the Rng module...
Rng is not a module, it is a trait.
thread_rng is a function of the rand module.
See the rand docs.

Why do I need both mod and use to bring a module to the scope?

Why do I need to write mod and use when I want to bring a module to the scope?
mod from_other_file;
use from_other_file::sub_module;
fn main() {
sub_module::do_something();
}
If I do this it gives me error because the module isn't imported inside the current file:
use from_other_file::sub_module;
fn main() {
sub_module::do_something();
}
Error Message:
error[E0432]: unresolved import `from_other_file`
--> src/main.rs:1:5
|
1 | use from_other_file::sub_module;
| ^^^^^^^^^^^^^^^ use of undeclared type or module `from_other_file`
use and mod are doing two very different things.
mod declares a module. It has two forms:
mod foo {
// Everything inside here is inside the module foo
}
// Look for a file 'bar.rs' in the current directory or
// if that does not exist, a file bar/mod.rs. The module
// bar contains the items defined in that file.
mod bar;
use, on the other hand, brings items into the current scope. It does not play a part in defining which files should be considered part of which module namespaces, rather it just brings items that the compiler already knows about (such as locally declared modules and/or external dependencies from the Cargo.toml file) into the scope of the current file.
Modules in Rust should be declared explicitly with mod declaration.
Without mod from_other_file; which introduces the name from_other_file into the current scope Rust knows nothing about it. The name refers to module item.

How does Rust handle functions with "..." at the end of args?

I have this code:
pub type f_t =
::std::option::Option<extern "C" fn(a: ::std::os::raw::c_int, ...)>;
#[repr(C)]
#[derive(Copy, Clone)]
#[derive(Debug)]
pub struct Foo {
pub f: f_t,
}
fn main() {
}
It does not compile because there is no default Clone implementation for functions with "..." at the end of args.
How does Rust handle this "..." at the end of line, does it do the same thing as "..." in C?
Rust can not compile this code, but if I comment , ..., it compiles fine. What is the difference, why does one class of function pointers implement Clone while the other does not?
How should I implement Clone for such functions?
It means approximately the same as it does in C. Rust does not have native variadic functions (you cannot implement one in Rust itself), but it supports the syntax as a special case for binding to C functions.
Rust does not know what the real signature of the C function is. So you can declare it as whatever you want, but if you get it wrong then calling the function will likely crash at runtime.
It's an unintentional omission, these function pointers are supposed to magically be Clone. On nightly and beta this is already fixed.

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