pub struct ErrorSentinel<E> { /* private fields */ }Expand description
Represents errors which must be handled before this sentinel is dropped.
ErrorSentinel has a custom implementation of the Drop trait which checks that the errors
were handled in some way, and panics if not.
{
let errors = ErrorSentinel::new(vec!["error 1", "error 2"]);
// Panic occurs here!
}Using a method which marks the errors as handled will suppress the panic:
{
let errors = ErrorSentinel::new(vec!["error 1", "error 2"]);
errors.handle(|errs| {
for err in errs {
println!("error: {err}");
}
});
// No panic, because errors were handled
}Methods which consider the errors “handled” are documented as such, and all also consume the
ErrorSentinel. Most often, you will want to do one of the following:
- Handle errors with some custom logic:
handle - Assert that there are no errors:
unwraporexpect - Delegate the errors to another object:
propagate
In addition, an ErrorSentinel can be used as a generic container to accumulate errors during
an operation, which can then be returned as an Outcome. See into_outcome and
Outcome::build.
Implementations§
Source§impl<E> ErrorSentinel<E>
impl<E> ErrorSentinel<E>
Sourcepub fn new(errors: Vec<E>) -> Self
pub fn new(errors: Vec<E>) -> Self
Constructs a new unhandled ErrorSentinel with errors.
Usually this is not needed to be called manually, and an ErrorSentinel will be created by
Outcome::finalize instead.
Sourcepub fn handle<R>(self, handler: impl FnOnce(Vec<E>) -> R) -> R
pub fn handle<R>(self, handler: impl FnOnce(Vec<E>) -> R) -> R
Handles the errors by executing a closure, returning the value which it evaluates to.
let errors = ErrorSentinel::new(vec!["error 1", "error 2", "error 3"]);
let mut error_count = 0;
errors.handle(|errs| {
for err in errs {
println!("error: {err}");
error_count += 1;
}
});
assert_eq!(error_count, 3);The closure should implement appropriate error-handling logic for your application, such as printing messages.
ErrorSentinel’s checking can only go so far, and does not understand if you have actually
done something appropriate with the errors. This would be considered a valid handling of
errors:
errors.handle(|_| ());Sourcepub fn propagate(self, other: &mut impl ErrorCollector<E>)
pub fn propagate(self, other: &mut impl ErrorCollector<E>)
Handles the errors by moving them into an ErrorCollector, effectively postponing them to
be handled later instead.
let source = ErrorSentinel::new(vec!["error 1", "error 2"]);
let mut dest = ErrorSentinel::new(vec!["error 3", "error 4", "error 5"]);
source.propagate(&mut dest);
assert_eq!(dest.peek().len(), 5);Sourcepub fn ignore(self)
pub fn ignore(self)
Handles the errors by ignoring them, dropping the list of errors.
let errors = ErrorSentinel::new(vec!["error 1", "error 2", "error 3"]);
errors.ignore();This exists as an “escape hatch”, but its use is strongly not recommended. There is probably
a more suitable method for what you are trying to do. Consider using unwrap or
expect if there should not be any errors in the ErrorSentinel, which will panic if
this assumption is violated unlike ignore.
Sourcepub fn into_outcome<T>(self, value: T) -> Outcome<T, E>
pub fn into_outcome<T>(self, value: T) -> Outcome<T, E>
Handles the errors by moving them into a new Outcome with a given value.
let errors = ErrorSentinel::new(vec!["error 1", "error 2", "error 3"]);
let outcome = errors.into_outcome(42);
assert_eq!(outcome.len_errors(), 3);This can be useful for performing some logic which accumulates errors over time, and then
finally creating an Outcome to return with a calculated value. Using an ErrorSentinel
to accumulate the errors ensures that you cannot forget to return them.
See also Outcome::build, which provides a closure-based helper for the same pattern.
/// Sum the integer values in a sequence of strings.
/// Any non-integer values are returned as errors.
pub fn sum_ints<'a>(input: &[&'a str]) -> Outcome<u32, &'a str> {
let mut errors = ErrorSentinel::empty();
let mut sum = 0;
for item in input {
match item.parse::<u32>() {
Ok(num) => sum += num,
Err(_) => errors.push_error(*item),
}
}
errors.into_outcome(sum)
}
let result = sum_ints(&["12", "a", "5", "b", "c", "2"]);
let (value, errors) = result.finalize();
assert_eq!(value, 12 + 5 + 2);
assert_eq!(errors.peek(), &["a", "b", "c"]);Sourcepub fn into_errors_iter(self) -> ErrorSentinelIter<E> ⓘ
pub fn into_errors_iter(self) -> ErrorSentinelIter<E> ⓘ
Consumes this ErrorSentinel to create an ErrorSentinelIter, enabling errors to be
handled as an iterator.
The iterator must be entirely consumed to consider the errors handled, else the iterator
will panic on drop. Refer to the type-level documentation for ErrorSentinelIter for more
details.
This is deliberately not an IntoIterator implementation, so that the decision to handle
errors one-by-one is explicit, by calling this method.
Sourcepub fn peek(&self) -> &[E]
pub fn peek(&self) -> &[E]
Inspect the list of errors, without considering them handled.
let errors = ErrorSentinel::new(vec!["error 1", "error 2"]);
assert_eq!(errors.peek(), &["error 1", "error 2"]);
errors.ignore(); // Without this, the sentinel would still panicSourcepub fn len(&self) -> usize
pub fn len(&self) -> usize
The number of errors within this ErrorSentinel.
let errors = ErrorSentinel::new(vec!["error 1", "error 2"]);
assert_eq!(errors.len(), 2);Sourcepub fn unwrap(self)where
E: Debug,
pub fn unwrap(self)where
E: Debug,
Handles the errors by panicking if there are any errors.
The panic message includes the Debug representation of the errors. If you would like
to provide a custom message instead, use expect.
let errors = ErrorSentinel::new(vec!["error 1", "error 2"]);
errors.unwrap(); // Panicslet errors = ErrorSentinel::ok();
errors.unwrap(); // OKSourcepub fn expect(self, msg: &str)where
E: Debug,
pub fn expect(self, msg: &str)where
E: Debug,
Handles the errors by panicking with a message if there are any errors.
let errors = ErrorSentinel::new(vec!["error 1", "error 2"]);
errors.expect("something went wrong"); // Panicslet errors = ErrorSentinel::ok();
errors.expect("something went wrong"); // OKSource§impl ErrorSentinel<!>
impl ErrorSentinel<!>
Sourcepub fn ok() -> Self
pub fn ok() -> Self
Constructs an ErrorSentinel which does not and will never contain errors, by using the
never type ! as the error type.
Sourcepub fn safely_ignore(self)
pub fn safely_ignore(self)
An alias for ignore which is only available when the error type is the never type !.
In this case, an error can never occur, so it is safe to ignore errors. Using
safely_ignore instead of ignore will signal to readers that this is a safe assumption,
and will cause a compile error if the error type ever changes from !.
let errors = ErrorSentinel::ok();
errors.safely_ignore(); // Prevents panicTrait Implementations§
Source§impl<E> Drop for ErrorSentinel<E>
impl<E> Drop for ErrorSentinel<E>
Source§impl<E> ErrorCollector<E> for ErrorSentinel<E>
impl<E> ErrorCollector<E> for ErrorSentinel<E>
Source§type WrappedInner = ()
type WrappedInner = ()
propagate.