cons_cell 0.1.0

Swiss knife for heterogenous containers
Documentation
use crate::cons::Cons;
use typenum::{False, True};
use typenum_uuid_trait::{IsTypeEqual, TypeId};

// TODO: Reason about how to deal with stuff that should contain exactly one instance of a type.
// TODO: get_first_mut
// TODO: take_first

pub trait Contains<Query: TypeId>: Cons {
    fn get_first(&self) -> &Query;
}

impl<C: Cons, Query: TypeId + IsTypeEqual<C::Head>> Contains<Query> for C
where
    C: ContainsHelper<Query, Query::Value>,
    <C as Cons>::Head: TypeId,
{
    #[inline(always)]
    fn get_first(&self) -> &Query {
        ContainsHelper::get_first(self)
    }
}

pub trait ContainsHelper<Query: TypeId, IsEqual> {
    fn get_first(&self) -> &Query;
}

impl<Query: TypeId, C: Cons<Head = Query>> ContainsHelper<Query, True> for C {
    #[inline(always)]
    fn get_first(&self) -> &Query {
        self.head()
    }
}

impl<Query: TypeId, C: Cons> ContainsHelper<Query, False> for C
where
    C::Tail: Contains<Query>,
{
    #[inline(always)]
    fn get_first(&self) -> &Query {
        self.tail().get_first()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::cons::ConsCell;
    use crate::cons::test_types::*;
    use crate::cons::types::hcons::HNil;

    #[test]
    fn get_first_works() {
        let x = HNil::new()
            .extend(U8(1))
            .extend(U16(2))
            .extend(U8(3))
            .extend(U32(4));

        let i: &U8 = Contains::<U8>::get_first(&x);
        assert_eq!(i, &U8(3));
    }
}