cons_cell 0.1.0

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

pub trait ContainsSwitch<T: TypeId>: ConsCell {
    type Value: Bit;
}

pub trait ContainsSwitchHelper<T: TypeId, Value: Bit>: Cons
where
    Self::Head: TypeId,
    Self::Tail: ContainsSwitch<T>,
{
    type Value: Bit;
}

impl<T: TypeId, C: Cons> ContainsSwitch<T> for C
where
    C::Head: TypeId,
    C::Tail: ContainsSwitch<T>,
    C::Head: IsTypeEqual<T>,
    C: ContainsSwitchHelper<T, <<C as Cons>::Head as IsTypeEqual<T>>::Value>,
{
    type Value =
        <C as ContainsSwitchHelper<T, <<C as Cons>::Head as IsTypeEqual<T>>::Value>>::Value;
}

impl<C: Cons, T: TypeId> ContainsSwitchHelper<T, True> for C
where
    C::Head: TypeId,
    C::Tail: ContainsSwitch<T>,
{
    type Value = True;
}

impl<C: Cons, T: TypeId> ContainsSwitchHelper<T, False> for C
where
    C::Head: TypeId,
    C::Tail: ContainsSwitch<T>,
{
    type Value = <C::Tail as ContainsSwitch<T>>::Value;
}

impl<T: TypeId, NilSeed> ContainsSwitch<T> for Nil<NilSeed> {
    type Value = False;
}

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

    pub trait ContainsTest<T: TypeId>: Cons {}

    impl<C: Cons + ContainsSwitch<T, Value = True>, T: TypeId> ContainsTest<T> for C {}

    fn only_contains<T: TypeId, C: ContainsTest<T>>(_: &C) {}

    #[test]
    fn contains() {
        let c = HNil::new().extend(U8(1)).extend(U32(2));
        only_contains::<U8, _>(&c);

        // Does not compile
        //only_contains::<U16,_>(&c);
    }

    pub trait DoesNotContainTest<T: TypeId>: Cons {}

    impl<C: Cons + ContainsSwitch<T, Value = False>, T: TypeId> DoesNotContainTest<T> for C {}

    fn only_does_not_contain<T: TypeId, C: DoesNotContainTest<T>>(_: &C) {}

    #[test]
    fn does_not_contain() {
        let c = HNil::new().extend(U8(1)).extend(U32(2));
        only_does_not_contain::<U16, _>(&c);

        // Does not compile
        //only_does_not_contain::<U8, _>(&c);
    }
}