diff options
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 |