use std::ops::{Deref, DerefMut};
#[derive(Debug, Clone, PartialEq, Default)]
pub struct Optional<T>(Box<Option<T>>);
impl<T> Optional<T> {
pub fn new(value: T) -> Self {
Self(Box::new(Some(value)))
}
pub fn none() -> Self {
Self(Box::new(None))
}
pub fn into_option(self) -> Option<T> {
*self.0
}
pub fn from_option(opt: Option<T>) -> Self {
Self(Box::new(opt))
}
pub fn as_option(&self) -> &Option<T> {
&self.0
}
pub fn as_option_mut(&mut self) -> &mut Option<T> {
&mut self.0
}
pub fn as_ref(&self) -> Optional<&T> {
Optional::from_option(self.as_option().as_ref())
}
pub fn as_mut(&mut self) -> Optional<&mut T> {
Optional::from_option(self.as_option_mut().as_mut())
}
pub fn map<U, F>(self, f: F) -> Optional<U>
where
F: FnOnce(T) -> U,
{
Optional::from_option(self.into_option().map(f))
}
pub fn inspect<F>(self, f: F) -> Self
where
F: FnOnce(&T),
{
Optional::from_option(self.into_option().inspect(f))
}
pub fn filter<P>(self, predicate: P) -> Self
where
P: FnOnce(&T) -> bool,
{
Optional::from_option(self.0.filter(predicate))
}
pub fn or(self, other: Optional<T>) -> Optional<T> {
Optional::from_option(self.0.or(other.into_option()))
}
pub fn or_else<F>(self, f: F) -> Optional<T>
where
F: FnOnce() -> Optional<T>,
{
Optional::from_option(self.into_option().or_else(|| f().into_option()))
}
pub fn xor(self, other: Optional<T>) -> Optional<T> {
Optional::from_option(self.0.xor(other.into_option()))
}
pub fn and<U>(self, other: Optional<U>) -> Optional<U> {
Optional::from_option(self.0.and(other.into_option()))
}
pub fn and_then<U, F>(self, f: F) -> Optional<U>
where
F: FnOnce(T) -> Optional<U>,
{
Optional::from_option(self.into_option().and_then(|t| f(t).into_option()))
}
pub fn take(&mut self) -> Optional<T> {
Optional::from_option(self.0.take())
}
pub fn take_if<P>(&mut self, predicate: P) -> Optional<T>
where
P: FnOnce(&mut T) -> bool,
{
Optional::from_option(self.0.take_if(predicate))
}
pub fn replace(&mut self, value: T) -> Optional<T> {
Self::from_option(self.0.replace(value))
}
pub fn zip<U>(self, other: Optional<U>) -> Optional<(T, U)> {
Optional::from_option(self.into_option().zip(other.into_option()))
}
pub fn as_deref(&self) -> Optional<&<T as Deref>::Target>
where
T: Deref,
{
Optional::from_option(self.0.as_deref())
}
pub fn as_deref_mut(&mut self) -> Optional<&mut <T as Deref>::Target>
where
T: DerefMut,
{
Optional::from_option(self.0.as_deref_mut())
}
}
impl<T, U> Optional<(T, U)> {
pub fn unzip(self) -> (Optional<T>, Optional<U>) {
let (v, w) = self.into_option().unzip();
(Optional::from_option(v), Optional::from_option(w))
}
}
impl<T> Optional<&T> {
pub fn copied(self) -> Optional<T>
where
T: Copy,
{
Optional::from_option(self.0.copied())
}
pub fn cloned(self) -> Optional<T>
where
T: Clone,
{
Optional::from_option(self.0.cloned())
}
}
impl<T> Optional<&mut T> {
pub fn copied(self) -> Optional<T>
where
T: Copy,
{
Optional::from_option(self.0.copied())
}
pub fn cloned(self) -> Optional<T>
where
T: Clone,
{
Optional::from_option(self.0.cloned())
}
}
impl<T, E> Optional<Result<T, E>> {
pub fn transpose(self) -> Result<Optional<T>, E> {
self.into_option()
.transpose()
.map(|option| Optional::from_option(option))
}
}
impl<T> Optional<Optional<T>> {
pub fn flatten(self) -> Optional<T> {
match self.into_option() {
Some(inner) => inner,
None => Optional::none(),
}
}
}
impl<T> Deref for Optional<T> {
type Target = Option<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for Optional<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T> From<Option<T>> for Optional<T> {
fn from(opt: Option<T>) -> Self {
Self::from_option(opt)
}
}
impl<T> From<Optional<T>> for Option<T> {
fn from(opt: Optional<T>) -> Self {
opt.into_option()
}
}
impl<T: std::fmt::Display> std::fmt::Display for Optional<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.as_option() {
Some(v) => write!(f, "optional({v})"),
None => write!(f, "optional.none()"),
}
}
}