protobuf/reflect/file/
fds.rs
1use std::collections::HashMap;
2use std::collections::HashSet;
3use std::mem;
4
5use protobuf_support::toposort::toposort;
6
7use crate::descriptor::FileDescriptorProto;
8use crate::reflect::error::ReflectError;
9use crate::reflect::FileDescriptor;
10
11pub(crate) fn build_fds(
12 protos: Vec<FileDescriptorProto>,
13 dependencies: &[FileDescriptor],
14) -> crate::Result<Vec<FileDescriptor>> {
15 let mut index_by_name: HashMap<&str, usize> = HashMap::new();
16 for (i, proto) in protos.iter().enumerate() {
17 let prev = index_by_name.insert(proto.name(), i);
18 if prev.is_some() {
19 return Err(ReflectError::NonUniqueFileDescriptor(proto.name().to_owned()).into());
20 }
21 }
22
23 let sorted = match toposort(0..protos.len(), |&i| {
24 protos[i]
25 .dependency
26 .iter()
27 .filter_map(|d| index_by_name.get(d.as_str()).copied())
28 }) {
29 Ok(s) => s,
30 Err(_) => return Err(ReflectError::CycleInFileDescriptors.into()),
31 };
32
33 let mut built_descriptors_by_index = vec![None; protos.len()];
34
35 let mut protos: Vec<Option<FileDescriptorProto>> = protos.into_iter().map(Some).collect();
36
37 let mut all_descriptors = dependencies.to_vec();
38 for f in sorted {
39 let proto = mem::take(&mut protos[f]).unwrap();
40 let d = FileDescriptor::new_dynamic(proto, &all_descriptors)?;
41 all_descriptors.push(d.clone());
42 built_descriptors_by_index[f] = Some(d);
43 }
44
45 Ok(built_descriptors_by_index
46 .into_iter()
47 .map(Option::unwrap)
48 .collect())
49}
50
51pub(crate) fn fds_extend_with_public(file_descriptors: Vec<FileDescriptor>) -> Vec<FileDescriptor> {
52 let mut visited = HashSet::new();
53
54 let mut r = Vec::new();
55 let mut stack = file_descriptors;
56 stack.reverse();
57
58 while let Some(f) = stack.pop() {
59 if !visited.insert(f.proto().name().to_owned()) {
60 continue;
61 }
62
63 stack.extend(f.public_deps());
64
65 r.push(f);
66 }
67 r
68}