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}