Skip to main content

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