Rust
====
.. _rust-license:
License
-------
Use the `MIT license `__.
Development
-----------
- Install Rust via `rustup `__ rather than via Homebrew.
Preferences
-----------
- Prefer crates in the top 250 according to `lib.rs `__
- Read the ``Cargo.toml`` files of OCP projects for inspiration
- Use unstable language features or compiler flags instead of related crates. For example:
- `let_chains `__ instead of `if_chain `__
- `once_cell `__ instead of `once_cell `__ (crate) or `lazy_static `__
- `on-broken-pipe `__ instead of `calm_io `__
.. seealso::
- `Serde documentation `__
.. Candidates for preferences https://github.com/open-contracting/cardinal-rs/issues/4
Performance
-----------
.. seealso::
`coz `__ profiler
Code style
----------
- `Avoid matching an Option or Result `__. Instead, use `Option `__ and `Result `__ methods.
- `Don't panic `__. This includes ``panic!``, ``unreachable!``, ``unwrap()`` and ``expect()``.
- Use the same word for macro tokens as for local variables, if appropriate.
- Use ``super::*`` in ``mod tests`` only. Use ``crate::`` elsewhere.
.. seealso::
- `Common Message Styles `__
Macros
~~~~~~
Prefer functions, but use macros if you need:
- Variadic arguments, like ``println!`` or ``vec!``.
- Code generation at the `item level `__, like creating structs.
- Code generation at the `expression level `__, like accessing struct fields dynamically.
.. seealso::
- `The Little Book of Rust Macros `__
- `Macros `__ in *The Rust Reference*
Debugging:
- `Debugging `__ in *The Little Book of Rust Macros*
- `cargo-expand `__
- `proc-macro-error `__
Crates:
- `paste `__, to use macro arguments to generate identifiers and strings.
- To write procedural macros more easily: `quote `__, `proc_macro2 `__, `darling `__.
Guard clauses
~~~~~~~~~~~~~
Code with too much indentation is hard to read. One option is to use guard clauses. For example:
.. code-block:: rust
let Some(inner_value) = outer_value else {
return
};
.. code-block:: rust
let inner_value = match outer_value {
Ok(o) => o,
Err(e) => return e,
};
Continuous integration
----------------------
Create a ``.github/workflows/ci.yml`` file. As a base, use:
.. literalinclude:: samples/ci.yml
:language: yaml
Release process
---------------
#. Ensure that you are on an up-to-date ``main`` branch:
.. code-block:: bash
git checkout main
git pull --rebase
#. Ensure that the package is ready for release:
- All tests pass on continuous integration
- The version number is correct in ``Cargo.toml``
- The changelog is up-to-date and dated
#. Tag the release, replacing ``x.y.z`` twice:
.. code-block:: bash
git tag -a x.y.z -m 'x.y.z release.'
#. Push the release:
.. code-block:: bash
git push --follow-tags
#. Edit the GitHub release that is created by GitHub Actions, to add the ``description`` value from ``Cargo.toml`` followed by the relevant section of the changelog.
#. If the software has a formula in our `Homebrew tap `__, update the ``url`` and ``sha256`` values. For example, from the ``homebrew-tap`` directory, after updating the ``url`` values, prepare the ``sha256`` values for the ``ocdscardinal`` formula with:
.. code-block:: bash
grep --only-matching -E 'https://.+zip' Formula/ocdscardinal.rb | xargs -I{} sh -c 'curl -sSL {} | shasum -a 256'
Then, push the changes.
#. Publish the crate:
.. code-block:: bash
cargo publish
#. Announce on the `discussion group `__ if relevant
Development
-----------
Troubleshooting
~~~~~~~~~~~~~~~
If you're getting confusing compile errors, especially any involving type annotations, check that:
- You wrote enough code. If you produce results that you don't use, the compiler still wants to determine their definite type. Adding more code to give the compiler a hint can spare adding optional type annotations.
- Your annotations are correct. If you change your code but don't change your annotations, the compiler might report errors that are distantly related to the misannotation.
- You duck type using trait objects: for example, ``Box`` to use ``std::io:stdin()`` and ``File::open(file).unwrap()`` interchangeably. The compiler can't determine which traits are relevant across the two types.
If errors relate to ownership, try using:
- ``Arc>``, as discussed in sections `16.3 `__ and `20.2 `__ of *The Rust Programming Language*.
- ``Option`` with ``take()``, as discussed in sections `17.3 `__ and `20.3 `__ of *The Rust Programming Language*.
To reduce the number of allocations, try using:
- ``mem::take`` or ``mem::replace`` (`Rust Design Patterns `__).
.. seealso::
- `Winning Fights against the Borrow Checker `__
.. _rust-learn:
Learning
~~~~~~~~
Rust has no:
- `Exception `__
- `Reflection `__
Introductions
^^^^^^^^^^^^^
- `The Rust Programming Language `__ (`Moving Captured Values Out of Closures and the Fn Traits `__)
- `Exercism Rust Track `__: Read the most upvoted community solution after each exercise.
- `Unofficial community Discord `__, in particular ``#rust-help`` and ``#rust-beginners``
.. tip::
Use `Rust Playground `__ to test code snippets.
..
I prefer Exercism to Rustlings (https://github.com/rust-lang/rustlings). Rustlings' exercises often repeat examples from The Rust Programming Language, and are often solved by the compiler's feedback.
I don't find it useful to read the examples in Rust by Example (https://doc.rust-lang.org/rust-by-example/), but I occasionally read it when it's a search result.
Topics
^^^^^^
- `Command line apps in Rust `__
Memory container cheatsheet
^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. image:: https://media.githubusercontent.com/media/usagi/rust-memory-container-cs/master/3840x2160/rust-memory-container-cs-3840x2160-light-back-high-contrast.png
:class: only-light
.. image:: https://media.githubusercontent.com/media/usagi/rust-memory-container-cs/master/3840x2160/rust-memory-container-cs-3840x2160-dark-back-high-contrast.png
:class: only-dark
From `usagi/rust-memory-container-cs `__.
Reference
^^^^^^^^^
- `The Rust Standard Library `__
- `The Rust Reference `__
- `docs.rs `__ for crate documentation
.. tip::
Scroll up after the page loads to access the within-crate search bar.