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///
33/// With the `serde` feature it serialises transparently as its `u32` index, so a
34/// handle stored in an AST node or a cached diagnostic round-trips on its own.
35#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
36#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
37pub struct SourceId(u32);
38
39impl SourceId {
40    /// Wraps a raw index. Internal: only a map may mint an id, so that every id
41    /// in circulation names a source the map actually holds.
42    #[inline]
43    pub(crate) const fn from_index(index: u32) -> Self {
44        Self(index)
45    }
46
47    /// Returns the raw index this id wraps.
48    ///
49    /// The value is the source's insertion order, starting at `0`. It is useful
50    /// as a dense array key — for a side table of per-source data — but the id
51    /// itself should be preferred wherever an opaque handle will do.
52    ///
53    /// # Examples
54    ///
55    /// ```
56    /// use source_lang::SourceMap;
57    ///
58    /// let mut map = SourceMap::new();
59    /// let id = map.add("only.txt", "x").expect("fits");
60    /// assert_eq!(id.to_u32(), 0);
61    /// ```
62    #[inline]
63    #[must_use]
64    pub const fn to_u32(self) -> u32 {
65        self.0
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72
73    #[test]
74    fn test_id_round_trips_through_its_index() {
75        let id = SourceId::from_index(7);
76        assert_eq!(id.to_u32(), 7);
77    }
78
79    #[test]
80    fn test_ids_order_by_index() {
81        assert!(SourceId::from_index(1) < SourceId::from_index(2));
82        assert_eq!(SourceId::from_index(3), SourceId::from_index(3));
83    }
84}