- [Testing and Benchmarking](#testing-and-benchmarking)
- [Warnings, and Lints](#warnings-and-lints)
<!-- /MarkdownTOC -->
## Code Formatting
This section explains the rules for visually laying out your code. They provide
a robust set of guidelines for creating a consistent visual to the code.
Primary formatting is dealt with using the Rust formatting tool
['rustfmt'](https://rust-lang.github.io/rustfmt/), which enforces rules around
whitespace, line-wrapping, and alignment. The Enso repository contains the main
[`.rustfmt.toml`](../.rustfmt.toml) configuration file, and this is what should
be used for all new Rust projects.
All files must be formatted using `rustfmt` before commit, and this should be
set up as either a precommit hook, or using functionality for automatic
formatting in your editor. To quickly format code, it can be run via `cargo`
using the `cargo fmt` command.
## Naming
Enso has some fairly simple general naming conventions, though the sections
below may provide more rules for use in specific cases.
- Types are written using `UpperCamelCase`.
- Variables and function names are written using `snake_case`.
- If a name contains an initialism or acronym, all parts of that initialism
should be lower-case: `make_http_request`, not `make_HTTP_request`.
- Short variable names such as `a` and `b` should only be used in the following
contexts:
- Where there is no other appropriate name.
- Named lifetimes.
They should _never_ be used to refer to temporary data in a function, as all
temporaries should be given descriptive names.
- Names should be descriptive, even if this makes them longer.
- Any function that performs an unsafe operation that is not documented in its
type (e.g. `fn head<T>(ts: Vec<T>) -> T`, which fails if the list is empty),
must be named using the word 'unsafe' (e.g. `unsafeHead`). For more
information on unsafe function usage, see the section on [safety](#safety).
## Package Structure and Naming
Enso follows the standard rust convention for structuring crates, as provided
by `cargo new`. This is discussed more in depth [here](https://learning-rust.github.io/docs/a4.cargo,crates_and_basic_project_structure.html#Project-Structure).
In order to match up with the project naming convention we use for Scala and
Java projects, any rust code must be in a directory named using `UpperCamelCase`
in the root of the project (e.g. `enso/BaseGL`).
### The Public API
Whereas Rust defaults to making module members _private_ by default, this is not
the philosophy used by the Enso codebases. We tend to want our codebase to be
flexible for consumers, so we tend to avoid making things private. Instead, we
use the concept of an `internal` module to separate public from private.
If you are writing code in a module `foo.bar.baz` and would like to signal that
a particular construct (e.g. a function) is for internal use in that package,
you should create a `foo.bar.baz.internal` package. You can then write the
relevant language construct in that package instead of the source package.
#### Using Access Modifiers
Given Rust's performance guarantees, making things `pub` has no impact on the
performance of the compiled code. As a result, the _only_ circumstance under
which things are allowed to not be `pub` is when doing so would allow consumers
of an API to break internal guarantees provided by that API (e.g. building an
immutable collection on top of a mutable buffer).
## Build Tooling
All Rust projects are built and managed using [cargo](https://doc.rust-lang.org/cargo/).
## Commenting
Comments in code are a tricky area to get right as we have found that comments
often expire quickly, and in absence of a way to validate them, remain incorrect
for long periods of time. In order to best deal with this problem, we make the
keeping of comments up-to-date into an integral part of our programming practice
while also limiting the types and kinds of comments we allow.
Comments across the Enso codebases fall into three main types:
- **Documentation Comments:** API documentation for all appropriate language
constructs.
- **Source Notes:** Detailed explorations of design reasoning that avoid
cluttering the code itself.
- **Tasks:** Things that need doing or fixing in the codebase.
When we write comments, we try to follow one general guideline. A comment should
explain _what_ and _why_, without mentioning _how_. The _how_ should be
self-explanatory from reading the code, and if you find that it is not, that is
a sign that the code in question needs refactoring.
Code should be written in such a way that it guides you over what it does, and
comments should not be used as a crutch for badly-designed code.
### Documentation Comments
One of the primary forms of comment that we allow across the Enso codebases is
the doc comment. We use these comments to document the public API of a module,
as defined in [The Public API](#the-public-api). For constructs that _are_ part
of the public API, the following should be documented:
1.**Top-Level Type Definitions:** All top-level type definitions must have a
doc comment.
2.**Functions:** Function documentation should provide at-a-glance intuition
for how to use that function.
Documentation comments are intended for consumption by the users of the API, and
are written using the standard [rustdoc](https://doc.rust-lang.org/rustdoc/index.html)
syntax. Doc comments should contain:
1.**Summary:** A one-line summary of the construct's behaviour or purpose.
2.**Description (Optional):** Any useful information that would be necessary
for a consumer of the API to know (that is not encoded in the types). This
should be written in grammatically correct English.
Convention in rust is to not document function or return parameters, and so
rustdoc does not provide a way to do so.
An example of a valid set of comments for some rust code is as follows:
```rust
/// A representation of tree structures containing elements of type `T`.
pub trait Tree<T> {
/// Provides a sequence representation of the tree.
///
/// The function provides configurable behaviour for the order in which the
/// tree is walked. See [WalkStrategy](org.enso.WalkStrategy.html) for