scsys_core/id/
identifier.rs

1/*
2    Appellation: id <mod>
3    Contrib: FL03 <jo3mccain@icloud.com>
4*/
5use super::Identifier;
6
7/// [`Id`] is a generic identifier type that wraps a value of type `T`.
8#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
9#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
10#[repr(transparent)]
11pub struct Id<T = usize>(pub T);
12
13impl<T> Id<T> {
14    /// create a new identifier from the given value
15    pub const fn new(id: T) -> Self {
16        Self(id)
17    }
18    #[allow(clippy::should_implement_trait)]
19    /// Create a new identifier with the default value
20    pub fn default() -> Self
21    where
22        T: Default,
23    {
24        Self::new(T::default())
25    }
26    /// returns a new id with a value of `1`
27    pub fn one() -> Self
28    where
29        T: num_traits::One,
30    {
31        Self::new(T::one())
32    }
33    /// returns a new id with a value of `0`
34    pub fn zero() -> Self
35    where
36        T: num_traits::Zero,
37    {
38        Self::new(T::zero())
39    }
40    #[cfg(feature = "rand")]
41    pub fn random() -> Self
42    where
43        rand_distr::StandardUniform: rand_distr::Distribution<T>,
44    {
45        use rand::Rng;
46        let mut rng = rand::rng();
47        Self::new(rng.random())
48    }
49    /// returns an immutable reference to the inner value
50    pub const fn get(&self) -> &T {
51        &self.0
52    }
53    /// returns a mutable reference to the inner value
54    pub const fn get_mut(&mut self) -> &mut T {
55        &mut self.0
56    }
57    /// consumes the current instance to return the inner value
58    #[inline]
59    pub fn value(self) -> T {
60        self.0
61    }
62    /// use the [`replace`](core::mem::replace) method to update and return the inner value
63    pub const fn replace(&mut self, id: T) -> T {
64        core::mem::replace(self.get_mut(), id)
65    }
66    /// mutate the inner value and return a mutable reference to the wrapper for chaining
67    pub fn set(&mut self, id: T) -> &mut Self {
68        *self.get_mut() = id;
69        self
70    }
71    /// [`swap`](core::mem::swap) the inner value with that of another identifier instance of
72    /// the same type `T`
73    pub const fn swap(&mut self, id: &mut Id<T>) {
74        core::mem::swap(self.get_mut(), id.get_mut())
75    }
76    /// [`take`](core::mem::take) the inner value, leaving the logical [`default`](Default::default)
77    /// value in its place.
78    pub fn take(&mut self) -> T
79    where
80        T: Default,
81    {
82        core::mem::take(self.get_mut())
83    }
84    /// consumes the current instance to replace it with another.
85    pub fn with<U>(self, id: U) -> Id<U> {
86        Id::new(id)
87    }
88    /// apply a function onto the inner value and return a new instance with the result
89    pub fn map<U, F>(self, f: F) -> Id<U>
90    where
91        F: FnOnce(T) -> U,
92    {
93        Id::new(f(self.value()))
94    }
95    /// replaces the current id with the next logical value of type `T`
96    ///
97    /// ```rust
98    /// use scsys::Id;
99    ///
100    /// let mut id = Id::zero();
101    /// assert_eq!(id.step(), 0);
102    /// assert_eq!(id.step(), 1);
103    ///
104    /// ```
105    pub fn step(&mut self) -> T
106    where
107        T: num_traits::One,
108        for<'a> &'a T: core::ops::Add<T, Output = T>,
109    {
110        self.replace(self.get() + T::one())
111    }
112    /// returns a new identifier with a reference to the inner value
113    pub const fn view(&self) -> Id<&T> {
114        Id::new(self.get())
115    }
116    /// returns a new identifier with a mutable reference to the inner value
117    pub const fn view_mut(&mut self) -> Id<&mut T> {
118        Id::new(self.get_mut())
119    }
120}
121
122impl Id<usize> {
123    pub fn atomic() -> Self {
124        use core::sync::atomic::{AtomicUsize, Ordering::Relaxed};
125        static COUNTER: AtomicUsize = AtomicUsize::new(1);
126        Self::new(COUNTER.fetch_add(1, Relaxed))
127    }
128    /// replaces the current id with the atomic-ally next value and returns the previous value.
129    /// see [`step`](Id::step) for more information
130    pub fn atomic_step(&mut self) -> usize {
131        use core::sync::atomic::{AtomicUsize, Ordering::Relaxed};
132        static COUNTER: AtomicUsize = AtomicUsize::new(1);
133        self.replace(COUNTER.fetch_add(1, Relaxed))
134    }
135}
136
137#[cfg(feature = "uuid")]
138impl Id<uuid::Uuid> {
139    pub fn v3(namespace: &uuid::Uuid, name: &[u8]) -> Self {
140        let id = uuid::Uuid::new_v3(namespace, name);
141        Self::new(id)
142    }
143
144    #[cfg(all(feature = "rng", feature = "uuid"))]
145    pub fn v4() -> Self {
146        let id = uuid::Uuid::new_v4();
147        Self::new(id)
148    }
149}
150
151impl<T> Default for Id<T>
152where
153    T: Default,
154{
155    fn default() -> Self {
156        Self::new(T::default())
157    }
158}
159
160impl<T> Identifier for Id<T> {
161    seal!();
162}