Project Organization

Workspace vs Single Crate

If your project will consist of many different crates you should make use of a cargo workspace.

Workspace Organization

location of workspace members

  • src
  • crates
  • / (root)
.
├── Cargo.lock
├── Cargo.toml
├── clippy.toml
├── crates
│   └── single
│       ├── Cargo.toml
│       └── src
│           ├── lib.rs
│           ├── logging.rs
│           └── main.rs
├── README.md
├── rustfmt.toml
├── rust-toolchain.toml
├── taplo.toml
├── tools
│   └── lint
└── typos.toml

Single Crate Organization

Cargo Generate

cargo-generate is a tool to generate a repo using an existing git repo as a template. Using it isn't strictly necessary, you could just clone the repo and change the package name.

cargo install cargo-generate
cargo generate https://github.com/richardscollin/rust-template-workspace

Recommended Tools

Taplo

Rust projects use a lot of toml configuration files. It's nice to be able to format it.

Typos

Check code for typos.A

Clippy config

[lints.rust] # https://doc.rust-lang.org/rustc/lints/groups.html
unknown_lints                   = "allow" # non_exhaustive_omitted_patterns, unqualified_local_imports

exported_private_dependencies   = "warn"
let_underscore_drop             = "warn"
non_exhaustive_omitted_patterns = "deny"
unqualified_local_imports       = "deny" # https://github.com/rust-lang/rust/pull/125645
unused_imports                  = "allow"

[lints.clippy] # https://rust-lang.github.io/rust-clippy/master/index.html
shadow_reuse                  = "warn"
shadow_same                   = "warn"
shadow_unrelated              = "warn"
unwrap_used                   = "warn"
significant_drop_in_scrutinee = "warn"
# print_stdout                 = "warn"

References

mod.rs convention vs. module.rs and module/ folder

Yet another arbitrary decision that doesn't really matter. The main thing that matters in being consistent within a project. Choose one that you prefer and try to stick to that.

There's not a clear benefit to using one style over the other. If you're working on a project which already makes use of one of these styles, you're best continuing to use that.

  • #[warn(clippy::mod_module_files)]
  • #[warn(clippy::self_named_module_files)]

mod.rs

pros:

  • all files in a modules are at the same hierarchy level
  • supported on older (pre-2018) rust compilers

module.rs and module/

pros:

  • no need to rename if converting code to a module
  • less filename duplication in editor tabs (though many editors handle this well already)

improve file tree editor support

ideally editors would know to not order files in the file tree alphabetically, but to follow module convention such that module.rs files are grouped with their corresponding module/ directory and mod.rs is put at the root.

neo-tree custom ordering

Organization

  • extern crates
  • mod
  • use std
  • use external crates
  • use workspace
  • use crate::

The first lines in your rust code will likely be some use declarations. How should you group your use declarations?

Consistent import style is useful because it can help reduce merge conflicts.

When I started my first job programming rust, our team had a discussion over a good convention to follow for formatting use statements (imports). Most of use being familiar with python, we settled on the convention similar to PEP8 import convention.

The first import group belongs to std. The second group: external crates. The third: our own code.

The problem with this choice is it's not the default rust formatting option. It requires manual effort to maintain compared to just using a single import group. The imports quickly deteriorated into ... whatever, no convention.

After unsuccessfully trying to follow this style, I recommend projects with multiple team members adhere to the One import group style.

When StdExternalCrate is properly* supported by stable rustfmt, then it may make sense to reconsider this decision. Until then: just group your imports into a single sorted group and let rust-analyzer manage them.

It's difficult to enforce a style for other developers to use if rustfmt doesn't support it. Currently the style I use is the StdExternalWorkspaceCrate, but it's a annoying to maintain when other co-workers use rustfmt and rust-analyzer to handle imports and this isn't a real mode.

group_imports https://github.com/rust-lang/rustfmt/issues/5083

Rust-analyzer doesn't follow this. rustfmt will sort groups if they are grouped

programmers will use their ide to auto import if things aren't setup the same way then it

mod before use

Impl ordering

how to structure impl. still unsure, instead I'll discuss trade-offs.

Want important code first

  • struct def
  • trait impls
  • inherent impl

there are alternatives:

  • struct def
  • trait impls
  • inherent impl

Or:

  • all structs
  • traits and impls

This site is still a work in progress subject to large changes. Submit any feedback though github issues.
Also, if you're hiring, I'm available to work.