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}