c3_lang_linearization/
c3.rs

1use std::collections::HashMap;
2
3use crate::{id::Id, split_coma};
4
5use super::{C3Error, Sets};
6
7pub type Class = Id;
8pub type Fn = Id;
9pub type Var = Id;
10
11#[derive(Debug, PartialEq, Eq, Clone)]
12pub struct C3 {
13    /// HashMap that maps base classes to path list.
14    classes: HashMap<Class, Vec<Class>>,
15    functions: HashMap<Class, Vec<Fn>>,
16    variables: HashMap<Class, Vec<Var>>,
17}
18
19impl C3 {
20    /// Build new empty instance.
21    pub fn new() -> Self {
22        Self {
23            classes: HashMap::new(),
24            functions: HashMap::new(),
25            variables: HashMap::new(),
26        }
27    }
28
29    /// Add new class via strings.
30    pub fn add(&mut self, base: Class, path: Vec<Class>) {
31        self.classes.insert(base, path);
32    }
33
34    /// Add new class via strings.
35    pub fn add_class_str(&mut self, base: &str, parents: &str) {
36        let input: Vec<Class> = split_coma(parents).into_iter().map(Class::from).collect();
37        self.add(Class::from(base), input);
38    }
39
40    /// Remove an element. Fails if element doesn't exists.
41    pub fn remove(&mut self, base: &Class) -> Result<(), C3Error> {
42        match self.classes.remove(base) {
43            Some(_) => Ok(()),
44            None => Err(C3Error::BaseClassDoesNotExists(base.clone().into())),
45        }
46    }
47
48    /// Returns all base classes as a vector Classes.
49    pub fn all_classes(&self) -> Vec<Class> {
50        let mut keys: Vec<Class> = self.classes.keys().cloned().collect();
51        keys.sort();
52        keys
53    }
54
55    /// Returns all base classes as a vector of Strings.
56    pub fn all_classes_str(&self) -> Vec<String> {
57        self.all_classes()
58            .into_iter()
59            .map(|class| class.into())
60            .collect()
61    }
62
63    /// Check if the collection is empty.
64    pub fn is_empty(&self) -> bool {
65        self.classes.is_empty()
66    }
67
68    /// Return list of parents for a given base class.
69    pub fn path(&self, base: &Class) -> Result<Vec<Class>, C3Error> {
70        match self.classes.get(base) {
71            Some(path) => Ok(path.clone()),
72            None => Err(C3Error::BaseClassDoesNotExists(base.clone().into())),
73        }
74    }
75
76    /// Prepare sets for the merge function.
77    pub fn sets_for(&self, bases: Vec<Class>) -> Result<Sets<Class>, C3Error> {
78        let mut sets = Sets::new();
79        for base in &bases {
80            let path = self.path(base)?;
81            if !path.is_empty() {
82                sets.push(path.clone())?;
83            }
84        }
85        if !bases.is_empty() {
86            sets.push(bases)?;
87        }
88        Ok(sets)
89    }
90
91    pub fn register_fn(&mut self, class: Class, fun: Fn) {
92        self.functions.entry(class).or_insert(vec![]).push(fun);
93    }
94
95    pub fn register_fns(&mut self, class: Class, funs: Vec<Fn>) {
96        for fun in funs {
97            self.register_fn(class.clone(), fun);
98        }
99    }
100
101    pub fn register_fn_str(&mut self, class: &str, function: &str) {
102        self.register_fn(Class::from(class), Fn::from(function))
103    }
104
105    pub fn functions(&self, class: &Class) -> Vec<Fn> {
106        let path: Vec<Class> = self.path(class).unwrap();
107        let mut functions: Vec<Fn> = vec![];
108        for class in path {
109            let mut list: Vec<Fn> = self.functions.get(&class).cloned().unwrap_or_default();
110            functions.append(&mut list);
111        }
112        functions.sort();
113        functions.dedup();
114        functions
115    }
116
117    pub fn functions_str(&self, class: &str) -> Vec<String> {
118        self.functions(&Class::from(class))
119            .into_iter()
120            .map(|x| x.to_string())
121            .collect()
122    }
123
124    pub fn register_var(&mut self, class: Class, var: Var) {
125        self.variables.entry(class).or_insert(vec![]).push(var);
126    }
127
128    pub fn register_vars(&mut self, class: Class, vars: Vec<Var>) {
129        for var in vars {
130            self.register_var(class.clone(), var);
131        }
132    }
133
134    pub fn register_var_str(&mut self, class: &str, variable: &str) {
135        self.register_var(Class::from(class), Var::from(variable))
136    }
137
138    pub fn variables(&self, class: &Class) -> Vec<Var> {
139        let path: Vec<Class> = self.path(class).unwrap();
140        let mut varialbes: Vec<Var> = vec![];
141        for class in path {
142            let mut list: Vec<Var> = self.variables.get(&class).cloned().unwrap_or_default();
143            varialbes.append(&mut list);
144        }
145        varialbes.sort();
146        varialbes.dedup();
147        varialbes
148    }
149
150    pub fn varialbes_str(&self, class: &str) -> Vec<String> {
151        self.variables(&Class::from(class))
152            .into_iter()
153            .map(|x| x.to_string())
154            .collect()
155    }
156}
157
158#[cfg(test)]
159mod tests {
160    use super::C3;
161
162    #[test]
163    fn test_c3() {
164        let mut c3 = C3::new();
165        c3.add_class_str("A", "A");
166        c3.add_class_str("B", "B, A");
167        c3.add_class_str("K1", "K1, K2, A");
168
169        assert_eq!(c3.all_classes_str(), vec!["A", "B", "K1"]);
170
171        c3.register_fn_str("A", "foo");
172        c3.register_fn_str("A", "bar");
173        c3.register_fn_str("B", "bar");
174        assert_eq!(c3.functions_str("A"), vec!["bar", "foo"]);
175        assert_eq!(c3.functions_str("B"), vec!["bar", "foo"]);
176
177        c3.register_var_str("A", "x");
178        c3.register_var_str("B", "y");
179        assert_eq!(c3.varialbes_str("A"), vec!["x"]);
180        assert_eq!(c3.varialbes_str("B"), vec!["x", "y"]);
181    }
182
183    // TODO: More tests.
184}