object_rainbow/
enumkind.rs1use 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}