#![doc(html_root_url = "https://docs.rs/this-is-fine/0.0.1")]
#![warn(clippy::pedantic)]
#![allow(clippy::semicolon_if_nothing_returned)]
#![no_std]
use core::{
fmt::Debug,
ops::{Deref, DerefMut},
};
#[cfg(doctest)]
pub mod readme {
doc_comment::doctest!("../README.md");
}
#[allow(clippy::doc_markdown)]
#[must_use]
pub type Fine<T, E> = (T, Result<(), E>);
pub fn from_inverse<T, E>((value, error): (T, Option<E>)) -> Fine<T, E> {
(value, error.map_or(Ok(()), Err))
}
pub mod prelude {
pub use crate::{
FineExt, FineExtWhereEDebug, FineExtWhereTDebug, FineExtWhereTDeref, FineExtWhereTDerefMut,
FineTransposeExt,
};
}
pub trait FineExt<T, E> {
#[must_use]
fn is_ok(&self) -> bool;
#[must_use]
fn is_err(&self) -> bool;
fn ok(self) -> Option<T>;
fn fine(self) -> T;
#[must_use = "It's unclear whether you meant to discard the error. Prefer `.fine()` if you do."]
fn err(self) -> Option<E>;
fn not_fine(self) -> Result<T, E>;
fn as_ref(&self) -> Fine<&T, &E>;
fn as_mut(&mut self) -> Fine<&mut T, &mut E>;
fn map<U, F>(self, op: F) -> Fine<U, E>
where
F: FnOnce(T) -> U;
fn map_err<F, O>(self, op: O) -> Fine<T, F>
where
O: FnOnce(E) -> F;
}
impl<T, E> FineExt<T, E> for Fine<T, E> {
fn is_ok(&self) -> bool {
self.1.is_ok()
}
fn is_err(&self) -> bool {
self.1.is_err()
}
fn ok(self) -> Option<T> {
self.1.is_ok().then(|| self.0)
}
fn fine(self) -> T {
self.0
}
fn err(self) -> Option<E> {
self.1.err()
}
fn not_fine(self) -> Result<T, E> {
self.1?;
Ok(self.0)
}
fn as_ref(&self) -> Fine<&T, &E> {
(&self.0, self.1.as_ref().err().map_or(Ok(()), Err))
}
fn as_mut(&mut self) -> Fine<&mut T, &mut E> {
(&mut self.0, self.1.as_mut().err().map_or(Ok(()), Err))
}
fn map<U, F>(self, op: F) -> Fine<U, E>
where
F: FnOnce(T) -> U,
{
(op(self.0), self.1)
}
fn map_err<F, O>(self, op: O) -> Fine<T, F>
where
O: FnOnce(E) -> F,
{
(self.0, self.1.map_err(op))
}
}
pub trait FineExtWhereEDebug<T, E>
where
E: Debug,
{
#[track_caller]
fn expect(self, msg: &str) -> T;
#[track_caller]
fn unwrap(self) -> T;
}
impl<T, E> FineExtWhereEDebug<T, E> for Fine<T, E>
where
E: Debug,
{
#[track_caller]
fn expect(self, msg: &str) -> T {
self.1.expect(msg);
self.0
}
#[track_caller]
fn unwrap(self) -> T {
self.1.unwrap();
self.0
}
}
pub trait FineExtWhereTDebug<T, E>
where
T: Debug,
{
#[track_caller]
fn expect_err(self, msg: &str) -> E;
#[track_caller]
fn unwrap_err(self) -> E;
}
impl<T, E> FineExtWhereTDebug<T, E> for Fine<T, E>
where
T: Debug,
{
#[track_caller]
fn expect_err(self, msg: &str) -> E {
self.not_fine().expect_err(msg)
}
#[track_caller]
fn unwrap_err(self) -> E {
self.not_fine().unwrap_err()
}
}
pub trait FineExtWhereTDeref<T, E>
where
T: Deref,
{
fn as_deref(&self) -> Fine<&<T as Deref>::Target, &E>;
}
impl<T, E> FineExtWhereTDeref<T, E> for Fine<T, E>
where
T: Deref,
{
fn as_deref(&self) -> Fine<&<T as Deref>::Target, &E> {
self.as_ref().map(Deref::deref)
}
}
pub trait FineExtWhereTDerefMut<T, E>
where
T: DerefMut,
{
fn as_deref_mut(&mut self) -> Fine<&mut <T as Deref>::Target, &mut E>;
}
impl<T, E> FineExtWhereTDerefMut<T, E> for Fine<T, E>
where
T: DerefMut,
{
fn as_deref_mut(&mut self) -> Fine<&mut <T as Deref>::Target, &mut E> {
self.as_mut().map(DerefMut::deref_mut)
}
}
pub trait FineTransposeExt<T, E0, E1> {
fn transpose(self) -> Fine<Fine<T, E1>, E0>;
}
impl<T, E0, E1> FineTransposeExt<T, E0, E1> for Fine<Fine<T, E0>, E1> {
fn transpose(self) -> Fine<Fine<T, E1>, E0> {
let ((t, e0), e1) = self;
((t, e1), e0)
}
}