Skip to main content

chaud_hot/workspace/graph/
index.rs

1use crate::cargo::metadata::{Package, PackageName};
2use crate::util::CfgInto as _;
3use anyhow::{Context as _, Result, bail};
4use hashbrown::{HashMap, hash_map};
5
6/// A numeric index / identifier of a crate.
7#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
8pub struct KrateIdx(u32);
9
10impl KrateIdx {
11    #[inline]
12    #[must_use]
13    pub fn usize(self) -> usize {
14        self.0.cfg_into()
15    }
16}
17
18/// An index of all crates, mapping [`PackageName`] to [`KrateIdx`].
19pub struct KrateIndex {
20    by_pkg: HashMap<PackageName, KrateIdx>,
21}
22
23impl KrateIndex {
24    pub fn new(pkgs: &[Package]) -> Result<Self> {
25        let mut pkgs: Vec<_> = pkgs.iter().collect();
26        // Do not depend on Cargo's output order for determinism.
27        pkgs.sort_unstable_by_key(|p| p.name());
28
29        let mut this = Self { by_pkg: HashMap::new() };
30
31        for pkg in pkgs {
32            this.insert(pkg).context("Failed to build package index")?;
33        }
34
35        Ok(this)
36    }
37
38    fn insert(&mut self, pkg: &Package) -> Result<()> {
39        let pkg_name = pkg.name().clone();
40
41        let next = KrateIdx(
42            self.by_pkg
43                .len()
44                .try_into()
45                .context("Crate idx overflowed `u32`")?,
46        );
47
48        match self.by_pkg.entry(pkg_name) {
49            hash_map::Entry::Occupied(entry) => bail!("Duplicate package name: {:?}", entry.key()),
50            hash_map::Entry::Vacant(entry) => entry.insert(next),
51        };
52
53        Ok(())
54    }
55
56    pub fn get_pkg(&self, name: &PackageName) -> Option<KrateIdx> {
57        self.by_pkg.get(name).copied()
58    }
59}