In Rust, what is the purpose of a mod.rs file? - module

In some Rust projects I've seen (i.e pczarn/rustboot), I've seen mod.rs files in directories for whatever reason. I've not been able to find documentation about this, and I've seen it in many other Rust projects.
What is the purpose of a mod.rs file, and when should I use it?

Imagine the following directory structure:
code/
`- main.rs
- something/
`- mod.rs
If in main.rs you do mod something;, then it'll look in the something/mod.rs file to use as the contents of the module declaration for something.
The alternative to this is to have a something.rs file in the code/ directory.
So to recap, when you write an empty module declaration such as mod something;, it looks either in:
a file called something.rs in the same directory
a file called mod.rs in a folder called something in the same directory
It then uses the contents of either of those files to use as the contents of the module declaration.

Modules are important to understand, but I find most documentations often leave you scratching your head on that matter.
Coming from Python or Javascript?
Roughly, mod.rs is kind of like __init__.py in python or index.js in javascript.
But only kind of. This is a bit more complicated in Rust.
Rust is different
Folders are not immediately ready to use as modules in Rust.
You have to add a file named mod.rs in a folder to expose a new module named like that folder.
The code in mod.rs is the content of that module.
All other files in the folder may in turn be exposed as submodules (more on that below).
Wait, there is another way
You may also use a file at the same level as a folder and named after that folder (<folder_name>.rs).
This is the preferred way since rustc 1.30. (Credits to MarkusToman in the comments)
From the Rust reference:
Note: Previous to rustc 1.30, using mod.rs files was the way to load
a module with nested children. It is encouraged to use the new
naming convention as it is more consistent, and avoids having many
files named mod.rs within a project.
Complete example
src
utils
bar.rs
foo.rs
main.rs
At this point, the compiler doesn't know about src/utils/foo.rs and src/utils/bar.rs.
First, you must expose src/utils/. As seen above, you have 2 options:
add the file: src/utils/mod.rs
add the file src/utils.rs (named exactly like the folder, without the extension)
Now, relative to the src folder (aka the crate level), a module named utils is available.
Second, you must expose the files src/utils/foo.rs and src/utils/bar.rs.
To do that, the utils module must declare 2 new submodules named after these files.
So the content of src/utils/mod.rs (or src/utils.rs) should be:
pub mod bar;
pub mod foo;
Now whatever is public in those 2 files is available in other modules! 🎉
And you may write the following in src/main.rs:
mod utils;
use utils::{foo, bar};
Resulting file structure
Option 1 • mod.rs (the old way):
src
utils
bar.rs
foo.rs
mod.rs
main.rs
Option 2 • <folder_name>.rs (the preferred way):
src
utils
bar.rs
foo.rs
utils.rs
main.rs
More advanced details on how modules work
This remains a surface explanation, your next destination is the official documentation 🧑‍🎓
There is a third way to declare modules (core language):
mod utils {
// module code goes here. That's right, inside of the file.
}
But it is also possible to just write mod utils;.
In that case, as seen above, Rust knows to search for either of src/utils.rs or src/utils/mod.rs.
See, when you try to use a module in a file (in src/main.rs for example),
you may reference it in the following ways:
from inside: src/main.rs
mod module { ... }
from nested modules inside: src/main.rs
mod module { pub mod sub_module { ... } }
from sybling files: src/*.rs
from mod.rs files in sybling folders: src/*/mod.rs
(and infinite reccursive combinations of the above)
A file or a folder containing mod.rs does not become a module.
Rather, the Rust language lets you organize modules (a language feature) with a file hierarchy.
What makes it really interesting is that you are free to mix all approaches together.
For example, you may think you can't directly reference src/utils/foo.rs from main.rs.
But you can:
// src/main.rs
mod utils {
pub mod foo;
}
Important notes:
modules declared in files will always take precedence (because you in fact never need to search the file hierarchy)
you can't use the other 2 approaches to reference the same module
For example, having both src/utils.rs and src/utils/mod.rs will raise the following error at compile time:
error[E0761]: file for module `utils` found at both "src/utils.rs" and "src/utils/mod.rs"
--> src/main.rs:1:1
|
1 | mod utils;
| ^^^^^^^^^^
|
= help: delete or rename one of them to remove the ambiguity
Let's wrap up. Modules are exposed to the compiler:
from top to bottom
by reference only
(That's why you don't have intellisense until your modules are "imported")
starting from an entry point
(which is src/main.rs or src/lib.rs by default.
But it may be anything that you configure in Cargo.toml.
This has little to do with this question however)
With our previous example we get in order:
src/main.rs -> crate
Because the crate module contains mod utils; we next get:
src/utils.rs OR src/utils/mod.rs -> crate::utils
Because the utils module contains mod foo; we next get:
src/utils/foo.rs -> crate::utils::foo

Each rs file, except lib.rs and main.rs, which always match the crate module, gets its own module.
There is only one way to declare a module:
/* pub */ mod sub_module1;
A module cannot be declare outside the root/crate module tree (i.e., going up the module tree, a submodule must always have a parent that is declared directly in lib.rs or main.rs, so the first program submodule must always be declared there — a tree data structure if it isn't already obvious enough).
There are 2 ways to nest a module inside the module where it is declared:
in <module_where_it_is_declared>/<module_name.rs>
in <module_where_it_is_declared>/module_name/mod.rs
If module_where_it_is_declared is the crate module, then this corresponding subfolder is not needed (disappears from the scheme above).
Here is an example, valid for both lib and binary crates:
src
|---lib.rs ( contains: pub mod b2; )
|---b2.rs ( contains: pub mod bb2; )
|---b2
| |---bb2.rs
. .
Alternatively:
src
|---lib.rs ( contains: pub mod b2; )
|---b2
| |---mod.rs ( contains: pub mod bb2; )
| |---bb2.rs
. .
You can see that you can mix and match (b2 uses mod.rs way, bb2 uses the "file"-way).
Here's a way to only use the file pattern that is also valid:
src
|---lib.rs ( contains: pub mod b2; )
|---b2.rs ( contains: pub mod bb2; )
|---b2
| |---bb2.rs (contains: pub mod bbb2; )
| |---bbb2.rs (contains: pub mod bbbb2; )
| |---bbb2
| | |---bbbb2.rs
. . .
I guess it depends on you how you want to nest modules.
I like the mod.rs syntax for modules that just export other submodules and don't have any other (or very little) code in them, although you can put whatever you want in mod.rs.
I use mod.rs similar to the barrel pattern from JS/TS world, to rollup several submodules into a single parent module.
Also don't forget modules can be defined (not only declared) inline by adding a scope block:
pub mod my_submodule {
// ...
}

Related

Rust Reference Mods

I have a set of files in a workspace which I want to reference from another directory, but I cannot find the syntax I need to use.
The example is:
Primary
|_______ First
| |_____ src
| |______ Cool_thing.rs
|_______ Second
|_____ src
|______ main.rs
I want to reference a struct in Cool_things from main.rs
In Primary's Cargo.toml I put:
[workspace]
members= ["First","Second", "Third"]
[dependencies.Second]
First= { path = "First" }
In the Cargo.toml in the Second directory I have
[dependencies]
First = { path = "../First" }
I have been trying things in my main.rs like:
extern crate First;
use First::Cool_things::Cool_things;
No variation of use or mod seems to allow me to reference the struct or impl or functions in mod Cool_things.
The problem was it needed a "lib.rs" in the First src directory. Basically, the documentation for rust seems to be a bit remiss in telling people if you want to use local-dependancies then you have to have a lib.rs file which lists all the mods you are planning to access. So the creation of a lib.rs in the First src directory, and listing "Mod Cool_things" would allow the other package to reference the mod files in that directory.
The cargo.toml files: Inserted in the question above had the correct paths and dependancies, the issue was all around the lack of a lib.rs file.
So if you are planning a multiple binary program, you'll need to remember to have a lib.rs file whenever you're breaking up your code and then accessing modules from other parts of the workspace.

Why can't I import module from different file in same directory? [duplicate]

This question already has answers here:
How can I include a module from another file from the same project?
(6 answers)
Closed 3 years ago.
My directory structure:
src
main.rs
image.rs
decoders.rs
When I try to import my decoders module in image.rs I get this:
error[E0583]: File not found for module `decoders`
decoders.rs:
pub mod Decoders {}
image.rs:
mod decoders
use decoders::Decoders
pub mod Image {}
Note: I am using a module that wraps the entire file on purpose that's I can put attributes on entire files. This is why it's not a duplicate of How to include module from another file from the same project?
The weird thing is, is that this syntax works perfectly fine when I try to import Image in main.rs:
mod image;
use image::Image;
What's happening is that when you try to import decoders::Decoders in image.rs, you need to go through the next level up, because using this:
mod decoders
use decoders::Decoders
Means that decoders will now be "owned" or under image, which means that the compiler will search in the image subdirectory for decoders.rs. So, to fix this, you can either change your file structure to this:
src/
main.rs
image.rs ** or image/mod.rs
image/
decoder.rs
Or, use this in main.rs:
mod decoders;
mod image;
and this in image.rs:
use super::decoders::Decoders;
//Or alternatively
use crate::decoders::Decoders;
Also, to fix your nested-mod problem, do the following in decoders.rs:
//Your code, no `mod Decoders`
and the following where you have your mod decoders statement:
#[your_attribs]
mod decoders;
The rust compiler resolves modules differently depending on where they're defined.
When you use the mod keyword to declare an external module from the crate entry point (typically main.rs or lib.rs) or from a module root (mod.rs), the compiler will search for files adjacent to the declaring file. This is why it works properly when using mod image.rs in your main.rs file.
In other cases, the compiler will search for files in the folder with the same name as the declaring file. In your case, this means that your mod decoders; line in image.rs results in the compiler searching for the module in the image subfolder - specifically checking image/decoders.rs and image/decoders/mod.rs.
To fix this, you can either move decoders.rs to image/decoders.rs if you want to keep decoders as a submodule of image, or alternatively place mod decoders; in main.rs and leave the file where it is.

dynamic-require a module with respect to the current module path in Racket (Or how to find the current module path in Racket)

If I want to optionally require a module at runtime, I can use [dynamic-require'1. This works great if I want to require a package that has been installed, for example:
(dynamic-require 'racket/match 'match)
This will (provided I have racket/match installed), require racket/match and evaluate to the match binding in that library.
However, I run into trouble when I want to require a local, non installed module. Let's say I have some module called eat.rkt, which provides one function: bite:
#lang racket ;; eat.rkt
(provide bite)
(define (bite) "Nom nom")
Now lets say we want to make a lunch.rkt module that requires eat.rkt, and calls the function. Furthermore, lets suppose I put them in the same directory:
#lang racket ;; lunch.rkt
(require "eat.rkt")
(bite) ; => Nom Nom
This is fine because I used static require, but this falls apart when I want to do a dynamic-require:
#lang racket ;; lunch2.rkt
(define bite (dynamic-require "eat.rkt" 'bite)
(bite) ; => Nom Nom
While this appears to be fine, it turns out that the module required by dynamic-require is NOT required based on the module's path, but on current-directory. So, if I run the program in the directory the module is defined, that's fine, but if I'm in another directory, everything breaks:
$ racket lunch2.rkt
"Nom Nom"
$ cd snacks/
$ racket ../lunch2.rkt
; default-load-handler: cannot open module file
Obviously I could just change the current-directory to this module's directory if I know where it is. But if I don't know this module's path, is there any way to get it? Or, more directly, is it possible to dynamic-require a module relative to the requiring's module path?
The define-runtime-path form defines a path that will be available at runtime and is independent of the current-directory. Use it to define the path to the module you want to require dynamically, for example:
#lang racket
(require racket/runtime-path)
(define-runtime-path eat "eat.rkt")
(dynamic-require eat 'bite)
The easiest way to dynamic-require a module relative to the current module path (which is to say the path where the module is saved), is to get that module path and append it your relative module.
You can do this with #%variable-reference and variable-reference->module-path-index. (You may also want to use variable-reference->resolved-module-path for other situations, but we will not do it here.) Composing these two functions gives us a module-path-index? to the module being defined. (Or in general, the module that the #%variable-reference came from.)
So, we can a variable like:
(define here (variable-reference->module-path-index (#%variable-reference)))
Now all that is left is to compose this here path with the relative path to the module we want to require. We are looking for the module path analogy of build-path, if you will.
It turns out that the function we are looking for is: module-path-index-join, which takes a base path and a relative path and appends them together. The result will look something like:
(module-path-index-join "eat.rkt" here)
(Yes, it is backwards of what you would expect from build-path, but the base path comes second for this function.)
The resulting module, lunch3.rkt looks like:
#lang racket
(define here (variable-reference->module-path-index (#%variable-reference)))
(define bite (dynamic-require (module-path-index-join "eat.rkt" here) 'bite))
And now lunch3.rkt will require eat.rkt relative to where its defined, not based on the current-directory:
$ racket lunch3.rkt
"Nom Nom"
$ cd snacks/
$ racket ../lunch3.rkt
"Nom Nom"
Thank you to Matthew Flatt for helping with this answer.

How to organize Lua module path and write "require" calls without losing flexibility?

Say I have a project, whose folder structure looks like below:
| main.lua
|
|---<model> // this is a folder
| |a.lua
| |b.lua
|
|---<view>
|a.lua
|b.lua
model/a.lua requries model/b.lua: require "b"
view/a.lua requries view/b.lua: require "b"
main.lua requries files in model and view.
Now I have problem to get these modules loaded correctly. I know I can fix it by changing the require calls to:
model/a.lua: require "model.b"
view/a.lua: require "view.b"
But if I do that, I have to modify these files every time when I change the folder structure.
So my questions are:
How to fix the module path issue without hard code paths in module files?
Why Lua doesn't use the module search rule of Node.js, which looks easier?
When you require a module, the string parameter from require gets passed into the module which you can access using the variable-argument syntax .... You can use this to include other dependent modules which reside in the same path as the current module being requireed without making it dependent on a fixed hard-coded module name.
For your example, instead of doing:
-- model/a.lua
require "model.b"
and
-- view/a.lua
require "view.b"
You can do:
-- model/a.lua
local thispath = select('1', ...):match(".+%.") or ""
require(thispath.."b")
and
-- view/a.lua
local thispath = select('1', ...):match(".+%.") or ""
require(thispath.."b")
Now if you change directory structure, eg. move view to something like control/subcontrol/foobar, then control/subcontrol/foobar/a.lua (formerly view/a.lua) will now try to require control/subcontrol/foobar/b.lua instead and "do the right thing".
Of course main.lua will still need to fully qualify the paths since you need some way to disambiguate between model/a.lua and view/a.lua.
How to fix the module path issue without hard code paths in module files?
I don't have any better cross-platform solution, maybe you should plan the folder structure early on.
Why Lua doesn't use the module search rule of Node.js, which looks easier?
Because Lua tries its best to rely only on ANSI C, which is really successful. And in ANSI C, there's no such concept of directories.
There are a couple approaches you can use.
You can add relative paths to package.path as in this SO answer. In your case you'd want to add paths in main.lua that correspond to the various ways you might access the files. This keeps all the changes required when changing your directory structure local to one file.
You can add absolute paths to package.pathusing debug.getinfo -- this may be a little easier since you don't need to account for all the relative accesses, but you still need to do this in main.lua when changing your directory structure, and you need to do string manipulation on the value returned by debug.getinfo to strip the module name and add the subdirectory names.
> lunit = require "lunit"
> info = debug.getinfo(lunit.run, "S")
> =info.source
#/usr/local/share/lua/5.2/lunit.lua
> =info.short_src
/usr/local/share/lua/5.2/lunit.lua
The solution is to add the folder of main.lua (project root) to package.path in main.lua.
A naive way to support folders of 1 level deep:
-- main.lua
package.path = package.path .. ";../?.lua"
Note for requires in (project root) will look up files outside of project root, which is not desirable.
A better way of to use some library (e.g.: paths, penlight) to resolve the absolute path and add it instead:
-- main.lua
local projectRoot = lib.abspath(".")
package.path = package.path .. ";" .. projectRoot .. "/?.lua"
Then in you source use the folder name to scope the files:
-- model/a.lua
require "model.b"
-- you can even do this
require "view.b"
and
-- view/a.lua
require "view.b"

Best way to concatenate JavaScript files with dependencies and to output them as a module?

I know this question came up in similar variations often, but no solution seems to fully fit my needs. I have the following problem:
In development I use multiple JS files (a single file every "object"). These JS files have several dependencies within each other - some rely on others and I need to load them first. Currently I use RequireJS to load each JS file in the right order, so I define a module for each file. Fine and dandy.
But now I want to concatenate all my JS files into one big JS file which should be a module itself. I use the RequireJS optimizer r.js to do that. My problem: Every JS file is concatenated to a big JS file, but the module definition for each object is included to. I don't have one big module in one big file, but many modules in one big file.
After that I tried grunt for concatenating which works fine, but ignores dependencies of files. It just concatenates every file in alphabetical order or I have to hardcode the order in my gruntfile.
How can I solve this?
Just as an illustration to my problem:
I have following files (pseudo code):
FileA
- define FileA module
- depends on FileB
- FileA Logic
FileB
- define FileB module
- FileB Logic
And I want this output:
LibFile
- define LibFile module
- FileB Logic, FileA Logic
But I get this with r.js (module definition from FileA and FileB is copied):
LibFile
- define FileB module
- FileB Logic
- define FileA module
- depends on FileB
- FileA Logic
And I get this with grunt (wrong order):
LibFile
- FileA Logic
- FileB Logic
Maybe that questions is a little bit stupid, but I just can't solve this with the tools everybody seems to use...
I tried the grunt-requirejs plugin, too. But it throws several erros which I couldn't resolve.
Thank you,
Pipo
I am going to move it into an answer. Just so the code is a bit clearer.
I am doing these by memory (since I can't test it right now) so some little things may be not entirely accurate.
It depends of course on how you package your modules, but one way is to register all your smaller modules in a bigger module:
File A.js
define([], function() {
// do something
return A;
});
File B.js
define(['path/to/A'], function(A){
// do something with A and more
return B;
});
Then, you package them together:
File mylib.js
define(['path/to/A', 'path/to/B'], function(A, B){
return {
A : A,
B : B
}
}
you then can point your build profile to mylib.js and it will be combined into
one big file. It won't be one all-encapsulating module, but it will have an entry
module that references everything else. You then can use it like so:
require.config({
paths : {
'path/to/mylib' : 'real/path/to/mylib/on/server'
}
});
require(['path/to/mylib'], function(Lib) {
// do something using Lib.A or Lib.B
}
the one thing to pay attention to is the ID of your big module file. By default
RequireJS build gives ID that matches physical path (from appDir IIRC) and you
have to match that when you load your dependency. Simply put, if your resulting
mylib.js file has a main module that received the name 'path/to/mylib', you will
have to match it and load it by the same ID (using require.config.paths) or play with
maps and such (some of which requires RequireJS 2.0).
The following is the reason I asked you why would you want to do the "big module" thing
Other thing of note is that all your inner smaller modules also receive IDs matching their
physical path and you can use these IDs when you use the big package module (so that you can access them not only through Lib.A) if mylib.js has been loaded:
require(['path/to/A'], function(A) {
// do something using A
}