this_is_fine/
lib.rs

1//! Utilities for working with <code>type [Fine<T, E>] = (T, [Result<(), E>](`Result`))</code>.
2//!
3//! This crate for the most part just ports [`Result`]'s API onto [`Fine`]. See [`Fine`] for the full API.
4//!
5//! Note that any "`and`"-, "`or`" and "`iter`"-style methods that appear on [`Result`] are excluded from the extensions.
6//!
7//! If you need one of them, or to escalate with [`?`](https://doc.rust-lang.org/stable/reference/expressions/operator-expr.html#the-question-mark-operator),
8//! first call [`.not_fine()`](`FineExt::not_fine`) to crumple the [`Fine<T, E>`] into a classic [`Result<T, E>`].
9//!
10//! (More) `transpose` and `flatten` methods are also excluded, unless I figure out what makes the most sense there.
11//!
12//! ☕🐕
13
14#![doc(html_root_url = "https://docs.rs/this-is-fine/0.0.1")]
15#![warn(clippy::pedantic)]
16#![allow(clippy::semicolon_if_nothing_returned)]
17#![no_std]
18
19use core::{
20	fmt::Debug,
21	ops::{Deref, DerefMut},
22};
23
24#[cfg(doctest)]
25pub mod readme {
26	doc_comment::doctest!("../README.md");
27}
28
29/// Broadly speaking, this is the result of an operation that *sort of* can't fail.
30///
31/// # Added Methods
32///
33#[allow(clippy::doc_markdown)]
34/// - <code>[.fine()](`FineExt::fine`) -> T</code>
35/// - <code>[.not_fine()](`FineExt::not_fine`) -> [Result<T, E>]</code>
36#[must_use]
37pub type Fine<T, E> = (T, Result<(), E>);
38
39/// Creates a [`Fine`] from a pair of a value and optional error.
40pub fn from_inverse<T, E>((value, error): (T, Option<E>)) -> Fine<T, E> {
41	(value, error.map_or(Ok(()), Err))
42}
43
44pub mod prelude {
45	pub use crate::{
46		FineExt, FineExtWhereEDebug, FineExtWhereTDebug, FineExtWhereTDeref, FineExtWhereTDerefMut,
47		FineTransposeExt,
48	};
49}
50
51pub trait FineExt<T, E> {
52	/// Returns [`true`] iff the [`Result`] is [`Ok(())`](`Ok`).
53	#[must_use]
54	fn is_ok(&self) -> bool;
55
56	/// Returns [`true`] iff the [`Result`] is [`Err`].
57	#[must_use]
58	fn is_err(&self) -> bool;
59
60	/// Converts from [`Fine<T, E>`] to [`Option<T>`].
61	///
62	/// Only [`Some`] if the [`Result`] was [`Ok`].
63	fn ok(self) -> Option<T>;
64
65	/// Unwraps the `T`, ignoring any [`Err`].
66	fn fine(self) -> T;
67
68	/// Converts from [`Fine<T, E>`] to [`Option<E>`].
69	///
70	/// Equivalent to [`.1.err()`](`Result::err`).
71	#[must_use = "It's unclear whether you meant to discard the error. Prefer `.fine()` if you do."]
72	fn err(self) -> Option<E>;
73
74	/// Converts from [`Fine<T, E>`] to [`Result<T, E>`].
75	///
76	/// # Errors
77	///
78	/// Iff the [`Result`] was [`Err`], in which case the `T` is discarded.
79	fn not_fine(self) -> Result<T, E>;
80
81	/// Converts from [`&Fine<T, E>`](`Fine`) to [`Fine<&T, &E>`].
82	///
83	/// Produces a new [`Fine`], containing one or two references into the original, leaving the original in place.
84	fn as_ref(&self) -> Fine<&T, &E>;
85
86	/// Converts from [`&mut Fine<T, E>`](`Fine`) to [`Fine<&mut T, &mut E>`].
87	///
88	/// Produces a new [`Fine`], containing one or two references into the original, leaving the original in place.
89	fn as_mut(&mut self) -> Fine<&mut T, &mut E>;
90
91	/// Maps a [`Fine<T, E>`] to [`Fine<U, E>`],
92	/// by *unconditionally* applying a function to the contained `T`,
93	/// leaving the [`Result`] untouched.
94	fn map<U, F>(self, op: F) -> Fine<U, E>
95	where
96		F: FnOnce(T) -> U;
97
98	/// Maps a [`Fine<T, E>`] to [`Fine<T, F>`],
99	/// by applying a function to a contained [`Err`]'s `E`,
100	/// leaving the `T` untouched.
101	fn map_err<F, O>(self, op: O) -> Fine<T, F>
102	where
103		O: FnOnce(E) -> F;
104}
105impl<T, E> FineExt<T, E> for Fine<T, E> {
106	fn is_ok(&self) -> bool {
107		self.1.is_ok()
108	}
109
110	fn is_err(&self) -> bool {
111		self.1.is_err()
112	}
113
114	fn ok(self) -> Option<T> {
115		self.1.is_ok().then(|| self.0)
116	}
117
118	fn fine(self) -> T {
119		self.0
120	}
121
122	fn err(self) -> Option<E> {
123		self.1.err()
124	}
125
126	fn not_fine(self) -> Result<T, E> {
127		self.1?;
128		Ok(self.0)
129	}
130
131	fn as_ref(&self) -> Fine<&T, &E> {
132		(&self.0, self.1.as_ref().err().map_or(Ok(()), Err))
133	}
134
135	fn as_mut(&mut self) -> Fine<&mut T, &mut E> {
136		(&mut self.0, self.1.as_mut().err().map_or(Ok(()), Err))
137	}
138
139	fn map<U, F>(self, op: F) -> Fine<U, E>
140	where
141		F: FnOnce(T) -> U,
142	{
143		(op(self.0), self.1)
144	}
145
146	fn map_err<F, O>(self, op: O) -> Fine<T, F>
147	where
148		O: FnOnce(E) -> F,
149	{
150		(self.0, self.1.map_err(op))
151	}
152}
153
154pub trait FineExtWhereEDebug<T, E>
155where
156	E: Debug,
157{
158	/// Unwraps the `T`.
159	///
160	/// # Panics
161	///
162	/// Iff the [`Result`] is [`Err`], with a panic message including `msg` and the content of the [`Err`].
163	#[track_caller]
164	fn expect(self, msg: &str) -> T;
165
166	/// Unwraps the `T`.
167	///
168	/// # Panics
169	///
170	/// Iff the [`Result`] is [`Err`], with a panic message provided by the [`Err`]'s value.
171	#[track_caller]
172	fn unwrap(self) -> T;
173}
174impl<T, E> FineExtWhereEDebug<T, E> for Fine<T, E>
175where
176	E: Debug,
177{
178	#[track_caller]
179	fn expect(self, msg: &str) -> T {
180		self.1.expect(msg);
181		self.0
182	}
183
184	#[track_caller]
185	fn unwrap(self) -> T {
186		self.1.unwrap();
187		self.0
188	}
189}
190
191pub trait FineExtWhereTDebug<T, E>
192where
193	T: Debug,
194{
195	/// Unwraps the `E`.
196	///
197	/// # Panics
198	///
199	/// Iff the [`Result`] is not [`Err`], with a panic message including `msg` and the `T`.
200	#[track_caller]
201	fn expect_err(self, msg: &str) -> E;
202
203	/// Unwraps the `E`.
204	///
205	/// # Panics
206	///
207	/// Iff the [`Result`] is [`Err`], with a panic message provided by the `T`.
208	#[track_caller]
209	fn unwrap_err(self) -> E;
210}
211impl<T, E> FineExtWhereTDebug<T, E> for Fine<T, E>
212where
213	T: Debug,
214{
215	#[track_caller]
216	fn expect_err(self, msg: &str) -> E {
217		self.not_fine().expect_err(msg)
218	}
219
220	#[track_caller]
221	fn unwrap_err(self) -> E {
222		self.not_fine().unwrap_err()
223	}
224}
225
226pub trait FineExtWhereTDeref<T, E>
227where
228	T: Deref,
229{
230	/// Coerces the `T` via [`Deref`] and returns a new [`Fine`] referencing the original.
231	fn as_deref(&self) -> Fine<&<T as Deref>::Target, &E>;
232}
233impl<T, E> FineExtWhereTDeref<T, E> for Fine<T, E>
234where
235	T: Deref,
236{
237	fn as_deref(&self) -> Fine<&<T as Deref>::Target, &E> {
238		self.as_ref().map(Deref::deref)
239	}
240}
241
242pub trait FineExtWhereTDerefMut<T, E>
243where
244	T: DerefMut,
245{
246	/// Coerces the `T` via [`DerefMut`] and returns a new [`Fine`] referencing the original.
247	fn as_deref_mut(&mut self) -> Fine<&mut <T as Deref>::Target, &mut E>;
248}
249impl<T, E> FineExtWhereTDerefMut<T, E> for Fine<T, E>
250where
251	T: DerefMut,
252{
253	fn as_deref_mut(&mut self) -> Fine<&mut <T as Deref>::Target, &mut E> {
254		self.as_mut().map(DerefMut::deref_mut)
255	}
256}
257
258pub trait FineTransposeExt<T, E0, E1> {
259	/// Exchanges the [`Result`]s of nested [`Fine`]s.
260	fn transpose(self) -> Fine<Fine<T, E1>, E0>;
261}
262impl<T, E0, E1> FineTransposeExt<T, E0, E1> for Fine<Fine<T, E0>, E1> {
263	fn transpose(self) -> Fine<Fine<T, E1>, E0> {
264		let ((t, e0), e1) = self;
265		((t, e1), e0)
266	}
267}