sqruff_lib/utils/reflow/
depth_map.rs1use hashbrown::{HashMap, HashSet};
2use nohash_hasher::{IntMap, IntSet};
3use sqruff_lib_core::dialects::syntax::SyntaxSet;
4use sqruff_lib_core::parser::segments::{ErasedSegment, PathStep};
5
6#[derive(Debug, PartialEq, Eq, Clone)]
8pub struct StackPosition {
9 pub idx: usize,
10 pub len: usize,
11 pub type_: Option<StackPositionType>,
12}
13
14#[derive(Debug, PartialEq, Eq, Clone)]
15pub enum StackPositionType {
16 Solo,
17 Start,
18 End,
19}
20
21impl StackPosition {
22 fn stack_pos_interpreter(path_step: &PathStep) -> Option<StackPositionType> {
24 if path_step.code_idxs.is_empty() {
25 None
26 } else if path_step.code_idxs.len() == 1 {
27 Some(StackPositionType::Solo)
28 } else if path_step.idx == *path_step.code_idxs.first().unwrap() {
29 Some(StackPositionType::Start)
30 } else if path_step.idx == *path_step.code_idxs.last().unwrap() {
31 Some(StackPositionType::End)
32 } else {
33 None
34 }
35 }
36
37 fn from_path_step(path_step: &PathStep) -> StackPosition {
39 StackPosition {
40 idx: path_step.idx,
41 len: path_step.len,
42 type_: StackPosition::stack_pos_interpreter(path_step),
43 }
44 }
45}
46
47pub struct DepthMap {
48 depth_info: HashMap<u32, DepthInfo>,
49}
50
51impl DepthMap {
52 fn new<'a>(raws_with_stack: impl Iterator<Item = &'a (ErasedSegment, Vec<PathStep>)>) -> Self {
53 let depth_info = raws_with_stack
54 .into_iter()
55 .map(|(raw, stack)| (raw.id(), DepthInfo::from_stack(stack)))
56 .collect();
57 Self { depth_info }
58 }
59
60 pub fn from_raws_with_stack(raws_with_stack: &[(ErasedSegment, Vec<PathStep>)]) -> Self {
61 Self::new(raws_with_stack.iter())
62 }
63
64 pub fn get_depth_info(&self, seg: &ErasedSegment) -> DepthInfo {
65 self.depth_info[&seg.id()].clone()
66 }
67
68 pub fn copy_depth_info(
69 &mut self,
70 anchor: &ErasedSegment,
71 new_segment: &ErasedSegment,
72 trim: u32,
73 ) {
74 self.depth_info.insert(
75 new_segment.id(),
76 self.get_depth_info(anchor).trim(trim.try_into().unwrap()),
77 );
78 }
79
80 pub fn from_parent(parent: &ErasedSegment) -> Self {
81 Self::from_raws_with_stack(parent.raw_segments_with_ancestors())
82 }
83
84 pub fn from_raws_and_root(
85 raw_segments: impl Iterator<Item = ErasedSegment>,
86 root_segment: &ErasedSegment,
87 ) -> DepthMap {
88 let depth_info = raw_segments
89 .into_iter()
90 .map(|raw| {
91 let stack = root_segment.path_to(&raw);
92 (raw.id(), DepthInfo::from_stack(&stack))
93 })
94 .collect();
95
96 DepthMap { depth_info }
97 }
98}
99
100#[derive(Debug, PartialEq, Eq, Clone)]
102pub struct DepthInfo {
103 pub stack_depth: usize,
104 pub stack_hashes: Vec<u64>,
105 pub stack_hash_set: IntSet<u64>,
107 pub stack_class_types: Vec<SyntaxSet>,
108 pub stack_positions: IntMap<u64, StackPosition>,
109}
110
111impl DepthInfo {
112 fn from_stack(stack: &[PathStep]) -> DepthInfo {
113 let mut stack_hashes = Vec::with_capacity(stack.len());
116 let mut stack_hash_set: IntSet<u64> = IntSet::default();
117 stack_hash_set.reserve(stack.len());
118 let mut stack_class_types = Vec::with_capacity(stack.len());
119 let mut stack_positions: IntMap<u64, StackPosition> = IntMap::default();
120 stack_positions.reserve(stack.len());
121
122 for path in stack {
123 let hash = path.segment.hash_value();
124 stack_hashes.push(hash);
125 stack_hash_set.insert(hash);
126 stack_class_types.push(path.segment.class_types().clone());
127 stack_positions.insert(hash, StackPosition::from_path_step(path));
128 }
129
130 DepthInfo {
131 stack_depth: stack_hashes.len(),
132 stack_hashes,
133 stack_hash_set,
134 stack_class_types,
135 stack_positions,
136 }
137 }
138
139 pub fn trim(self, amount: usize) -> DepthInfo {
140 if amount == 0 {
142 return self;
144 }
145
146 let slice_set: IntSet<_> = IntSet::from_iter(
147 self.stack_hashes[self.stack_hashes.len() - amount..]
148 .iter()
149 .copied(),
150 );
151
152 let new_hash_set: IntSet<_> = self
153 .stack_hash_set
154 .difference(&slice_set)
155 .copied()
156 .collect();
157
158 let stack_positions = self
159 .stack_positions
160 .into_iter()
161 .filter(|(hash, _)| new_hash_set.contains(hash))
162 .collect();
163
164 DepthInfo {
165 stack_depth: self.stack_depth - amount,
166 stack_hashes: self.stack_hashes[..self.stack_hashes.len() - amount].to_vec(),
167 stack_hash_set: new_hash_set,
168 stack_class_types: self.stack_class_types[..self.stack_class_types.len() - amount]
169 .to_vec(),
170 stack_positions,
171 }
172 }
173
174 pub fn common_with(&self, other: &DepthInfo) -> Vec<u64> {
175 let common_hashes: HashSet<_> = self
180 .stack_hash_set
181 .intersection(&other.stack_hash_set)
182 .copied()
183 .collect();
184
185 assert!(
189 !common_hashes.is_empty(),
190 "DepthInfo comparison shares no common ancestor!"
191 );
192
193 let common_depth = common_hashes.len();
194 self.stack_hashes
195 .iter()
196 .take(common_depth)
197 .copied()
198 .collect()
199 }
200}