Skip to main content

lutra_compiler/pr/
path.rs

1/// A name referring to a statement within the module tree.
2/// This is glorified way of writing a "vec with at least one element".
3#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
4pub struct Path {
5    path: Vec<String>,
6}
7
8impl Path {
9    /// Creates a new ident from a non-empty path.
10    pub fn new<S: ToString, I: IntoIterator<Item = S>>(path: I) -> Self {
11        Path {
12            path: path.into_iter().map(|x| x.to_string()).collect(),
13        }
14    }
15    pub fn empty() -> Self {
16        Path { path: vec![] }
17    }
18
19    pub fn from_name<S: ToString>(name: S) -> Self {
20        Path {
21            path: vec![name.to_string()],
22        }
23    }
24
25    pub fn first(&self) -> &str {
26        self.path.first().unwrap()
27    }
28
29    pub fn last(&self) -> &str {
30        self.path.last().unwrap()
31    }
32
33    pub fn parent(&self) -> Option<&[String]> {
34        if self.is_empty() {
35            None
36        } else {
37            Some(&self.path[0..(self.len() - 1)])
38        }
39    }
40
41    pub fn as_steps(&self) -> &[String] {
42        &self.path
43    }
44
45    pub fn len(&self) -> usize {
46        self.path.len()
47    }
48
49    pub fn is_empty(&self) -> bool {
50        self.path.is_empty()
51    }
52
53    pub fn prepend(&mut self, mut prefix: Path) {
54        prefix.path.append(&mut self.path);
55        self.path = prefix.path;
56    }
57
58    pub fn append(mut self, suffix: Path) -> Path {
59        self.path.extend(suffix.path);
60        self
61    }
62
63    pub fn extend(&mut self, suffix: Path) {
64        self.path.extend(suffix);
65    }
66
67    pub fn push(&mut self, name: String) {
68        self.path.push(name);
69    }
70
71    pub fn pop(&mut self) -> Option<String> {
72        self.path.pop()
73    }
74
75    pub fn pop_first(&mut self) -> Option<String> {
76        if self.is_empty() {
77            return None;
78        }
79        let remaining = self.path.split_off(1);
80        let first = std::mem::replace(&mut self.path, remaining);
81        Some(first.into_iter().next().unwrap())
82    }
83
84    pub fn with_name<S: ToString>(mut self, name: S) -> Self {
85        *self.path.last_mut().unwrap() = name.to_string();
86        self
87    }
88
89    pub fn iter(&self) -> impl DoubleEndedIterator<Item = &String> {
90        self.path.iter()
91    }
92
93    pub fn starts_with(&self, prefix: &Path) -> bool {
94        if prefix.len() > self.len() {
95            return false;
96        }
97        prefix
98            .iter()
99            .zip(self.iter())
100            .all(|(prefix_component, self_component)| prefix_component == self_component)
101    }
102
103    pub fn starts_with_path<S: AsRef<str>>(&self, prefix: &[S]) -> bool {
104        // self is an I
105        if prefix.len() > self.len() {
106            return false;
107        }
108        prefix
109            .iter()
110            .zip(self.iter())
111            .all(|(prefix_component, self_component)| prefix_component.as_ref() == self_component)
112    }
113
114    pub fn starts_with_part(&self, prefix: &str) -> bool {
115        self.starts_with_path(&[prefix])
116    }
117}
118
119impl std::fmt::Debug for Path {
120    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121        f.write_str(&display_path(self))
122    }
123}
124
125impl std::fmt::Display for Path {
126    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127        f.write_str(&display_path(self))
128    }
129}
130
131impl IntoIterator for Path {
132    type Item = String;
133    type IntoIter = std::vec::IntoIter<std::string::String>;
134
135    fn into_iter(self) -> Self::IntoIter {
136        self.path.into_iter()
137    }
138}
139
140impl std::ops::Add<Path> for Path {
141    type Output = Path;
142
143    fn add(mut self, rhs: Path) -> Self::Output {
144        self.path.extend(rhs.path);
145        self
146    }
147}
148
149fn display_path(ident: &Path) -> String {
150    let path = &ident.path[..];
151
152    let mut r = String::new();
153    for (index, part) in path.iter().enumerate() {
154        if index > 0 {
155            r += "::";
156        }
157        r += lutra_bin::ident::display(part).as_ref();
158    }
159    r
160}