2020-07-03 13:08:14 +03:00
|
|
|
---
|
2021-11-02 16:05:43 +03:00
|
|
|
layout: style-guide title: Rust Style Guide category: style-guide tags: [style-guide,contributing]
|
2020-07-03 13:08:14 +03:00
|
|
|
---
|
|
|
|
|
2022-04-15 17:10:55 +03:00
|
|
|
# Rust style guide.
|
2019-12-06 10:01:58 +03:00
|
|
|
|
2022-04-19 09:05:30 +03:00
|
|
|
All of the codebase should be formatted by the `rustfmt`. However, the code
|
|
|
|
style is way more than just formatting. In many cases formatting can be
|
|
|
|
automated. According to rustfmt docs: “formatting code is a mostly mechanical
|
|
|
|
task which takes both time and mental effort. By using an automatic formatting
|
|
|
|
tool, a programmer is relieved of this task and can concentrate on more
|
|
|
|
important things.”. While in many cases it is true, if the code author does not
|
|
|
|
take extra effort to make his code pretty by refactoring long lines to
|
|
|
|
variables, moving code to specific modules, or sections, the formatting tool
|
|
|
|
will result in code that is hard to read and hard to write. Thus, it is
|
|
|
|
important to take time to write code in such way that we can be proud of its
|
|
|
|
quality. The following document provides you with a detailed guide regarding the
|
|
|
|
code quality we are looking for.
|
2019-12-06 10:01:58 +03:00
|
|
|
|
2022-04-15 17:10:55 +03:00
|
|
|
## Code formatting in macros.
|
2022-04-19 09:05:30 +03:00
|
|
|
|
|
|
|
Unfortunately, `rustfmt` is not working inside of macros. Thus, this code should
|
|
|
|
be manually formatted in the same was as `rustfmt` would do it.
|
2019-12-06 10:01:58 +03:00
|
|
|
|
2022-04-15 17:10:55 +03:00
|
|
|
## Submodules and imports.
|
2021-11-02 16:05:43 +03:00
|
|
|
|
2022-04-15 17:10:55 +03:00
|
|
|
- **Design your files to be imported as module.**
|
2022-04-19 09:05:30 +03:00
|
|
|
Design names of your libraries, structs, and functions to be imported as
|
|
|
|
modules. For example, prefer an import `use graph;` and it's usage
|
|
|
|
`graph::Node::new()` over `use graph::new_node`. This design minimizes the
|
|
|
|
amount of imports and allows related modules to import shorter names to the
|
|
|
|
scope.
|
2019-12-06 10:01:58 +03:00
|
|
|
|
2022-04-15 17:10:55 +03:00
|
|
|
- **Don't use relative imports.**
|
2022-04-19 09:05:30 +03:00
|
|
|
Do not use `super::` nor `self::` imports in files (you can use them in localy
|
|
|
|
defined modules). Use absolute imports or imports from local submodules only.
|
2019-12-06 10:01:58 +03:00
|
|
|
|
2022-04-15 17:10:55 +03:00
|
|
|
- **Use Enso Formatter to format your imports**
|
2022-04-19 09:05:30 +03:00
|
|
|
Run the `build/enso-formatter` script (e.g. by running
|
|
|
|
`cargo run -p enso-formatter`) to format imports in all files before
|
|
|
|
contributing your PR.
|
2019-12-06 10:01:58 +03:00
|
|
|
|
2022-04-15 17:10:55 +03:00
|
|
|
## Sections.
|
2019-12-06 10:01:58 +03:00
|
|
|
|
2021-11-05 14:51:43 +03:00
|
|
|
Source files should be divided into sections. Section headers should be placed
|
2022-04-15 17:10:55 +03:00
|
|
|
before each new "concept" defined in a file. By "concept" we normally mean a
|
2021-11-05 14:51:43 +03:00
|
|
|
structure with related implementations. In case related implementations use some
|
|
|
|
helper structs with very small implementations, these helper structs may be
|
|
|
|
defined in the same section. Moreover, the code in each section should be
|
|
|
|
divided into sub-sections, grouping related definitions. At least one section
|
|
|
|
should be defined in a file (if there is at least one struct definition as
|
|
|
|
well). For example:
|
2019-12-06 10:01:58 +03:00
|
|
|
|
|
|
|
```rust
|
|
|
|
// =================
|
|
|
|
// === AxisOrder ===
|
|
|
|
// =================
|
|
|
|
|
|
|
|
/// Defines the order in which particular axis coordinates are processed. Used
|
|
|
|
/// for example to define the rotation order in `DisplayObject`.
|
2021-11-02 16:05:43 +03:00
|
|
|
pub enum AxisOrder { XYZ, XZY, YXZ, YZX, ZXY, ZYX }
|
2019-12-06 10:01:58 +03:00
|
|
|
|
|
|
|
impl Default for AxisOrder {
|
2021-11-02 16:05:43 +03:00
|
|
|
fn default() -> Self { Self::XYZ }
|
2019-12-06 10:01:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// =================
|
|
|
|
// === Transform ===
|
|
|
|
// =================
|
|
|
|
|
|
|
|
/// Defines the order in which transformations (scale, rotate, translate) are
|
|
|
|
/// applied to a particular object.
|
|
|
|
pub enum TransformOrder {
|
|
|
|
ScaleRotateTranslate,
|
|
|
|
ScaleTranslateRotate,
|
|
|
|
RotateScaleTranslate,
|
|
|
|
RotateTranslateScale,
|
|
|
|
TranslateRotateScale,
|
|
|
|
TranslateScaleRotate
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for TransformOrder {
|
|
|
|
fn default() -> Self { Self::ScaleRotateTranslate }
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// =============================
|
|
|
|
// === HierarchicalTransform ===
|
|
|
|
// =============================
|
|
|
|
|
|
|
|
pub struct HierarchicalTransform<OnChange> {
|
2021-11-02 16:05:43 +03:00
|
|
|
transform: Transform,
|
|
|
|
transform_matrix: Matrix4<f32>,
|
|
|
|
origin: Matrix4<f32>,
|
|
|
|
matrix: Matrix4<f32>,
|
|
|
|
pub dirty: dirty::SharedBool<OnChange>,
|
|
|
|
pub logger: Logger,
|
2019-12-06 10:01:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<OnChange> HierarchicalTransform<OnChange> {
|
2021-11-02 16:05:43 +03:00
|
|
|
pub fn new(logger: Logger, on_change: OnChange) -> Self {
|
|
|
|
let logger_dirty = logger.sub("dirty");
|
|
|
|
let transform = default();
|
2019-12-06 10:01:58 +03:00
|
|
|
let transform_matrix = Matrix4::identity();
|
2021-11-02 16:05:43 +03:00
|
|
|
let origin = Matrix4::identity();
|
|
|
|
let matrix = Matrix4::identity();
|
|
|
|
let dirty = dirty::SharedBool::new(logger_dirty, on_change);
|
|
|
|
Self { transform, transform_matrix, origin, matrix, dirty, logger }
|
2019-12-06 10:01:58 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-03 16:46:27 +03:00
|
|
|
|
2019-12-06 10:01:58 +03:00
|
|
|
// === Getters ===
|
|
|
|
|
|
|
|
impl<OnChange> HierarchicalTransform<OnChange> {
|
|
|
|
pub fn position(&self) -> &Vector3<f32> {
|
|
|
|
&self.transform.position
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn rotation(&self) -> &Vector3<f32> {
|
|
|
|
&self.transform.rotation
|
|
|
|
}
|
|
|
|
|
|
|
|
...
|
|
|
|
}
|
|
|
|
|
2020-01-03 16:46:27 +03:00
|
|
|
|
2019-12-06 10:01:58 +03:00
|
|
|
// === Setters ===
|
|
|
|
|
2021-11-02 16:05:43 +03:00
|
|
|
impl<OnChange: Callback0> HierarchicalTransform<OnChange> {
|
2019-12-06 10:01:58 +03:00
|
|
|
pub fn position_mut(&mut self) -> &mut Vector3<f32> {
|
|
|
|
self.dirty.set();
|
|
|
|
&mut self.transform.position
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn rotation_mut(&mut self) -> &mut Vector3<f32> {
|
|
|
|
self.dirty.set();
|
|
|
|
&mut self.transform.rotation
|
|
|
|
}
|
|
|
|
|
|
|
|
...
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2022-04-15 17:10:55 +03:00
|
|
|
## Multiline Expressions
|
2021-11-02 16:05:43 +03:00
|
|
|
|
2021-11-05 14:51:43 +03:00
|
|
|
Most (preferably all) expressions should be single line. Multiline expressions
|
|
|
|
are hard to read and introduce noise in the code. Often, it is also an indicator
|
|
|
|
of code that is not properly refactored. Try to refactor parts of multiline
|
|
|
|
expressions to well-named variables, and divide them to several single-line
|
|
|
|
expressions.
|
2019-12-06 10:01:58 +03:00
|
|
|
|
2020-01-22 18:01:11 +03:00
|
|
|
Example of poorly formatted code:
|
2021-11-02 16:05:43 +03:00
|
|
|
|
2019-12-06 10:01:58 +03:00
|
|
|
```rust
|
|
|
|
pub fn new() -> Self {
|
|
|
|
let shape_dirty = ShapeDirty::new(logger.sub("shape_dirty"),
|
2021-11-02 16:05:43 +03:00
|
|
|
on_dirty.clone());
|
2019-12-06 10:01:58 +03:00
|
|
|
let dirty_flag = MeshRegistryDirty::new(logger.sub("mesh_registry_dirty"),
|
2021-11-02 16:05:43 +03:00
|
|
|
on_dirty);
|
2019-12-06 10:01:58 +03:00
|
|
|
Self { dirty_flag, dirty_flag }
|
|
|
|
}
|
|
|
|
```
|
2021-11-02 16:05:43 +03:00
|
|
|
|
2019-12-06 10:01:58 +03:00
|
|
|
Example of properly formatted code:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
pub fn new() -> Self {
|
2021-11-02 16:05:43 +03:00
|
|
|
let sub_logger = logger.sub("shape_dirty");
|
|
|
|
let shape_dirty = ShapeDirty::new(sub_logger, on_dirty.clone());
|
|
|
|
let sub_logger = logger.sub("mesh_registry_dirty");
|
|
|
|
let dirty_flag = MeshRegistryDirty::new(sub_logger, on_dirty);
|
|
|
|
Self { shape_dirty, dirty_flag }
|
2019-12-06 10:01:58 +03:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2022-04-15 17:10:55 +03:00
|
|
|
## Getters and Setters
|
2021-11-02 16:05:43 +03:00
|
|
|
|
2021-11-05 14:51:43 +03:00
|
|
|
Getters do not have the `get_` prefix, while setters do. If a setter is provided
|
|
|
|
(method with the `set_` prefix), a `mut` accessor should be provided as well.
|
|
|
|
The correct way of defining getters and setters is presented below:
|
2019-12-06 10:01:58 +03:00
|
|
|
|
|
|
|
```rust
|
2021-11-02 16:05:43 +03:00
|
|
|
fn field(&self) -> &Type {
|
|
|
|
&self.field
|
2019-12-06 10:01:58 +03:00
|
|
|
}
|
|
|
|
|
2021-11-02 16:05:43 +03:00
|
|
|
fn field_mut(&mut self) -> &mut Type {
|
|
|
|
&mut self.field
|
2019-12-06 10:01:58 +03:00
|
|
|
}
|
|
|
|
|
2021-11-02 16:05:43 +03:00
|
|
|
fn set_field(&mut self, val: Type) {
|
2019-12-06 10:01:58 +03:00
|
|
|
*self.field_mut = val;
|
|
|
|
}
|
|
|
|
```
|
2020-04-03 14:18:22 +03:00
|
|
|
|
2022-04-15 17:10:55 +03:00
|
|
|
## Trait exporting
|
2021-11-02 16:05:43 +03:00
|
|
|
|
2021-11-05 14:51:43 +03:00
|
|
|
All names should be designed to be used in a qualified fashion. However, this
|
|
|
|
makes one situation tricky. In order to use methods defined in a trait, it has
|
|
|
|
to be in scope. Consider a trait `display::Object`. We want to use it as
|
|
|
|
function bound like `fn test<T:display::Object>(t:T) {...}`, and we also want to
|
|
|
|
use methods defined in this trait (so it has to be in scope). In such a case,
|
|
|
|
`Clippy` warns that `display::Object` is unnecessary qualification and could be
|
|
|
|
replaced simply by `Object`, which is not what we want. Thus, in order to export
|
|
|
|
traits, please always rename them using the following convention:
|
2020-04-03 14:18:22 +03:00
|
|
|
|
|
|
|
```rust
|
|
|
|
/// Common traits.
|
|
|
|
pub mod traits {
|
|
|
|
// Read the Rust Style Guide to learn more about the used naming.
|
|
|
|
pub use super::Object as TRAIT_Object;
|
|
|
|
pub use super::ObjectOps as TRAIT_ObjectOps;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2021-11-05 14:51:43 +03:00
|
|
|
Having such a definition, we can import traits to scope using
|
|
|
|
`use display::object::traits::*`, and we would not have any warning about
|
|
|
|
unnecessary qualification anymore.
|