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);
}
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);
}
}