sqruff_lib_core/utils/functional/
segments.rs

1use crate::dialects::syntax::SyntaxSet;
2use crate::parser::segments::ErasedSegment;
3use crate::templaters::TemplatedFile;
4
5#[derive(Debug, Default, Clone)]
6pub struct Segments {
7    pub base: Vec<ErasedSegment>,
8    templated_file: Option<TemplatedFile>,
9}
10
11impl Segments {
12    pub fn into_vec(self) -> Vec<ErasedSegment> {
13        self.base
14    }
15
16    pub fn iter(&self) -> impl Iterator<Item = &ErasedSegment> {
17        self.base.iter()
18    }
19
20    pub fn recursive_crawl(&self, types: &SyntaxSet, recurse_into: bool) -> Segments {
21        let mut segments = Vec::new();
22
23        for segment in &self.base {
24            segments.extend(segment.recursive_crawl(types, recurse_into, &SyntaxSet::EMPTY, true));
25        }
26
27        Segments::from_vec(segments, self.templated_file.clone())
28    }
29
30    pub fn iterate_segments(&self) -> impl Iterator<Item = Segments> + '_ {
31        let mut iter = self.base.iter();
32
33        std::iter::from_fn(move || {
34            let segment = iter.next()?;
35            Segments::new(segment.clone(), self.templated_file.clone()).into()
36        })
37    }
38
39    pub fn from_vec(base: Vec<ErasedSegment>, templated_file: Option<TemplatedFile>) -> Self {
40        Self {
41            base,
42            templated_file,
43        }
44    }
45
46    pub fn reversed(&self) -> Self {
47        let mut base = self.base.clone();
48        base.reverse();
49
50        Self {
51            base,
52            templated_file: self.templated_file.clone(),
53        }
54    }
55
56    pub fn get(&self, index: usize, default: Option<ErasedSegment>) -> Option<ErasedSegment> {
57        self.base.get(index).cloned().or(default)
58    }
59
60    pub fn first(&self) -> Option<&ErasedSegment> {
61        self.base.first()
62    }
63
64    pub fn last(&self) -> Option<&ErasedSegment> {
65        self.base.last()
66    }
67
68    #[track_caller]
69    pub fn pop(&mut self) -> ErasedSegment {
70        self.base.pop().unwrap()
71    }
72
73    pub fn all_match<F: Fn(&ErasedSegment) -> bool>(&self, predicate: F) -> bool {
74        self.base.iter().all(predicate)
75    }
76
77    pub fn any_match<F: Fn(&ErasedSegment) -> bool>(&self, predicate: F) -> bool {
78        self.base.iter().any(predicate)
79    }
80
81    pub fn len(&self) -> usize {
82        self.base.len()
83    }
84
85    pub fn is_empty(&self) -> bool {
86        self.base.is_empty()
87    }
88
89    pub fn new(segment: ErasedSegment, templated_file: Option<TemplatedFile>) -> Self {
90        Self {
91            base: vec![segment],
92            templated_file,
93        }
94    }
95
96    pub fn children_all(&self) -> Segments {
97        let mut child_segments = Vec::with_capacity(self.len());
98        for segment in &self.base {
99            child_segments.extend(segment.segments().iter().cloned());
100        }
101        Segments {
102            base: child_segments,
103            templated_file: self.templated_file.clone(),
104        }
105    }
106
107    pub fn children_where<F: Fn(&ErasedSegment) -> bool>(&self, predicate: F) -> Segments {
108        let mut child_segments = Vec::with_capacity(self.len());
109        for segment in &self.base {
110            for child in segment.segments() {
111                if predicate(child) {
112                    child_segments.push(child.clone());
113                }
114            }
115        }
116        Segments {
117            base: child_segments,
118            templated_file: self.templated_file.clone(),
119        }
120    }
121
122    pub fn children_iter_where<F: Fn(&ErasedSegment) -> bool + 'static>(
123        &self,
124        predicate: F,
125    ) -> impl Iterator<Item = &ErasedSegment> + '_ {
126        self.base
127            .iter()
128            .flat_map(|segment| segment.segments().iter())
129            .filter(move |child| predicate(child))
130    }
131
132    pub fn find_last_where<F: Fn(&ErasedSegment) -> bool>(&self, predicate: F) -> Segments {
133        self.base
134            .iter()
135            .rev()
136            .find_map(|segment| {
137                if predicate(segment) {
138                    Some(Segments {
139                        base: vec![segment.clone()],
140                        templated_file: self.templated_file.clone(),
141                    })
142                } else {
143                    None
144                }
145            })
146            .unwrap_or_else(|| Segments {
147                base: vec![],
148                templated_file: self.templated_file.clone(),
149            })
150    }
151
152    pub fn find(&self, value: &ErasedSegment) -> Option<usize> {
153        self.index(value)
154    }
155
156    pub fn find_first_where<F: Fn(&ErasedSegment) -> bool>(&self, predicate: F) -> Segments {
157        for segment in &self.base {
158            if predicate(segment) {
159                return Segments {
160                    base: vec![segment.clone()],
161                    templated_file: self.templated_file.clone(),
162                };
163            }
164        }
165        Segments {
166            base: vec![],
167            templated_file: self.templated_file.clone(),
168        }
169    }
170
171    pub fn head(&self) -> Segments {
172        if let Some(segment) = self.base.first() {
173            return Segments {
174                base: vec![segment.clone()],
175                templated_file: self.templated_file.clone(),
176            };
177        }
178        Segments {
179            base: vec![],
180            templated_file: self.templated_file.clone(),
181        }
182    }
183
184    pub fn index(&self, value: &ErasedSegment) -> Option<usize> {
185        self.base.iter().position(|it| it == value)
186    }
187
188    pub fn filter<F: Fn(&ErasedSegment) -> bool>(&self, predicate: F) -> Segments {
189        let base = self
190            .base
191            .iter()
192            .filter(|segment| predicate(segment))
193            .cloned()
194            .collect();
195        Segments {
196            base,
197            templated_file: self.templated_file.clone(),
198        }
199    }
200
201    pub fn take_while<F: Fn(&ErasedSegment) -> bool>(&self, predicate: F) -> Segments {
202        let base = self
203            .base
204            .iter()
205            .take_while(|segment| predicate(segment))
206            .cloned()
207            .collect();
208        Segments {
209            base,
210            templated_file: self.templated_file.clone(),
211        }
212    }
213
214    pub fn iter_after<'a>(
215        &'a self,
216        start: &ErasedSegment,
217    ) -> impl Iterator<Item = &'a ErasedSegment> + 'a {
218        let start_idx = self
219            .base
220            .iter()
221            .position(|segment| segment == start)
222            .map(|index| index + 1)
223            .unwrap_or(self.base.len());
224        self.base[start_idx..].iter()
225    }
226
227    pub fn iter_after_while<'a, F: Fn(&ErasedSegment) -> bool + 'a>(
228        &'a self,
229        start: &ErasedSegment,
230        while_cond: F,
231    ) -> impl Iterator<Item = &'a ErasedSegment> + 'a {
232        self.iter_after(start)
233            .take_while(move |segment| while_cond(segment))
234    }
235
236    pub fn after(&self, start: &ErasedSegment) -> Segments {
237        let start_idx = self
238            .base
239            .iter()
240            .position(|segment| segment == start)
241            .expect("start segment not found");
242        let base = self.base[start_idx + 1..].to_vec();
243        Segments {
244            base,
245            templated_file: self.templated_file.clone(),
246        }
247    }
248
249    pub fn before(&self, stop: &ErasedSegment) -> Segments {
250        let stop_idx = self
251            .base
252            .iter()
253            .position(|segment| segment == stop)
254            .expect("stop segment not found");
255        let base = self.base[..stop_idx].to_vec();
256        Segments {
257            base,
258            templated_file: self.templated_file.clone(),
259        }
260    }
261
262    pub fn between_exclusive(&self, start: &ErasedSegment, stop: &ErasedSegment) -> Segments {
263        let len = self.base.len();
264
265        let start_idx = self
266            .base
267            .iter()
268            .position(|s| s == start)
269            .map(|i| i + 1)
270            .unwrap_or(0)
271            .min(len);
272
273        let end_idx = self
274            .base
275            .iter()
276            .position(|s| s == stop)
277            .unwrap_or(len)
278            .min(len);
279
280        let base = self.base.get(start_idx..end_idx).unwrap_or(&[]).to_vec();
281
282        Segments {
283            base,
284            templated_file: self.templated_file.clone(),
285        }
286    }
287}
288
289impl<I: std::slice::SliceIndex<[ErasedSegment]>> std::ops::Index<I> for Segments {
290    type Output = I::Output;
291
292    fn index(&self, index: I) -> &Self::Output {
293        &self.base[index]
294    }
295}
296
297impl IntoIterator for Segments {
298    type Item = ErasedSegment;
299    type IntoIter = std::vec::IntoIter<Self::Item>;
300
301    fn into_iter(self) -> Self::IntoIter {
302        self.base.into_iter()
303    }
304}