1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
use std::any::Any;
use std::marker::PhantomData;

use crate::type_set::{Contains, Narrow, TypeSet};

#[derive(Debug)]
pub struct OneOf<E: TypeSet> {
    value: Box<dyn Any>,
    _pd: PhantomData<E>,
}

impl<T> From<T> for OneOf<(T,)>
where
    T: Any,
{
    fn from(t: T) -> OneOf<(T,)> {
        OneOf::new(t)
    }
}

impl<E> OneOf<E>
where
    E: TypeSet,
{
    pub fn narrow<Target, Remainder, Index>(self) -> Result<Target, OneOf<Remainder>>
    where
        E::TList: Contains<Target, Index>,
        Remainder: TypeSet,
        Target: 'static,
        E::TList: Narrow<Target, Index, Remainder = Remainder::TList>,
    {
        if self.value.is::<Target>() {
            Ok(*self.value.downcast::<Target>().unwrap())
        } else {
            Err(OneOf {
                value: self.value,
                _pd: PhantomData,
            })
        }
    }

    pub fn new<T, Index>(t: T) -> OneOf<E>
    where
        T: Any,
        E::TList: Contains<T, Index>,
    {
        OneOf {
            value: Box::new(t),
            _pd: PhantomData,
        }
    }
}