Walter
Walter

Reputation: 724

Organising modules by folder/namespace instead of file name

I've organised a Rust library project in the following manner:

├── src
│   ├── models
│   │   ├── document.rs
│   │   ├── user.rs
│   │   └── mod.rs
│   ├── traits
│   │   ├── documents.rs
│   │   ├── users.rs
│   │   └── mod.rs
└── └── lib.rs

In each of the files I declare either a single struct or a single trait.

For the mod.rs file in the models folder I'm exporting the different structs in the following manner:

pub mod document;
pub mod user;

I'm doing something similar for the traits and I'm exporting the library module like so:

pub mod models;
pub mod traits;

While this works, what's ending up happening when I try to actually use the objects, importing them is odd:

use core::models::document::document;

You see I have to double up on the file and struct name in order to use the object. Is it possible to rather not use the file name as a module and have the document struct sitting in the document.rs file rather be part of the models module while still retaining the current folder structure?

I have tried reexporting with pub use but all I've managed to accomplish with that is to place everything (all traits and models) under the core namespace. Which is also something I'm not looking to do.

Essentially, I'd like to access the models like so:

use core::models::document

and traits like so:

use core::traits::documents

While still retaining the current folder structure.

Is this possible?

Upvotes: 0

Views: 1357

Answers (2)

Finomnis
Finomnis

Reputation: 22818

I agree with what @Silvio says.

I just wanted to add that if you want to pursue that train, you can do so with the means of reexports.

For example, in the models/mod.rs file, you can do:

mod document;
pub use document::Document;

mod user;
pub use user::User;

Then, you can indeed do

use core::models::Document;

Note that struct names are conventionally written in capital letters, according to the Rust naming guidelines.

Upvotes: 2

Silvio Mayolo
Silvio Mayolo

Reputation: 70387

First off, you've got to remember that Rust is not Java. That is, while it's reasonable to do what you're doing (a file representing one struct or one trait), it's not the universal rule, and there are definitely cases where a file might have two or three related structs/enums, or a bunch of standalone functions. So, again, it's not wrong to think the way you're thinking, but do keep in mind that not every idiomatic Rust module will follow this principle.

With that in mind, the second thing of note is that module names and structure/trait names should never coincide. Types and traits in Rust should be named in StudlyCase, and modules use snake_case, so your document module should contain a Document struct. Thus, the import is not redundant, as it reads

use core::models::document::Document;

And indicates that you are importing the structure called Document from the module document. With this naming convention, we can read that off at a glance.

With all of that in mind, you can do wildcard imports in Rust, though it's discouraged by most style guides and linters.

use core::models::document::*;

So in summary:

  • You can do wildcard imports to get rid of the redundancy, but
  • It's not very idiomatic Rust, and with a good naming convention the import reads better, and
  • You should challenge the frame that every structure should occupy its own module. If you have several (small) models, then you might consider having just one models module which defines (or re-exports) them all.

Upvotes: 4

Related Questions