resultit/lib.rs
1//! Rust iterators return `Option<Item>`, but what happens if `Item` is a `Result` that could possibly be `Err`? This crate supplies iterator adapters to simplify working with so-called "fallible" iterators. The supplied adapters are independent of each other; you can use the whole crate with `use resultit::*;` or just the iterator adapter traits you want with (for instance) `use resultit::FlattenResults`. You are also free to take individual files (e.g. flatten_results.rs) and use them in your own source tree without depending on this crate.
2//!
3//! Example:
4//!
5//! ```
6//! # struct Error1;
7//! # impl std::fmt::Display for Error1 {
8//! # fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
9//! # write!(f, "Error1")
10//! # }
11//! # }
12//! # impl std::fmt::Debug for Error1 {
13//! # fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14//! # <Error1 as std::fmt::Display>::fmt(self, f)
15//! # }
16//! # }
17//! # impl std::error::Error for Error1 { }
18//! #
19//! # struct Error2;
20//! # impl std::fmt::Display for Error2 {
21//! # fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22//! # write!(f, "Error2")
23//! # }
24//! # }
25//! # impl std::fmt::Debug for Error2 {
26//! # fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27//! # <Error2 as std::fmt::Display>::fmt(self, f)
28//! # }
29//! # }
30//! # impl std::error::Error for Error2 { }
31//! #
32//! // Use the flatten_results() and stop_after_error() iterator adapters.
33//! use resultit::FlattenResults;
34//! use resultit::StopAfterError;
35//!
36//! // Use the TryError convenience/shorthand type.
37//! use resultit::TryResult;
38//!
39//! // Nested vector of results with different error types.
40//! let v: Vec<Result<Vec<Result<i32, Error2>>, Error1>> = vec![
41//! Ok(vec![Ok(1), Ok(2)]),
42//! Ok(vec![Ok(3), Ok(4)]),
43//! Ok(vec![Err(Error2{}), Ok(5)]),
44//! Ok(vec![Ok(6), Ok(7)])
45//! ];
46//!
47//! // Flatten v, stopping after the first error.
48//! let v: Vec<TryResult<i32>> = v.into_iter()
49//! // Flatten the inner vectors.
50//! .flatten_results()
51//! // Flatten/erase error types by converting
52//! // Result<Result<i32, Error2>, Error1> to Result<i32, E>
53//! // where E is a boxed error trait object.
54//! .map(|res| -> TryResult<_> { Ok(res??) } )
55//! // Stop iterating after the first error is encountered.
56//! .stop_after_error()
57//! // Collect into vector v for this example.
58//! // Could just as easily have done try_for_each() or any other adapter.
59//! .collect();
60//!
61//! println!("{:?}", v);
62//! // [Ok(1), Ok(2), Ok(3), Ok(4), Err(Error2)]
63//! # assert_eq!(v.len(), 5);
64//! # assert_eq!(*v[0].as_ref().unwrap(), 1);
65//! # assert_eq!(*v[1].as_ref().unwrap(), 2);
66//! # assert_eq!(*v[2].as_ref().unwrap(), 3);
67//! # assert_eq!(*v[3].as_ref().unwrap(), 4);
68//! # assert_eq!(v[4].is_err(), true);
69//! #
70//! # // Additional testing embedded in rustdoc.
71//! # let v: Vec<Result<Vec<Result<i32, Error2>>, Error1>> = vec![
72//! # Ok(vec![Ok(1), Ok(2)]),
73//! # Ok(vec![Ok(3), Ok(4)]),
74//! # Err(Error1{}),
75//! # Ok(vec![Ok(5), Ok(6)])
76//! # ];
77//! # let v: Vec<TryResult<i32>> = v.into_iter()
78//! # .flatten_results()
79//! # .map(|res| -> TryResult<_> { Ok(res??) } )
80//! # .stop_after_error()
81//! # .collect();
82//! # println!("{:?}", v);
83//! # // [Ok(1), Ok(2), Ok(3), Ok(4), Err(Error1)]
84//! # assert_eq!(v.len(), 5);
85//! # assert_eq!(*v[0].as_ref().unwrap(), 1);
86//! # assert_eq!(*v[1].as_ref().unwrap(), 2);
87//! # assert_eq!(*v[2].as_ref().unwrap(), 3);
88//! # assert_eq!(*v[3].as_ref().unwrap(), 4);
89//! # assert_eq!(v[4].is_err(), true);
90//! #
91//! # let v: Vec<Result<Vec<Result<i32, Error2>>, Error1>> = vec![
92//! # Ok(vec![Ok(1), Ok(2)]),
93//! # Ok(vec![Ok(3), Ok(4)]),
94//! # Ok(vec![Ok(5), Err(Error2{})]),
95//! # Ok(vec![Ok(6), Ok(7)])
96//! # ];
97//! # let v: Vec<TryResult<i32>> = v.into_iter()
98//! # .flatten_results()
99//! # .map(|res| -> TryResult<_> { Ok(res??) } )
100//! # .stop_after_error()
101//! # .collect();
102//! # println!("{:?}", v);
103//! # // [Ok(1), Ok(2), Ok(3), Ok(4), Ok(5), Err(Error2)]
104//! # assert_eq!(v.len(), 6);
105//! # assert_eq!(*v[0].as_ref().unwrap(), 1);
106//! # assert_eq!(*v[1].as_ref().unwrap(), 2);
107//! # assert_eq!(*v[2].as_ref().unwrap(), 3);
108//! # assert_eq!(*v[3].as_ref().unwrap(), 4);
109//! # assert_eq!(*v[4].as_ref().unwrap(), 5);
110//! # assert_eq!(v[5].is_err(), true);
111//! ```
112
113// Re-export iterator adapter traits from submodules.
114pub mod flatten_results;
115pub use flatten_results::FlattenResults;
116pub mod stop_after_error;
117pub use stop_after_error::StopAfterError;
118
119/// Shorthand for a Result with a boxed error trait.
120/// Provided for convenience, not a dependency of any submodule.
121///
122/// Particularly useful for flattening iterators of nested results by
123/// flattening/combining/erasing the error types. See the the
124/// [crate level documentation](crate) for an example of how to do this. A
125/// simpler example of what this type does follows below:
126///
127/// ```
128/// // Trivial case in which we return just one error type.
129/// fn parse1(num: &str) -> Result<i32, <i32 as std::str::FromStr>::Err> {
130/// return num.parse();
131/// }
132///
133/// // What if our function can return more than one error type?
134/// // We can return a boxed error trait to erase the type of the error.
135/// // We can use then use the ? (aka try) operator to propagate errors.
136/// // For maximum compatibility with threaded programs,
137/// // the error should also implement send and sync.
138/// fn parse2(num: &str) -> Result<i32, std::boxed::Box<
139/// dyn std::error::Error
140/// + std::marker::Send
141/// + std::marker::Sync
142/// >> {
143/// // do_something_fallible()?;
144/// let parsed_num = (num.parse())?;
145/// return Ok(parsed_num);
146/// }
147///
148/// // Same as parse2() but using TryResult<i32> as shorthand.
149/// fn parse3(num: &str) -> resultit::TryResult<i32> {
150/// // do_something_fallible()?;
151/// let parsed_num = (num.parse())?;
152/// return Ok(parsed_num);
153/// }
154/// # assert_eq!(parse1("42").unwrap(), 42);
155/// # assert_eq!(parse2("42").unwrap(), 42);
156/// # assert_eq!(parse3("42").unwrap(), 42);
157/// ```
158pub type TryResult<T> = std::result::Result<
159 T,
160 std::boxed::Box< dyn
161 std::error::Error // must implement Error to satisfy Try
162 + std::marker::Send // needed to move errors between threads
163 + std::marker::Sync // needed to move errors between threads
164 >
165>;