use smallvec::SmallVec;
use crate::datatypes::validated::core::Validated;
use crate::traits::applicative::Applicative;
use crate::traits::bifunctor::Bifunctor;
use crate::traits::foldable::Foldable;
use crate::traits::functor::Functor;
use crate::traits::hkt::{BinaryHKT, HKT};
use crate::traits::monad::Monad;
use crate::traits::pure::Pure;
use crate::traits::semigroup::Semigroup;
use quickcheck::{Arbitrary, Gen};
impl<E, A> HKT for Validated<E, A> {
type Source = A;
type Output<T> = Validated<E, T>;
}
impl<E: Clone, A: Clone> Pure for Validated<E, A> {
#[inline]
fn pure<T: Clone>(x: &T) -> Self::Output<T> {
Validated::Valid(x.clone())
}
#[inline]
fn pure_owned<T: Clone>(x: T) -> Self::Output<T> {
Validated::Valid(x)
}
}
impl<E: Clone, A: Clone> Functor for Validated<E, A> {
#[inline]
fn fmap<B, F>(&self, f: F) -> Self::Output<B>
where
F: Fn(&Self::Source) -> B,
B: Clone,
{
match self {
Validated::Valid(x) => Validated::Valid(f(x)),
Validated::Invalid(e) => Validated::Invalid(e.clone()),
}
}
#[inline]
fn fmap_owned<B, F>(self, f: F) -> Self::Output<B>
where
Self: Sized,
F: FnOnce(Self::Source) -> B,
{
match self {
Validated::Valid(x) => Validated::Valid(f(x)),
Validated::Invalid(e) => Validated::Invalid(e),
}
}
}
impl<E, A> BinaryHKT for Validated<E, A> {
type Source2 = E;
type BinaryOutput<U, V> = Validated<V, U>;
fn map_second<F, C>(&self, f: F) -> Self::BinaryOutput<A, C>
where
F: Fn(&Self::Source2) -> C,
Self::Source: Clone,
Self::Source2: Clone,
C: Clone,
{
match self {
Validated::Valid(x) => Validated::Valid(x.clone()),
Validated::Invalid(es) => {
let transformed: SmallVec<[C; 4]> = es.iter().map(f).collect();
Validated::Invalid(transformed)
},
}
}
fn map_second_owned<F, C>(self, f: F) -> Self::BinaryOutput<A, C>
where
F: Fn(Self::Source2) -> C,
C: Clone,
{
match self {
Validated::Valid(x) => Validated::Valid(x),
Validated::Invalid(es) => {
let transformed: SmallVec<[C; 4]> = es.into_iter().map(f).collect();
Validated::Invalid(transformed)
},
}
}
}
impl<E: Clone, A: Clone> Bifunctor for Validated<E, A> {
fn bimap<C, D, F, G>(&self, f: F, g: G) -> Self::BinaryOutput<C, D>
where
F: Fn(&Self::Source) -> C,
G: Fn(&Self::Source2) -> D,
C: Clone,
D: Clone,
{
match self {
Validated::Valid(x) => Validated::Valid(f(x)),
Validated::Invalid(es) => {
let transformed: SmallVec<[D; 4]> = es.iter().map(g).collect();
Validated::Invalid(transformed)
},
}
}
fn first<C, F>(&self, f: F) -> Self::BinaryOutput<C, Self::Source2>
where
F: Fn(&Self::Source) -> C,
C: Clone,
{
match self {
Validated::Valid(x) => Validated::Valid(f(x)),
Validated::Invalid(e) => Validated::Invalid(e.clone()),
}
}
fn second<D, G>(&self, g: G) -> Self::BinaryOutput<Self::Source, D>
where
G: Fn(&Self::Source2) -> D,
D: Clone,
{
match self {
Validated::Valid(x) => Validated::Valid(x.clone()),
Validated::Invalid(es) => {
let transformed: SmallVec<[D; 4]> = es.iter().map(g).collect();
Validated::Invalid(transformed)
},
}
}
}
impl<E: Clone, A: Clone> Applicative for Validated<E, A> {
fn apply<T, B>(&self, value: &Self::Output<T>) -> Self::Output<B>
where
Self::Source: Fn(&T) -> B,
B: Clone,
{
match (self, value) {
(Validated::Valid(f), Validated::Valid(a)) => Validated::Valid(f(a)),
(Validated::Valid(_), Validated::Invalid(e)) => Validated::Invalid(e.clone()),
(Validated::Invalid(e), Validated::Valid(_)) => Validated::Invalid(e.clone()),
(Validated::Invalid(e1), Validated::Invalid(e2)) => {
let mut errors = SmallVec::<[E; 4]>::with_capacity(e1.len() + e2.len());
errors.extend(e1.iter().cloned());
errors.extend(e2.iter().cloned());
Validated::Invalid(errors)
},
}
}
fn apply_owned<T, B>(self, value: Self::Output<T>) -> Self::Output<B>
where
Self::Source: Fn(T) -> B,
T: Clone,
B: Clone,
{
match (self, value) {
(Validated::Valid(f), Validated::Valid(x)) => Validated::Valid(f(x)),
(a, b) => {
let mut errors = SmallVec::<[E; 4]>::new();
if let Validated::Invalid(e) = a {
errors.extend(e);
}
if let Validated::Invalid(e) = b {
errors.extend(e);
}
Validated::Invalid(errors)
},
}
}
fn lift2<T, U, C, F>(f: F, fa: &Self::Output<T>, fb: &Self::Output<U>) -> Self::Output<C>
where
F: Fn(&T, &U) -> C,
T: Clone,
U: Clone,
C: Clone,
Self: Sized,
{
match (fa, fb) {
(Validated::Valid(a), Validated::Valid(b)) => Validated::Valid(f(a, b)),
_ => {
let mut errors = SmallVec::<[E; 4]>::new();
if let Validated::Invalid(es) = fa {
errors.extend(es.iter().cloned());
}
if let Validated::Invalid(es) = fb {
errors.extend(es.iter().cloned());
}
Validated::Invalid(errors)
},
}
}
fn lift2_owned<T, U, C, F>(f: F, fa: Self::Output<T>, fb: Self::Output<U>) -> Self::Output<C>
where
F: Fn(T, U) -> C,
T: Clone,
U: Clone,
C: Clone,
Self: Sized,
{
match (fa, fb) {
(Validated::Valid(a), Validated::Valid(b)) => Validated::Valid(f(a, b)),
(a, b) => {
let mut errors = SmallVec::<[E; 4]>::new();
if let Validated::Invalid(e) = a {
errors.extend(e);
}
if let Validated::Invalid(e) = b {
errors.extend(e);
}
Validated::Invalid(errors)
},
}
}
#[inline]
fn lift3<T, U, V, C, F>(
f: F, fa: &Self::Output<T>, fb: &Self::Output<U>, fc: &Self::Output<V>,
) -> Self::Output<C>
where
F: Fn(&T, &U, &V) -> C,
T: Clone,
U: Clone,
V: Clone,
C: Clone,
Self: Sized,
{
match (fa, fb, fc) {
(Validated::Valid(a), Validated::Valid(b), Validated::Valid(c)) => {
Validated::Valid(f(a, b, c))
},
_ => {
let mut errors = SmallVec::<[E; 4]>::new();
if let Validated::Invalid(es) = fa {
errors.extend(es.iter().cloned());
}
if let Validated::Invalid(es) = fb {
errors.extend(es.iter().cloned());
}
if let Validated::Invalid(es) = fc {
errors.extend(es.iter().cloned());
}
Validated::Invalid(errors)
},
}
}
fn lift3_owned<T, U, V, C, F>(
f: F, fa: Self::Output<T>, fb: Self::Output<U>, fc: Self::Output<V>,
) -> Self::Output<C>
where
F: Fn(T, U, V) -> C,
T: Clone,
U: Clone,
V: Clone,
C: Clone,
Self: Sized,
{
match (fa, fb, fc) {
(Validated::Valid(a), Validated::Valid(b_val), Validated::Valid(c_val)) => {
Validated::Valid(f(a, b_val, c_val))
},
(Validated::Invalid(e1), Validated::Invalid(e2), Validated::Invalid(e3)) => {
let mut errors = SmallVec::<[E; 4]>::with_capacity(e1.len() + e2.len() + e3.len());
errors.extend(e1);
errors.extend(e2);
errors.extend(e3);
Validated::Invalid(errors)
},
(a, b, c) => {
let mut errors = SmallVec::<[E; 4]>::new();
if let Validated::Invalid(e) = a {
errors.extend(e);
}
if let Validated::Invalid(e) = b {
errors.extend(e);
}
if let Validated::Invalid(e) = c {
errors.extend(e);
}
Validated::Invalid(errors)
},
}
}
}
impl<E: Clone, A: Clone> Monad for Validated<E, A> {
#[inline]
fn bind<U, F>(&self, f: F) -> Self::Output<U>
where
U: Clone,
F: Fn(&Self::Source) -> Self::Output<U>,
{
match self {
Validated::Valid(a) => f(a),
Validated::Invalid(e) => Validated::Invalid(e.clone()),
}
}
#[inline]
fn join<U>(&self) -> Self::Output<U>
where
Self::Source: Clone + Into<Self::Output<U>>,
U: Clone,
E: Clone,
{
match self {
Validated::Valid(inner) => inner.clone().into(),
Validated::Invalid(e) => Validated::Invalid(e.clone()),
}
}
#[inline]
fn bind_owned<U, F>(self, f: F) -> Self::Output<U>
where
U: Clone,
F: FnOnce(Self::Source) -> Self::Output<U>,
{
match self {
Validated::Valid(a) => f(a),
Validated::Invalid(e) => Validated::Invalid(e),
}
}
#[inline]
fn join_owned<U>(self) -> Self::Output<U>
where
Self::Source: Into<Self::Output<U>>,
{
match self {
Validated::Valid(inner) => inner.into(),
Validated::Invalid(e) => Validated::Invalid(e),
}
}
}
impl<E, A> Foldable for Validated<E, A> {
#[inline]
fn fold_left<U, F>(&self, init: &U, f: F) -> U
where
F: Fn(&U, &Self::Source) -> U,
U: Clone,
{
match self {
Validated::Valid(a) => f(init, a),
_ => init.clone(),
}
}
#[inline]
fn fold_right<U, F>(&self, init: &U, f: F) -> U
where
F: Fn(&Self::Source, &U) -> U,
U: Clone,
{
match self {
Validated::Valid(a) => f(a, init),
_ => init.clone(),
}
}
}
impl<E: Clone, A: Clone> Semigroup for Validated<E, A> {
fn combine(&self, other: &Self) -> Self {
match (self, other) {
(Validated::Valid(_), _) => self.clone(),
(Validated::Invalid(_), Validated::Valid(_)) => other.clone(),
(Validated::Invalid(e1), Validated::Invalid(e2)) => {
let mut errors = SmallVec::<[E; 4]>::with_capacity(e1.len() + e2.len());
errors.extend(e1.iter().cloned());
errors.extend(e2.iter().cloned());
Validated::Invalid(errors)
},
}
}
fn combine_owned(self, other: Self) -> Self {
match (self, other) {
(s @ Validated::Valid(_), _) => s,
(Validated::Invalid(_), o @ Validated::Valid(_)) => o,
(Validated::Invalid(mut e1), Validated::Invalid(e2)) => {
e1.extend(e2);
Validated::Invalid(e1)
},
}
}
}
impl<E, A> Arbitrary for Validated<E, A>
where
E: Arbitrary,
A: Arbitrary,
{
fn arbitrary(g: &mut Gen) -> Self {
let x = A::arbitrary(g);
let y = E::arbitrary(g);
if bool::arbitrary(g) {
Validated::valid(x)
} else {
Validated::invalid(y)
}
}
}