• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use syn::{Arm, Ident, Result, Variant};
2 use syn::{Error, Field, Pat, PatIdent};
3 
4 use crate::compare::Path;
5 use crate::format;
6 use crate::parse::Input::{self, *};
7 
sorted(input: Input) -> Result<()>8 pub fn sorted(input: Input) -> Result<()> {
9     let paths = match input {
10         Enum(item) => collect_paths(item.variants)?,
11         Struct(fields) => collect_paths(fields.named)?,
12         Match(expr) | Let(expr) => collect_paths(expr.arms)?,
13     };
14 
15     for i in 1..paths.len() {
16         let cur = &paths[i];
17         if *cur < paths[i - 1] {
18             let lesser = cur;
19             let correct_pos = paths[..i - 1].binary_search(cur).unwrap_err();
20             let greater = &paths[correct_pos];
21             return Err(format::error(lesser, greater));
22         }
23     }
24 
25     Ok(())
26 }
27 
collect_paths<I>(iter: I) -> Result<Vec<Path>> where I: IntoIterator, I::Item: IntoPath,28 fn collect_paths<I>(iter: I) -> Result<Vec<Path>>
29 where
30     I: IntoIterator,
31     I::Item: IntoPath,
32 {
33     iter.into_iter().map(IntoPath::into_path).collect()
34 }
35 
36 trait IntoPath {
into_path(self) -> Result<Path>37     fn into_path(self) -> Result<Path>;
38 }
39 
40 impl IntoPath for Variant {
into_path(self) -> Result<Path>41     fn into_path(self) -> Result<Path> {
42         Ok(Path {
43             segments: vec![self.ident],
44         })
45     }
46 }
47 
48 impl IntoPath for Field {
into_path(self) -> Result<Path>49     fn into_path(self) -> Result<Path> {
50         Ok(Path {
51             segments: vec![self.ident.expect("must be named field")],
52         })
53     }
54 }
55 
56 impl IntoPath for Arm {
into_path(self) -> Result<Path>57     fn into_path(self) -> Result<Path> {
58         // Sort by just the first pat.
59         let pat = self.pats.into_iter().next().expect("at least one pat");
60 
61         let segments = match pat {
62             Pat::Wild(pat) => vec![Ident::from(pat.underscore_token)],
63             Pat::Path(pat) => idents_of_path(pat.path),
64             Pat::Struct(pat) => idents_of_path(pat.path),
65             Pat::TupleStruct(pat) => idents_of_path(pat.path),
66             Pat::Ident(ref pat) if is_just_ident(pat) => vec![pat.ident.clone()],
67             other => {
68                 let msg = "unsupported by #[remain::sorted]";
69                 return Err(Error::new_spanned(other, msg));
70             }
71         };
72 
73         Ok(Path { segments })
74     }
75 }
76 
idents_of_path(path: syn::Path) -> Vec<Ident>77 fn idents_of_path(path: syn::Path) -> Vec<Ident> {
78     path.segments.into_iter().map(|seg| seg.ident).collect()
79 }
80 
is_just_ident(pat: &PatIdent) -> bool81 fn is_just_ident(pat: &PatIdent) -> bool {
82     pat.by_ref.is_none() && pat.mutability.is_none() && pat.subpat.is_none()
83 }
84