use crate::error::{ComposableError, ComposableResult, WithError};
use crate::traits::alternative::Alternative;
use crate::traits::applicative::Applicative;
use crate::traits::functor::Functor;
use crate::traits::hkt::HKT;
use crate::traits::monad::Monad;
use crate::traits::monad_plus::MonadPlus;
use crate::traits::pure::Pure;
use quickcheck::{Arbitrary, Gen};
use std::marker::PhantomData;
#[derive(Copy, Clone, Eq, Debug, Hash, PartialEq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Maybe<T> {
Just(T),
Nothing,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MaybeError {
ValueNotPresent,
Custom(String),
}
impl std::fmt::Display for MaybeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MaybeError::ValueNotPresent => write!(f, "Attempted to access a value in a Nothing"),
MaybeError::Custom(msg) => write!(f, "{msg}"),
}
}
}
impl std::error::Error for MaybeError {}
impl<T> Maybe<T> {
#[inline]
pub const fn some(value: T) -> Self {
Maybe::Just(value)
}
#[inline]
pub const fn none() -> Self {
Maybe::Nothing
}
#[inline]
pub fn when(condition: bool, value: T) -> Self {
if condition {
Maybe::Just(value)
} else {
Maybe::Nothing
}
}
#[inline]
pub const fn is_just(&self) -> bool {
matches!(self, Maybe::Just(_))
}
#[inline]
pub const fn is_nothing(&self) -> bool {
matches!(self, Maybe::Nothing)
}
#[inline]
pub fn from_option(opt: Option<T>) -> Self {
match opt {
Some(x) => Maybe::Just(x),
None => Maybe::Nothing,
}
}
#[inline]
pub fn to_option(self) -> Option<T> {
match self {
Maybe::Just(x) => Some(x),
Maybe::Nothing => None,
}
}
#[inline]
pub fn to_result<E>(self, error: E) -> Result<T, E> {
match self {
Maybe::Just(x) => Ok(x),
Maybe::Nothing => Err(error),
}
}
#[inline]
pub fn to_standard_result(self) -> Result<T, MaybeError> {
self.to_result(MaybeError::ValueNotPresent)
}
#[inline]
pub fn try_unwrap(self) -> ComposableResult<T, &'static str> {
match self {
Maybe::Just(val) => Ok(val),
Maybe::Nothing => Err(ComposableError::new("Cannot unwrap Nothing value")
.with_context("Called `try_unwrap()` on a `Nothing` value")),
}
}
#[inline]
pub fn unwrap(self) -> T {
match self {
Maybe::Just(val) => val,
Maybe::Nothing => panic!("called `Maybe::unwrap()` on a `Nothing` value"),
}
}
#[inline]
pub fn unwrap_or(self, default: T) -> T {
match self {
Maybe::Just(val) => val,
Maybe::Nothing => default,
}
}
#[inline]
pub fn fmap_or<U, F>(self, default: U, f: F) -> U
where
F: FnOnce(T) -> U,
{
match self {
Maybe::Just(val) => f(val),
Maybe::Nothing => default,
}
}
#[inline]
pub const fn as_ref(&self) -> Option<&T> {
match *self {
Maybe::Just(ref x) => Some(x),
Maybe::Nothing => None,
}
}
#[inline]
pub fn unwrap_or_else<F>(self, f: F) -> T
where
F: FnOnce() -> T,
{
match self {
Maybe::Just(val) => val,
Maybe::Nothing => f(),
}
}
#[inline]
pub fn as_option(&self) -> Option<&T> {
match self {
Maybe::Just(val) => Some(val),
Maybe::Nothing => None,
}
}
#[inline]
pub fn filter<P>(self, predicate: P) -> Self
where
P: FnOnce(&T) -> bool,
{
match self {
Maybe::Just(value) if predicate(&value) => Maybe::Just(value),
_ => Maybe::Nothing,
}
}
#[inline]
pub fn tap<F>(self, f: F) -> Self
where
F: FnOnce(&T),
{
if let Maybe::Just(ref value) = self {
f(value);
}
self
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.as_ref().into_iter()
}
#[inline]
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
match self {
Maybe::Just(x) => Some(x).into_iter(),
Maybe::Nothing => None.into_iter(),
}
}
#[inline]
pub fn to_vec(self) -> Vec<T> {
match self {
Maybe::Just(x) => vec![x],
Maybe::Nothing => vec![],
}
}
}
#[allow(dead_code)]
struct MaybeNullTestStruct<T>(PhantomData<T>);
const _: () = assert!(std::mem::size_of::<Maybe<Box<i32>>>() == std::mem::size_of::<Box<i32>>());
impl<T> HKT for Maybe<T> {
type Source = T;
type Output<U> = Maybe<U>;
}
impl<T> Pure for Maybe<T> {
#[inline]
fn pure<U: Clone>(value: &U) -> Self::Output<U> {
Maybe::Just(value.clone())
}
}
impl<T> Functor for Maybe<T> {
#[inline]
fn fmap<B, F>(&self, f: F) -> Self::Output<B>
where
F: FnOnce(&Self::Source) -> B,
{
match self {
Maybe::Just(x) => Maybe::Just(f(x)),
Maybe::Nothing => Maybe::Nothing,
}
}
#[inline]
fn fmap_owned<B, F>(self, f: F) -> Self::Output<B>
where
F: FnOnce(Self::Source) -> B,
{
match self {
Maybe::Just(x) => Maybe::Just(f(x)),
Maybe::Nothing => Maybe::Nothing,
}
}
}
impl<T> Applicative for Maybe<T> {
#[inline]
fn apply<A, B>(&self, value: &Self::Output<A>) -> Self::Output<B>
where
Self::Source: Fn(&A) -> B,
{
match (self, value) {
(Maybe::Just(g), Maybe::Just(x)) => Maybe::Just(g(x)),
_ => Maybe::Nothing,
}
}
#[inline]
fn lift2<A, B, C, F>(f: F, fa: &Self::Output<A>, fb: &Self::Output<B>) -> Self::Output<C>
where
F: Fn(&A, &B) -> C,
Self: Sized,
{
match (fa, fb) {
(Maybe::Just(a), Maybe::Just(b)) => Maybe::Just(f(a, b)),
_ => Maybe::Nothing,
}
}
#[inline]
fn lift3<A, B, C, D, F>(
f: F, fa: &Self::Output<A>, fb: &Self::Output<B>, fc: &Self::Output<C>,
) -> Self::Output<D>
where
F: Fn(&A, &B, &C) -> D,
Self: Sized,
{
match (fa, fb, fc) {
(Maybe::Just(a), Maybe::Just(b), Maybe::Just(c)) => Maybe::Just(f(a, b, c)),
_ => Maybe::Nothing,
}
}
#[inline]
fn apply_owned<U, B>(self, value: Self::Output<U>) -> Self::Output<B>
where
Self::Source: Fn(U) -> B,
U: Clone,
B: Clone,
{
match (self, value) {
(Maybe::Just(f), Maybe::Just(x)) => Maybe::Just(f(x)),
_ => Maybe::Nothing,
}
}
#[inline]
fn lift2_owned<A, B, C, F>(f: F, fa: Self::Output<A>, fb: Self::Output<B>) -> Self::Output<C>
where
F: Fn(A, B) -> C,
A: Clone,
B: Clone,
C: Clone,
Self: Sized,
{
match (fa, fb) {
(Maybe::Just(a), Maybe::Just(b)) => Maybe::Just(f(a, b)),
_ => Maybe::Nothing,
}
}
#[inline]
fn lift3_owned<A, B, C, D, F>(
f: F, fa: Self::Output<A>, fb: Self::Output<B>, fc: Self::Output<C>,
) -> Self::Output<D>
where
F: Fn(A, B, C) -> D,
A: Clone,
B: Clone,
C: Clone,
D: Clone,
Self: Sized,
{
match (fa, fb, fc) {
(Maybe::Just(a), Maybe::Just(b), Maybe::Just(c)) => Maybe::Just(f(a, b, c)),
_ => Maybe::Nothing,
}
}
}
impl<T> Monad for Maybe<T> {
#[inline]
fn bind<U, F>(&self, f: F) -> Self::Output<U>
where
F: Fn(&Self::Source) -> Self::Output<U>,
{
match self {
Maybe::Just(x) => f(x),
Maybe::Nothing => Maybe::Nothing,
}
}
#[inline]
fn bind_owned<U, F>(self, f: F) -> Self::Output<U>
where
F: FnOnce(Self::Source) -> Self::Output<U>,
Self: Sized,
{
match self {
Maybe::Just(x) => f(x),
Maybe::Nothing => Maybe::Nothing,
}
}
#[inline]
fn join<U>(&self) -> Self::Output<U>
where
Self::Source: Clone + Into<Self::Output<U>>,
{
match self {
Maybe::Just(m) => m.clone().into(),
Maybe::Nothing => Maybe::Nothing,
}
}
#[inline]
fn join_owned<U>(self) -> Self::Output<U>
where
Self::Source: Into<Self::Output<U>>,
Self: Sized,
{
match self {
Maybe::Just(m) => m.into(),
Maybe::Nothing => Maybe::Nothing,
}
}
}
impl<T: Clone> MonadPlus for Maybe<T> {
#[inline]
fn mzero<U: Clone>() -> Self::Output<U> {
Maybe::Nothing
}
fn mplus(&self, other: &Self) -> Self {
match (self, other) {
(Maybe::Just(_), _) => self.clone(),
(Maybe::Nothing, Maybe::Just(_)) => other.clone(),
_ => Maybe::Nothing,
}
}
fn mplus_owned(self, other: Self) -> Self
where
Self: Sized,
{
match &self {
Maybe::Just(_) => self,
Maybe::Nothing => other,
}
}
}
impl<T: Clone> Alternative for Maybe<T> {
#[inline]
fn empty_alt<U>() -> Self::Output<U> {
Maybe::Nothing
}
#[inline]
fn alt(&self, other: &Self) -> Self {
match self {
Maybe::Just(_) => self.clone(),
Maybe::Nothing => other.clone(),
}
}
#[inline]
fn guard(condition: bool) -> Self::Output<()> {
if condition {
Maybe::Just(())
} else {
Maybe::Nothing
}
}
#[inline]
fn many(&self) -> Self::Output<Vec<Self::Source>>
where
Self::Source: Clone,
{
match self {
Maybe::Just(x) => Maybe::Just(vec![x.clone()]),
Maybe::Nothing => Maybe::Nothing,
}
}
}
impl<T> FromIterator<T> for Maybe<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
iter.into_iter().next().map_or(Maybe::Nothing, Maybe::Just)
}
}
impl<T> From<Option<T>> for Maybe<T> {
#[inline]
fn from(opt: Option<T>) -> Self {
match opt {
Some(x) => Maybe::Just(x),
None => Maybe::Nothing,
}
}
}
impl<T> From<Maybe<T>> for Option<T> {
#[inline]
fn from(maybe: Maybe<T>) -> Self {
match maybe {
Maybe::Just(x) => Some(x),
Maybe::Nothing => None,
}
}
}
impl<T> WithError<MaybeError> for Maybe<T> {
type Success = T;
type ErrorOutput<G> = Maybe<G>;
fn fmap_error<F, G>(self, f: F) -> Self::ErrorOutput<G>
where
F: Fn(MaybeError) -> G,
G: Clone,
{
match self {
Maybe::Just(_) => Maybe::Just(f(MaybeError::ValueNotPresent)),
Maybe::Nothing => Maybe::Nothing,
}
}
fn to_result(self) -> Result<Self::Success, MaybeError> {
match self {
Maybe::Just(x) => Ok(x),
Maybe::Nothing => Err(MaybeError::ValueNotPresent),
}
}
}
impl<T, E> From<Result<T, E>> for Maybe<T> {
#[inline]
fn from(result: Result<T, E>) -> Self {
match result {
Ok(value) => Maybe::Just(value),
Err(_) => Maybe::Nothing,
}
}
}
pub trait MaybeExt<T> {
fn to_result<E>(self, err: E) -> Result<T, E>;
fn try_unwrap(self) -> ComposableResult<T, &'static str>;
}
impl<T> MaybeExt<T> for Maybe<T> {
#[inline]
fn to_result<E>(self, err: E) -> Result<T, E> {
match self {
Maybe::Just(x) => Ok(x),
Maybe::Nothing => Err(err),
}
}
#[inline]
fn try_unwrap(self) -> ComposableResult<T, &'static str> {
match self {
Maybe::Just(val) => Ok(val),
Maybe::Nothing => Err(ComposableError::new("Cannot unwrap Nothing value")
.with_context("Called `try_unwrap()` on a `Nothing` value")),
}
}
}
impl<T> Default for Maybe<T> {
#[inline]
fn default() -> Self {
Maybe::Nothing
}
}
impl<T> IntoIterator for Maybe<T> {
type Item = T;
type IntoIter = std::option::IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
match self {
Maybe::Just(val) => Some(val).into_iter(),
Maybe::Nothing => None.into_iter(),
}
}
}
impl<'a, T> IntoIterator for &'a Maybe<T> {
type Item = &'a T;
type IntoIter = std::slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
match self {
Maybe::Just(val) => std::slice::from_ref(val).iter(),
Maybe::Nothing => [].iter(),
}
}
}
impl<'a, T> IntoIterator for &'a mut Maybe<T> {
type Item = &'a mut T;
type IntoIter = std::slice::IterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
match self {
Maybe::Just(val) => std::slice::from_mut(val).iter_mut(),
Maybe::Nothing => [].iter_mut(),
}
}
}
impl<T> Arbitrary for Maybe<T>
where
T: Arbitrary + Clone,
{
fn arbitrary(g: &mut Gen) -> Self {
if bool::arbitrary(g) {
Maybe::Nothing
} else {
Maybe::Just(T::arbitrary(g))
}
}
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
match self {
Maybe::Just(a) => Box::new(
a.shrink()
.map(Maybe::Just)
.chain(std::iter::once(Maybe::Nothing)),
),
Maybe::Nothing => Box::new(std::iter::empty()),
}
}
}