kaze/graph/
context.rs

1use super::instance::*;
2use super::mem::*;
3use super::module::*;
4use super::register::*;
5use super::signal::*;
6
7use typed_arena::Arena;
8
9use std::cell::{Ref, RefCell};
10use std::collections::BTreeMap;
11
12/// A top-level container/owner object for a [`Module`] graph.
13///
14/// A `Context` owns all parts of a module graph, and provides an API for creating [`Module`] objects.
15///
16/// # Examples
17///
18/// ```
19/// use kaze::*;
20///
21/// let c = Context::new();
22///
23/// let m = c.module("MyModule");
24/// m.output("out", m.input("in", 1));
25/// ```
26#[must_use]
27pub struct Context<'a> {
28    module_arena: Arena<Module<'a>>,
29    pub(super) signal_arena: Arena<Signal<'a>>,
30    pub(super) register_data_arena: Arena<RegisterData<'a>>,
31    pub(super) register_arena: Arena<Register<'a>>,
32    pub(super) instance_arena: Arena<Instance<'a>>,
33    pub(super) mem_arena: Arena<Mem<'a>>,
34
35    pub(super) modules: RefCell<BTreeMap<String, &'a Module<'a>>>,
36}
37
38impl<'a> Context<'a> {
39    /// Creates a new, empty `Context`.
40    ///
41    /// # Examples
42    ///
43    /// ```
44    /// use kaze::*;
45    ///
46    /// let c = Context::new();
47    /// ```
48    pub fn new() -> Context<'a> {
49        Context {
50            module_arena: Arena::new(),
51            signal_arena: Arena::new(),
52            register_data_arena: Arena::new(),
53            register_arena: Arena::new(),
54            instance_arena: Arena::new(),
55            mem_arena: Arena::new(),
56
57            modules: RefCell::new(BTreeMap::new()),
58        }
59    }
60
61    /// Creates a new [`Module`] called `name` in this `Context`.
62    ///
63    /// Conventionally, `name` should be `CamelCase`, though this is not enforced.
64    ///
65    /// # Panics
66    ///
67    /// Panics if a [`Module`] with the same `name` already exists in this `Context`.
68    ///
69    /// # Examples
70    ///
71    /// ```
72    /// use kaze::*;
73    ///
74    /// let c = Context::new();
75    ///
76    /// let my_module = c.module("MyModule");
77    /// let another_mod = c.module("AnotherMod");
78    /// ```
79    ///
80    /// The following example panics by creating a `Module` with the same `name` as a previously-created `Module` in the same `Context`:
81    ///
82    /// ```should_panic
83    /// use kaze::*;
84    ///
85    /// let c = Context::new();
86    ///
87    /// let _ = c.module("A"); // Unique name, OK
88    /// let _ = c.module("B"); // Unique name, OK
89    ///
90    /// let _ = c.module("A"); // Non-unique name, panic!
91    /// ```
92    pub fn module<S: Into<String>>(&'a self, name: S) -> &Module {
93        let name = name.into();
94        let mut modules = self.modules.borrow_mut();
95        if modules.contains_key(&name) {
96            panic!(
97                "A module with the name \"{}\" already exists in this context.",
98                name
99            );
100        }
101        let module = self.module_arena.alloc(Module::new(self, name.clone()));
102        modules.insert(name, module);
103        module
104    }
105
106    /// Immutably borrows this `Context`'s [`Module`]s.
107    ///
108    /// This is primarily useful for iterating over every [`Module`] in this `Context` when generating code.
109    ///
110    /// # Examples
111    ///
112    /// ```
113    /// use kaze::*;
114    ///
115    /// let c = Context::new();
116    ///
117    /// let my_module = c.module("MyModule");
118    /// let another_mod = c.module("AnotherMod");
119    ///
120    /// assert_eq!(c.modules().len(), 2);
121    /// ```
122    pub fn modules(&'a self) -> Ref<BTreeMap<String, &'a Module<'a>>> {
123        self.modules.borrow()
124    }
125}
126
127#[cfg(test)]
128mod tests {
129    use super::*;
130
131    #[test]
132    #[should_panic(expected = "A module with the name \"A\" already exists in this context.")]
133    fn unique_module_names() {
134        let c = Context::new();
135
136        let _ = c.module("A"); // Unique name, OK
137        let _ = c.module("B"); // Unique name, OK
138
139        // Panic
140        let _ = c.module("A");
141    }
142
143    #[test]
144    fn new_context_has_no_modules() {
145        let c = Context::new();
146
147        assert!(c.modules().is_empty());
148    }
149}