use std::collections::HashMap; use std::collections::HashSet; use std::mem; use protobuf_support::toposort::toposort; use crate::descriptor::FileDescriptorProto; use crate::reflect::error::ReflectError; use crate::reflect::FileDescriptor; pub(crate) fn build_fds( protos: Vec, dependencies: &[FileDescriptor], ) -> crate::Result> { let mut index_by_name: HashMap<&str, usize> = HashMap::new(); for (i, proto) in protos.iter().enumerate() { let prev = index_by_name.insert(proto.name(), i); if prev.is_some() { return Err(ReflectError::NonUniqueFileDescriptor(proto.name().to_owned()).into()); } } let sorted = match toposort(0..protos.len(), |&i| { protos[i] .dependency .iter() .filter_map(|d| index_by_name.get(d.as_str()).copied()) }) { Ok(s) => s, Err(_) => return Err(ReflectError::CycleInFileDescriptors.into()), }; let mut built_descriptors_by_index = vec![None; protos.len()]; let mut protos: Vec> = protos.into_iter().map(Some).collect(); let mut all_descriptors = dependencies.to_vec(); for f in sorted { let proto = mem::take(&mut protos[f]).unwrap(); let d = FileDescriptor::new_dynamic(proto, &all_descriptors)?; all_descriptors.push(d.clone()); built_descriptors_by_index[f] = Some(d); } Ok(built_descriptors_by_index .into_iter() .map(Option::unwrap) .collect()) } pub(crate) fn fds_extend_with_public(file_descriptors: Vec) -> Vec { let mut visited = HashSet::new(); let mut r = Vec::new(); let mut stack = file_descriptors; stack.reverse(); while let Some(f) = stack.pop() { if !visited.insert(f.proto().name().to_owned()) { continue; } stack.extend(f.public_deps()); r.push(f); } r }