ToErrorCode

Trait ToErrorCode 

Source
pub trait ToErrorCode {
    // Required method
    fn code(&self) -> ErrorCode;
}
Expand description

Provides a non-ambiguous way to retrieve the error code associated with a given error.

An error code is meant to be a precise ID that helps users locate detailed documentation of the error.

Required Methods§

Source

fn code(&self) -> ErrorCode

Returns the error code associated with this error.

If an application only requires one error type (and that type happens to be a unit enum), an implementation like this might be sufficient:

#[derive(Clone, Copy)]
pub enum MyError {
    Foo,
    Bar,
    Baz,
}

impl ToErrorCode for MyError {
    fn code(&self) -> ErrorCode {
        *self as ErrorCode
    }
}

For more complex situations, it may make more sense to give each error type its own “prefix” and add that to the discriminant.

#[derive(Clone, Copy)]
pub enum ErrorA {
    Foo,
    Bar,
    Baz,
}

#[derive(Clone, Copy)]
pub enum ErrorB {
    Qux,
    Quux,
}

#[derive(Clone, Copy)]
pub enum ErrorC {
    Fizz,
    Buzz,
}

impl ToErrorCode for ErrorA {
    fn code(&self) -> ErrorCode {
        const PREFIX: ErrorCode = 0;
        PREFIX + *self as ErrorCode
    }
}

impl ToErrorCode for ErrorB {
    fn code(&self) -> ErrorCode {
        const PREFIX: ErrorCode = 100;
        PREFIX + *self as ErrorCode
    }
}

impl ToErrorCode for ErrorC {
    fn code(&self) -> ErrorCode {
        const PREFIX: ErrorCode = 200;
        PREFIX + *self as ErrorCode
    }
}

With this approach, the prefixes must be large enough to accomodate all error variants in each type. Otherwise, multiple errors might have the same error code.

The previous two approaches rely on errors being unit enums. Although this can work in some situations, it is not uncommon for error types to have tuple and/or struct variants as well. In these situations, it is still possible (albeit more difficult) to automatically retrieve the discriminant if the enum uses a primitive representation:

#[derive(Clone, Copy)]
#[repr(u16)] // `ErrorCode` is two bytes wide.
pub enum MyError {
    Foo,
    Bar(bool),
    Baz {
        something: f32,
    }
}

impl ToErrorCode for MyError {
    fn code(&self) -> ErrorCode {
        unsafe { *<*const _>::from(self).cast::<ErrorCode>() }
    }
}

This approach is compatible with the prefixes from before, but examples will be omitted for the sake of brevity.

For more details regarding discriminants and safety, see the documentation for core::mem::discriminant.

Implementors§