Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ra-salsa/src/intern_id.rs')
-rw-r--r--crates/ra-salsa/src/intern_id.rs131
1 files changed, 131 insertions, 0 deletions
diff --git a/crates/ra-salsa/src/intern_id.rs b/crates/ra-salsa/src/intern_id.rs
new file mode 100644
index 0000000000..35b495998e
--- /dev/null
+++ b/crates/ra-salsa/src/intern_id.rs
@@ -0,0 +1,131 @@
+use std::fmt;
+use std::num::NonZeroU32;
+
+/// The "raw-id" is used for interned keys in salsa -- it is basically
+/// a newtype'd u32. Typically, it is wrapped in a type of your own
+/// devising. For more information about interned keys, see [the
+/// interned key RFC][rfc].
+///
+/// # Creating a `InternId`
+//
+/// InternId values can be constructed using the `From` impls,
+/// which are implemented for `u32` and `usize`:
+///
+/// ```
+/// # use ra_salsa::InternId;
+/// let intern_id1 = InternId::from(22_u32);
+/// let intern_id2 = InternId::from(22_usize);
+/// assert_eq!(intern_id1, intern_id2);
+/// ```
+///
+/// # Converting to a u32 or usize
+///
+/// Normally, there should be no need to access the underlying integer
+/// in a `InternId`. But if you do need to do so, you can convert to a
+/// `usize` using the `as_u32` or `as_usize` methods or the `From` impls.
+///
+/// ```
+/// # use ra_salsa::InternId;;
+/// let intern_id = InternId::from(22_u32);
+/// let value = u32::from(intern_id);
+/// assert_eq!(value, 22);
+/// ```
+///
+/// ## Illegal values
+///
+/// Be warned, however, that `InternId` values cannot be created from
+/// *arbitrary* values -- in particular large values greater than
+/// `InternId::MAX` will panic. Those large values are reserved so that
+/// the Rust compiler can use them as sentinel values, which means
+/// that (for example) `Option<InternId>` is represented in a single
+/// word.
+///
+/// ```should_panic
+/// # use ra_salsa::InternId;;
+/// InternId::from(InternId::MAX);
+/// ```
+///
+/// [rfc]: https://github.com/salsa-rs/salsa-rfcs/pull/2
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct InternId {
+ value: NonZeroU32,
+}
+
+impl InternId {
+ /// The maximum allowed `InternId`. This value can grow between
+ /// releases without affecting semver.
+ pub const MAX: u32 = 0xFFFF_FF00;
+
+ /// Creates a new InternId.
+ ///
+ /// # Safety
+ ///
+ /// `value` must be less than `MAX`
+ pub const unsafe fn new_unchecked(value: u32) -> Self {
+ debug_assert!(value < InternId::MAX);
+ let value = unsafe { NonZeroU32::new_unchecked(value + 1) };
+ InternId { value }
+ }
+
+ /// Convert this raw-id into a u32 value.
+ ///
+ /// ```
+ /// # use ra_salsa::InternId;
+ /// let intern_id = InternId::from(22_u32);
+ /// let value = intern_id.as_usize();
+ /// assert_eq!(value, 22);
+ /// ```
+ pub fn as_u32(self) -> u32 {
+ self.value.get() - 1
+ }
+
+ /// Convert this raw-id into a usize value.
+ ///
+ /// ```
+ /// # use ra_salsa::InternId;
+ /// let intern_id = InternId::from(22_u32);
+ /// let value = intern_id.as_usize();
+ /// assert_eq!(value, 22);
+ /// ```
+ pub fn as_usize(self) -> usize {
+ self.as_u32() as usize
+ }
+}
+
+impl From<InternId> for u32 {
+ fn from(raw: InternId) -> u32 {
+ raw.as_u32()
+ }
+}
+
+impl From<InternId> for usize {
+ fn from(raw: InternId) -> usize {
+ raw.as_usize()
+ }
+}
+
+impl From<u32> for InternId {
+ fn from(id: u32) -> InternId {
+ assert!(id < InternId::MAX);
+ unsafe { InternId::new_unchecked(id) }
+ }
+}
+
+impl From<usize> for InternId {
+ fn from(id: usize) -> InternId {
+ assert!(id < (InternId::MAX as usize));
+ unsafe { InternId::new_unchecked(id as u32) }
+ }
+}
+
+impl fmt::Debug for InternId {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.as_usize().fmt(f)
+ }
+}
+
+impl fmt::Display for InternId {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.as_usize().fmt(f)
+ }
+}