Skip to main content

tupa_effects/
lib.rs

1use std::collections::BTreeSet;
2
3#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4pub enum Effect {
5    Pure,
6    IO,
7    Random,
8    Time,
9    ExternalCall(String),
10}
11
12#[derive(Debug, Clone, Default)]
13pub struct EffectSet {
14    effects: BTreeSet<Effect>,
15}
16
17impl EffectSet {
18    pub fn is_pure(&self) -> bool {
19        self.effects.is_empty() || (self.effects.len() == 1 && self.effects.contains(&Effect::Pure))
20    }
21
22    pub fn insert(&mut self, effect: Effect) {
23        if effect != Effect::Pure {
24            self.effects.insert(effect);
25        }
26    }
27
28    pub fn contains(&self, effect: &Effect) -> bool {
29        self.effects.contains(effect)
30    }
31
32    pub fn union(&self, other: &Self) -> Self {
33        let mut out = self.clone();
34        out.effects.extend(other.effects.iter().cloned());
35        out
36    }
37
38    pub fn iter(&self) -> std::collections::btree_set::Iter<'_, Effect> {
39        self.effects.iter()
40    }
41
42    pub fn to_names(&self) -> Vec<String> {
43        self.effects
44            .iter()
45            .map(|e| match e {
46                Effect::Pure => "pure".to_string(),
47                Effect::IO => "io".to_string(),
48                Effect::Random => "random".to_string(),
49                Effect::Time => "time".to_string(),
50                Effect::ExternalCall(name) => format!("external:{name}"),
51            })
52            .collect()
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    #[test]
61    fn default_is_pure() {
62        let set = EffectSet::default();
63        assert!(set.is_pure());
64        assert!(set.to_names().is_empty());
65    }
66
67    #[test]
68    fn union_combines_effects() {
69        let mut a = EffectSet::default();
70        a.insert(Effect::IO);
71        let mut b = EffectSet::default();
72        b.insert(Effect::Random);
73        let u = a.union(&b);
74        assert!(!u.is_pure());
75        let names = u.to_names();
76        assert!(names.contains(&"io".to_string()));
77        assert!(names.contains(&"random".to_string()));
78    }
79}