object_rainbow/
enumkind.rs

1use crate::*;
2
3pub trait UsizeTag: Sized {
4    fn from_usize(n: usize) -> Self;
5    fn to_usize(&self) -> usize;
6    fn try_to_usize(&self) -> Option<usize>;
7}
8
9#[derive(ToOutput, Topological, Tagged, ParseAsInline, Size, MaybeHasNiche)]
10pub struct EnumTag<T, const MAX: usize>(T);
11
12impl<T: Deref<Target: UsizeTag> + From<T::Target>, const MAX: usize> UsizeTag for EnumTag<T, MAX> {
13    fn from_usize(n: usize) -> Self {
14        assert!(n < MAX);
15        Self(T::from(UsizeTag::from_usize(n)))
16    }
17
18    fn to_usize(&self) -> usize {
19        self.0.to_usize()
20    }
21
22    fn try_to_usize(&self) -> Option<usize> {
23        self.0.try_to_usize()
24    }
25}
26
27impl<T: Deref<Target: UsizeTag> + From<T::Target>, const MAX: usize> EnumTag<T, MAX> {
28    pub fn to_usize(&self) -> usize {
29        self.0.to_usize()
30    }
31
32    pub fn from_const<const N: usize>() -> Self {
33        assert!(N < MAX);
34        Self(T::from(UsizeTag::from_usize(N)))
35    }
36}
37
38impl<T: ParseInline<I> + Deref<Target: UsizeTag>, I: ParseInput, const MAX: usize> ParseInline<I>
39    for EnumTag<T, MAX>
40{
41    fn parse_inline(input: &mut I) -> crate::Result<Self> {
42        let n_raw = T::parse_inline(input)?;
43        let n: Option<usize> = n_raw.try_to_usize();
44        if let Some(n) = n {
45            if n < MAX {
46                return Ok(Self(n_raw));
47            }
48        }
49        Err(Error::DiscriminantOverflow)
50    }
51}
52
53pub trait EnumKind: Copy {
54    type Tag;
55    fn to_tag(self) -> Self::Tag;
56    fn from_tag(tag: Self::Tag) -> Self;
57}
58
59pub trait Enum {
60    type Kind: EnumKind;
61    fn kind(&self) -> Self::Kind;
62}
63
64pub trait EnumParse<I: ParseInput>: Enum + Parse<I> {
65    fn enum_parse(kind: Self::Kind, input: I) -> crate::Result<Self>;
66    fn parse_as_enum(mut input: I) -> crate::Result<Self>
67    where
68        <Self::Kind as EnumKind>::Tag: ParseInline<I>,
69    {
70        Self::enum_parse(Self::Kind::from_tag(input.parse_inline()?), input)
71    }
72}
73
74pub trait EnumParseInline<I: ParseInput>: Enum + ParseInline<I> {
75    fn enum_parse_inline(kind: Self::Kind, input: &mut I) -> crate::Result<Self>;
76    fn parse_as_inline_enum(input: &mut I) -> crate::Result<Self>
77    where
78        <Self::Kind as EnumKind>::Tag: ParseInline<I>,
79    {
80        Self::enum_parse_inline(Self::Kind::from_tag(input.parse_inline()?), input)
81    }
82}