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