codegen_rs/
scope.rs

1use std::fmt::{self, Write};
2
3use indexmap::IndexMap;
4
5use crate::docs::Docs;
6use crate::formatter::Formatter;
7use crate::function::Function;
8use crate::import::Import;
9use crate::item::Item;
10use crate::module::Module;
11
12use crate::r#enum::Enum;
13use crate::r#impl::Impl;
14use crate::r#struct::Struct;
15use crate::r#trait::Trait;
16
17/// Defines a scope.
18///
19/// A scope contains modules, types, etc...
20#[derive(Debug, Clone)]
21pub struct Scope {
22    /// Scope documentation
23    docs: Option<Docs>,
24
25    /// Imports
26    imports: IndexMap<String, IndexMap<String, Import>>,
27
28    /// Contents of the documentation,
29    items: Vec<Item>,
30}
31
32impl Scope {
33    /// Returns a new scope
34    pub fn new() -> Self {
35        Self {
36            docs: None,
37            imports: IndexMap::new(),
38            items: vec![],
39        }
40    }
41
42    /// Import a type into the scope.
43    ///
44    /// This results in a new `use` statement being added to the beginning of
45    /// the scope.
46    pub fn import(&mut self, path: &str, ty: &str) -> &mut Import {
47        // handle cases where the caller wants to refer to a type namespaced
48        // within the containing namespace, like "a::B".
49        let ty = ty.split("::").next().unwrap_or(ty);
50        self.imports
51            .entry(path.to_string())
52            .or_insert(IndexMap::new())
53            .entry(ty.to_string())
54            .or_insert_with(|| Import::new(path, ty))
55    }
56
57    /// Push a new module definition, returning a mutable reference to it.
58    ///
59    /// # Panics
60    ///
61    /// Since a module's name must uniquely identify it within the scope in
62    /// which it is defined, pushing a module whose name is already defined
63    /// in this scope will cause this function to panic.
64    ///
65    /// In many cases, the [`get_or_new_module`] function is preferrable, as it
66    /// will return the existing definition instead.
67    ///
68    /// [`get_or_new_module`]: #method.get_or_new_module
69    pub fn new_module(&mut self, name: &str) -> &mut Module {
70        self.push_module(Module::new(name));
71
72        match self.items.last_mut().unwrap() {
73            Item::Module(v) => v,
74            _ => unreachable!(),
75        }
76    }
77
78    /// Returns a mutable reference to a module if it is exists in this scope.
79    pub fn get_module_mut<Q: ?Sized>(&mut self, name: &Q) -> Option<&mut Module>
80    where
81        String: PartialEq<Q>,
82    {
83        self.items
84            .iter_mut()
85            .filter_map(|item| match item {
86                Item::Module(ref mut module) if module.name == *name => Some(module),
87                _ => None,
88            })
89            .next()
90    }
91
92    /// Returns a mutable reference to a module if it is exists in this scope.
93    pub fn get_module<Q: ?Sized>(&self, name: &Q) -> Option<&Module>
94    where
95        String: PartialEq<Q>,
96    {
97        self.items
98            .iter()
99            .filter_map(|item| match item {
100                Item::Module(module) if module.name == *name => Some(module),
101                _ => None,
102            })
103            .next()
104    }
105
106    /// Returns a mutable reference to a module, creating it if it does
107    /// not exist.
108    pub fn get_or_new_module(&mut self, name: &str) -> &mut Module {
109        if self.get_module(name).is_some() {
110            self.get_module_mut(name).unwrap()
111        } else {
112            self.new_module(name)
113        }
114    }
115
116    /// Push a module definition.
117    ///
118    /// # Panics
119    ///
120    /// Since a module's name must uniquely identify it within the scope in
121    /// which it is defined, pushing a module whose name is already defined
122    /// in this scope will cause this function to panic.
123    ///
124    /// In many cases, the [`get_or_new_module`] function is preferrable, as it will
125    /// return the existing definition instead.
126    ///
127    /// [`get_or_new_module`]: #method.get_or_new_module
128    pub fn push_module(&mut self, item: Module) -> &mut Self {
129        assert!(self.get_module(&item.name).is_none());
130        self.items.push(Item::Module(item));
131        self
132    }
133
134    /// Push a new struct definition, returning a mutable reference to it.
135    pub fn new_struct(&mut self, name: &str) -> &mut Struct {
136        self.push_struct(Struct::new(name));
137
138        match self.items.last_mut().unwrap() {
139            Item::Struct(v) => v,
140            _ => unreachable!(),
141        }
142    }
143
144    /// Push a struct definition
145    pub fn push_struct(&mut self, item: Struct) -> &mut Self {
146        self.items.push(Item::Struct(item));
147        self
148    }
149
150    /// Push a new function definition, returning a mutable reference to it.
151    pub fn new_fn(&mut self, name: &str) -> &mut Function {
152        self.push_fn(Function::new(name));
153
154        match *self.items.last_mut().unwrap() {
155            Item::Function(ref mut v) => v,
156            _ => unreachable!(),
157        }
158    }
159
160    /// Push a function definition
161    pub fn push_fn(&mut self, item: Function) -> &mut Self {
162        self.items.push(Item::Function(item));
163        self
164    }
165
166    /// Push a new trait definition, returning a mutable reference to it.
167    pub fn new_trait(&mut self, name: &str) -> &mut Trait {
168        self.push_trait(Trait::new(name));
169
170        match *self.items.last_mut().unwrap() {
171            Item::Trait(ref mut v) => v,
172            _ => unreachable!(),
173        }
174    }
175
176    /// Push a trait definition
177    pub fn push_trait(&mut self, item: Trait) -> &mut Self {
178        self.items.push(Item::Trait(item));
179        self
180    }
181
182    /// Push a new struct definition, returning a mutable reference to it.
183    pub fn new_enum(&mut self, name: &str) -> &mut Enum {
184        self.push_enum(Enum::new(name));
185
186        match *self.items.last_mut().unwrap() {
187            Item::Enum(ref mut v) => v,
188            _ => unreachable!(),
189        }
190    }
191
192    /// Push a structure definition
193    pub fn push_enum(&mut self, item: Enum) -> &mut Self {
194        self.items.push(Item::Enum(item));
195        self
196    }
197
198    /// Push a new `impl` block, returning a mutable reference to it.
199    pub fn new_impl(&mut self, target: &str) -> &mut Impl {
200        self.push_impl(Impl::new(target));
201
202        match *self.items.last_mut().unwrap() {
203            Item::Impl(ref mut v) => v,
204            _ => unreachable!(),
205        }
206    }
207
208    /// Push an `impl` block.
209    pub fn push_impl(&mut self, item: Impl) -> &mut Self {
210        self.items.push(Item::Impl(item));
211        self
212    }
213
214    /// Push a raw string to the scope.
215    ///
216    /// This string will be included verbatim in the formatted string.
217    pub fn raw(&mut self, val: &str) -> &mut Self {
218        self.items.push(Item::Raw(val.to_string()));
219        self
220    }
221
222    /// Return a string representation of the scope.
223    pub fn to_string(&self) -> String {
224        let mut ret = String::new();
225
226        self.fmt(&mut Formatter::new(&mut ret)).unwrap();
227
228        // Remove the trailing newline
229        if ret.as_bytes().last() == Some(&b'\n') {
230            ret.pop();
231        }
232
233        ret
234    }
235
236    /// Formats the scope using the given formatter.
237    pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
238        self.fmt_imports(fmt)?;
239
240        if !self.imports.is_empty() {
241            writeln!(fmt)?;
242        }
243
244        for (i, item) in self.items.iter().enumerate() {
245            if i != 0 {
246                writeln!(fmt)?;
247            }
248
249            match &item {
250                Item::Module(v) => v.fmt(fmt)?,
251                Item::Struct(v) => v.fmt(fmt)?,
252                Item::Function(v) => v.fmt(false, fmt)?,
253                Item::Trait(v) => v.fmt(fmt)?,
254                Item::Enum(v) => v.fmt(fmt)?,
255                Item::Impl(v) => v.fmt(fmt)?,
256                Item::Raw(v) => {
257                    writeln!(fmt, "{}", v)?;
258                }
259            }
260        }
261
262        Ok(())
263    }
264
265    fn fmt_imports(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
266        // First, collect all visibilities
267        let mut visibilities = vec![];
268
269        for (_, imports) in &self.imports {
270            for (_, import) in imports {
271                if !visibilities.contains(&import.vis) {
272                    visibilities.push(import.vis.clone());
273                }
274            }
275        }
276
277        let mut tys = vec![];
278
279        // Loop over all visibilities and format the associated imports
280        for vis in &visibilities {
281            for (path, imports) in &self.imports {
282                tys.clear();
283
284                for (ty, import) in imports {
285                    if *vis == import.vis {
286                        tys.push(ty);
287                    }
288                }
289
290                if !tys.is_empty() {
291                    if let Some(vis) = &vis {
292                        write!(fmt, "{} ", vis)?;
293                    }
294
295                    write!(fmt, "use {}::", path)?;
296
297                    if tys.len() > 1 {
298                        write!(fmt, "{{")?;
299
300                        for (i, ty) in tys.iter().enumerate() {
301                            if i != 0 {
302                                write!(fmt, ", ")?;
303                            }
304                            write!(fmt, "{}", ty)?;
305                        }
306
307                        writeln!(fmt, "}};")?;
308                    } else if tys.len() == 1 {
309                        writeln!(fmt, "{};", tys[0])?;
310                    }
311                }
312            }
313        }
314
315        Ok(())
316    }
317}