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}