Trait snafu::ResultExt

source ·
pub trait ResultExt<T, E>: Sized {
    // Required methods
    fn context<C, E2>(self, context: C) -> Result<T, E2>
       where C: IntoError<E2, Source = E>,
             E2: Error + ErrorCompat;
    fn with_context<F, C, E2>(self, context: F) -> Result<T, E2>
       where F: FnOnce(&mut E) -> C,
             C: IntoError<E2, Source = E>,
             E2: Error + ErrorCompat;
    fn whatever_context<S, E2>(self, context: S) -> Result<T, E2>
       where S: Into<String>,
             E2: FromString,
             E: Into<E2::Source>;
    fn with_whatever_context<F, S, E2>(self, context: F) -> Result<T, E2>
       where F: FnOnce(&mut E) -> S,
             S: Into<String>,
             E2: FromString,
             E: Into<E2::Source>;
    fn boxed<'a>(self) -> Result<T, Box<dyn Error + Send + Sync + 'a>>
       where E: Error + Send + Sync + 'a;
    fn boxed_local<'a>(self) -> Result<T, Box<dyn Error + 'a>>
       where E: Error + 'a;
}
Expand description

Additions to Result.

Required Methods§

source

fn context<C, E2>(self, context: C) -> Result<T, E2>
where C: IntoError<E2, Source = E>, E2: Error + ErrorCompat,

Extend a Result’s error with additional context-sensitive information.

use snafu::prelude::*;

#[derive(Debug, Snafu)]
enum Error {
    Authenticating {
        user_name: String,
        user_id: i32,
        source: ApiError,
    },
}

fn example() -> Result<(), Error> {
    another_function().context(AuthenticatingSnafu {
        user_name: "admin",
        user_id: 42,
    })?;
    Ok(())
}

fn another_function() -> Result<i32, ApiError> {
    /* ... */
}

Note that the context selector will call Into::into on each field, so the types are not required to exactly match.

source

fn with_context<F, C, E2>(self, context: F) -> Result<T, E2>
where F: FnOnce(&mut E) -> C, C: IntoError<E2, Source = E>, E2: Error + ErrorCompat,

Extend a Result’s error with lazily-generated context-sensitive information.

use snafu::prelude::*;

#[derive(Debug, Snafu)]
enum Error {
    Authenticating {
        user_name: String,
        user_id: i32,
        source: ApiError,
    },
}

fn example() -> Result<(), Error> {
    another_function().with_context(|_| AuthenticatingSnafu {
        user_name: "admin".to_string(),
        user_id: 42,
    })?;
    Ok(())
}

fn another_function() -> Result<i32, ApiError> {
    /* ... */
}

Note that this may not be needed in many cases because the context selector will call Into::into on each field.

source

fn whatever_context<S, E2>(self, context: S) -> Result<T, E2>
where S: Into<String>, E2: FromString, E: Into<E2::Source>,

Extend a Result’s error with information from a string.

The target error type must implement FromString by using the #[snafu(whatever)] attribute. The premade Whatever type is also available.

In many cases, you will want to use with_whatever_context instead as it gives you access to the error and is only called in case of error. This method is best suited for when you have a string literal.

use snafu::{prelude::*, Whatever};

fn example() -> Result<(), Whatever> {
    std::fs::read_to_string("/this/does/not/exist")
        .whatever_context("couldn't open the file")?;
    Ok(())
}

let err = example().unwrap_err();
assert_eq!("couldn't open the file", err.to_string());
source

fn with_whatever_context<F, S, E2>(self, context: F) -> Result<T, E2>
where F: FnOnce(&mut E) -> S, S: Into<String>, E2: FromString, E: Into<E2::Source>,

Extend a Result’s error with information from a lazily-generated string.

The target error type must implement FromString by using the #[snafu(whatever)] attribute. The premade Whatever type is also available.

use snafu::{prelude::*, Whatever};

fn example() -> Result<(), Whatever> {
    let filename = "/this/does/not/exist";
    std::fs::read_to_string(filename)
        .with_whatever_context(|_| format!("couldn't open the file {filename}"))?;
    Ok(())
}

let err = example().unwrap_err();
assert_eq!(
    "couldn't open the file /this/does/not/exist",
    err.to_string(),
);

The closure is not called when the Result is Ok:

use snafu::{prelude::*, Whatever};

let value: std::io::Result<i32> = Ok(42);
let result = value.with_whatever_context::<_, String, Whatever>(|_| {
    panic!("This block will not be evaluated");
});

assert!(result.is_ok());
source

fn boxed<'a>(self) -> Result<T, Box<dyn Error + Send + Sync + 'a>>
where E: Error + Send + Sync + 'a,

Convert a Result’s error into a boxed trait object compatible with multiple threads.

This is useful when you have errors of multiple types that you wish to treat as one type. This may occur when dealing with errors in a generic context, such as when the error is a trait’s associated type.

In cases like this, you cannot name the original error type without making the outer error type generic as well. Using an error trait object offers an alternate solution.

use snafu::prelude::*;

fn convert_value_into_u8<V>(v: V) -> Result<u8, ConversionFailedError>
where
    V: TryInto<u8>,
    V::Error: snafu::Error + Send + Sync + 'static,
{
    v.try_into().boxed().context(ConversionFailedSnafu)
}

#[derive(Debug, Snafu)]
struct ConversionFailedError {
    source: Box<dyn snafu::Error + Send + Sync + 'static>,
}
§Avoiding misapplication

We recommended against using this to create fewer error variants which in turn would group unrelated errors. While convenient for the programmer, doing so usually makes lower quality error messages for the user.

use snafu::prelude::*;
use std::fs;

fn do_not_do_this() -> Result<i32, UselessError> {
    let content = fs::read_to_string("/path/to/config/file")
        .boxed()
        .context(UselessSnafu)?;
    content.parse().boxed().context(UselessSnafu)
}

#[derive(Debug, Snafu)]
struct UselessError {
    source: Box<dyn snafu::Error + Send + Sync + 'static>,
}
source

fn boxed_local<'a>(self) -> Result<T, Box<dyn Error + 'a>>
where E: Error + 'a,

Convert a Result’s error into a boxed trait object.

This is useful when you have errors of multiple types that you wish to treat as one type. This may occur when dealing with errors in a generic context, such as when the error is a trait’s associated type.

In cases like this, you cannot name the original error type without making the outer error type generic as well. Using an error trait object offers an alternate solution.

use snafu::prelude::*;

fn convert_value_into_u8<V>(v: V) -> Result<u8, ConversionFailedError>
where
    V: TryInto<u8>,
    V::Error: snafu::Error + 'static,
{
    v.try_into().boxed_local().context(ConversionFailedSnafu)
}

#[derive(Debug, Snafu)]
struct ConversionFailedError {
    source: Box<dyn snafu::Error + 'static>,
}
§Avoiding misapplication

We recommended against using this to create fewer error variants which in turn would group unrelated errors. While convenient for the programmer, doing so usually makes lower quality error messages for the user.

use snafu::prelude::*;
use std::fs;

fn do_not_do_this() -> Result<i32, UselessError> {
    let content = fs::read_to_string("/path/to/config/file")
        .boxed_local()
        .context(UselessSnafu)?;
    content.parse().boxed_local().context(UselessSnafu)
}

#[derive(Debug, Snafu)]
struct UselessError {
    source: Box<dyn snafu::Error + 'static>,
}

Object Safety§

This trait is not object safe.

Implementations on Foreign Types§

source§

impl<T, E> ResultExt<T, E> for Result<T, E>

source§

fn context<C, E2>(self, context: C) -> Result<T, E2>
where C: IntoError<E2, Source = E>, E2: Error + ErrorCompat,

source§

fn with_context<F, C, E2>(self, context: F) -> Result<T, E2>
where F: FnOnce(&mut E) -> C, C: IntoError<E2, Source = E>, E2: Error + ErrorCompat,

source§

fn whatever_context<S, E2>(self, context: S) -> Result<T, E2>
where S: Into<String>, E2: FromString, E: Into<E2::Source>,

source§

fn with_whatever_context<F, S, E2>(self, context: F) -> Result<T, E2>
where F: FnOnce(&mut E) -> S, S: Into<String>, E2: FromString, E: Into<E2::Source>,

source§

fn boxed<'a>(self) -> Result<T, Box<dyn Error + Send + Sync + 'a>>
where E: Error + Send + Sync + 'a,

source§

fn boxed_local<'a>(self) -> Result<T, Box<dyn Error + 'a>>
where E: Error + 'a,

Implementors§