cons_cell 0.1.0

Swiss knife for heterogenous containers
Documentation
use core::fmt;
use std::any::type_name;
use std::fmt::Debug;
use std::marker::PhantomData;

pub mod ops;
#[cfg(test)]
pub(crate) mod test_types;
pub mod traits;
pub mod types;

pub trait ConsCell: Sized {
    fn extend<NewHead>(self, new_head: NewHead) -> <Self as Extend<NewHead>>::Extension
    where
        Self: Extend<NewHead>,
    {
        Self::Extension::new(new_head, self)
    }
}

pub trait Extend<NewHead> {
    type Extension: Cons<Head = NewHead, Tail = Self>;
}

pub trait NilExtend<NewHead>: Sized {
    type Extension: Cons<Head = NewHead, Tail = Nil<Self>>;
}

// Nil used as a base case for each Cons implementation.
// NilSeed is used to specialize Nil for each concrete implementation of Cons.
pub struct Nil<NilSeed> {
    _marker: PhantomData<NilSeed>,
}

impl<NilSeed> Nil<NilSeed> {
    pub fn new() -> Self {
        Nil {
            _marker: Default::default(),
        }
    }
}

impl<NilSeed> ConsCell for Nil<NilSeed> {}

impl<NewHead, NilSeed> Extend<NewHead> for Nil<NilSeed>
where
    NilSeed: NilExtend<NewHead>,
{
    type Extension = <NilSeed as NilExtend<NewHead>>::Extension;
}

impl<NilSeed> Debug for Nil<NilSeed> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct(type_name::<NilSeed>()).finish()
    }
}

pub trait Cons: ConsCell {
    type Head;
    type Tail: ConsCell;

    fn head(&self) -> &Self::Head;
    fn tail(&self) -> &Self::Tail;

    fn mut_head(&mut self) -> &mut Self::Head;
    fn mut_tail(&mut self) -> &mut Self::Tail;

    fn new(head: Self::Head, tail: Self::Tail) -> Self;
    fn split(self) -> (Self::Head, Self::Tail);
}