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§
sourcefn context<C, E2>(self, context: C) -> Result<T, E2>
fn context<C, E2>(self, context: C) -> Result<T, E2>
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.
sourcefn with_context<F, C, E2>(self, context: F) -> Result<T, E2>
fn with_context<F, C, E2>(self, context: F) -> Result<T, E2>
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.
sourcefn whatever_context<S, E2>(self, context: S) -> Result<T, E2>
fn whatever_context<S, E2>(self, context: S) -> Result<T, E2>
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());
sourcefn with_whatever_context<F, S, E2>(self, context: F) -> Result<T, E2>
fn with_whatever_context<F, S, E2>(self, context: F) -> Result<T, E2>
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());
sourcefn boxed<'a>(self) -> Result<T, Box<dyn Error + Send + Sync + 'a>>
fn boxed<'a>(self) -> Result<T, Box<dyn 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>,
}
sourcefn boxed_local<'a>(self) -> Result<T, Box<dyn Error + 'a>>where
E: Error + 'a,
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>,
}