shepmaster / snafu

Easily assign underlying errors into domain-specific errors while adding context
https://docs.rs/snafu/
Apache License 2.0
1.4k stars 60 forks source link

Adding a trait for build/fail #378

Open l4l opened 1 year ago

l4l commented 1 year ago

I want to wrap a snafu-managed error with mine that captures some implicit context. Basically I do smth like this:

pub struct MyError {
 context: Context,
 kind: ErrorKind,
}

impl From<ErrorKind> for MyError {
 fn from(kind: ErrorKind) -> Self {
  Self { context: capture(), kind }
 }

#[derive(Snafu)]
pub enum ErrorKind {
  Xyz { .. }
  ..
}

Then in the code I have statements like this return XyzSnafu { .. }.fail().into(). Basically I want to combine that fail() + into() (and similarly for build) into a single call, e.g:

trait MyResExt {
  fn fail_into() -> Error;
}

But here's the problem, there's no generic type bound to implement it for and use fail/build in implementation. So is there any reason why it doesn't exist?

shepmaster commented 1 year ago

any reason why it doesn't exist?

The big one would be that using a trait for build or fail would require the user to import that trait first. That's not insurmountable, but it's an annoying papercut. If "inherent traits" were a thing, then this would be an easy win.

Without that, the next best thing would be some kind of adjacent implementation, e.g.

struct X;

impl X {
    fn foo() {}
}

trait TheFooTrait {
    fn foo_from_trait();
}

impl TheFooTrait for X {
    fn foo_from_trait() { self.foo() }
}

Note that this is also annoying as there are different names (IIRC this is required because you can't disambiguate a trait and inherent method of the same name).


captures some implicit context

Would #[snafu(implicit)] help?

In cases where I've wanted to be generic over selectors, I usually end up using the IntoError trait. Note that you may need to use NoneError for your case.