cons_cell 0.1.0

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

pub trait ContainsAnySwitch<Contained: ConsCell> {
    type Value: Bit;
}

pub trait ContainsAnySwitchHelper<Tail: ConsCell, HeadContained: Bit>
where
    Self: ContainsAnySwitch<Tail>,
{
    type Value: Bit;
}

impl<Contained: Cons, Container: ConsCell> ContainsAnySwitch<Contained> for Container
where
    Contained::Head: TypeId,
    Container: ContainsSwitch<Contained::Head>,
    Container: ContainsAnySwitch<Contained::Tail>,
    Container: ContainsAnySwitchHelper<
            Contained::Tail,
            <Container as ContainsSwitch<Contained::Head>>::Value,
        >,
{
    type Value = <Container as ContainsAnySwitchHelper<
        Contained::Tail,
        <Container as ContainsSwitch<Contained::Head>>::Value,
    >>::Value;
}

impl<Tail: ConsCell, C: ConsCell> ContainsAnySwitchHelper<Tail, True> for C
where
    Self: ContainsAnySwitch<Tail>,
{
    type Value = <C as ContainsAnySwitch<Tail>>::Value;
}

impl<Tail: ConsCell, C: ConsCell> ContainsAnySwitchHelper<Tail, False> for C
where
    Self: ContainsAnySwitch<Tail>,
{
    type Value = False;
}

impl<NilSeed, Container: ConsCell> ContainsAnySwitch<Nil<NilSeed>> for Container {
    type Value = True;
}

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

    pub trait ContainsManyTest<Contained: ConsCell>: Cons {}

    impl<Container: Cons + ContainsAnySwitch<Contained, Value = True>, Contained: ConsCell>
        ContainsManyTest<Contained> for Container
    {
    }

    fn only_contains_many<Contained: ConsCell, C: ContainsManyTest<Contained>>(_: &C) {}

    #[test]
    fn contains_many() {
        let c = HNil::new().extend(U8(1)).extend(U32(2)).extend(U64(3));
        only_contains_many::<HCons<U8, HCons<U64, HNil>>, _>(&c);

        // Does not compile
        //only_contains_many::<HCons<U16, HCons<U8, HNil>>, _>(&c);
    }

    pub trait DoesNotContainManyTest<Contained: ConsCell>: Cons {}

    impl<Container: Cons + ContainsAnySwitch<Contained, Value = False>, Contained: ConsCell>
        DoesNotContainManyTest<Contained> for Container
    {
    }

    fn only_does_not_contain_many<Contained: ConsCell, C: DoesNotContainManyTest<Contained>>(
        _: &C,
    ) {
    }

    #[test]
    fn does_not_contain_many() {
        let c = HNil::new().extend(U8(1)).extend(U32(2)).extend(U64(3));
        only_does_not_contain_many::<HCons<U16, HCons<U8, HNil>>, _>(&c);

        // Does not compile
        //only_does_not_contain_many::<HCons<U8, HCons<U64, HNil>>, _>(&c);
    }
}