We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Modules, Visibility, Testing and Docs step 11 of 22
Module file layout: foo.rs, foo/mod.rs, and #[path]
This is the part of the module system most beginners think is the module system — and it is the one thing this site cannot demonstrate directly, because your submission is a single file with no filesystem behind it. So you implement the resolution rules instead, and the article has to be unusually precise.
pub fn module_file(entry: &str, module_path: Vec<String>, style: &str) -> String
pub fn path_attr_file(containing_file: &str, inline_mods: Vec<String>, attr_path: &str) -> String
mod foo; and where the body comes from
mod foo; — with a semicolon, no block — tells the compiler “the body of this
module is in another file”. There are exactly two places it will look, and it is
an error for both to exist:
src/foo.rs <- the modern style
src/foo/mod.rs <- the older style
Which directory it looks in is the interesting part, and the rule composes. A submodule’s file lives under a directory named after its parent module:
src/lib.rs mod util; -> src/util.rs
src/util.rs mod config; -> src/util/config.rs
Yes, src/util.rs and src/util/ coexist. That looks wrong to newcomers and it
is correct: the file holds the module, the directory holds its children. With
mod.rs style it is one directory deeper the whole way:
src/lib.rs mod util; -> src/util/mod.rs
mod util::config; -> src/util/config/mod.rs
module_file implements exactly this: style is "self_named" or "mod_rs",
module_path is the chain of module names from the entry file down, and an
empty chain returns the entry file itself.
#[path], and the most obscure rule in the modules chapter
#[path = "…"] overrides the search. Its base directory depends on what kind
of file the attribute is written in:
-
mod-rs files are the ones that own their directory:
lib.rs,main.rs, and anymod.rs. -
non-mod-rs files are all other module files —
util.rs,platform.rs.
And then:
where the #[path] sits |
resolved relative to |
|---|---|
not inside any inline mod block |
the directory of the containing file |
| inside inline blocks, in a mod-rs file | that directory, then the inline module names as directories |
| inside inline blocks, in a non-mod-rs file | that directory, then a directory named after the file, then the inline module names |
Concretely:
src/a/mod.rs mod inline { #[path = "other.rs"] mod x; } -> src/a/inline/other.rs
src/a/b.rs mod inline { #[path = "other.rs"] mod x; } -> src/a/b/inline/other.rs
src/a/b.rs #[path = "other.rs"] mod x; -> src/a/other.rs
The extra b/ in the second line is the rule almost nobody knows, and it is how
platform-specific trees get built:
#[cfg(unix)] #[path = "unix.rs"] mod sys;
#[cfg(windows)] #[path = "windows.rs"] mod sys;
Two clippy lints that enforce opposite conventions
-
clippy::mod_module_files— “every module should befoo/mod.rs“. -
clippy::self_named_module_files— “every module should befoo.rs“.
Both are restriction. Enabling both is always wrong; enabling neither is
completely fine. This is the cleanest example in the whole lint set of what
restriction means: a menu of team policies, not a quality standard. Pick one
if your team cares, and then the lint stops the drift.
What does not work here
mod foo; with no body cannot work under this harness at all — there is no
second file to find. Every module in a submission must be an inline block. That
is a property of this site, not of Rust, and it is why this item is an oracle
problem.
Stuck?
Rust reference solution
Sign in to attempt this problem and reveal the reference solution.