Skip to main content

module_lang/
id.rs

1//! Stable handles identifying a module within a graph.
2
3/// A small, copyable handle to one module in a [`ModuleGraph`](crate::ModuleGraph).
4///
5/// A `ModuleId` is a 32-bit index minted by the graph when a module is added with
6/// [`ModuleGraph::add_module`](crate::ModuleGraph::add_module). It is stable for
7/// the life of the graph: the id returned for a module keeps pointing at that same
8/// module no matter how many more are added afterwards, because modules are only
9/// ever appended. That stability is what lets an import edge, an AST node, or a
10/// cached diagnostic hold a `ModuleId` and resolve it later.
11///
12/// The id is deliberately opaque — there is no public constructor — so an id can
13/// only come from the graph that actually holds the module it names. Passing an id
14/// minted by a *different* graph to a query is a defined error
15/// ([`ResolveError::UnknownModule`](crate::ResolveError::UnknownModule)), never a
16/// panic or an out-of-bounds read.
17///
18/// # Examples
19///
20/// ```
21/// use intern_lang::Interner;
22/// use module_lang::ModuleGraph;
23/// use source_lang::SourceMap;
24///
25/// let mut sources = SourceMap::new();
26/// let mut names = Interner::new();
27/// let mut graph: ModuleGraph<()> = ModuleGraph::new();
28///
29/// let a = graph.add_module(names.intern("a"), sources.add("a", "").expect("fits"));
30/// let b = graph.add_module(names.intern("b"), sources.add("b", "").expect("fits"));
31///
32/// // Ids are assigned in order and stay distinct.
33/// assert_eq!(a.to_u32(), 0);
34/// assert_eq!(b.to_u32(), 1);
35/// assert_ne!(a, b);
36/// ```
37///
38/// With the `serde` feature it serialises transparently as its `u32` index, so a
39/// handle stored in an AST node or an import table round-trips on its own.
40#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
41#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
42pub struct ModuleId(u32);
43
44impl ModuleId {
45    /// Wraps a raw index. Internal: only a graph may mint an id, so that every id
46    /// in circulation names a module the graph actually holds.
47    #[inline]
48    pub(crate) const fn from_index(index: u32) -> Self {
49        Self(index)
50    }
51
52    /// The index into the graph's module list this id wraps.
53    #[inline]
54    pub(crate) const fn to_index(self) -> usize {
55        self.0 as usize
56    }
57
58    /// Returns the raw index this id wraps.
59    ///
60    /// The value is the module's insertion order, starting at `0`. It is useful as
61    /// a dense array key — for a side table of per-module data — but the id itself
62    /// should be preferred wherever an opaque handle will do.
63    ///
64    /// # Examples
65    ///
66    /// ```
67    /// use intern_lang::Interner;
68    /// use module_lang::ModuleGraph;
69    /// use source_lang::SourceMap;
70    ///
71    /// let mut sources = SourceMap::new();
72    /// let mut names = Interner::new();
73    /// let mut graph: ModuleGraph<()> = ModuleGraph::new();
74    /// let only = graph.add_module(names.intern("only"), sources.add("only", "").expect("fits"));
75    /// assert_eq!(only.to_u32(), 0);
76    /// ```
77    #[inline]
78    #[must_use]
79    pub const fn to_u32(self) -> u32 {
80        self.0
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87
88    #[test]
89    fn test_id_round_trips_through_its_index() {
90        let id = ModuleId::from_index(7);
91        assert_eq!(id.to_u32(), 7);
92        assert_eq!(id.to_index(), 7);
93    }
94
95    #[test]
96    fn test_ids_order_by_index() {
97        assert!(ModuleId::from_index(1) < ModuleId::from_index(2));
98        assert_eq!(ModuleId::from_index(3), ModuleId::from_index(3));
99    }
100}