Skip to main content

callisto_graph/
resolver.rs

1use std::collections::{BTreeMap, HashSet};
2
3use callisto_model::{DepEdge, Diagnostic, Package, PackageId};
4
5use crate::error::GraphError;
6use crate::identity::IdentityIndex;
7use crate::toposort::toposort_impl;
8
9pub use callisto_model::DependencyResolver;
10
11pub trait DependencyResolverExt: DependencyResolver {
12    fn toposort(&self, subset: &HashSet<PackageId>) -> Result<Vec<PackageId>, GraphError> {
13        // The DependencyResolver::packages() trait method yields &Package, not PackageId, so
14        // we must clone each id. The Vec is required to produce a &[PackageId] slice for
15        // toposort_impl; it cannot be eliminated without changing the function signature.
16        let all_pkg_ids: Vec<PackageId> = self.packages().map(|p| p.id.clone()).collect();
17        toposort_impl(subset, &all_pkg_ids, |id| {
18            self.dependencies_of(id)
19                .map(|e| (e.to.clone(), e.kind))
20                .collect()
21        })
22    }
23}
24
25impl<T: DependencyResolver + ?Sized> DependencyResolverExt for T {}
26
27pub struct ManifestWalkResolver {
28    pub(crate) packages: BTreeMap<PackageId, Package>,
29    pub(crate) edges: Vec<DepEdge>,
30    pub(crate) out_index: BTreeMap<PackageId, Vec<usize>>,
31    pub(crate) in_index: BTreeMap<PackageId, Vec<usize>>,
32    pub(crate) index: IdentityIndex,
33    pub(crate) diagnostics: Vec<Diagnostic>,
34}
35
36impl ManifestWalkResolver {
37    pub fn diagnostics(&self) -> &[Diagnostic] {
38        &self.diagnostics
39    }
40
41    pub fn identity(&self) -> &IdentityIndex {
42        &self.index
43    }
44
45    pub fn get(&self, id: &PackageId) -> Option<&Package> {
46        self.packages.get(id)
47    }
48
49    pub fn edges(&self) -> &[DepEdge] {
50        &self.edges
51    }
52}
53
54impl DependencyResolver for ManifestWalkResolver {
55    fn packages(&self) -> impl Iterator<Item = &Package> {
56        self.packages.values()
57    }
58
59    fn dependencies_of(&self, id: &PackageId) -> impl Iterator<Item = &DepEdge> {
60        // Avoid an intermediate Vec by streaming index lookups directly as edge references.
61        let edges = &self.edges;
62        self.out_index
63            .get(id)
64            .into_iter()
65            .flat_map(|v| v.iter())
66            .map(move |&idx| &edges[idx])
67    }
68
69    fn dependents_of(&self, id: &PackageId) -> impl Iterator<Item = &DepEdge> {
70        let edges = &self.edges;
71        self.in_index
72            .get(id)
73            .into_iter()
74            .flat_map(|v| v.iter())
75            .map(move |&idx| &edges[idx])
76    }
77
78    fn diagnostics(&self) -> &[Diagnostic] {
79        &self.diagnostics
80    }
81}