diff options
author | Piepmatz <git+github@cptpiepmatz.de> | 2024-09-30 13:20:15 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-30 13:20:15 +0200 |
commit | f0c83a445977c894c4c46ca9e1c97e3372eddd69 (patch) | |
tree | b2e3e81437f4e8fc527171bca8baab1bb8f92946 /crates/nu-protocol/src/id.rs | |
parent | fc61416c7942b51051051fb93e0f33efcf6e6dce (diff) |
Replace raw usize IDs with new types (#13832)
# Description
In this PR I replaced most of the raw usize IDs with
[newtypes](https://doc.rust-lang.org/rust-by-example/generics/new_types.html).
Some other IDs already started using new types and in this PR I did not
want to touch them. To make the implementation less repetitive, I made
use of a generic `Id<T>` with marker structs. If this lands I would try
to move make other IDs also in this pattern.
Also at some places I needed to use `cast`, I'm not sure if the type was
incorrect and therefore casting not needed or if actually different ID
types intermingle sometimes.
# User-Facing Changes
Probably few, if you got a `DeclId` via a function and placed it later
again it will still work.
Diffstat (limited to 'crates/nu-protocol/src/id.rs')
-rw-r--r-- | crates/nu-protocol/src/id.rs | 92 |
1 files changed, 85 insertions, 7 deletions
diff --git a/crates/nu-protocol/src/id.rs b/crates/nu-protocol/src/id.rs index 829ee8f36..84600e3c0 100644 --- a/crates/nu-protocol/src/id.rs +++ b/crates/nu-protocol/src/id.rs @@ -1,12 +1,90 @@ +use std::any; +use std::fmt::{Debug, Error, Formatter}; +use std::marker::PhantomData; + use serde::{Deserialize, Serialize}; -pub type VarId = usize; -pub type DeclId = usize; -pub type BlockId = usize; -pub type ModuleId = usize; -pub type OverlayId = usize; -pub type FileId = usize; -pub type VirtualPathId = usize; +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Id<T> { + inner: usize, + _phantom: PhantomData<T>, +} + +impl<T> Id<T> { + /// Creates a new `Id`. + /// + /// Using a distinct type like `Id` instead of `usize` helps us avoid mixing plain integers + /// with identifiers. + #[inline] + pub const fn new(inner: usize) -> Self { + Self { + inner, + _phantom: PhantomData, + } + } + + /// Returns the inner `usize` value. + /// + /// This requires an explicit call, ensuring we only use the raw value when intended. + #[inline] + pub const fn get(self) -> usize { + self.inner + } +} + +impl<T> Debug for Id<T> { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { + let marker = any::type_name::<T>().split("::").last().expect("not empty"); + write!(f, "{marker}Id({})", self.inner) + } +} + +impl<T> Serialize for Id<T> { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + self.inner.serialize(serializer) + } +} + +impl<'de, T> Deserialize<'de> for Id<T> { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::Deserializer<'de>, + { + let inner = usize::deserialize(deserializer)?; + Ok(Self { + inner, + _phantom: PhantomData, + }) + } +} + +pub mod marker { + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct Var; + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct Decl; + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct Block; + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct Module; + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct Overlay; + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct File; + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct VirtualPath; +} + +pub type VarId = Id<marker::Var>; +pub type DeclId = Id<marker::Decl>; +pub type BlockId = Id<marker::Block>; +pub type ModuleId = Id<marker::Module>; +pub type OverlayId = Id<marker::Overlay>; +pub type FileId = Id<marker::File>; +pub type VirtualPathId = Id<marker::VirtualPath>; #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] pub struct SpanId(pub usize); // more robust ID style used in the new parser |