/
Rust Standards & Tips

Rust Standards & Tips

We use rust for a few projects right now, including both well supported Odyssey projects and lesser used experimental firmware projects. This page is split into 3 sections → general notes, linux/multithreaded notes, and firmware notes. Make sure to read the applicable sections before developing in rust at NER.

 

IDE Setup

Use rust-analyzer extension and you should be all set for both embedded and applications context.

Helpful cargo commands

  • cargo run to test your code

  • cargo run --release to test your code’s performance

  • cargo clippy to check your code passes linter

  • cargo fmt to format your code

  • cargo test to use your tests on the code

General Notes

  • Do not use (import) modules in lib.rs!! This could global import things. Instead use full paths.

  • Use Result and Option. These structs are not just for libraries, use them for your own return results.

    • Use Result for things that could return an error object.

    • Use Option for things that could return null or may not “find” anything.

  • NEVER unwrap. Alternatives

    • expect if an error is a critical failure and rare

    • unwrap_or_default if you do not care about the value and will no-op if the value is empty, 0, etc.

    • match the some/none or ok/err if you need to transform the error and/or break out/return from a function

    • unwrap_or_else if you need to provide a default value and want to perform other operations

    • unwrap_or to provide a const-context default

  • For functions with alot of parameters, use an options struct and pass that struct in.

  • For struct initialization, use a new function which returns Self

  • Printing

    • Debug print something (implement with derive(Debug) on the struct): {:?}

    • Display value of something (implement with derive(Display) on the struct): {}

  • If you use a library, do not use its dependencies directly. Instead add them to Cargo.toml.

    • Example: dont use prisma_client_rust::chrono , instead use chrono as then if you remove prisma_client_rust chrono will still work

  •  

Applications notes

Entrypoint/settings

  • Use clap and clap_derive for all settings that should be changed at runtime. As rust is a compiled language, making a setting that may require changing involves rebuiliding and deploying a sometimes hefty application. Use clap_derive (as seen here) to expose your setting to the program. Use the environment variables as the example shows

  • Dockerization should use environment variables for all settings (see above)

Tokio/Threading

  • Use threads conservatively. If you need two+ things to happen on a loop, use a tokio::select in order to time multiple things that require access to the same variables.

  • Use print levels (trace, debug, info, warn) when you want a print to be included in the final product

 

Firmware notes

  • Use the embassy version of stuff. Embassy provides alternatives of normal functions for most stuff, use them. Do not consider adding a new library unless you are sure an embassy proejct doesn’t already include it.

  • Do all initialization of hardware using the peripherals variable in main.rs , and then once a new object is procured initialize that in the task.

  • Ensure you arent copying things into functions. Make their context static or give a lifetime, do not copy a variable, especially a String.

  • Use DMA/await when possible. No matter how much work, avoid the xxx_blocking function available, use the await async functions. This allows better parallelism within code leading to optimal performance.

 

Related content

Firmware Environment Setup
Firmware Environment Setup
More like this
Firmware Launchpad
Firmware Launchpad
More like this
Firmware Onboarding | Embedded Software
Firmware Onboarding | Embedded Software
More like this
C Coding Standards
C Coding Standards
More like this
Vault Guidelines
Vault Guidelines
More like this
Software Onboarding
Software Onboarding
More like this