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