• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use proc_macro2::Ident;
2 use std::cmp::Ordering;
3 
4 use crate::atom::iter_atoms;
5 
6 #[derive(Copy, Clone, PartialEq)]
7 pub enum UnderscoreOrder {
8     First,
9     Last,
10 }
11 
12 pub struct Path {
13     pub segments: Vec<Ident>,
14 }
15 
cmp(lhs: &Path, rhs: &Path, mode: UnderscoreOrder) -> Ordering16 pub fn cmp(lhs: &Path, rhs: &Path, mode: UnderscoreOrder) -> Ordering {
17     // Lexicographic ordering across path segments.
18     for (lhs, rhs) in lhs.segments.iter().zip(&rhs.segments) {
19         match cmp_segment(&lhs.to_string(), &rhs.to_string(), mode) {
20             Ordering::Equal => {}
21             non_eq => return non_eq,
22         }
23     }
24 
25     lhs.segments.len().cmp(&rhs.segments.len())
26 }
27 
cmp_segment(lhs: &str, rhs: &str, mode: UnderscoreOrder) -> Ordering28 fn cmp_segment(lhs: &str, rhs: &str, mode: UnderscoreOrder) -> Ordering {
29     // Sort `_` last.
30     match (lhs, rhs) {
31         ("_", "_") => return Ordering::Equal,
32         ("_", _) => return Ordering::Greater,
33         (_, "_") => return Ordering::Less,
34         (_, _) => {}
35     }
36 
37     let mut lhs_atoms = iter_atoms(lhs);
38     let mut rhs_atoms = iter_atoms(rhs);
39 
40     // Path segments can't be empty.
41     let mut left = lhs_atoms.next().unwrap();
42     let mut right = rhs_atoms.next().unwrap();
43 
44     if mode == UnderscoreOrder::Last {
45         // Compare leading underscores.
46         match left.underscores().cmp(&right.underscores()) {
47             Ordering::Equal => {}
48             non_eq => return non_eq,
49         }
50     }
51 
52     loop {
53         match left.cmp(&right) {
54             Ordering::Equal => {}
55             non_eq => return non_eq,
56         }
57 
58         match (lhs_atoms.next(), rhs_atoms.next()) {
59             (None, None) => return Ordering::Equal,
60             (None, Some(_)) => return Ordering::Less,
61             (Some(_), None) => return Ordering::Greater,
62             (Some(nextl), Some(nextr)) => {
63                 left = nextl;
64                 right = nextr;
65             }
66         }
67     }
68 }
69