err_into/
lib.rs

1#![no_std]
2//! A `no_std` library to simpify chaining methods when you are returning a [`Result`]. It is a
3//! trivial library which sould be compatible with all environments.
4//!
5//! This is specially noticeable when using crates like [`anyhow`](https://crates.io/crates/anyhow)
6//! which provide a "catch all" error type, so you need to convert all errors you recieve.
7//!
8//! It is also helpful when you have many custom errors constructed with
9//! [`thiserror`](https://crates.io/crates/thiserror) or
10//! [`justerror`](https://crates.io/crates/justerror), or use many libraries with different error
11//! types.
12//!
13//! # Usage
14//!
15//! Import the traits and you can benefit from it immediately:
16//!
17//! ```rust
18//! use err_into::MapInto;
19//! use err_into::ErrorInto;
20//! use err_into::ResultInto;
21//!
22//! // ...
23//!
24//! let _: Option<i32> = Some(0u8).map_into();
25//! let _: Result<i32, ()> = Ok(0u8).map_into();
26//! let _: Result<(), i32> = Err(0u8).err_into();
27//! let _: Result<u16, i32> = (if false { Ok(0u8) } else { Err(0i8) }).res_into();
28//! ```
29//!
30//! ## Motivating example
31//!
32//! This is slightly contrived because I don't want to depend on any libraries but showcases where
33//! `err_into` excels:
34//!
35//! ```rust
36//! use err_into::ErrorInto;
37//!
38//! fn process(val: u16) -> Result<u8, u8> {
39//!     if val > 255 {
40//!         Err((val >> 8) as u8)
41//!     } else {
42//!         Ok(val as _)
43//!     }
44//! }
45//!
46//! fn long_chain() -> Result<u8, i32> {
47//!     (0u16..16u16).map(|x| x * x * x * x)
48//!         .filter(|x| x % 2 == 0)
49//!         .map(process)
50//!         .next()
51//!         .unwrap_or(Err(0))
52//!         .err_into()
53//! }
54//!
55//! fn long_chain_no_err_into() -> Result<u8, i32> {
56//!     // May be confusing
57//!     (0u16..16u16).map(|x| x * x * x * x)
58//!         .filter(|x| x % 2 == 0)
59//!         .map(process)
60//!         .next()
61//!         .unwrap_or(Err(0))
62//!         .map_err(Into::into)
63//! }
64//!
65//! fn long_chain_no_map_err() -> Result<u8, i32> {
66//!     // Please don't do this
67//!     Ok((0u16..16u16).map(|x| x * x * x * x)
68//!         .filter(|x| x % 2 == 0)
69//!         .map(process)
70//!         .next()
71//!         .unwrap_or(Err(0))?)
72//! }
73//! ```
74
75/// Maps an error using [`Into::into`]
76///
77/// Short version of `Result::map_err(self, Into::into)` that simplifies operation chains like
78///
79/// ```rust
80/// use err_into::ErrorInto;
81///
82/// fn get_data() -> Result<(), u8> {
83///     Err(0u8)
84/// }
85///
86/// fn handle_data_question_mark() -> Result<(), i32> {
87///     // Can't be split into multiple lines
88///     Ok(get_data()?)
89/// }
90///
91/// fn handle_data_map_err() -> Result<(), i32> {
92///     // Slightly harder to read
93///     get_data().map_err(Into::into)
94/// }
95///
96/// fn handle_data_err_into() -> Result<(), i32> {
97///     get_data().err_into()
98/// }
99///
100/// assert_eq!(handle_data_err_into(), handle_data_question_mark());
101/// assert_eq!(handle_data_err_into(), handle_data_map_err());
102/// ```
103pub trait ErrorInto<T, E> {
104    fn err_into(self) -> Result<T, E>;
105}
106
107/// Maps both the Value and the Error of a [`Result`] using [`Into::into`]
108///
109/// Shorthand for `result.map(Into::into).map_err(Into::into)`
110///
111/// ```rust
112/// use err_into::ResultInto;
113///
114/// let res: Result<u8, i8> = Ok(0);
115/// let _: Result<i32, i16> = res.res_into();
116/// ```
117pub trait ResultInto<T, E> {
118    fn res_into(self) -> Result<T, E>;
119}
120
121/// Maps a value using [`Into::into`]
122///
123/// Shorthand for `Option::map(self, Into::into)` and `Result::map(self, Into::into)`
124///
125/// ```rust
126/// use err_into::MapInto;
127///
128/// let value = Some(0u8);
129/// let map_into: Option<i32> = value.map_into();
130/// let map_into_std: Option<i32> = value.map(Into::into);
131/// assert_eq!(map_into, map_into_std);
132///
133/// let result = Ok(0u8);
134/// let map_into: Result<i32, ()> = result.map_into();
135/// let map_into_std: Result<i32, ()> = result.map(Into::into);
136/// assert_eq!(map_into, map_into_std);
137/// ```
138pub trait MapInto<T> {
139    fn map_into(self) -> T;
140}
141
142impl<T, E, F> ErrorInto<T, E> for Result<T, F>
143where
144    F: Into<E>,
145{
146    fn err_into(self) -> Result<T, E> {
147        self.map_err(Into::into)
148    }
149}
150
151impl<T, U, E, F> ResultInto<T, E> for Result<U, F>
152where
153    F: Into<E>,
154    U: Into<T>,
155{
156    fn res_into(self) -> Result<T, E> {
157        self.map(Into::into).map_err(Into::into)
158    }
159}
160
161impl<T, U, E> MapInto<Result<U, E>> for Result<T, E>
162where
163    T: Into<U>,
164{
165    fn map_into(self) -> Result<U, E> {
166        self.map(Into::into)
167    }
168}
169
170impl<T, U> MapInto<Option<U>> for Option<T>
171where
172    T: Into<U>,
173{
174    fn map_into(self) -> Option<U> {
175        self.map(Into::into)
176    }
177}