1use std::fmt;
6use std::collections::HashMap;
7
8#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
10pub struct LevelId(u32);
11
12impl LevelId {
13 pub(crate) fn new(id: u32) -> Self {
15 Self(id)
16 }
17
18 pub fn raw(self) -> u32 {
20 self.0
21 }
22}
23
24#[derive(Debug, Clone, PartialEq, Eq, Hash)]
26pub enum Level {
27 Zero,
29
30 Const(u32),
32
33 Param(u32),
35
36 Succ(LevelId),
38
39 Max(LevelId, LevelId),
41
42 IMax(LevelId, LevelId),
44}
45
46impl Level {
47 pub fn is_zero(&self) -> bool {
49 matches!(self, Level::Zero)
50 }
51
52 pub fn is_const(&self) -> bool {
54 matches!(self, Level::Const(_))
55 }
56
57 pub fn from_u32(n: u32) -> Self {
59 if n == 0 {
60 Level::Zero
61 } else {
62 Level::Const(n)
63 }
64 }
65}
66
67impl fmt::Display for Level {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 match self {
70 Level::Zero => write!(f, "0"),
71 Level::Const(n) => write!(f, "{}", n),
72 Level::Param(n) => write!(f, "u{}", n),
73 Level::Succ(id) => write!(f, "(succ {})", id.0),
74 Level::Max(a, b) => write!(f, "(max {} {})", a.0, b.0),
75 Level::IMax(a, b) => write!(f, "(imax {} {})", a.0, b.0),
76 }
77 }
78}
79
80pub struct LevelArena {
82 levels: Vec<Level>,
83 cache: HashMap<Level, LevelId>,
84}
85
86impl LevelArena {
87 pub fn new() -> Self {
89 let mut arena = Self {
90 levels: Vec::new(),
91 cache: HashMap::new(),
92 };
93 arena.intern(Level::Zero);
95 arena
96 }
97
98 pub fn intern(&mut self, level: Level) -> LevelId {
100 if let Some(&id) = self.cache.get(&level) {
101 return id;
102 }
103
104 let id = LevelId::new(self.levels.len() as u32);
105 self.levels.push(level.clone());
106 self.cache.insert(level, id);
107 id
108 }
109
110 pub fn get(&self, id: LevelId) -> Option<&Level> {
112 self.levels.get(id.0 as usize)
113 }
114
115 pub fn zero(&mut self) -> LevelId {
117 self.intern(Level::Zero)
118 }
119
120 pub fn constant(&mut self, n: u32) -> LevelId {
122 self.intern(Level::from_u32(n))
123 }
124
125 pub fn param(&mut self, n: u32) -> LevelId {
127 self.intern(Level::Param(n))
128 }
129
130 pub fn succ(&mut self, id: LevelId) -> LevelId {
132 self.intern(Level::Succ(id))
133 }
134
135 pub fn max(&mut self, a: LevelId, b: LevelId) -> LevelId {
137 self.intern(Level::Max(a, b))
138 }
139
140 pub fn imax(&mut self, a: LevelId, b: LevelId) -> LevelId {
142 self.intern(Level::IMax(a, b))
143 }
144
145 pub fn normalize(&mut self, id: LevelId) -> LevelId {
147 let level = self.get(id).unwrap().clone();
148
149 match level {
150 Level::Succ(inner) => {
151 let normalized = self.normalize(inner);
152 if let Some(Level::Const(n)) = self.get(normalized) {
153 return self.constant(n + 1);
154 }
155 self.succ(normalized)
156 }
157 Level::Max(a, b) => {
158 let a_norm = self.normalize(a);
159 let b_norm = self.normalize(b);
160
161 if let (Some(Level::Const(n)), Some(Level::Const(m))) =
163 (self.get(a_norm), self.get(b_norm))
164 {
165 return self.constant((*n).max(*m));
166 }
167
168 self.max(a_norm, b_norm)
169 }
170 Level::IMax(a, b) => {
171 let a_norm = self.normalize(a);
172 let b_norm = self.normalize(b);
173
174 if let Some(Level::Zero) = self.get(b_norm) {
176 return self.zero();
177 }
178
179 if let (Some(Level::Const(n)), Some(Level::Const(m))) =
181 (self.get(a_norm), self.get(b_norm))
182 {
183 return self.constant((*n).max(*m));
184 }
185
186 self.imax(a_norm, b_norm)
187 }
188 _ => id,
189 }
190 }
191}
192
193impl Default for LevelArena {
194 fn default() -> Self {
195 Self::new()
196 }
197}
198
199#[cfg(test)]
200mod tests {
201 use super::*;
202
203 #[test]
204 fn test_level_interning() {
205 let mut arena = LevelArena::new();
206
207 let zero1 = arena.zero();
208 let zero2 = arena.zero();
209 assert_eq!(zero1, zero2);
210
211 let one = arena.constant(1);
212 let succ_zero = arena.succ(zero1);
213 assert_ne!(one, succ_zero); }
215
216 #[test]
217 fn test_level_normalization() {
218 let mut arena = LevelArena::new();
219
220 let zero = arena.zero();
221 let one = arena.constant(1);
222 let two = arena.constant(2);
223
224 let max = arena.max(one, two);
225 let normalized = arena.normalize(max);
226
227 assert_eq!(normalized, two);
228 }
229
230 #[test]
231 fn test_imax_reduction() {
232 let mut arena = LevelArena::new();
233
234 let zero = arena.zero();
235 let one = arena.constant(1);
236
237 let imax = arena.imax(one, zero);
238 let normalized = arena.normalize(imax);
239
240 assert_eq!(normalized, zero);
241 }
242}