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