use crate::enums::IDeterminantProvider;
use crate::result::OkGuard;
use crate::{unreachable_unchecked, IStable};
#[crate::stabby]
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Option<T: IStable + IDeterminantProvider<()>> {
inner: crate::result::Result<T, ()>,
}
impl<T: IStable> core::fmt::Debug for Option<T>
where
T: IDeterminantProvider<()>,
T: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.as_ref().fmt(f)
}
}
impl<T: IStable> From<core::option::Option<T>> for Option<T>
where
T: IDeterminantProvider<()>,
{
fn from(value: core::option::Option<T>) -> Self {
match value {
Some(value) => Self {
inner: crate::result::Result::Ok(value),
},
None => Self {
inner: crate::result::Result::Err(()),
},
}
}
}
impl<T: IStable> From<Option<T>> for core::option::Option<T>
where
T: IDeterminantProvider<()>,
{
fn from(value: Option<T>) -> Self {
value.inner.ok()
}
}
impl<T: IStable> Default for Option<T>
where
T: IDeterminantProvider<()>,
{
fn default() -> Self {
Self::None()
}
}
pub type SomeGuard<'a, T> = OkGuard<'a, T, ()>;
impl<T: IStable> Option<T>
where
T: IDeterminantProvider<()>,
{
#[allow(non_snake_case)]
pub fn Some(value: T) -> Self {
Self {
inner: crate::result::Result::Ok(value),
}
}
#[allow(non_snake_case)]
pub fn None() -> Self {
Self {
inner: crate::result::Result::Err(()),
}
}
pub fn as_ref(&self) -> core::option::Option<&T> {
self.match_ref(Some, || None)
}
pub fn as_mut(&mut self) -> core::option::Option<SomeGuard<T>> {
self.match_mut(Some, || None)
}
pub fn match_ref<'a, U, FnSome: FnOnce(&'a T) -> U, FnNone: FnOnce() -> U>(
&'a self,
some: FnSome,
none: FnNone,
) -> U {
self.inner.match_ref(some, |_| none())
}
pub fn match_ref_ctx<'a, I, U, FnSome: FnOnce(I, &'a T) -> U, FnNone: FnOnce(I) -> U>(
&'a self,
ctx: I,
some: FnSome,
none: FnNone,
) -> U {
self.inner.match_ref_ctx(ctx, some, move |ctx, _| none(ctx))
}
pub fn match_mut<'a, U, FnSome: FnOnce(SomeGuard<'a, T>) -> U, FnNone: FnOnce() -> U>(
&'a mut self,
some: FnSome,
none: FnNone,
) -> U {
self.inner.match_mut(some, |_| none())
}
pub fn match_mut_ctx<
'a,
I,
U,
FnSome: FnOnce(I, SomeGuard<'a, T>) -> U,
FnNone: FnOnce(I) -> U,
>(
&'a mut self,
ctx: I,
some: FnSome,
none: FnNone,
) -> U {
self.inner.match_mut_ctx(ctx, some, move |ctx, _| none(ctx))
}
pub fn match_owned<U, FnSome: FnOnce(T) -> U, FnNone: FnOnce() -> U>(
self,
some: FnSome,
none: FnNone,
) -> U {
self.inner.match_owned(some, |_| none())
}
pub fn match_owned_ctx<I, U, FnSome: FnOnce(I, T) -> U, FnNone: FnOnce(I) -> U>(
self,
ctx: I,
some: FnSome,
none: FnNone,
) -> U {
self.inner
.match_owned_ctx(ctx, some, move |ctx, _| none(ctx))
}
pub fn is_some(&self) -> bool {
self.inner.is_ok()
}
pub fn is_none(&self) -> bool {
!self.is_some()
}
pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
self.match_owned(|x| x, f)
}
pub unsafe fn unwrap_unchecked(self) -> T {
self.unwrap_or_else(|| unsafe { unreachable_unchecked!() })
}
pub fn unwrap(self) -> T {
self.unwrap_or_else(|| panic!("Option::unwrap called on None"))
}
}
#[cfg(feature = "serde")]
mod serde_impl {
use super::*;
use serde::{Deserialize, Serialize};
impl<Ok: Serialize> Serialize for Option<Ok>
where
Ok: IDeterminantProvider<()>,
{
fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let this = self.as_ref();
this.serialize(serializer)
}
}
impl<'a, Ok: IDeterminantProvider<()>> Deserialize<'a> for Option<Ok>
where
core::option::Option<Ok>: Deserialize<'a>,
{
fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
where
D: serde::Deserializer<'a>,
{
Ok(core::option::Option::<Ok>::deserialize(deserializer)?.into())
}
}
}