Skip to main content

chaud_hot/workspace/graph/
def.rs

1//! The **def**inition of the [`Graph`] type.
2
3use super::{BuildEnv, Krate, KrateIdx, KrateIndex};
4use crate::cargo::Cargo;
5use crate::cargo::metadata::{ManifestPath, Metadata};
6use crate::util::assert::err_assert;
7use anyhow::{Context as _, Result};
8use core::ops;
9use hashbrown::HashSet;
10use std::collections::VecDeque;
11
12pub struct Graph {
13    env: BuildEnv,
14    krates: Box<[Krate]>,
15}
16
17impl ops::Index<KrateIdx> for Graph {
18    type Output = Krate;
19
20    #[expect(
21        clippy::indexing_slicing,
22        reason = "crate indices are assumed to be valid"
23    )]
24    fn index(&self, idx: KrateIdx) -> &Self::Output {
25        &self.krates[idx.usize()]
26    }
27}
28
29impl Graph {
30    pub fn new(
31        root_mani: ManifestPath,
32        feature_flags: Option<&'static str>,
33    ) -> Result<&'static Self> {
34        new_inner(root_mani, feature_flags).context("Failed to load crate graph")
35    }
36
37    pub fn env(&self) -> &BuildEnv {
38        &self.env
39    }
40
41    pub fn collect_krates_to_watch(&self) -> impl Iterator<Item = &Krate> {
42        collect_inner(self).into_iter().map(|k| &self[k])
43    }
44}
45
46fn new_inner(
47    root_mani: ManifestPath,
48    feature_flags: Option<&'static str>,
49) -> Result<&'static Graph> {
50    let cargo = Cargo::new(root_mani);
51    let meta = cargo.load_metadata()?;
52
53    let index = KrateIndex::new(meta.packages())?;
54    let env = BuildEnv::new(cargo, feature_flags, &meta, &index)?;
55    let krates = load_krates(&meta, &env, &index)?;
56
57    Ok(Box::leak(Box::new(Graph { env, krates })))
58}
59
60fn load_krates(meta: &Metadata, env: &BuildEnv, index: &KrateIndex) -> Result<Box<[Krate]>> {
61    let mut krates = vec![];
62
63    for pkg in meta.packages() {
64        krates.push(Krate::new(env, index, pkg)?);
65    }
66
67    krates.sort_unstable_by_key(|k| k.idx());
68    for (pos, krate) in krates.iter().enumerate() {
69        err_assert!(pos == krate.idx().usize());
70    }
71
72    Ok(krates.into_boxed_slice())
73}
74
75fn collect_inner(graph: &Graph) -> Box<[KrateIdx]> {
76    let mut found = vec![];
77    let mut seen = HashSet::new();
78    let mut queue = VecDeque::new();
79    seen.insert(graph.env.root());
80    queue.push_back(graph.env.root());
81
82    while let Some(idx) = queue.pop_front() {
83        found.push(idx);
84        for &dep in graph[idx].deps() {
85            if seen.insert(dep) {
86                queue.push_back(dep);
87            }
88        }
89    }
90
91    found.into_boxed_slice()
92}