1#![allow(clippy::too_many_arguments)]
2use crate::types::{FileDescriptor, MessageIndex};
3use std::cmp::min;
4use std::collections::HashMap;
5
6fn scc(
7 vertices: &[MessageIndex],
8 desc: &FileDescriptor,
9 u: usize,
10 count: &mut isize,
11 low: &mut [isize],
12 disc: &mut [isize],
13 stack: &mut Vec<usize>,
14 sccs: &mut Vec<Vec<usize>>,
15 ids: &HashMap<MessageIndex, usize>,
16) {
17 disc[u] = *count;
18 low[u] = *count;
19 *count += 1;
20 stack.push(u);
21
22 for &v in vertices[u]
23 .get_message(desc)
24 .all_fields()
25 .filter(|f| !f.boxed && !f.frequency.is_repeated())
26 .filter_map(|f| f.typ.message())
27 .filter_map(|m| ids.get(m))
28 {
29 if disc[v] == -1 {
30 scc(vertices, desc, v, count, low, disc, stack, sccs, ids);
31 low[u] = min(low[u], low[v]);
32 } else if stack.contains(&v) {
33 low[u] = min(low[u], disc[v]);
34 }
35 }
36
37 if low[u] == disc[u] {
38 let mut scc = Vec::new();
39 while let Some(w) = stack.pop() {
40 scc.push(w);
41 if w == u {
42 break;
43 }
44 }
45 sccs.push(scc);
46 }
47}
48
49impl FileDescriptor {
50 fn flatten_messages(&self) -> Vec<MessageIndex> {
51 let mut all_msgs = self
52 .messages
53 .iter()
54 .map(|m| m.index.clone())
55 .collect::<Vec<_>>();
56 let mut vertices = Vec::with_capacity(all_msgs.len());
57 while let Some(m) = all_msgs.pop() {
58 all_msgs.extend(m.get_message(self).messages.iter().map(|m| m.index.clone()));
59 vertices.push(m);
60 }
61 vertices
62 }
63
64 pub fn sccs(&self) -> Vec<Vec<MessageIndex>> {
65 let vertices = self.flatten_messages();
66 let ids = vertices
67 .iter()
68 .enumerate()
69 .map(|(i, m)| (m.get_message(self).index.clone(), i))
70 .collect::<HashMap<_, _>>();
71 let mut low = vec![-1; vertices.len()];
72 let mut disc = vec![-1; vertices.len()];
73 let mut stack: Vec<usize> = Vec::new();
74 let mut count = 0isize;
75 let mut sccs: Vec<Vec<usize>> = Vec::new();
76 for u in 0..vertices.len() {
77 if disc[u] == -1 {
78 scc(
79 &vertices, self, u, &mut count, &mut low, &mut disc, &mut stack, &mut sccs,
80 &ids,
81 );
82 }
83 }
84 sccs.into_iter()
85 .map(|scc| scc.into_iter().map(|i| vertices[i].clone()).collect())
86 .collect()
87 }
88}