1use std::borrow;
2use std::sync::atomic::{self, AtomicUsize};
3
4static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
5
6#[derive(Debug, Clone, PartialEq, Eq, Hash)]
8pub struct Id(Internal);
9
10impl Id {
11 pub const fn new(id: &'static str) -> Self {
13 Self(Internal::Custom(borrow::Cow::Borrowed(id)))
14 }
15
16 pub fn unique() -> Self {
20 let id = NEXT_ID.fetch_add(1, atomic::Ordering::Relaxed);
21
22 Self(Internal::Unique(id))
23 }
24}
25
26impl std::fmt::Display for Id {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 match &self.0 {
29 Internal::Unique(n) => write!(f, "__unique_{n}"),
30 Internal::Custom(name) => f.write_str(name),
31 }
32 }
33}
34
35impl From<&'static str> for Id {
36 fn from(value: &'static str) -> Self {
37 Self::new(value)
38 }
39}
40
41impl From<String> for Id {
42 fn from(value: String) -> Self {
43 Self(Internal::Custom(borrow::Cow::Owned(value)))
44 }
45}
46
47#[derive(Debug, Clone, PartialEq, Eq, Hash)]
48enum Internal {
49 Unique(usize),
50 Custom(borrow::Cow<'static, str>),
51}
52
53#[cfg(test)]
54mod tests {
55 use super::Id;
56
57 #[test]
58 fn unique_generates_different_ids() {
59 let a = Id::unique();
60 let b = Id::unique();
61
62 assert_ne!(a, b);
63 }
64}