codegen/
scope.rs

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