pub struct BoxedStash { /* private fields */ }Expand description
An ErrorStash that produces an ErrorList containing boxed, potentially
heterogeneous error values.
BoxedErrorList is designed to be a simple output type for ErrorStash when
you want to collect multiple potential error types and report them together.
An ErrorStash that produces BoxedErrorList values can be created using
the [BoxedErrorList::new_stash] function.
The individual errors within a BoxedErrorList will be instances of Box<dyn Error + Send + Sync + 'static>, allowing most types that implements the
Error trait to be stored. These values themselves implement the Error trait,
and can be downcast back to their original types if needed.
§Terminal methods
Methods that can return a BoxedErrorList (i.e. inside a Result or
Option) are considered terminal methods, as they consume the collected
errors to produce the wrapper error. In BoxedStash, these methods not only
consume all collected errors, they also reset the stash’s summary line to
its default value.
Typically, this doesn’t matter, because these methods
are normally called with the ? operator, causing the calling function to
return and the stash to likely no longer be used if any errors ocurred. However,
if you do call a terminal method without propagating the error immediately
(i.e. without using ?), be aware after the call the stash will be empty
and the summary line reset- if you intend to continue using the stash, you
may need to configure any custom summary line again.
The terminal methods on BoxedStash are:
§Compatibility
The two error types encountered when using BoxedStash are the wrapper error type,
BoxedErrorList, and the child error type, BoxedError. Both of these implement
std::error::Error + Send + Sync + 'static, making them compatible with other popular
error handling crates, including anyhow, thiserror, and eyre.
§anyhow example
use anyhow::{Error, anyhow};
let mut stash = BoxedStash::new();
stash.set_summary("Found {count} errors:");
stash.push("a string error");
stash.push(anyhow!("an anyhow error"));
let wrapper = stash.to_error().unwrap();
let wrapper_as_anyhow: anyhow::Error = wrapper.into();
let wrapper_back: BoxedErrorList = wrapper_as_anyhow.downcast().unwrap();§thiserror example
use thiserror::Error;
#[derive(Debug, Error)]
enum CustomChildError {
#[error("Value is too big: {0}")]
TooBig(usize),
#[error("Value is too small: {0}")]
TooSmall(usize),
}
#[derive(Debug, Error)]
#[error(transparent)]
struct ValidationError(#[from] BoxedErrorList);
let error = BoxedStash::new()
.set_summary("Found {count} errors:")
.push("a string error")
.fail_now(CustomChildError::TooBig(100))
.unwrap_err();
let result: Result<String, ValidationError> = Err(ValidationError(error));
let expected: &str = "
Found 2 errors:
- a string error
- Value is too big: 100
";
assert_eq!(expected.trim(), result.unwrap_err().to_string().trim());The Rust standard library also implements From<&str> and From<String> for
Box<dyn Error + Send + Sync + 'static>, so &str and String values
can be passed directly to BoxedStash::push and BoxedStash::push_all,
like this:
use errorstash::{ErrorStash, BoxedStash, BoxedError, StashableResult, StashErrorsIter};
use anyhow::{Error, bail};
let mut stash = BoxedStash::new();
stash.set_summary("Found {count} errors:");
stash.push("the first error");
let error2: String = "another string error".to_string();
stash.push(error2);
fn fail_if_negative(x: i32) -> Result<i32, anyhow::Error> {
if x < 0 {
bail!("Negative value: {}", x);
}
Ok(x)
}
let values: Vec<i32> = vec![10, -3, 5, -1].into_iter()
.map(fail_if_negative)
.stash_errors(&mut stash)
.collect();
assert_eq!(vec![10, 5], values);
let wrapper = stash.to_error().unwrap();
assert_eq!(4, wrapper.len());
let expected: &str = "
Found 4 errors:
- the first error
- another string error
- Negative value: -3
- Negative value: -1
";
assert_eq!(expected.trim(), wrapper.to_string().trim());§Formatting
The std::fmt::Display implementation for BoxedErrorList prints them in this
format:
<summary line>
- <error 1>
- <error 2>
- <error 3>Implementations§
Source§impl BoxedStash
impl BoxedStash
Sourcepub fn with_summary(summary: &'static str) -> Self
pub fn with_summary(summary: &'static str) -> Self
Creates a new BoxedStash with the given summary line.
Sourcepub fn set_summary(&mut self, summary: &'static str) -> &mut Self
pub fn set_summary(&mut self, summary: &'static str) -> &mut Self
Sets a custom summary line for the wrapper error.
If the summary string contains the {count} placeholder, it will be
replaced with the number of errors when formatted.
Sourcepub fn set_summary_with(
&mut self,
summary_func: impl Fn() -> String + Send + Sync + 'static,
) -> &mut Self
pub fn set_summary_with( &mut self, summary_func: impl Fn() -> String + Send + Sync + 'static, ) -> &mut Self
Sets a custom summary line generator closure for the wrapper error.
The closure will be called when the summary is formatted. If the
returned string contains the {count} placeholder, it will be replaced
with the number of errors when formatted.
The provided closure may capture local state and must be Send + Sync
so that the resulting BoxedStash remains thread-safe.
Sourcepub fn push(&mut self, err: impl Into<BoxedError>) -> &mut Self
pub fn push(&mut self, err: impl Into<BoxedError>) -> &mut Self
Adds a child error to the stash.
Sourcepub fn push_all<T, It>(&mut self, errors: It) -> &mut Self
pub fn push_all<T, It>(&mut self, errors: It) -> &mut Self
Adds multiple child errors to the stash.
Sourcepub fn check(&mut self, condition: bool, e: impl Into<BoxedError>) -> &mut Self
pub fn check(&mut self, condition: bool, e: impl Into<BoxedError>) -> &mut Self
If the condition is false, adds error e to the stash. Otherwise,
does nothing.
If you want to return immediately if the condition is false,
chain a call to [fail_unless_empty] after this method. For example:
let mut stash = BoxedStash::new();
let value = 42;
stash.check(value > 100, "value must be greater than 100")
.fail_unless_empty()?;Sourcepub fn fail_now(
&mut self,
e: impl Into<BoxedError>,
) -> Result<(), BoxedErrorList>
pub fn fail_now( &mut self, e: impl Into<BoxedError>, ) -> Result<(), BoxedErrorList>
Adds an error and immediately returns Err(W) with all collected
errors.
Trait Implementations§
Source§impl Debug for BoxedStash
impl Debug for BoxedStash
Source§impl Default for BoxedStash
impl Default for BoxedStash
Source§fn default() -> BoxedStash
fn default() -> BoxedStash
Source§impl ErrorStash<Box<dyn Error + Sync + Send>, ErrorList<Box<dyn Error + Sync + Send>>> for BoxedStash
impl ErrorStash<Box<dyn Error + Sync + Send>, ErrorList<Box<dyn Error + Sync + Send>>> for BoxedStash
Source§fn to_result<T>(self, closure: impl FnOnce() -> T) -> Result<T, BoxedErrorList>
fn to_result<T>(self, closure: impl FnOnce() -> T) -> Result<T, BoxedErrorList>
Ok(result). Otherwise,
consumes the collected errors and returns Err(W).Source§fn to_error(self) -> Option<BoxedErrorList>
fn to_error(self) -> Option<BoxedErrorList>
None. Otherwise,
consumes the collected errors and returns Some(W).Source§impl<T> Extend<T> for BoxedStashwhere
T: Into<BoxedError>,
impl<T> Extend<T> for BoxedStashwhere
T: Into<BoxedError>,
Source§fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I)
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I)
Source§fn extend_one(&mut self, item: A)
fn extend_one(&mut self, item: A)
extend_one)Source§fn extend_reserve(&mut self, additional: usize)
fn extend_reserve(&mut self, additional: usize)
extend_one)Source§impl IntoIterator for BoxedStash
impl IntoIterator for BoxedStash
Source§impl<T, FE> StashableResult<T, Box<dyn Error + Sync + Send>, ErrorList<Box<dyn Error + Sync + Send>>, BoxedStash> for Result<T, FE>
Lets you stash errors from a Result<T, FE> into a BoxedStash.
impl<T, FE> StashableResult<T, Box<dyn Error + Sync + Send>, ErrorList<Box<dyn Error + Sync + Send>>, BoxedStash> for Result<T, FE>
Lets you stash errors from a Result<T, FE> into a BoxedStash.
This implementation allows stashing errors from any error type FE that can be converted
into a BoxedError using the Into trait.
If the result’s error type FE is itself an ErrorList<BoxedError> (i.e.
the error type produced by another BoxedStash), its errors will be
unpacked and individually added to the target BoxedStash (rather than
nesting the entire ErrorList as a single error). In this case, summary
message from the source ErrorList will be discarded, and only its child
errors retained.
Note that this implementation leverages the Into<BoxedError> trait to auto-convert
compatible error types into BoxedError. This behavior differs from the StashableResult
implementation for TypedStash, which requires the error type to match exactly.
Source§fn or_stash(self, stash: &mut BoxedStash) -> Option<T>
fn or_stash(self, stash: &mut BoxedStash) -> Option<T>
Consumes this Result, returning Some(T) if this result is ok, or
collecting the error into the provided ErrorStash and returning None
if this result is an error.
If the error type FE is an ErrorList<BoxedError>, its individual errors
will be unpacked and added to the stash, rather than nesting the entire
ErrorList as a single error.
Source§fn or_fail(self, stash: &mut BoxedStash) -> Result<T, ErrorList<BoxedError>>
fn or_fail(self, stash: &mut BoxedStash) -> Result<T, ErrorList<BoxedError>>
Consumes this Result, returning Ok(T) if this result is ok, or
collecting the error into the provided ErrorStash and returning the
aggregated errors in a Err(W) if this result is an error.
If the error type FE is an ErrorList<BoxedError>, its individual errors
will be unpacked and added to the stash, rather than nesting the entire
ErrorList as a single error.