unique_token/
lib.rs

1//! This crate provides a unique token type.
2
3#![forbid(unsafe_code)]
4
5use std::sync::atomic::{AtomicU64, Ordering};
6
7/// This type represents a unique token.
8///
9/// Each call to [`Unique::new()`] returns a unique value.
10/// The only way to create a token that compares equal is to
11/// clone or copy an existing token.
12///
13/// # Examples
14///
15/// ```
16/// use unique_token::Unique;
17///
18/// let x = Unique::new();
19/// let y = Unique::new();
20///
21/// // clones are equal
22/// assert_eq!(x, x.clone());
23/// assert_eq!(y, y.clone());
24///
25/// // tokens from different calls are unequal
26/// assert_ne!(x, y);
27/// ```
28///
29/// # Implementation
30///
31/// Each token is provided with a unique ID
32/// by incrementing a static [`AtomicU64`](std::sync::atomic::AtomicU64).
33#[derive(Clone, Copy, PartialEq, Eq, Hash)]
34pub struct Unique(u64);
35
36impl Unique {
37    /// Create a new token.
38    ///
39    /// All tokens created by this function compare unequal.
40    ///
41    /// # Panics
42    ///
43    /// This function panics if [`u64::MAX`]
44    /// unique tokens have been created.
45    /// In practice, this should never happen;
46    /// creating one token per nanosecond allows for
47    /// a runtime of almost six centuries.
48    #[inline]
49    pub fn new() -> Self {
50        static NEXT_ID: AtomicU64 = AtomicU64::new(1);
51
52        let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
53        if id == 0 {
54            panic!("id overflow")
55        }
56        Self(id)
57    }
58}
59
60impl std::fmt::Debug for Unique {
61    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
62        let len = (u64::BITS / 4) as usize;
63        write!(fmt, "0x{:0len$X}", u64::from(self))
64    }
65}
66
67impl From<&Unique> for u64 {
68    #[inline]
69    fn from(token: &Unique) -> u64 {
70        token.0
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    use super::Unique;
77
78    #[test]
79    fn test_eq() {
80        let x = Unique::new();
81        let y = Unique::new();
82        assert_ne!(&x, &y);
83        assert_eq!(&x, &x.clone());
84        assert_eq!(&y, &y.clone());
85    }
86
87    #[test]
88    fn test_into_u64() {
89        let x = Unique::new();
90        let y = Unique::new();
91        assert_ne!(u64::from(&x), u64::from(&y));
92        assert_eq!(u64::from(&x), u64::from(&x.clone()));
93        assert_eq!(u64::from(&y), u64::from(&y.clone()));
94    }
95}