Skip to main content

source_lang/
id.rs

1//! Stable handles identifying a source within a map.
2
3/// A small, copyable handle to one source in a [`SourceMap`](crate::SourceMap).
4///
5/// A `SourceId` is a 32-bit index minted by the map when a source is added. It
6/// is stable for the life of the map: the id returned by
7/// [`SourceMap::add`](crate::SourceMap::add) keeps pointing at the same source
8/// no matter how many more are added afterwards, because sources are only ever
9/// appended. That stability is what lets a token, an AST node, or a cached
10/// diagnostic store a `SourceId` and resolve it later.
11///
12/// The id is deliberately opaque — there is no public constructor — so an id can
13/// only come from a map that actually holds the source it names. Pass it back to
14/// [`SourceMap::source`](crate::SourceMap::source) to borrow the source, or to
15/// the result of [`SourceMap::locate`](crate::SourceMap::locate) to identify
16/// where a global position resolved.
17///
18/// # Examples
19///
20/// ```
21/// use source_lang::SourceMap;
22///
23/// let mut map = SourceMap::new();
24/// let first = map.add("a.txt", "alpha").expect("fits");
25/// let second = map.add("b.txt", "beta").expect("fits");
26///
27/// // Ids are assigned in order and stay distinct.
28/// assert_eq!(first.to_u32(), 0);
29/// assert_eq!(second.to_u32(), 1);
30/// assert_ne!(first, second);
31/// ```
32#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
33pub struct SourceId(u32);
34
35impl SourceId {
36    /// Wraps a raw index. Internal: only a map may mint an id, so that every id
37    /// in circulation names a source the map actually holds.
38    #[inline]
39    pub(crate) const fn from_index(index: u32) -> Self {
40        Self(index)
41    }
42
43    /// Returns the raw index this id wraps.
44    ///
45    /// The value is the source's insertion order, starting at `0`. It is useful
46    /// as a dense array key — for a side table of per-source data — but the id
47    /// itself should be preferred wherever an opaque handle will do.
48    ///
49    /// # Examples
50    ///
51    /// ```
52    /// use source_lang::SourceMap;
53    ///
54    /// let mut map = SourceMap::new();
55    /// let id = map.add("only.txt", "x").expect("fits");
56    /// assert_eq!(id.to_u32(), 0);
57    /// ```
58    #[inline]
59    #[must_use]
60    pub const fn to_u32(self) -> u32 {
61        self.0
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn test_id_round_trips_through_its_index() {
71        let id = SourceId::from_index(7);
72        assert_eq!(id.to_u32(), 7);
73    }
74
75    #[test]
76    fn test_ids_order_by_index() {
77        assert!(SourceId::from_index(1) < SourceId::from_index(2));
78        assert_eq!(SourceId::from_index(3), SourceId::from_index(3));
79    }
80}