1use std::sync::atomic::{AtomicU64, Ordering};
2
3use serde::{Deserialize, Serialize};
4
5macro_rules! define_id {
10 ($name:ident, $doc:literal) => {
11 #[doc = $doc]
12 #[derive(
13 Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize,
14 )]
15 pub struct $name(u64);
16
17 impl $name {
18 #[inline]
20 pub fn new(id: u64) -> Self {
21 Self(id)
22 }
23
24 #[inline]
26 pub fn value(self) -> u64 {
27 self.0
28 }
29 }
30
31 impl std::fmt::Display for $name {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 write!(f, "{}({})", stringify!($name), self.0)
34 }
35 }
36 };
37}
38
39define_id!(AtomId, "Unique identifier for an `Atom`.");
40define_id!(BlockId, "Unique identifier for a `Block`.");
41define_id!(EdgeId, "Unique identifier for a `HyperEdge`.");
42define_id!(GraphId, "Unique identifier for a `Graph`.");
43define_id!(PortId, "Unique identifier for a `Port`.");
44
45pub struct IdGen {
52 atom: AtomicU64,
53 block: AtomicU64,
54 edge: AtomicU64,
55 graph: AtomicU64,
56 port: AtomicU64,
57}
58
59impl IdGen {
60 pub const fn new() -> Self {
62 Self {
63 atom: AtomicU64::new(1),
64 block: AtomicU64::new(1),
65 edge: AtomicU64::new(1),
66 graph: AtomicU64::new(1),
67 port: AtomicU64::new(1),
68 }
69 }
70
71 pub fn next_atom_id(&self) -> AtomId {
73 AtomId::new(self.atom.fetch_add(1, Ordering::Relaxed))
74 }
75
76 pub fn next_block_id(&self) -> BlockId {
78 BlockId::new(self.block.fetch_add(1, Ordering::Relaxed))
79 }
80
81 pub fn next_edge_id(&self) -> EdgeId {
83 EdgeId::new(self.edge.fetch_add(1, Ordering::Relaxed))
84 }
85
86 pub fn next_graph_id(&self) -> GraphId {
88 GraphId::new(self.graph.fetch_add(1, Ordering::Relaxed))
89 }
90
91 pub fn next_port_id(&self) -> PortId {
93 PortId::new(self.port.fetch_add(1, Ordering::Relaxed))
94 }
95}
96
97impl Default for IdGen {
98 fn default() -> Self {
99 Self::new()
100 }
101}
102
103#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn id_new_and_value_round_trip() {
113 assert_eq!(AtomId::new(42).value(), 42);
114 assert_eq!(BlockId::new(0).value(), 0);
115 }
116
117 #[test]
118 fn id_gen_monotonic() {
119 let id_gen = IdGen::new();
120 let a1 = id_gen.next_atom_id();
121 let a2 = id_gen.next_atom_id();
122 assert!(a2.value() > a1.value());
123 }
124
125 #[test]
126 fn id_gen_types_independent() {
127 let id_gen = IdGen::new();
128 let atom = id_gen.next_atom_id();
129 let block = id_gen.next_block_id();
130 assert_eq!(atom.value(), 1);
132 assert_eq!(block.value(), 1);
133 }
134}