1use std::{cell::Cell, collections::BTreeMap};
6
7use crate::{
8 context::Context,
9 function::{Function, FunctionIterator},
10 Constant, GlobalVar, MetadataIndex, StorageKey, Type,
11};
12
13#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
16pub struct Module(pub slotmap::DefaultKey);
17
18#[doc(hidden)]
19pub struct ModuleContent {
20 pub kind: Kind,
21 pub functions: Vec<Function>,
22 pub global_variables: BTreeMap<Vec<String>, GlobalVar>,
23 pub configs: BTreeMap<String, ConfigContent>,
24 pub storage_keys: BTreeMap<String, StorageKey>,
25}
26
27#[derive(Clone, Debug)]
28pub enum ConfigContent {
29 V0 {
30 name: String,
31 ty: Type,
32 ptr_ty: Type,
33 constant: Constant,
34 opt_metadata: Option<MetadataIndex>,
35 },
36 V1 {
37 name: String,
38 ty: Type,
39 ptr_ty: Type,
40 encoded_bytes: Vec<u8>,
41 decode_fn: Cell<Function>,
42 opt_metadata: Option<MetadataIndex>,
43 },
44}
45
46#[derive(Clone, Copy, Debug, Eq, PartialEq)]
48pub enum Kind {
49 Contract,
50 Library,
51 Predicate,
52 Script,
53}
54
55impl Module {
56 pub fn new(context: &mut Context, kind: Kind) -> Module {
58 let content = ModuleContent {
59 kind,
60 functions: Vec::new(),
61 global_variables: BTreeMap::new(),
62 configs: BTreeMap::new(),
63 storage_keys: BTreeMap::new(),
64 };
65 Module(context.modules.insert(content))
66 }
67
68 pub fn get_kind(&self, context: &Context) -> Kind {
70 context.modules[self.0].kind
71 }
72
73 pub fn function_iter(&self, context: &Context) -> FunctionIterator {
75 FunctionIterator::new(context, self)
76 }
77
78 pub fn add_global_variable(
80 &self,
81 context: &mut Context,
82 call_path: Vec<String>,
83 const_val: GlobalVar,
84 ) {
85 context.modules[self.0]
86 .global_variables
87 .insert(call_path, const_val);
88 }
89
90 pub fn new_unique_global_var(
94 &self,
95 context: &mut Context,
96 name: String,
97 local_type: Type,
98 initializer: Option<Constant>,
99 mutable: bool,
100 ) -> GlobalVar {
101 let module = &context.modules[self.0];
102 let new_name = if module.global_variables.contains_key(&vec![name.clone()]) {
103 (0..)
106 .find_map(|n| {
107 let candidate = format!("{name}{n}");
108 if module
109 .global_variables
110 .contains_key(&vec![candidate.clone()])
111 {
112 None
113 } else {
114 Some(candidate)
115 }
116 })
117 .unwrap()
118 } else {
119 name
120 };
121 let gv = GlobalVar::new(context, local_type, initializer, mutable);
122 self.add_global_variable(context, vec![new_name], gv);
123 gv
124 }
125
126 pub fn get_global_variable(
128 &self,
129 context: &Context,
130 call_path: &Vec<String>,
131 ) -> Option<GlobalVar> {
132 context.modules[self.0]
133 .global_variables
134 .get(call_path)
135 .copied()
136 }
137
138 pub fn lookup_global_variable_name(
140 &self,
141 context: &Context,
142 global: &GlobalVar,
143 ) -> Option<String> {
144 context.modules[self.0]
145 .global_variables
146 .iter()
147 .find(|(_key, val)| *val == global)
148 .map(|(key, _)| key.join("::"))
149 }
150
151 pub fn add_config(&self, context: &mut Context, name: String, content: ConfigContent) {
153 context.modules[self.0].configs.insert(name, content);
154 }
155
156 pub fn get_config<'a>(&self, context: &'a Context, name: &str) -> Option<&'a ConfigContent> {
158 context.modules[self.0].configs.get(name)
159 }
160
161 pub fn add_storage_key(&self, context: &mut Context, path: String, storage_key: StorageKey) {
163 context.modules[self.0]
164 .storage_keys
165 .insert(path, storage_key);
166 }
167
168 pub fn get_storage_key<'a>(&self, context: &'a Context, path: &str) -> Option<&'a StorageKey> {
170 context.modules[self.0].storage_keys.get(path)
171 }
172
173 pub fn lookup_storage_key_path<'a>(
175 &self,
176 context: &'a Context,
177 storage_key: &StorageKey,
178 ) -> Option<&'a str> {
179 context.modules[self.0]
180 .storage_keys
181 .iter()
182 .find(|(_key, val)| *val == storage_key)
183 .map(|(key, _)| key.as_str())
184 }
185
186 pub fn remove_function(&self, context: &mut Context, function: &Function) {
190 context
191 .modules
192 .get_mut(self.0)
193 .expect("Module must exist in context.")
194 .functions
195 .retain(|mod_fn| mod_fn != function);
196 }
197
198 pub fn iter_configs<'a>(
199 &'a self,
200 context: &'a Context,
201 ) -> impl Iterator<Item = &'a ConfigContent> + 'a {
202 context.modules[self.0].configs.values()
203 }
204}
205
206pub struct ModuleIterator {
208 modules: Vec<slotmap::DefaultKey>,
209 next: usize,
210}
211
212impl ModuleIterator {
213 pub fn new(context: &Context) -> ModuleIterator {
215 ModuleIterator {
218 modules: context.modules.iter().map(|pair| pair.0).collect(),
219 next: 0,
220 }
221 }
222}
223
224impl Iterator for ModuleIterator {
225 type Item = Module;
226
227 fn next(&mut self) -> Option<Module> {
228 if self.next < self.modules.len() {
229 let idx = self.next;
230 self.next += 1;
231 Some(Module(self.modules[idx]))
232 } else {
233 None
234 }
235 }
236}