use crate::datatypes::either::Either;
use crate::datatypes::validated::Validated;
use crate::traits::hkt::HKT;
use smallvec::SmallVec;
pub trait WithError<E>: HKT {
type Success;
type ErrorOutput<G>;
fn fmap_error<F, G>(self, f: F) -> Self::ErrorOutput<G>
where
F: Fn(E) -> G,
G: Clone;
fn to_result(self) -> Result<Self::Success, E>;
}
#[inline]
pub fn sequence<A, E>(collection: Vec<Result<A, E>>) -> Result<Vec<A>, E> {
sequence_result(collection)
}
#[inline]
pub fn traverse<A, B, E, F>(collection: impl IntoIterator<Item = A>, f: F) -> Result<Vec<B>, E>
where
F: FnMut(A) -> Result<B, E>,
{
traverse_result(collection, f)
}
pub fn traverse_validated<A, B, E, F>(
collection: impl IntoIterator<Item = A>, mut f: F,
) -> Validated<E, Vec<B>>
where
F: FnMut(A) -> Result<B, E>,
E: Clone,
{
let mut values = Vec::new();
let mut errors = SmallVec::<[E; 4]>::new();
let mut had_error = false;
for item in collection {
match f(item) {
Ok(value) => values.push(value),
Err(error) => {
had_error = true;
errors.push(error);
},
}
}
if had_error {
Validated::Invalid(errors)
} else {
Validated::Valid(values)
}
}
#[inline]
pub fn sequence_with_error<C, T, E>(collection: Vec<C>) -> Result<Vec<T>, E>
where
C: WithError<E>,
C::Success: Clone + Into<T>,
E: Clone,
{
let mut values = Vec::with_capacity(collection.len());
for item in collection {
match item.to_result() {
Ok(value) => values.push(value.into()),
Err(error) => return Err(error),
}
}
Ok(values)
}
#[inline]
fn sequence_result<A, E>(collection: Vec<Result<A, E>>) -> Result<Vec<A>, E> {
let mut values = Vec::with_capacity(collection.len());
for item in collection {
match item {
Ok(value) => values.push(value),
Err(error) => return Err(error),
}
}
Ok(values)
}
#[inline]
fn traverse_result<A, B, E, F>(
collection: impl IntoIterator<Item = A>, mut f: F,
) -> Result<Vec<B>, E>
where
F: FnMut(A) -> Result<B, E>,
{
let mut values = Vec::new();
for item in collection {
match f(item) {
Ok(value) => values.push(value),
Err(error) => return Err(error),
}
}
Ok(values)
}
impl<T, E: Clone> WithError<E> for Result<T, E> {
type Success = T;
type ErrorOutput<G> = Result<T, G>;
fn fmap_error<F, G>(self, f: F) -> Self::ErrorOutput<G>
where
F: Fn(E) -> G,
{
match self {
Ok(t) => Ok(t),
Err(e) => Err(f(e)),
}
}
fn to_result(self) -> Result<Self::Success, E> {
self
}
}
impl<T, E> WithError<E> for Either<E, T> {
type Success = T;
type ErrorOutput<G> = Either<G, T>;
fn fmap_error<F, G>(self, f: F) -> Self::ErrorOutput<G>
where
F: Fn(E) -> G,
{
match self {
Either::Left(e) => Either::Left(f(e)),
Either::Right(t) => Either::Right(t),
}
}
fn to_result(self) -> Result<Self::Success, E> {
match self {
Either::Left(e) => Err(e),
Either::Right(t) => Ok(t),
}
}
}
impl<T: Clone, E: Clone> WithError<E> for Validated<E, T> {
type Success = T;
type ErrorOutput<G> = Validated<G, T>;
fn fmap_error<F, G>(self, f: F) -> Self::ErrorOutput<G>
where
F: Fn(E) -> G,
G: Clone,
T: Clone,
{
match self {
Validated::Valid(t) => Validated::Valid(t),
Validated::Invalid(e) => Validated::Invalid(e.into_iter().map(f).collect()),
}
}
fn to_result(self) -> Result<Self::Success, E> {
match self {
Validated::Valid(t) => Ok(t),
Validated::Invalid(e) => Err(e.into_iter().next().unwrap()),
}
}
}
pub trait ResultExt<T, E> {
#[deprecated(note = "Use `crate::error::result_to_validated` instead")]
fn to_validated(self) -> Validated<E, T>;
#[deprecated(note = "Use `crate::error::result_to_either` instead")]
fn to_either(self) -> Either<E, T>;
fn unwrap_or_default(self) -> T
where
T: Default;
#[deprecated(note = "Use `crate::error::ErrorOps::bimap_result` instead")]
fn bimap<F, G, U, E2>(self, success_map: F, error_map: G) -> Result<U, E2>
where
F: FnOnce(T) -> U,
G: FnOnce(E) -> E2;
}
impl<T, E> ResultExt<T, E> for Result<T, E> {
fn to_validated(self) -> Validated<E, T> {
use smallvec::smallvec;
match self {
Ok(value) => Validated::Valid(value),
Err(error) => Validated::Invalid(smallvec![error]),
}
}
fn to_either(self) -> Either<E, T> {
crate::error::result_to_either(self)
}
fn unwrap_or_default(self) -> T
where
T: Default,
{
self.unwrap_or_else(|_| T::default())
}
fn bimap<F, G, U, E2>(self, success_map: F, error_map: G) -> Result<U, E2>
where
F: FnOnce(T) -> U,
G: FnOnce(E) -> E2,
{
match self {
Ok(value) => Ok(success_map(value)),
Err(error) => Err(error_map(error)),
}
}
}
pub trait ErrorCategory<E> {
type ErrorFunctor<T: Clone>: WithError<E>;
fn lift<T: Clone>(value: T) -> Self::ErrorFunctor<T>;
fn handle_error<T: Clone>(error: E) -> Self::ErrorFunctor<T>;
}
impl<E: Clone> ErrorCategory<E> for Result<(), E> {
type ErrorFunctor<T: Clone> = Result<T, E>;
#[inline]
fn lift<T>(value: T) -> Result<T, E> {
Ok(value)
}
#[inline]
fn handle_error<T>(error: E) -> Result<T, E> {
Err(error)
}
}
impl<E: Clone> ErrorCategory<E> for Either<E, ()> {
type ErrorFunctor<T: Clone> = Either<E, T>;
#[inline]
fn lift<T: Clone>(value: T) -> Either<E, T> {
Either::Right(value)
}
#[inline]
fn handle_error<T: Clone>(error: E) -> Either<E, T> {
Either::Left(error)
}
}
impl<E: Clone> ErrorCategory<E> for Validated<E, ()> {
type ErrorFunctor<T: Clone> = Validated<E, T>;
#[inline]
fn lift<T: Clone>(value: T) -> Validated<E, T> {
Validated::Valid(value)
}
#[inline]
fn handle_error<T: Clone>(error: E) -> Validated<E, T> {
Validated::invalid(error)
}
}
pub trait ErrorOps<E>: WithError<E> {
fn recover<F>(self, recovery: F) -> Self
where
F: FnOnce(E) -> Self,
Self: Sized;
fn bimap_result<B, F, SuccessF, ErrorF>(
self, success_f: SuccessF, error_f: ErrorF,
) -> Result<B, F>
where
SuccessF: FnOnce(Self::Success) -> B,
ErrorF: FnOnce(E) -> F,
Self: Sized;
}
impl<T: Clone, E: Clone> ErrorOps<E> for Result<T, E> {
#[inline]
fn recover<F>(self, recovery: F) -> Self
where
F: FnOnce(E) -> Self,
{
match self {
Ok(value) => Ok(value),
Err(error) => recovery(error),
}
}
#[inline]
fn bimap_result<B, F, SuccessF, ErrorF>(
self, success_f: SuccessF, error_f: ErrorF,
) -> Result<B, F>
where
SuccessF: FnOnce(T) -> B,
ErrorF: FnOnce(E) -> F,
{
match self {
Ok(value) => Ok(success_f(value)),
Err(error) => Err(error_f(error)),
}
}
}
impl<E: Clone, T: Clone> ErrorOps<E> for Either<E, T> {
#[inline]
fn recover<F>(self, recovery: F) -> Self
where
F: FnOnce(E) -> Self,
{
match self {
Either::Right(value) => Either::Right(value),
Either::Left(error) => recovery(error),
}
}
fn bimap_result<B, F, SuccessF, ErrorF>(
self, success_f: SuccessF, error_f: ErrorF,
) -> Result<B, F>
where
SuccessF: FnOnce(Self::Success) -> B,
ErrorF: FnOnce(E) -> F,
Self: Sized,
{
match self {
Either::Right(value) => Ok(success_f(value)),
Either::Left(error) => Err(error_f(error)),
}
}
}