1use crate::{FrameId, GiffError, Stack, StackFrame, StackStore};
2use std::collections::{HashMap, HashSet};
3
4impl StackStore {
5 pub fn find_stack_for_branch(&self, branch: &str) -> Option<(&Stack, &StackFrame)> {
7 for stack in &self.stacks {
8 if let Some(frame) = stack.frames.iter().find(|f| f.branch == branch) {
9 return Some((stack, frame));
10 }
11 }
12 None
13 }
14}
15
16impl Stack {
17 pub fn roots(&self) -> Vec<&StackFrame> {
21 self.frames.iter().filter(|f| f.parent.is_none()).collect()
22 }
23
24 pub fn children(&self, id: &FrameId) -> Vec<&StackFrame> {
27 self.frames
28 .iter()
29 .filter(|f| f.parent.as_ref() == Some(id))
30 .collect()
31 }
32
33 pub fn frame(&self, id: &FrameId) -> Option<&StackFrame> {
35 self.frames.iter().find(|f| &f.id == id)
36 }
37
38 pub fn frame_below(&self, id: &FrameId) -> Option<&StackFrame> {
40 let frame = self.frame(id)?;
41 let parent_id = frame.parent.as_ref()?;
42 self.frame(parent_id)
43 }
44
45 pub fn descendants(&self, id: &FrameId) -> Vec<&StackFrame> {
48 let mut out = Vec::new();
49 let mut stack = vec![id.clone()];
50 while let Some(cur) = stack.pop() {
51 for child in self.children(&cur) {
52 out.push(child);
53 stack.push(child.id.clone());
54 }
55 }
56 out
57 }
58
59 pub fn ancestors(&self, id: &FrameId) -> Vec<&StackFrame> {
62 let mut out = Vec::new();
63 let mut cursor = self.frame(id).and_then(|f| f.parent.as_ref()).cloned();
64 while let Some(cur) = cursor {
65 if let Some(frame) = self.frame(&cur) {
66 out.push(frame);
67 cursor = frame.parent.clone();
68 } else {
69 break;
70 }
71 }
72 out
73 }
74
75 pub fn path_to_root(&self, id: &FrameId) -> Vec<&StackFrame> {
77 let mut chain: Vec<&StackFrame> = self.ancestors(id);
78 chain.reverse();
79 if let Some(self_frame) = self.frame(id) {
80 chain.push(self_frame);
81 }
82 chain
83 }
84
85 pub fn depth(&self, id: &FrameId) -> usize {
87 self.ancestors(id).len()
88 }
89
90 pub fn topological_order(&self) -> Vec<&StackFrame> {
94 let mut out: Vec<&StackFrame> = Vec::with_capacity(self.frames.len());
95 let mut visited: HashSet<FrameId> = HashSet::new();
96 for root in self.roots() {
97 self.dfs_collect(&root.id, &mut visited, &mut out);
98 }
99 for f in &self.frames {
103 if !visited.contains(&f.id) {
104 out.push(f);
105 visited.insert(f.id.clone());
106 }
107 }
108 out
109 }
110
111 fn dfs_collect<'a>(
112 &'a self,
113 id: &FrameId,
114 visited: &mut HashSet<FrameId>,
115 out: &mut Vec<&'a StackFrame>,
116 ) {
117 if !visited.insert(id.clone()) {
118 return;
119 }
120 if let Some(frame) = self.frame(id) {
121 out.push(frame);
122 }
123 for child in self.children(id) {
124 self.dfs_collect(&child.id, visited, out);
125 }
126 }
127
128 pub fn ordered_frames(&self) -> Vec<&StackFrame> {
131 self.topological_order()
132 }
133
134 pub fn is_linear(&self) -> bool {
136 if self.roots().len() != 1 {
137 return false;
138 }
139 self.frames.iter().all(|f| self.children(&f.id).len() <= 1)
140 }
141
142 pub fn parent_updates_after_pruning(
151 &self,
152 merged: &HashSet<FrameId>,
153 ) -> HashMap<FrameId, Option<FrameId>> {
154 let by_id: HashMap<&FrameId, &StackFrame> =
155 self.frames.iter().map(|f| (&f.id, f)).collect();
156 let mut out = HashMap::new();
157 for frame in &self.frames {
158 if merged.contains(&frame.id) {
159 continue;
160 }
161 let mut p = frame.parent.clone();
162 while let Some(ref pid) = p {
163 if merged.contains(pid) {
164 p = by_id.get(pid).and_then(|f| f.parent.clone());
165 } else {
166 break;
167 }
168 }
169 if p != frame.parent {
170 out.insert(frame.id.clone(), p);
171 }
172 }
173 out
174 }
175
176 pub fn validate(&self) -> Result<(), GiffError> {
179 let mut ids: HashMap<&FrameId, ()> = HashMap::new();
181 for f in &self.frames {
182 if ids.insert(&f.id, ()).is_some() {
183 return Err(GiffError::InvalidStack(format!(
184 "duplicate frame id `{}`",
185 f.id.0
186 )));
187 }
188 }
189
190 let mut branches: HashMap<&str, ()> = HashMap::new();
192 for f in &self.frames {
193 if branches.insert(f.branch.as_str(), ()).is_some() {
194 return Err(GiffError::InvalidStack(format!(
195 "duplicate branch `{}` in stack",
196 f.branch
197 )));
198 }
199 }
200
201 for f in &self.frames {
203 if let Some(p) = f.parent.as_ref() {
204 if !ids.contains_key(p) {
205 return Err(GiffError::InvalidStack(format!(
206 "frame `{}` has dangling parent `{}`",
207 f.branch, p.0
208 )));
209 }
210 }
211 }
212
213 for f in &self.frames {
215 let mut seen: HashSet<&FrameId> = HashSet::new();
216 let mut cur = Some(&f.id);
217 while let Some(id) = cur {
218 if !seen.insert(id) {
219 return Err(GiffError::InvalidStack(format!(
220 "cycle detected at frame `{}`",
221 f.branch
222 )));
223 }
224 cur = self
225 .frames
226 .iter()
227 .find(|x| &x.id == id)
228 .and_then(|x| x.parent.as_ref());
229 }
230 }
231
232 Ok(())
233 }
234}