1use super::signal::Signal;
3use std::collections::{BTreeMap, BTreeSet};
4
5#[derive(Debug)]
6pub enum ScopeChild {
7 Signal,
8 Scope,
9}
10
11#[derive(Debug)]
12pub struct Scope {
13 pub name: String,
14 signals: BTreeSet<String>,
15 scopes: BTreeMap<String, Scope>,
16 path: Vec<String>,
17}
18
19impl Scope {
20 pub fn new(name: String) -> Scope {
21 Scope {
22 name,
23 signals: BTreeSet::new(),
24 scopes: BTreeMap::new(),
25 path: Vec::new(),
26 }
27 }
28
29 pub fn add_scope(&mut self, path: &[&str]) {
30 if let Some(name) = path.first() {
31 match self.scopes.get(*name) {
32 Some(_) => self.get_scope(name).unwrap().add_scope(&path[1..]),
33 None => {
34 let mut s = Scope::new(name.to_string());
35 s.path = self.path.clone();
36 s.path.push(self.name.clone());
37 s.add_scope(&path[1..]);
38 self.scopes.insert(s.name.clone(), s);
39 }
40 }
41 }
42 }
43
44 pub fn get_scope(&mut self, name: &str) -> Option<&mut Scope> {
45 self.scopes.get_mut(name)
46 }
47
48 pub fn get_scope_by_path(&mut self, path: &[&str]) -> Option<&mut Scope> {
49 match path.first() {
50 Some(name) => match self.scopes.get(*name) {
51 Some(_) => self.get_scope(name).unwrap().get_scope_by_path(&path[1..]),
52 None => None,
53 },
54 None => Some(self),
55 }
56 }
57
58 pub fn add_signal(&mut self, signal: &mut Signal) {
59 self.signals.insert(signal.id.clone());
60 signal.path = self.path.clone();
61 signal.path.push(self.name.clone())
62 }
63
64 fn _traverse<T, F: FnMut(&str, &ScopeChild, u64) -> T>(&self, depth: u64, f: &mut F) {
65 for name in &self.signals {
66 f(name, &ScopeChild::Signal, depth);
67 }
68
69 for (name, scope) in &self.scopes {
70 f(name, &ScopeChild::Scope, depth);
71 scope._traverse(depth + 1, f);
72 }
73 }
74
75 pub fn traverse<T, F: FnMut(&str, &ScopeChild, u64) -> T>(&self, f: &mut F) {
76 self._traverse(0, f)
77 }
78}
79
80#[cfg(test)]
81mod test {
82 use super::*;
83
84 #[test]
85 fn scope() {
86 let mut s = Scope::new(String::from("top"));
87 s.add_scope(&["foo", "bar"]);
88
89 let foo = s.get_scope_by_path(&["foo"]).expect("Path doesn't exist");
90 foo.add_signal(&mut Signal::new("bar", "bar", 42));
91
92 s.get_scope_by_path(&["foo", "bar"])
93 .expect("Path doesn't exist");
94 }
95}