object_rainbow/
enumkind.rs1use crate::*;
2
3pub trait UsizeTag: Sized {
5 fn from_usize(n: usize) -> Self;
11 fn to_usize(&self) -> usize;
13 fn try_to_usize(&self) -> Option<usize>;
15}
16
17impl UsizeTag for bool {
18 fn from_usize(n: usize) -> Self {
19 match n {
20 0 => false,
21 1 => true,
22 _ => panic!("out of bounds"),
23 }
24 }
25
26 fn to_usize(&self) -> usize {
27 *self as _
28 }
29
30 fn try_to_usize(&self) -> Option<usize> {
31 Some(self.to_usize())
32 }
33}
34
35#[derive(
37 ToOutput, InlineOutput, ListHashes, Topological, Tagged, ParseAsInline, Size, MaybeHasNiche,
38)]
39pub struct EnumTag<T, const MAX: usize>(T);
40
41impl<T: UsizeTag, const MAX: usize> UsizeTag for EnumTag<T, MAX> {
42 fn from_usize(n: usize) -> Self {
43 assert!(n < MAX);
44 Self(UsizeTag::from_usize(n))
45 }
46
47 fn to_usize(&self) -> usize {
48 self.0.to_usize()
49 }
50
51 fn try_to_usize(&self) -> Option<usize> {
52 self.0.try_to_usize()
53 }
54}
55
56impl<T: UsizeTag, const MAX: usize> EnumTag<T, MAX> {
57 pub fn to_usize(&self) -> usize {
59 self.0.to_usize()
60 }
61
62 pub fn from_const<const N: usize>() -> Self {
64 assert!(N < MAX);
65 Self(UsizeTag::from_usize(N))
66 }
67}
68
69impl<T: ParseInline<I> + UsizeTag, I: ParseInput, const MAX: usize> ParseInline<I>
70 for EnumTag<T, MAX>
71{
72 fn parse_inline(input: &mut I) -> crate::Result<Self> {
73 let n_raw = T::parse_inline(input)?;
74 let n: Option<usize> = n_raw.try_to_usize();
75 if let Some(n) = n {
76 if n < MAX {
77 return Ok(Self(n_raw));
78 }
79 }
80 Err(Error::DiscriminantOverflow)
81 }
82}
83
84pub trait EnumKind: Copy {
86 type Tag;
88 fn to_tag(self) -> Self::Tag;
90 fn from_tag(tag: Self::Tag) -> Self;
95}
96
97pub trait Enum {
99 type Kind: EnumKind;
101 fn kind(&self) -> Self::Kind;
103}
104
105pub trait EnumParse<I: ParseInput>: Enum + Parse<I> {
107 fn enum_parse(kind: Self::Kind, input: I) -> crate::Result<Self>;
109 fn parse_as_enum(mut input: I) -> crate::Result<Self>
111 where
112 <Self::Kind as EnumKind>::Tag: ParseInline<I>,
113 {
114 Self::enum_parse(Self::Kind::from_tag(input.parse_inline()?), input)
115 }
116}
117
118pub trait EnumParseInline<I: ParseInput>: Enum + ParseInline<I> {
120 fn enum_parse_inline(kind: Self::Kind, input: &mut I) -> crate::Result<Self>;
122 fn parse_as_inline_enum(input: &mut I) -> crate::Result<Self>
124 where
125 <Self::Kind as EnumKind>::Tag: ParseInline<I>,
126 {
127 Self::enum_parse_inline(Self::Kind::from_tag(input.parse_inline()?), input)
128 }
129}