ra_salsa/
intern_id.rs

1use std::fmt;
2use std::num::NonZeroU32;
3
4/// The "raw-id" is used for interned keys in salsa -- it is basically
5/// a newtype'd u32. Typically, it is wrapped in a type of your own
6/// devising. For more information about interned keys, see [the
7/// interned key RFC][rfc].
8///
9/// # Creating a `InternId`
10//
11/// InternId values can be constructed using the `From` impls,
12/// which are implemented for `u32` and `usize`:
13///
14/// ```
15/// # use ra_salsa::InternId;
16/// let intern_id1 = InternId::from(22_u32);
17/// let intern_id2 = InternId::from(22_usize);
18/// assert_eq!(intern_id1, intern_id2);
19/// ```
20///
21/// # Converting to a u32 or usize
22///
23/// Normally, there should be no need to access the underlying integer
24/// in a `InternId`. But if you do need to do so, you can convert to a
25/// `usize` using the `as_u32` or `as_usize` methods or the `From` impls.
26///
27/// ```
28/// # use ra_salsa::InternId;;
29/// let intern_id = InternId::from(22_u32);
30/// let value = u32::from(intern_id);
31/// assert_eq!(value, 22);
32/// ```
33///
34/// ## Illegal values
35///
36/// Be warned, however, that `InternId` values cannot be created from
37/// *arbitrary* values -- in particular large values greater than
38/// `InternId::MAX` will panic. Those large values are reserved so that
39/// the Rust compiler can use them as sentinel values, which means
40/// that (for example) `Option<InternId>` is represented in a single
41/// word.
42///
43/// ```should_panic
44/// # use ra_salsa::InternId;;
45/// InternId::from(InternId::MAX);
46/// ```
47///
48/// [rfc]: https://github.com/salsa-rs/salsa-rfcs/pull/2
49#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
50pub struct InternId {
51    value: NonZeroU32,
52}
53
54impl InternId {
55    /// The maximum allowed `InternId`. This value can grow between
56    /// releases without affecting semver.
57    pub const MAX: u32 = 0xFFFF_FF00;
58
59    /// Creates a new InternId.
60    ///
61    /// # Safety
62    ///
63    /// `value` must be less than `MAX`
64    pub const unsafe fn new_unchecked(value: u32) -> Self {
65        debug_assert!(value < InternId::MAX);
66        let value = unsafe { NonZeroU32::new_unchecked(value + 1) };
67        InternId { value }
68    }
69
70    /// Convert this raw-id into a u32 value.
71    ///
72    /// ```
73    /// # use ra_salsa::InternId;
74    /// let intern_id = InternId::from(22_u32);
75    /// let value = intern_id.as_usize();
76    /// assert_eq!(value, 22);
77    /// ```
78    pub fn as_u32(self) -> u32 {
79        self.value.get() - 1
80    }
81
82    /// Convert this raw-id into a usize value.
83    ///
84    /// ```
85    /// # use ra_salsa::InternId;
86    /// let intern_id = InternId::from(22_u32);
87    /// let value = intern_id.as_usize();
88    /// assert_eq!(value, 22);
89    /// ```
90    pub fn as_usize(self) -> usize {
91        self.as_u32() as usize
92    }
93}
94
95impl From<InternId> for u32 {
96    fn from(raw: InternId) -> u32 {
97        raw.as_u32()
98    }
99}
100
101impl From<InternId> for usize {
102    fn from(raw: InternId) -> usize {
103        raw.as_usize()
104    }
105}
106
107impl From<u32> for InternId {
108    fn from(id: u32) -> InternId {
109        assert!(id < InternId::MAX);
110        unsafe { InternId::new_unchecked(id) }
111    }
112}
113
114impl From<usize> for InternId {
115    fn from(id: usize) -> InternId {
116        assert!(id < (InternId::MAX as usize));
117        unsafe { InternId::new_unchecked(id as u32) }
118    }
119}
120
121impl fmt::Debug for InternId {
122    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123        self.as_usize().fmt(f)
124    }
125}
126
127impl fmt::Display for InternId {
128    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129        self.as_usize().fmt(f)
130    }
131}