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#[derive(Debug, Clone)]
22pub struct Scope {
23 docs: Option<Docs>,
25
26 imports: IndexMap<String, IndexMap<String, Import>>,
28
29 items: Vec<Item>,
31}
32
33impl Scope {
34 pub fn new() -> Self {
36 Scope {
37 docs: None,
38 imports: IndexMap::new(),
39 items: vec![],
40 }
41 }
42
43 pub fn import(&mut self, path: &str, ty: &str) -> &mut Import {
48 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 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 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 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 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 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 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 pub fn push_struct(&mut self, item: Struct) -> &mut Self {
147 self.items.push(Item::Struct(item));
148 self
149 }
150
151 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 pub fn push_fn(&mut self, item: Function) -> &mut Self {
163 self.items.push(Item::Function(item));
164 self
165 }
166
167 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 pub fn push_trait(&mut self, item: Trait) -> &mut Self {
179 self.items.push(Item::Trait(item));
180 self
181 }
182
183 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 pub fn push_enum(&mut self, item: Enum) -> &mut Self {
195 self.items.push(Item::Enum(item));
196 self
197 }
198
199 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 pub fn push_impl(&mut self, item: Impl) -> &mut Self {
211 self.items.push(Item::Impl(item));
212 self
213 }
214
215 pub fn raw(&mut self, val: impl Into<String>) -> &mut Self {
219 self.items.push(Item::Raw(val.into()));
220 self
221 }
222
223 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 pub fn push_type_alias(&mut self, item: TypeAlias) -> &mut Self {
239 self.items.push(Item::TypeAlias(item));
240 self
241 }
242
243 pub fn to_string(&self) -> String {
245 let mut ret = String::new();
246
247 self.fmt(&mut Formatter::new(&mut ret)).unwrap();
248
249 if ret.as_bytes().last() == Some(&b'\n') {
251 ret.pop();
252 }
253
254 ret
255 }
256
257 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 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 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}