1#![warn(missing_docs)]
54
55#[cfg(doctest)]
57mod test_readme {
58 macro_rules! external_doc_test {
59 ($x:expr) => {
60 #[doc = $x]
61 extern "C" {}
62 };
63 }
64
65 external_doc_test!(include_str!("../README.md"));
66}
67
68use quote::__private::TokenStream;
69use quote::{ToTokens, TokenStreamExt};
70
71use indexmap::IndexMap;
72use std::collections::HashSet;
73use std::error::Error as StdError;
74use std::{cmp, fmt, hash};
75
76const STD: [&str; 5] = ["std", "alloc", "core", "proc_macro", "test"];
77const CRATE: [&str; 3] = ["self", "super", "crate"];
78
79pub struct UseItems {
85 items: Vec<syn::ItemUse>,
86}
87
88impl UseItems {
89 #[inline]
91 pub fn from_items(items: Vec<syn::ItemUse>) -> Self {
92 Self { items }
93 }
94
95 #[inline]
97 pub fn into_inner(self) -> Vec<syn::ItemUse> {
98 self.items
99 }
100}
101
102impl syn::parse::Parse for UseItems {
103 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
104 let mut items = Vec::with_capacity(5);
106
107 while !input.is_empty() {
108 items.push(input.parse()?);
109 }
110
111 Ok(Self { items })
112 }
113}
114
115impl ToTokens for UseItems {
116 fn to_tokens(&self, tokens: &mut TokenStream) {
117 tokens.append_all(&self.items);
118 }
119}
120
121impl IntoIterator for UseItems {
122 type Item = syn::ItemUse;
123 type IntoIter = std::vec::IntoIter<Self::Item>;
124
125 #[inline]
126 fn into_iter(self) -> Self::IntoIter {
127 self.items.into_iter()
128 }
129}
130
131#[derive(Clone, Debug, cmp::Eq, hash::Hash, cmp::PartialEq)]
134enum UseKey {
135 Name(syn::Ident),
136 Rename(syn::Ident, syn::Ident),
137 Glob,
138}
139
140#[derive(Clone, Debug, cmp::Eq, hash::Hash, cmp::PartialEq)]
143struct UseData {
144 vis: syn::Visibility,
145 attrs: Vec<syn::Attribute>,
146 has_leading_colons: bool,
147}
148
149impl UseData {
150 #[inline]
151 fn new(vis: syn::Visibility, attrs: Vec<syn::Attribute>, has_leading_colons: bool) -> Self {
152 Self {
153 vis,
154 attrs,
155 has_leading_colons,
156 }
157 }
158}
159
160#[derive(Clone, Default, Debug)]
163struct UseValue {
164 nodes: HashSet<UseData>,
165 paths: UseBuilder,
166}
167
168#[derive(fmt::Debug)]
172pub enum Error {
173 TopLevelGlob,
175 TopLevelGroup,
177 UseWithDiffAttr,
179}
180
181impl fmt::Display for Error {
182 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183 use Error::*;
184
185 match self {
186 TopLevelGlob => f.write_str("Top level glob is not allowed"),
187 TopLevelGroup => f.write_str("Top level group is not allowed"),
188 UseWithDiffAttr => f.write_str(
189 "Multiple copies of the same import with differing attributes are not allowed",
190 ),
191 }
192 }
193}
194
195impl StdError for Error {}
196
197#[derive(Clone, Default)]
200struct ItemUseBuilder {
201 paths: Vec<syn::Ident>,
202}
203
204impl ItemUseBuilder {
205 #[inline]
206 fn add_path(&mut self, path: syn::Ident) {
207 self.paths.push(path);
208 }
209
210 fn into_item_use(mut self, names: Vec<UseKey>, data: UseData) -> syn::ItemUse {
211 let key_to_tree = |key| match key {
212 UseKey::Name(name) => syn::UseTree::Name(syn::UseName { ident: name }),
213 UseKey::Rename(name, rename) => syn::UseTree::Rename(syn::UseRename {
214 ident: name,
215 as_token: Default::default(),
216 rename,
217 }),
218 _ => unreachable!("Impossible glob"),
219 };
220
221 let mut tree = if names.contains(&UseKey::Glob) {
225 syn::UseTree::Glob(syn::UseGlob {
226 star_token: Default::default(),
227 })
228 } else if names.len() == 1 {
230 key_to_tree(names.into_iter().next().unwrap())
232 } else {
234 let items = names.into_iter().map(key_to_tree).collect();
235
236 syn::UseTree::Group(syn::UseGroup {
237 brace_token: Default::default(),
238 items,
239 })
240 };
241
242 while !self.paths.is_empty() {
245 let path = self.paths.remove(self.paths.len() - 1);
246
247 tree = syn::UseTree::Path(syn::UsePath {
248 ident: path,
249 colon2_token: Default::default(),
250 tree: Box::new(tree),
251 });
252 }
253
254 let leading_colon = if data.has_leading_colons {
257 Some(syn::token::Colon2::default())
258 } else {
259 None
260 };
261
262 syn::ItemUse {
263 attrs: data.attrs,
264 vis: data.vis,
265 use_token: Default::default(),
266 leading_colon,
267 tree,
268 semi_token: Default::default(),
269 }
270 }
271}
272
273pub type StdExtCrateUse = (Vec<syn::ItemUse>, Vec<syn::ItemUse>, Vec<syn::ItemUse>);
277
278#[derive(Clone, Default, Debug)]
281pub struct UseBuilder {
282 map: IndexMap<UseKey, UseValue>,
283 entries: usize,
284}
285
286impl UseBuilder {
287 pub fn from_uses(items: Vec<UseItems>) -> Self {
289 let mut root_map = Self {
290 map: IndexMap::new(),
291 entries: 0,
292 };
293
294 for inner_items in items {
295 for item in inner_items.items {
296 let data = UseData::new(item.vis, item.attrs, item.leading_colon.is_some());
297 root_map.parse_tree(item.tree, data);
298 }
299 }
300
301 root_map
302 }
303
304 fn add_node(&mut self, entry: UseKey, data: UseData) {
305 match self.map.entry(entry) {
306 indexmap::map::Entry::Occupied(mut e) => {
307 e.get_mut().nodes.insert(data);
308 }
309 indexmap::map::Entry::Vacant(e) => {
310 self.entries += 1;
311 let mut u = UseValue::default();
312 u.nodes.insert(data);
313 e.insert(u);
314 }
315 }
316 }
317
318 fn add_path(&mut self, entry: UseKey) -> &mut UseBuilder {
319 match self.map.entry(entry) {
320 indexmap::map::Entry::Occupied(e) => &mut e.into_mut().paths,
321 indexmap::map::Entry::Vacant(e) => {
322 let u = UseValue::default();
323 &mut e.insert(u).paths
324 }
325 }
326 }
327
328 fn parse_tree(&mut self, tree: syn::UseTree, data: UseData) {
329 use syn::UseTree::*;
330
331 match tree {
332 Path(syn::UsePath { ident, tree, .. }) => {
333 let map = self.add_path(UseKey::Name(ident));
334 map.parse_tree(syn::UseTree::clone(&*tree), data);
336 }
337 Name(syn::UseName { ident }) => {
338 self.add_node(UseKey::Name(ident), data);
339 }
340 Rename(syn::UseRename { ident, rename, .. }) => {
341 self.add_node(UseKey::Rename(ident, rename), data);
342 }
343 Glob(syn::UseGlob { .. }) => {
344 self.add_node(UseKey::Glob, data);
345 }
346 Group(syn::UseGroup { items, .. }) => {
347 for item in items {
348 self.parse_tree(item, data.clone());
349 }
350 }
351 }
352 }
353
354 fn next_map(
355 use_map: UseBuilder,
356 builder: ItemUseBuilder,
357 items: &mut Vec<syn::ItemUse>,
358 ) -> Result<(), Error> {
359 let mut map: IndexMap<UseData, Vec<UseKey>> = IndexMap::new();
360 let len = use_map.map.len();
361
362 for (key, value) in use_map.map {
364 if let UseKey::Name(path) = key.clone() {
368 let mut builder = builder.clone();
370 builder.add_path(path);
371 if let err @ Err(_) = Self::next_map(value.paths, builder, items) {
372 return err;
373 }
374 }
375
376 if !value.nodes.is_empty() {
380 if value.nodes.len() > 1 {
382 return Err(Error::UseWithDiffAttr);
383 }
384
385 match map.entry(value.nodes.into_iter().next().unwrap()) {
388 indexmap::map::Entry::Occupied(mut e) => {
389 e.get_mut().push(key);
390 }
391 indexmap::map::Entry::Vacant(e) => {
392 let mut set = Vec::with_capacity(len);
393 set.push(key);
394 e.insert(set);
395 }
396 }
397 }
398 }
399
400 for (data, names) in map {
402 let item = builder.clone().into_item_use(names, data);
403 items.push(item);
404 }
405
406 Ok(())
407 }
408
409 pub fn into_items(self) -> Result<Vec<syn::ItemUse>, Error> {
411 let mut items = Vec::with_capacity(self.entries);
412 let builder = ItemUseBuilder::default();
413 Self::next_map(self, builder, &mut items)?;
414 Ok(items)
415 }
416
417 pub fn into_items_sections(self) -> Result<StdExtCrateUse, Error> {
420 let items = self.into_items()?;
421
422 let mut std_uses = Vec::with_capacity(items.len());
424 let mut extern_uses = Vec::with_capacity(items.len());
425 let mut crate_uses = Vec::with_capacity(items.len());
426
427 for item in items {
428 use syn::UseTree::*;
429
430 match &item.tree {
431 Path(syn::UsePath { ident, .. })
433 | Name(syn::UseName { ident })
434 | Rename(syn::UseRename { ident, .. }) => {
435 let name = &*ident.to_string();
436
437 if STD.contains(&name) {
438 std_uses.push(item);
439 } else if CRATE.contains(&name) {
440 crate_uses.push(item);
441 } else {
442 extern_uses.push(item);
443 };
444 }
445 Glob(_) => return Err(Error::TopLevelGlob),
446 Group(_) => {}
447 }
448 }
449
450 Ok((std_uses, extern_uses, crate_uses))
451 }
452}
453
454#[cfg(test)]
455mod tests {
456 use assert_unordered::assert_eq_unordered;
457 use quote::quote;
458
459 use crate::{UseBuilder, UseItems};
460
461 fn make_builder() -> UseBuilder {
462 let use1 = quote! {
463 use crate::Test;
464 use std::error::Error as StdError;
465 use std::fmt::Debug;
466 };
467
468 let use2 = quote! {
469 use syn::ItemUse;
470 use std::fmt::Display;
471 use crate::*;
472 };
473
474 let items1: UseItems = syn::parse2(use1).unwrap();
475 let items2: UseItems = syn::parse2(use2).unwrap();
476
477 UseBuilder::from_uses(vec![items1, items2])
478 }
479
480 #[test]
481 fn items() {
482 let builder = make_builder();
483 let uses = builder.into_items().unwrap();
485 let expected = quote! {
488 use crate::*;
489 use std::error::Error as StdError;
490 use std::fmt::{Debug, Display};
491 use syn::ItemUse;
492 };
493 let expected = syn::parse2::<UseItems>(expected).unwrap().into_inner();
494
495 assert_eq_unordered!(expected, uses);
496 }
497
498 #[test]
499 fn items_separated() {
500 let builder = make_builder();
501 let (std_use, ext_use, crate_use) = builder.into_items_sections().unwrap();
502
503 let std_expected = quote! {
504 use std::error::Error as StdError;
505 use std::fmt::{Debug, Display};
506 };
507 let std_expected = syn::parse2::<UseItems>(std_expected).unwrap().into_inner();
508
509 let ext_expected = quote! {
510 use syn::ItemUse;
511 };
512 let ext_expected = syn::parse2::<UseItems>(ext_expected).unwrap().into_inner();
513
514 let crate_expected = quote! {
515 use crate::*;
516 };
517 let crate_expected = syn::parse2::<UseItems>(crate_expected)
518 .unwrap()
519 .into_inner();
520
521 assert_eq_unordered!(std_expected, std_use);
522 assert_eq_unordered!(ext_expected, ext_use);
523 assert_eq_unordered!(crate_expected, crate_use);
524 }
525}