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
9impl UsizeTag for bool {
10    fn from_usize(n: usize) -> Self {
11        match n {
12            0 => false,
13            1 => true,
14            _ => panic!("out of bounds"),
15        }
16    }
17
18    fn to_usize(&self) -> usize {
19        *self as _
20    }
21
22    fn try_to_usize(&self) -> Option<usize> {
23        Some(self.to_usize())
24    }
25}
26
27#[derive(ToOutput, Topological, Tagged, ParseAsInline, Size, MaybeHasNiche)]
28pub struct EnumTag<T, const MAX: usize>(T);
29
30impl<T: UsizeTag, const MAX: usize> UsizeTag for EnumTag<T, MAX> {
31    fn from_usize(n: usize) -> Self {
32        assert!(n < MAX);
33        Self(UsizeTag::from_usize(n))
34    }
35
36    fn to_usize(&self) -> usize {
37        self.0.to_usize()
38    }
39
40    fn try_to_usize(&self) -> Option<usize> {
41        self.0.try_to_usize()
42    }
43}
44
45impl<T: UsizeTag, const MAX: usize> EnumTag<T, MAX> {
46    pub fn to_usize(&self) -> usize {
47        self.0.to_usize()
48    }
49
50    pub fn from_const<const N: usize>() -> Self {
51        assert!(N < MAX);
52        Self(UsizeTag::from_usize(N))
53    }
54}
55
56impl<T: ParseInline<I> + UsizeTag, I: ParseInput, const MAX: usize> ParseInline<I>
57    for EnumTag<T, MAX>
58{
59    fn parse_inline(input: &mut I) -> crate::Result<Self> {
60        let n_raw = T::parse_inline(input)?;
61        let n: Option<usize> = n_raw.try_to_usize();
62        if let Some(n) = n {
63            if n < MAX {
64                return Ok(Self(n_raw));
65            }
66        }
67        Err(Error::DiscriminantOverflow)
68    }
69}
70
71pub trait EnumKind: Copy {
72    type Tag;
73    fn to_tag(self) -> Self::Tag;
74    fn from_tag(tag: Self::Tag) -> Self;
75}
76
77pub trait Enum {
78    type Kind: EnumKind;
79    fn kind(&self) -> Self::Kind;
80}
81
82pub trait EnumParse<I: ParseInput>: Enum + Parse<I> {
83    fn enum_parse(kind: Self::Kind, input: I) -> crate::Result<Self>;
84    fn parse_as_enum(mut input: I) -> crate::Result<Self>
85    where
86        <Self::Kind as EnumKind>::Tag: ParseInline<I>,
87    {
88        Self::enum_parse(Self::Kind::from_tag(input.parse_inline()?), input)
89    }
90}
91
92pub trait EnumParseInline<I: ParseInput>: Enum + ParseInline<I> {
93    fn enum_parse_inline(kind: Self::Kind, input: &mut I) -> crate::Result<Self>;
94    fn parse_as_inline_enum(input: &mut I) -> crate::Result<Self>
95    where
96        <Self::Kind as EnumKind>::Tag: ParseInline<I>,
97    {
98        Self::enum_parse_inline(Self::Kind::from_tag(input.parse_inline()?), input)
99    }
100}