owner-monad 0.1.0

Rust implementation of a monad which provides ownership of an object
Documentation
//! Rust implementation of a monad which provides ownership of an object.

#![no_std]
#![warn(missing_docs)]

extern crate alloc;

use alloc::{rc, sync};
use core::marker::PhantomData;

/// A monad which conditionally provides access to a `T` value.
///
/// This is included alongside [`Owner`] and [`OwnerMut`] for completeness, but
/// this trait is isomorphic to `FnOnce() -> T`.
pub trait OwnerOnce<T> {
    /// Consumes the monad, applying the given function to the contained value,
    /// if it exists.
    fn with<U>(self, f: impl FnOnce(T) -> U) -> Option<U>;
}

/// A monad which conditionally provides immutable access to a `T` value.
pub trait Owner<T: ?Sized> {
    /// Applies the given function to the contained value, if it exists.
    fn with<'a, U>(&'a self, f: impl FnOnce(&T) -> U) -> Option<U>
    where
        T: 'a;
}

/// A monad which conditionally provides mutable access to a `T` value.
pub trait OwnerMut<T: ?Sized> {
    /// Applies the given function to the contained value, if it exists.
    fn with<'a, U>(&'a mut self, f: impl FnOnce(&mut T) -> U) -> Option<U>
    where
        T: 'a;
}

impl<T: ?Sized, O: ?Sized + Owner<T>> Owner<T> for &O {
    fn with<'a, U>(&'a self, f: impl FnOnce(&T) -> U) -> Option<U>
    where
        T: 'a,
    {
        (*self).with(f)
    }
}

impl<T: ?Sized, O: ?Sized + OwnerMut<T>> OwnerMut<T> for &mut O {
    fn with<'a, U>(&'a mut self, f: impl FnOnce(&mut T) -> U) -> Option<U>
    where
        T: 'a,
    {
        (*self).with(f)
    }
}

impl<T: ?Sized> Owner<T> for rc::Weak<T> {
    fn with<'a, U>(&'a self, f: impl FnOnce(&T) -> U) -> Option<U>
    where
        T: 'a,
    {
        Some(f(&*self.upgrade()?))
    }
}

impl<T: ?Sized> Owner<T> for sync::Weak<T> {
    fn with<'a, U>(&'a self, f: impl FnOnce(&T) -> U) -> Option<U>
    where
        T: 'a,
    {
        Some(f(&*self.upgrade()?))
    }
}

/// An implementation of the [`OwnerOnce`], [`Owner`] and [`OwnerMut`] traits
/// which simply contains a single (pure) value; see [`pure()`].
pub struct PureOwner<T>(T);

impl<T> OwnerOnce<T> for PureOwner<T> {
    fn with<U>(self, f: impl FnOnce(T) -> U) -> Option<U> {
        Some(f(self.0))
    }
}

impl<T> Owner<T> for PureOwner<T> {
    fn with<'a, U>(&'a self, f: impl FnOnce(&T) -> U) -> Option<U>
    where
        T: 'a,
    {
        Some(f(&self.0))
    }
}

impl<T> OwnerMut<T> for PureOwner<T> {
    fn with<'a, U>(&'a mut self, f: impl FnOnce(&mut T) -> U) -> Option<U>
    where
        T: 'a,
    {
        Some(f(&mut self.0))
    }
}

/// Creates an instance of ownership monads which provides access to the given
/// value.
pub fn pure<T>(t: T) -> PureOwner<T> {
    PureOwner(t)
}

/// An implementation of the [`OwnerOnce`], [`Owner`] and [`OwnerMut`] traits
/// which contains a mapping from one owner to another; see [`bind()`].
pub struct BindOwner<T, U, OT, OU, F> {
    owner: OT,
    func: F,
    _phantom: PhantomData<(T, U, OU)>,
}

impl<T, U, OT: OwnerOnce<T>, OU: OwnerOnce<U>, F: FnOnce(T) -> OU> OwnerOnce<U>
    for BindOwner<T, U, OT, OU, F>
{
    fn with<V>(self, f: impl FnOnce(U) -> V) -> Option<V> {
        let func = self.func;
        self.owner.with(move |t| func(t).with(f))?
    }
}

impl<T, U, OT: Owner<T>, OU: Owner<U>, F: Fn(&T) -> OU> Owner<U> for BindOwner<&T, U, OT, OU, F> {
    fn with<'a, V>(&'a self, f: impl FnOnce(&U) -> V) -> Option<V>
    where
        U: 'a,
    {
        self.owner.with(|t| (&self.func)(t).with(f))?
    }
}

impl<T, U, OT: OwnerMut<T>, OU: OwnerMut<U>, F: FnMut(&mut T) -> OU> OwnerMut<U>
    for BindOwner<&mut T, U, OT, OU, F>
{
    fn with<'a, V>(&'a mut self, f: impl FnOnce(&mut U) -> V) -> Option<V>
    where
        U: 'a,
    {
        let func = &mut self.func;
        self.owner.with(|t| func(t).with(f))?
    }
}

/// Creates an instance of ownership monads which maps from the given owner to
/// another using the given function.
pub fn bind<T, U, OT, OU, F>(o: OT, f: F) -> BindOwner<T, U, OT, OU, F> {
    BindOwner {
        owner: o,
        func: f,
        _phantom: PhantomData,
    }
}