voile_util/
level.rs

1use std::cmp::{max, Ordering};
2use std::collections::{BTreeMap, HashMap};
3use std::fmt::{Display, Error, Formatter};
4use std::ops::{Add, Sub};
5
6pub type LevelType = u32;
7
8/// Level, can be inferred or user-specified.
9#[derive(Debug, Copy, Clone, Ord, Eq, PartialEq)]
10pub enum Level {
11    Omega,
12    Num(LevelType),
13}
14
15impl Level {
16    pub fn max(self, other: Self) -> Self {
17        use Level::*;
18        match (self, other) {
19            (Num(a), Num(b)) => Num(max(a, b)),
20            _ => Omega,
21        }
22    }
23
24    pub fn map(self, f: impl FnOnce(LevelType) -> LevelType) -> Self {
25        self.and_then(|a| Level::Num(f(a)))
26    }
27
28    pub fn and_then(self, f: impl FnOnce(LevelType) -> Self) -> Self {
29        use Level::*;
30        match self {
31            Omega => Omega,
32            Num(n) => f(n),
33        }
34    }
35}
36
37/// Internal API, public only because it's used in public traits' internal APIs.
38/// Produced during level calculation.<br/>
39/// `Some(Level)` -- level of non-recursive definitions.<br/>
40/// `None` -- level of self-reference.<br/>
41/// Trying to lift this will result in omega, otherwise it should be computed as 0 level.
42pub type LevelCalcState = Option<Level>;
43
44/// Expression with universe level (which means they can be lifted).
45pub trait LiftEx: Sized {
46    /// Lift the level of `self`.
47    fn lift(self, levels: LevelType) -> Self;
48
49    /// Down-lift the level of `self`.
50    /// Separated with `lift` instead of allowing negative numbers to `lift`
51    /// because we want the symbol to be explicit.
52    fn fall(self, levels: u32) -> Self;
53
54    /// Internal API, for code sharing only.
55    fn calc_level(&self) -> LevelCalcState;
56
57    /// Calculate the level of `self`,
58    /// like a normal value will have level 0,
59    /// a type expression will have level 1 (or higher).
60    fn level(&self) -> Level {
61        self.calc_level().unwrap_or_default()
62    }
63}
64
65impl From<LevelType> for Level {
66    fn from(n: LevelType) -> Self {
67        Level::Num(n)
68    }
69}
70
71impl From<usize> for Level {
72    fn from(n: usize) -> Self {
73        From::from(n as LevelType)
74    }
75}
76
77impl Display for Level {
78    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
79        match self {
80            Level::Omega => f.write_str("\u{03C9}"),
81            Level::Num(n) => n.fmt(f),
82        }
83    }
84}
85
86impl Default for Level {
87    fn default() -> Self {
88        From::from(0 as LevelType)
89    }
90}
91
92impl PartialOrd for Level {
93    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
94        use Level::*;
95        match (self, other) {
96            (Omega, Omega) => Some(Ordering::Equal),
97            (Omega, Num(..)) => Some(Ordering::Greater),
98            (Num(..), Omega) => Some(Ordering::Less),
99            (Num(a), Num(b)) => a.partial_cmp(b),
100        }
101    }
102}
103
104impl Add for Level {
105    type Output = Self;
106
107    fn add(self, rhs: Self) -> Self::Output {
108        use Level::*;
109        match (self, rhs) {
110            (Num(a), Num(b)) => Num(a + b),
111            _ => Omega,
112        }
113    }
114}
115
116impl Add<LevelType> for Level {
117    type Output = Self;
118
119    fn add(self, rhs: LevelType) -> Self::Output {
120        self.map(|a| a + rhs)
121    }
122}
123
124impl Sub<LevelType> for Level {
125    type Output = Self;
126
127    fn sub(self, rhs: LevelType) -> Self::Output {
128        self.map(|a| a - rhs)
129    }
130}
131
132pub fn lift_tree_map<T: LiftEx>(
133    levels: LevelType,
134    map: BTreeMap<String, T>,
135) -> BTreeMap<String, T> {
136    map.into_iter()
137        .map(|(name, e)| (name, e.lift(levels)))
138        .collect()
139}
140
141pub fn lift_hash_map<T: LiftEx>(levels: LevelType, map: HashMap<String, T>) -> HashMap<String, T> {
142    map.into_iter()
143        .map(|(name, e)| (name, e.lift(levels)))
144        .collect()
145}
146
147pub fn fall_tree_map<T: LiftEx>(levels: u32, map: BTreeMap<String, T>) -> BTreeMap<String, T> {
148    map.into_iter()
149        .map(|(name, e)| (name, e.fall(levels)))
150        .collect()
151}
152
153pub fn fall_hash_map<T: LiftEx>(levels: u32, map: HashMap<String, T>) -> HashMap<String, T> {
154    map.into_iter()
155        .map(|(name, e)| (name, e.fall(levels)))
156        .collect()
157}
158
159pub fn calc_tree_map_level(map: &BTreeMap<String, impl LiftEx>) -> LevelCalcState {
160    let levels: Option<Vec<_>> = map.values().map(LiftEx::calc_level).collect();
161    Some(levels?.into_iter().max().unwrap_or_default())
162}
163
164pub fn calc_tree_map_plus_one_level(
165    one: &impl LiftEx,
166    map: &BTreeMap<String, impl LiftEx>,
167) -> LevelCalcState {
168    let levels: Option<Vec<_>> = map.values().map(LiftEx::calc_level).collect();
169    let level = levels?.into_iter().max().unwrap_or_default();
170    Some(one.calc_level()?.max(level))
171}
172
173pub fn calc_slice_level(vec: &[impl LiftEx]) -> LevelCalcState {
174    let levels: Option<Vec<_>> = vec.iter().map(LiftEx::calc_level).collect();
175    Some(levels?.into_iter().max().unwrap_or_default())
176}
177
178pub fn calc_slice_plus_one_level(one: &impl LiftEx, vec: &[impl LiftEx]) -> LevelCalcState {
179    let levels: Option<Vec<_>> = vec.iter().map(LiftEx::calc_level).collect();
180    let level = levels?.into_iter().max().unwrap_or_default();
181    Some(one.calc_level()?.max(level))
182}
183
184pub fn calc_hash_map_level(map: &HashMap<String, impl LiftEx>) -> LevelCalcState {
185    let levels: Option<Vec<_>> = map.values().map(LiftEx::calc_level).collect();
186    Some(levels?.into_iter().max().unwrap_or_default())
187}