---
# System prepended metadata

title: esp-hal API guidelines

---

## esp-hal API guidelines

## Construction / Destruction of drivers

- Avoid methods like `free(self) -> Self` instead, the driver should use the `PeripheralRef` API.
    - See: https://docs.esp-rs.org/esp-hal/esp-hal/0.16.1/esp32c6/esp_hal/peripheral/index.html
- Add `Drop` implementations to drivers that reset the peripheral to idle state. (with the exception of GPIO, imo, but we can discuss that)
- Drivers that consume optional numbers of pins should use the builder pattern to do so (see SPI for example)
    - JB: I would also like to see anything with more advanced configuration use this pattern! We're already doing so for UART, for example


## Interop

- Structs and enums implement the [common-traits](https://rust-lang.github.io/api-guidelines/interoperability.html#types-eagerly-implement-common-traits-c-common-traits) where applicable.
- cfg'd `defmt` derives and impls are added to new structs and enums.
- Don't use `log::XXX!` macros directly - use the wrappers in `fmt.rs` (e.g. just `info!` instead of `log::info!` or importing `log::*`)

## API Surface

- All new public items must be documented (once we've caught up this can be automated with `deny(missing_docs)`)
- Private details shouldn't be leaked into the public API, and should be make private where possible.
- Implementation details that _need_ to be public should be marked with `doc(hidden)` and a comment as to why it needs to be public.
- Any public traits, that **must** not be implemented downstream need to be `Sealed`
- Prefer compile-time checks over runtime checks where possible, prefer a fallible API over panics
    - JB: Even better, evaluate whether it's possible to create an API that *cannot* fail! Sometimes we can get clever!
- Follow naming conventions in order to be consistent across drivers
    - For example, users would expect that similar peripherals, say the UART and USB Serial/JTAG, probably work in about the same way, e.g.) `write_bytes`, `read_byte`, etc.
    - TODO: Codify the naming conventions as much as possible
- APIs should ideally be as simple as possible, and require as few function calls as practical to use. Configuration should be secondary to ease of use right now, IMO.
- Driver API decisions should be assessed individually, and _not_ just follow embedded-hal or other ecosystem trait crates
- Avoid type states and extraneous generics whenever possible
    - These often lead to usability, and tend to just complicate things needlessly
    - Common cases of useless type info is storing pin information, this is usually not required and will bloat the complexity of the type massively
- Structures and Enums should be CamelCase
- SM: Avoiding `&mut self` when `&self` is safe to use. `&self` is generally easier to use as an API. Typical applications of this are where the methods just do writes to registers which don't have side effects. For example starting a timer is fine for &self, worst case a timer will be started twice if two parts of the program call it. A real example here: https://github.com/esp-rs/esp-hal/pull/1500#pullrequestreview-2015911974

## Maintainability

- Avoid excessive use of macros unless there is no other option; modification of the PAC crates should be considered before resorting to macros.
- If you are adding `#[cfg]` attributes to stick-handle around differences in PACs, stop! Update the PACs instead!
- Every line of code is a liability. Take some time to see if your implementation can be simplified before opening a PR. See if community PRs can be simplified before merging
- If your are porting code from ESP-IDF, please include a link WITH the commit hash in it, and please highlight the relevant line(s) of code!
    - I have seen a lot of links in comments already without hashes, which now point to meaningless code
    - This just adds further confusion, and does nothing to help people in the future (in this case, me :D)
- Follow standard coding "good practices"
    - Avoid magic numbers
    - Give variables/functions meanginful names, avoid single-character names unless it is obvious (e.g. `i` for index)
    - If a part of the code is complex/confusing, or additional context/information is required to fully grok it, please add a comment including all relevant information, issues/PRs, links, etc.
        - If you are linking to a file within a git repository, ensure that the URL contains a commit hash
