sqruff_lib_core/utils/functional/
segments.rs

1use std::ops::Range;
2
3use crate::dialects::syntax::SyntaxSet;
4use crate::parser::segments::ErasedSegment;
5use crate::templaters::TemplatedFile;
6
7type PredicateType = Option<fn(&ErasedSegment) -> bool>;
8
9#[derive(Debug, Default, Clone)]
10pub struct Segments {
11    pub base: Vec<ErasedSegment>,
12    templated_file: Option<TemplatedFile>,
13}
14
15impl Segments {
16    pub fn into_vec(self) -> Vec<ErasedSegment> {
17        self.base
18    }
19
20    pub fn iter(&self) -> impl Iterator<Item = &ErasedSegment> {
21        self.base.iter()
22    }
23
24    pub fn recursive_crawl(&self, types: &SyntaxSet, recurse_into: bool) -> Segments {
25        let mut segments = Vec::new();
26
27        for s in &self.base {
28            segments.extend(s.recursive_crawl(types, recurse_into, &SyntaxSet::EMPTY, true));
29        }
30
31        Segments::from_vec(segments, self.templated_file.clone())
32    }
33
34    pub fn iterate_segments(&self) -> impl Iterator<Item = Segments> + '_ {
35        let mut iter = self.base.iter();
36
37        std::iter::from_fn(move || {
38            let segment = iter.next()?;
39            Segments::new(segment.clone(), self.templated_file.clone()).into()
40        })
41    }
42
43    pub fn from_vec(base: Vec<ErasedSegment>, templated_file: Option<TemplatedFile>) -> Self {
44        Self {
45            base,
46            templated_file,
47        }
48    }
49
50    pub fn reversed(&self) -> Self {
51        let mut base = self.base.clone();
52        base.reverse();
53
54        Self {
55            base,
56            templated_file: self.templated_file.clone(),
57        }
58    }
59
60    pub fn get(&self, index: usize, default: Option<ErasedSegment>) -> Option<ErasedSegment> {
61        self.base.get(index).cloned().or(default)
62    }
63
64    pub fn first(&self) -> Option<&ErasedSegment> {
65        self.base.first()
66    }
67
68    pub fn last(&self) -> Option<&ErasedSegment> {
69        self.base.last()
70    }
71
72    #[track_caller]
73    pub fn pop(&mut self) -> ErasedSegment {
74        self.base.pop().unwrap()
75    }
76
77    pub fn all(&self, predicate: PredicateType) -> bool {
78        self.base
79            .iter()
80            .all(|s| predicate.is_none_or(|pred| pred(s)))
81    }
82
83    pub fn any(&self, predicate: PredicateType) -> bool {
84        self.base
85            .iter()
86            .any(|s| predicate.is_none_or(|pred| pred(s)))
87    }
88
89    pub fn len(&self) -> usize {
90        self.base.len()
91    }
92
93    pub fn is_empty(&self) -> bool {
94        self.base.is_empty()
95    }
96
97    pub fn new(segment: ErasedSegment, templated_file: Option<TemplatedFile>) -> Self {
98        Self {
99            base: vec![segment],
100            templated_file,
101        }
102    }
103
104    pub fn children(&self, predicate: PredicateType) -> Segments {
105        let mut child_segments = Vec::with_capacity(predicate.map_or(0, |_| self.len()));
106
107        for s in &self.base {
108            for child in s.segments() {
109                if let Some(ref pred) = predicate {
110                    if pred(child) {
111                        child_segments.push(child.clone());
112                    }
113                } else {
114                    child_segments.push(child.clone());
115                }
116            }
117        }
118
119        Segments {
120            base: child_segments,
121            templated_file: self.templated_file.clone(),
122        }
123    }
124
125    pub fn find_last(&self, predicate: PredicateType) -> Segments {
126        self.base
127            .iter()
128            .rev()
129            .find_map(|s| {
130                if predicate.as_ref().is_none_or(|p| p(s)) {
131                    Some(Segments {
132                        base: vec![s.clone()],
133                        templated_file: self.templated_file.clone(),
134                    })
135                } else {
136                    None
137                }
138            })
139            .unwrap_or_else(|| Segments {
140                base: vec![],
141                templated_file: self.templated_file.clone(),
142            })
143    }
144
145    pub fn find(&self, value: &ErasedSegment) -> Option<usize> {
146        self.index(value)
147    }
148
149    pub fn find_first<F: Fn(&ErasedSegment) -> bool>(&self, predicate: Option<F>) -> Segments {
150        for s in &self.base {
151            if predicate.as_ref().is_none_or(|p| p(s)) {
152                return Segments {
153                    base: vec![s.clone()],
154                    templated_file: self.templated_file.clone(),
155                };
156            }
157        }
158
159        Segments {
160            base: vec![],
161            templated_file: self.templated_file.clone(),
162        }
163    }
164
165    pub fn index(&self, value: &ErasedSegment) -> Option<usize> {
166        self.base.iter().position(|it| it == value)
167    }
168
169    #[track_caller]
170    pub fn select<SelectIf: Fn(&ErasedSegment) -> bool>(
171        &self,
172        select_if: Option<SelectIf>,
173        loop_while: PredicateType,
174        start_seg: Option<&ErasedSegment>,
175        stop_seg: Option<&ErasedSegment>,
176    ) -> Segments {
177        let start_index = start_seg
178            .map(|seg| self.base.iter().position(|x| x == seg).unwrap() as isize)
179            .unwrap_or(-1);
180
181        let stop_index = stop_seg
182            .map(|seg| self.base.iter().position(|x| x == seg).unwrap() as isize)
183            .unwrap_or_else(|| self.base.len() as isize);
184
185        let mut buff = Vec::new();
186
187        for seg in pyslice(&self.base, start_index + 1..stop_index) {
188            if let Some(loop_while) = &loop_while
189                && !loop_while(seg)
190            {
191                break;
192            }
193
194            if select_if.as_ref().is_none_or(|f| f(seg)) {
195                buff.push(seg.clone());
196            }
197        }
198
199        Segments {
200            base: buff,
201            templated_file: self.templated_file.clone(),
202        }
203    }
204}
205
206impl<I: std::slice::SliceIndex<[ErasedSegment]>> std::ops::Index<I> for Segments {
207    type Output = I::Output;
208
209    fn index(&self, index: I) -> &Self::Output {
210        &self.base[index]
211    }
212}
213
214impl IntoIterator for Segments {
215    type Item = ErasedSegment;
216    type IntoIter = std::vec::IntoIter<Self::Item>;
217
218    fn into_iter(self) -> Self::IntoIter {
219        self.base.into_iter()
220    }
221}
222
223fn pyslice<T>(collection: &[T], Range { start, end }: Range<isize>) -> impl Iterator<Item = &T> {
224    let slice = slyce::Slice {
225        start: start.into(),
226        end: end.into(),
227        step: None,
228    };
229    slice.apply(collection)
230}