Description
As demonstrated by #181 and other issues there's a real world usability issue with the Error
type of the Result
of operations being an associated type. An associated type means that a driver or user of an HAL impl is required to adapt to the custom Error type; while possible for applications this makes universal drivers impossible.
In my estimation the main reason for this was probably caused by embedded-hal
predating the improvements to Rust type and specifically Error
handling. Now we do have better possibilities and with the upcoming big 1.0 breakage it should be possible to also revamp the Error types without too much grief.
Currently our trait definition e.g. for I2C looks as follows:
pub trait Read {
/// Error type
type Error;
...
fn try_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error>;
}
My proposal would be to instead provide a specific Error
type such as:
#[non_exhaustive]
pub enum Error {
/// An unspecific bus error occured
BusError,
/// The arbitration was lost, e.g. electrical problems with the clock signal
ArbitrationLoss,
/// A bus operation received a NACK, e.g. due to the addressed device not being online
NoAcknowledge,
/// The peripheral buffer was overrun
Overrun,
/// The peripheral buffer ran out of data
Underrun,
}
and then redefine all traits as:
pub trait Read {
fn try_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error>;
}
The #[non_exhaustive]
flag (available from Rust 1.40.0, cf. https://blog.rust-lang.org/2019/12/19/Rust-1.40.0.html) allows us to easily extend the reasons in the feature without being a breaking change because it requires implementations which care about the actual error to also have a wildcard match branch, which is a good idea anyway.
By having the Error
types defined in embeded-hal
we do some advantages:
- Drivers can now universally check the error kind reported by a HAL implementation (cf. I²C Polling (detecting NACKs) #181 where a chip might return a NACK due to currently not being able to handle more requests, yet the driver cannot make use of this information and retry later) and act accordingly
- More uniform and exhaustive documentation of available error conditions next to the API itself
- Better guidelines for HAL authors which cases might be work distinguishing
- Improved portability of embedded applications between different hardware
Dowsides:
- More breakage right now
- MRSV 1.40