Can I split crate in multiple files without introducing modules for each file? - module

All examples that I found create a lib.rs and then inside that file create mod foo;, mod bar; for each file foo.rs, bar.rs and so on.
Basically what I want is to to split my crate into multiple files but without having to introduce lots of modules for every file. Is this not possible with Rust?

In order to include another source file, it has to be its own module.
However, this does not mean that you must expose this fact in your API. For example, let's say you want to put some code in a file called hidden.rs:
pub fn inside_hidden() {}
Now in your lib.rs file, you could expose this module:
#![crate_type = "lib"]
pub mod hidden;
But if your library doesn't require sub-modules, it's probably better to keep the hidden module a secret, and instead expose its contents as members of your top-level module:
#![crate_type = "lib"]
pub use hidden::inside_hidden;
mod hidden;
This way, users won't know you have a hidden sub-module. They will see inside_hidden as if it were a member of your top-level module.

Related

Is there a way to require a module and change the name of some its bindings?

I need to test different implementations of the same function from one single unit test file, with different files holding different implementations.
The problem is that with normal requires, everything is imported without a name space, so functions with the same name cannot co-exist.
Is there a way to bind imported modules to a name space? Or to rename the elements of an imported module?
Something like
; All files contain a function named "fun" that needs to be tested.
(require
(rename "implementation-one.rkt" fun fun-one)
(rename "implementation-two.rkt" fun fun-two)
(rename "implementation-three.rkt" fun fun-three))
(check-equal? (fun-one 0) 0 "first implementation")
(check-equal? (fun-two 0) 0 "second implementation")
(check-equal? (fun-three 0) 0 "third implementation")
Here I'm importing the fun function from each implementation file, and renaming it so something else. This is not valid Racket though.
I looked into modules, but it seems that the same problem happens; when requiring a module everything inside is exposed without a name space.
Is there a way to specify the name of an imported module, or change the names of the contents of the module? Perhaps by renaming the module's bindings, or by encapsulating imports in a name space, or some sort of named import? How are name conflicts like this normally resolved in Racket?
Should modules contain structs and/or objects that encapsulate each implementation? Or is there a way to do it with simple modules that provide functions?
(require
(rename-in "implementation-one.rkt" [fun fun-one])
(rename-in "implementation-two.rkt" [fun fun-two])
(rename-in "implementation-three.rkt" [fun fun-three]))
This is not hard to find in the manual.

Separating operator definitions for a class to other files and using them

I have 4 files all in the same directory: main.rakumod, infix_ops.rakumod, prefix_ops.rakumod and script.raku:
main module has a class definition (class A)
*_ops modules have some operator routine definitions to write, e.g., $a1 + $a2 in an overloaded way.
script.raku tries to instantaniate A object(s) and use those user-defined operators.
Why 3 files not 1? Since class definition might be long and separating overloaded operator definitions in files seemed like a good idea for writing tidier code (easier to manage).
e.g.,
# main.rakumod
class A {
has $.x is rw;
}
# prefix_ops.rakumod
use lib ".";
use main;
multi prefix:<++>(A:D $obj) {
++$obj.x;
$obj;
}
and similar routines in infix_ops.rakumod. Now, in script.raku, my aim is to import main module only and see the overloaded operators also available:
# script.raku
use lib ".";
use main;
my $a = A.new(x => -1);
++$a;
but it naturally doesn't see ++ multi for A objects because main.rakumod doesn't know the *_ops.rakumod files as it stands. Is there a way I can achieve this? If I use prefix_ops in main.rakumod, it says 'use lib' may not be pre-compiled perhaps because of circular dependentness
it says 'use lib' may not be pre-compiled
The word "may" is ambiguous. Actually it cannot be precompiled.
The message would be better if it said something to the effect of "Don't put use lib in a module."
This has now been fixed per #codesections++'s comment below.
perhaps because of circular dependentness
No. use lib can only be used by the main program file, the one directly run by Rakudo.
Is there a way I can achieve this?
Here's one way.
We introduce a new file that's used by the other packages to eliminate the circularity. So now we have four files (I've rationalized the naming to stick to A or variants of it for the packages that contribute to the type A):
A-sawn.rakumod that's a role or class or similar:
unit role A-sawn;
Other packages that are to be separated out into their own files use the new "sawn" package and does or is it as appropriate:
use A-sawn;
unit class A-Ops does A-sawn;
multi prefix:<++>(A-sawn:D $obj) is export { ++($obj.x) }
multi postfix:<++>(A-sawn:D $obj) is export { ($obj.x)++ }
The A.rakumod file for the A type does the same thing. It also uses whatever other packages are to be pulled into the same A namespace; this will import symbols from it according to Raku's standard importing rules. And then relevant symbols are explicitly exported:
use A-sawn;
use A-Ops;
sub EXPORT { Map.new: OUTER:: .grep: /'fix:<'/ }
unit class A does A-sawn;
has $.x is rw;
Finally, with this setup in place, the main program can just use A;:
use lib '.';
use A;
my $a = A.new(x => -1);
say $a++; # A.new(x => -1)
say ++$a; # A.new(x => 1)
say ++$a; # A.new(x => 2)
The two main things here are:
Introducing an (empty) A-sawn package
This type eliminates circularity using the technique shown in #codesection's answer to Best Way to Resolve Circular Module Loading.
Raku culture has a fun generic term/meme for techniques that cut through circular problems: "circular saws". So I've used a -sawn suffix of the "sawn" typename as a convention when using this technique.[1]
Importing symbols into a package and then re-exporting them
This is done via sub EXPORT { Map.new: ... }.[2] See the doc for sub EXPORT.
The Map must contain a list of symbols (Pairs). For this case I've grepped through keys from the OUTER:: pseudopackage that refers to the symbol table of the lexical scope immediately outside the sub EXPORT the OUTER:: appears in. This is of course the lexical scope into which some symbols (for operators) have just been imported by the use Ops; statement. I then grep that symbol table for keys containing fix:<; this will catch all symbol keys with that string in their name (so infix:<..., prefix:<... etc.). Alter this code as needed to suit your needs.[3]
Footnotes
[1] As things stands this technique means coming up with a new name that's different from the one used by the consumer of the new type, one that won't conflict with any other packages. This suggests a suffix. I think -sawn is a reasonable choice for an unusual and distinctive and mnemonic suffix. That said, I imagine someone will eventually package this process up into a new language construct that does the work behind the scenes, generating the name and automating away the manual changes one has to make to packages with the shown technique.
[2] A critically important point is that, if a sub EXPORT is to do what you want, it must be placed outside the package definition to which it applies. And that in turn means it must be before a unit package declaration. And that in turn means any use statement relied on by that sub EXPORT must appear within the same or outer lexical scope. (This is explained in the doc but I think it bears summarizing here to try head off much head scratching because there's no error message if it's in the wrong place.)
[3] As with the circularity saw aspect discussed in footnote 1, I imagine someone will also eventually package up this import-and-export mechanism into a new construct, or, perhaps even better, an enhancement of Raku's built in use statement.
Hi #hanselmann here is how I would write this (in 3 files / same dir):
Define my class(es):
# MyClass.rakumod
unit module MyClass;
class A is export {
has $.x is rw;
}
Define my operators:
# Prefix_Ops.rakumod
unit module Prefix_Ops;
use MyClass;
multi prefix:<++>(A:D $obj) is export {
++$obj.x;
$obj;
}
Run my code:
# script.raku
use lib ".";
use MyClass;
use Prefix_Ops;
my $a = A.new(x => -1);
++$a;
say $a.x; #0
Taking my cue from the Module docs there are a couple of things I am doing different:
Avoiding the use of main (or Main, or MAIN) --- I am wary that MAIN is a reserved name and just want to keep clear of engaging any of that (cool) machinery
Bringing in the unit module declaration at the top of each 'rakumod' file ... it may be possible to use bare files in Raku ... but I have never tried this and would say that it is not obvious from the docs that it is even possible, or supported
Now since I wanted this to work first time you will note that I use the same file name and module name ... again it may be possible to do that differently (multiple modules in one file and so on) ... but I have not tried that either
Using the 'is export' trait where I want my script to be able to use these definitions ... as you will know from close study of the docs ;-) is that each module has it's own namespace (the "stash") and we need export to shove the exported definitions into the namespace of the script
As #raiph mentions you only need the script to define the module library location
Since you want your prefix multi to "know" about class A then you also need to use MyClass in the Prefix_Ops module
Anyway, all-in-all, I think that the raku module system exemplifies the unique combination of "easy things easy and hard thinks doable" ... all I had to do with your code (which was very close) was tweak a few filenames and sprinkle in some concise concepts like 'unit module' and 'is export' and it really does not look much different since raku keeps all the import/export machinery under the surface like the swan gliding over the river...

What is the proper way to reference a sibling module such as Diesel's generated schema? [duplicate]

This question already has an answer here:
How do I import from a sibling module?
(1 answer)
Closed 2 years ago.
I'm building a web service that uses Diesel to access a MySQL database. Everything is setup correctly and Diesel is generating the schema.rs file with content that reflects my database schema:
table! {
user (id) {
// ...
}
}
I created a store.rs file that resides next to main.rs. If my understanding of modules is correct, any code I put in the store.rs file, will belong to a module named store that is a child of the crate module. My intention is to put all the code that deals with database stuff in the store module. However, I can't seem to be able to use the stuff from the schema module in my store module to start doing some querying using the Diesel APIs.
I tried:
use schema;
use crate::schema;
use super::schema;
use super::schema::user;
Nothing works. The compiler always says that it cannot resolve one piece of the path or another.
What is the proper way to reference a sibling module in Rust?
In your main.rs, make sure you're setting diesel for #[macro_use] and importing the schema mod.
#[macro_use]
extern crate diesel;
mod schema;
In store.rs, you should be able to use the schema as you see fit.
use crate::schema::user;
I hope this would help.
in store.rs
use crate::schema::*;
// … any other diesel related code you want to put here
in main.rs
pub mod schema;
mod store;

How do I use a new local module?

I'm unable to import and use a module I've written, not sure where I went wrong.
My starting directory structure is:
/src/main.rs <- contains fn main()
/Cargo.toml
I wanted to refactor some code out of one big main file I had, so I ran
cargo new mnemonic
leaving me with:
/src/main.rs <- contains fn main()
/Cargo.toml
/mnemonic/src/lib.rs
/mnemonic/Cargo.toml
in the /mnemonic/src/lib.rs that was created I put:
pub mod mnemonic;
then put my code in /mnemonic/src/mnemonic.rs (has 2 public functions I want to use from main). I ran cargo build from mnemonic/ and back in my main src, I tried
extern crate mnemonic;
and
use mnemonic;
I also tried use mnemonic::mnemonic;
In all instances, it was unable to find the crate or gave an unresolved import error.
I've also tried putting my code containing the 2 pub functions in /src/mnemonic.rs
and in /src/main.rs putting:
use mnemonic;
I also tried just putting my code in mnemonic/src/lib.rs and trying extern crate mnemonic; use mnemonic; from src/main.rs
Am I supposed to edit Cargo.toml in any of the instances you proposed?
Updated Answer
Yes, you need to tell Cargo where to find your crate. In your binaries Cargo.toml, add something like:
[dependencies.mnemonic]
path = "./mnemonic"
Original Answer
When you create a new crate, it automatically has one layer of namespacing: the name of the crate itself. In addition, you don't need to extern use a crate if it is your current crate!
Using crate mnemonic from other crates
This is probably what you want to do: Create a new crate called mnemonic, then you will have a src/lib.rs. Put your code in there, and you can then use it from other crates with
extern crate mnemonic;
use mnemonic::ItemInLibDotRs; // Make sure this item is marked as `pub`!
Using a nested module mnemonic from the crate mnemonic
Say you have some implementation detail you want to hide from the end user. We will put it in a module within the crate, and use it only from within the same crate.
Put your code in src/mnemonic.rs. In src/lib.rs, you will reference that module and items:
use mnemonic::ItemInMnemonic; // Make sure this is `pub`!
mod mnemonic;
Using a nested module mnemonic from the crate mnemonic in other crates
Export the module from your crate, and then reference it from other crates:
// src/lib.rs
pub mod mnemonic; // Note the module is now public
// In the crate that consumes mnemonic
extern crate mnemonic;
use mnemonic::mnemonic::ItemInMnemonic;
This last option is kind of ugly though, you probably don't want to make your users type mnemonic::mnemonic, which is why I suggest just putting it in src/lib.rs.

Split a module across several files

I want to have a module with multiple structs in it, each in its own file. Using a Math module as an example:
Math/
Vector.rs
Matrix.rs
Complex.rs
I want each struct to be in the same module, which I would use from my main file, like so:
use Math::Vector;
fn main() {
// ...
}
However Rust's module system (which is a bit confusing to begin with) does not provide an obvious way to do this. It seems to only allow you to have your entire module in one file. Is this un-rustic? If not, how do I do this?
Rust's module system is actually incredibly flexible and will let you expose whatever kind of structure you want while hiding how your code is structured in files.
I think the key here is to make use of pub use, which will allow you to re-export identifiers from other modules. There is precedent for this in Rust's std::io crate where some types from sub-modules are re-exported for use in std::io.
Edit (2019-08-25): the following part of the answer was written quite some time ago. It explains how to setup such a module structure with rustc alone. Today, one would usually use Cargo for most use cases. While the following is still valid, some parts of it (e.g. #![crate_type = ...]) might seem strange. This is not the recommended solution.
To adapt your example, we could start with this directory structure:
src/
lib.rs
vector.rs
main.rs
Here's your main.rs:
extern crate math;
use math::vector;
fn main() {
println!("{:?}", vector::VectorA::new());
println!("{:?}", vector::VectorB::new());
}
And your src/lib.rs:
#[crate_id = "math"];
#[crate_type = "lib"];
pub mod vector; // exports the module defined in vector.rs
And finally, src/vector.rs:
// exports identifiers from private sub-modules in the current
// module namespace
pub use self::vector_a::VectorA;
pub use self::vector_b::VectorB;
mod vector_b; // private sub-module defined in vector_b.rs
mod vector_a { // private sub-module defined in place
#[derive(Debug)]
pub struct VectorA {
xs: Vec<i64>,
}
impl VectorA {
pub fn new() -> VectorA {
VectorA { xs: vec![] }
}
}
}
And this is where the magic happens. We've defined a sub-module math::vector::vector_a which has some implementation of a special kind of vector. But we don't want clients of your library to care that there is a vector_a sub-module. Instead, we'd like to make it available in the math::vector module. This is done with pub use self::vector_a::VectorA, which re-exports the vector_a::VectorA identifier in the current module.
But you asked how to do this so that you could put your special vector implementations in different files. This is what the mod vector_b; line does. It instructs the Rust compiler to look for a vector_b.rs file for the implementation of that module. And sure enough, here's our src/vector_b.rs file:
#[derive(Debug)]
pub struct VectorB {
xs: Vec<i64>,
}
impl VectorB {
pub fn new() -> VectorB {
VectorB { xs: vec![] }
}
}
From the client's perspective, the fact that VectorA and VectorB are defined in two different modules in two different files is completely opaque.
If you're in the same directory as main.rs, you should be able to run it with:
rustc src/lib.rs
rustc -L . main.rs
./main
In general, the "Crates and Modules" chapter in the Rust book is pretty good. There are lots of examples.
Finally, the Rust compiler also looks in sub-directories for you automatically. For example, the above code will work unchanged with this directory structure:
src/
lib.rs
vector/
mod.rs
vector_b.rs
main.rs
The commands to compile and run remain the same as well.
The Rust module rules are:
A source file is just its own module (except the special files main.rs, lib.rs and mod.rs).
A directory is just a module path component.
The file mod.rs is just the directory's module.
The file matrix.rs1 in the directory math is just the module math::matrix. It's easy. What you see on your filesystem you also find in your source code. This is an one-to-one correspondence of file paths and module paths2.
So you can import a struct Matrix with use math::matrix::Matrix, because the struct is inside the file matrix.rs in a directory math. Not happy? You'd prefer use math::Matrix; very much instead, don't you? It's possible. Re-export the identifier math::matrix::Matrix in math/mod.rs with:
pub use self::math::Matrix;
There's another step to get this working. Rust needs a module declaration to load the module. Add a mod math; in main.rs. If you don't do that, you get an error message from the compiler when importing like this:
error: unresolved import `math::Matrix`. Maybe a missing `extern crate math`?
The hint is misleading here. There's no need for additional crates, except of course you really intend to write a separate library.
Add this at the top of main.rs:
mod math;
pub use math::Matrix;
The module declaration is also neccessary for the submodules vector, matrix and complex, because math needs to load them to re-export them. A re-export of an identifier only works if you have loaded the module of the identifier. This means, to re-export the identifier math::matrix::Matrix you need to write mod matrix;. You can do this in math/mod.rs. Therefore create the file with this content:
mod vector;
pub use self::vector::Vector;
mod matrix;
pub use self::matrix::Matrix;
mod complex;
pub use self::complex::Complex;
Aaaand you are done.
1Source file names usually start with a lowercase letter in Rust. That's why I use matrix.rs and not Matrix.rs.
2Java's different. You declare the path with package, too. It's redundant. The path is already evident from the source file location in the filesystem. Why repeat this information in a declaration at the top of the file? Of course sometimes it's easier to have a quick look at the source code instead of finding out the filesystem location of the file. I can understand people who say it's less confusing.
Rusts purists will probably call me a heretic and hate this solution, but this is much simpler: just do each thing in its own file, then use the "include!" macro in mod.rs:
include!("math/Matrix.rs");
include!("math/Vector.rs");
include!("math/Complex.rs");
That way you get no added nested modules, and avoid complicated export and rewrite rules.
Simple, effective, no fuss.
Alright, fought my compiler for a while and finally got it to work(thanks to BurntSushi for pointing out pub use.
main.rs:
use math::Vec2;
mod math;
fn main() {
let a = Vec2{x: 10.0, y: 10.0};
let b = Vec2{x: 20.0, y: 20.0};
}
math/mod.rs:
pub use self::vector::Vec2;
mod vector;
math/vector.rs
use std::num::sqrt;
pub struct Vec2 {
x: f64,
y: f64
}
impl Vec2 {
pub fn len(&self) -> f64 {
sqrt(self.x * self.x + self.y * self.y)
}
// other methods...
}
Other structs could be added in the same manner. NOTE: compiled with 0.9, not master.
I'd like to add in here how you include Rust files when they are deeply nested. I have the following structure:
|-----main.rs
|-----home/
|---------bathroom/
|-----------------sink.rs
|-----------------toilet.rs
How do you access sink.rs or toilet.rs from main.rs?
As others have mentioned, Rust has no knowledge of files. Instead it sees everything as modules and submodules. To access the files inside the bathroom directory you need to export them or barrel them to the top. You do this by specifying a filename with the directory you'd like to access and pub mod filename_inside_the_dir_without_rs_ext inside the file.
Example.
// sink.rs
pub fn run() {
println!("Wash my hands for 20 secs!");
}
// toilet.rs
pub fn run() {
println!("Ahhh... This is sooo relaxing.")
}
Create a file called bathroom.rs inside the home directory:
Export the filenames:
// bathroom.rs
pub mod sink;
pub mod toilet;
Create a file called home.rs next to main.rs
pub mod the bathroom.rs file
// home.rs
pub mod bathroom;
Within main.rs
// main.rs
// Note: If you mod something, you just specify the
// topmost module, in this case, home.
mod home;
fn main() {
home::bathroom::sink::run();
}
use statements can be also used:
// main.rs
// Note: If you mod something, you just specify the
// topmost module, in this case, home.
use home::bathroom::{sink, toilet};
fn main() {
sink::run();
sink::toilet();
}
Including other sibling modules (files) within submodules
In the case you'd like to use sink.rs from toilet.rs, you can call the module by specifying the self or super keywords.
// inside toilet.rs
use self::sink;
pub fn run() {
sink::run();
println!("Ahhh... This is sooo relaxing.")
}
Final Directory Structure
You'd end up with something like this:
|-----main.rs
|-----home.rs
|-----home/
|---------bathroom.rs
|---------bathroom/
|-----------------sink.rs
|-----------------toilet.rs
The structure above only works with Rust 2018 onwards. The following directory structure is also valid for 2018, but it's how 2015 used to work.
|-----main.rs
|-----home/
|---------mod.rs
|---------bathroom/
|-----------------mod.rs
|-----------------sink.rs
|-----------------toilet.rs
In which home/mod.rs is the same as ./home.rs and home/bathroom/mod.rs is the same as home/bathroom.rs. Rust made this change because the compiler would get confused if you included a file with the same name as the directory. The 2018 version (the one shown first) fixes that structure.
See this repo for more information and this YouTube video for an overall explanation.
One last thing... avoid hyphens! Use snake_case instead.
Important Note
You must barrel all the files to the top, even if deep files aren't required by top-level ones.
This means, that for sink.rs to discover toilet.rs, you'd need to barrel them by using the methods above all the way up to main.rs!
In other words, doing pub mod sink; or use self::sink; inside toilet.rs will not work unless you have exposed them all the way up to main.rs!
Therefore, always remember to barrel your files to the top!
A more rustlings method to export module, which I picked up from Github.
mod foo {
//! inner docstring comment 1
//! inner docstring comment 2
mod a;
mod b;
pub use a::*;
pub use b::*;
}
Adjusting the question's example directory and file names to conform to Rust naming conventions:
main.rs
math.rs
math/
vector.rs
matrix.rs
complex.rs
Make sure to export the public symbols (types, functions, etc.) in each of the files in the math directory by preceding them with the keyword pub.
Define math.rs:
mod vector;
pub use vector::*;
mod matrix;
pub use matrix::*;
mod complex;
pub use complex::*;
The above file keeps the sub-modules of math private but the submodules' public symbols are exported from module math. This effectively flattens the module structure.
Use math::Vector in main.rs:
mod math;
use crate::math::Vector;
fn main() {
// ...
}