Is there an error crate like this?

Someone suggested that I post this here and link it back to the original reddit post, so I'm doing that. Here's the link: Is there a crate like this? : rust (reddit.com)

It finally occurred to me to ask before I kept implementing this. Is there an error crate that generates a "tree" of errors? Something that looks like:

error_tree! {
    UnifiedError {
        "internal: {}"
        Internal: {
            Frontend: {
                Discord: @nogen SerenityError,
                DiscordBadInteraction,
            },
            Sim: Sirror {
                @nofrom MultipleStatusLoadFailed: @nogen Vec<StatusKind>,
                MissingComponent: (EntityKind, @nogen Cow<'static, str>),
            },
            BadConfig: ConfigSource,
            Unknown,
        },
        @nodisplay User {
            @nofrom BadState: String,
            SomethingElse: @nogen CustomError,
            LackingItems: @struct {
                somethingelse: AnotherErrorTree,
                message_maybe: String,
            },
        },
    }
}

and generates

use thiserror::Error;

#[derive(Error)]
pub enum UnifiedError {
    #[error("internal: {}"]
    Internal(InternalError),
    #[error(transparent)]
    User(UserError).
}

from_impl!(UnifiedError = User(UserError));
from_impl!(UnifiedError = Internal(InternalError));

#[derive(Error)]
pub enum InternalError {
    #[error(transparent)]
    Frontend(FrontendError),
    #[error(transparent)]
    Sim(Sirror),
    #[error(transparent)]
    BadConfig(ConfigSource),
    #[error(transparent)]
    Unknown,
}

from_impl!(InternalError = Frontend(FrontendError));
from_impl!(InternalError = Sim(Sirror));
from_impl!(InternalError = BadConfig(ConfigSource));

#[derive(Error)]
pub enum FrontendError {
    #[error(transparent)]
    Discord(SerenityError),
    #[error(transparent)]
    DiscordBadInteraction,
}

#[derive(Error)]
pub enum Sirror {
    MultipleStatusLoadFailed(Vec<StatusKind>)
    MissingComponent(Dunno, Cow<'static, str>),
}

from_impl!(Sirror = MultipleStatusLoadFailed(Vec<StatusKind>));
impl From<(Dunno, Cow<'static, str>)> for Sirror {
    fn from((a, b): (Dunno, Cow<'static, str>)) -> Self {
        Sirror::MissingComponent(a, b)
    }
}

#[derive(Error)]
pub struct Dunno;

#[derive(Error)]
pub enum UserError {
    BadState(String),
    SomethingElse(CustomError),
    LackingItems {
        lacking: Vec<LackingItem>,
        command: String,
    },
}

from_impl!(UserError = SomethingElse(CustomError));

from_many!(UnifiedError : Internal [
    Sirror, FrontendError, ConfigSource, Sirror,
    (Dunno, Cow<'static, str>)
]);
from_many!(UnifiedError : User [
    CustomError,
]);

because I almost finished implementing it, but it's got all kinds of rough edges. If one already exists, I'd rather use that than work through all the issues/features.

1 Like