embedded-error-chain

Crates.ioembedded-error-chain
lib.rsembedded-error-chain
version1.0.0
sourcesrc
created_at2020-11-12 21:40:29.356641
updated_at2020-11-20 02:14:37.900187
descriptionEasy error handling in no-alloc and no-std environments
homepage
repositoryhttps://github.com/N3xed/embedded-error-chain
max_upload_size
id311761
size76,548
Dominik Gschwind (N3xed)

documentation

https://docs.rs/embedded-error-chain

README

embedded-error-chain

build crates.io docs

Easy error handling for embedded devices (no liballoc and no_std).

Errors are represented by error codes and come from enums that implement the ErrorCategory trait (a derive macro exists), which is used for custom debug printing per error code among other things. Each error code can have a value from 0 to 15 (4 bits) and you can chain an error with up to four different error codes of different categories.

The Error type encapsulates an error code and error chain, and is only a single u32 in size. There is also an untyped DynError type, which unlike Error does not have a type parameter for the current error code. Its size is a u32 + pointer (usize), which can be used to forward source errors of different categories to the caller.

This library was inspired by libraries such as error-chain, anyhow and thiserror, though it was made to work in no_std and no liballoc environments with very little memory overhead.

Example

use embedded_error_chain::prelude::*;

#[derive(Clone, Copy, ErrorCategory)]
#[repr(u8)]
enum SpiError {
    BusError,
    // ...
}

static LAST_GYRO_ACC_READOUT: usize = 200;

#[derive(Clone, Copy, ErrorCategory)]
#[error_category(links(SpiError))]
#[repr(u8)]
enum GyroAccError {
    InitFailed,

    #[error("{variant} (readout={})", LAST_GYRO_ACC_READOUT)]
    ReadoutFailed,

    /// Value must be in range [0, 256)
    #[error("{variant}: {summary}")]
    InvalidValue,
}

fn main() {
    if let Err(err) = calibrate() {
        // log the error
        println!("{:?}", err);
        // ...
    }

    let readout = match gyro_acc_readout() {
        Ok(val) => val,
        Err(err) => {
            if let Some(spi_error) = err.code_of_category::<SpiError>() {
                // try to fix it
                0
            }
            else {
                panic!("unfixable spi error");
            }
        }
    };
}

fn spi_init() -> Result<(), SpiError> {
    Err(SpiError::BusError)
}

fn gyro_acc_init() -> Result<(), Error<GyroAccError>> {
    spi_init().chain_err(GyroAccError::InitFailed)?;
    Ok(())
}

fn gyro_acc_readout() -> Result<u32, Error<GyroAccError>> {
    Err(SpiError::BusError.chain(GyroAccError::InvalidValue))
}

fn calibrate() -> Result<(), DynError> {
    gyro_acc_init()?;
    // other stuff...
    Ok(())
}

License: MIT

Commit count: 13

cargo fmt