1use serde::{Deserialize, Serialize};
2use std::fmt;
3use std::sync::atomic::{AtomicU64, Ordering};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
6#[serde(transparent)]
7pub struct CallId(u64);
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
10#[serde(transparent)]
11pub struct PromiseId(u64);
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
14#[serde(transparent)]
15pub struct CapId(u64);
16
17impl CallId {
18 pub fn new(value: u64) -> Self {
19 CallId(value)
20 }
21
22 pub fn as_u64(&self) -> u64 {
23 self.0
24 }
25}
26
27impl PromiseId {
28 pub fn new(value: u64) -> Self {
29 PromiseId(value)
30 }
31
32 pub fn as_u64(&self) -> u64 {
33 self.0
34 }
35}
36
37impl CapId {
38 pub fn new(value: u64) -> Self {
39 CapId(value)
40 }
41
42 pub fn as_u64(&self) -> u64 {
43 self.0
44 }
45}
46
47impl fmt::Display for CallId {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 write!(f, "CallId({})", self.0)
50 }
51}
52
53impl fmt::Display for PromiseId {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 write!(f, "PromiseId({})", self.0)
56 }
57}
58
59impl fmt::Display for CapId {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 write!(f, "CapId({})", self.0)
62 }
63}
64
65impl From<u64> for CallId {
66 fn from(value: u64) -> Self {
67 CallId::new(value)
68 }
69}
70
71impl From<u64> for PromiseId {
72 fn from(value: u64) -> Self {
73 PromiseId::new(value)
74 }
75}
76
77impl From<u64> for CapId {
78 fn from(value: u64) -> Self {
79 CapId::new(value)
80 }
81}
82
83pub struct CallIdAllocator {
84 next: AtomicU64,
85}
86
87pub struct PromiseIdAllocator {
88 next: AtomicU64,
89}
90
91pub struct CapIdAllocator {
92 next: AtomicU64,
93}
94
95impl CallIdAllocator {
96 pub fn new() -> Self {
97 CallIdAllocator {
98 next: AtomicU64::new(1),
99 }
100 }
101
102 pub fn allocate(&self) -> CallId {
103 let id = self.next.fetch_add(1, Ordering::Relaxed);
104 CallId::new(id)
105 }
106
107 pub fn peek_next(&self) -> u64 {
108 self.next.load(Ordering::Relaxed)
109 }
110}
111
112impl PromiseIdAllocator {
113 pub fn new() -> Self {
114 PromiseIdAllocator {
115 next: AtomicU64::new(1),
116 }
117 }
118
119 pub fn allocate(&self) -> PromiseId {
120 let id = self.next.fetch_add(1, Ordering::Relaxed);
121 PromiseId::new(id)
122 }
123
124 pub fn peek_next(&self) -> u64 {
125 self.next.load(Ordering::Relaxed)
126 }
127}
128
129impl CapIdAllocator {
130 pub fn new() -> Self {
131 CapIdAllocator {
132 next: AtomicU64::new(1),
133 }
134 }
135
136 pub fn allocate(&self) -> CapId {
137 let id = self.next.fetch_add(1, Ordering::Relaxed);
138 CapId::new(id)
139 }
140
141 pub fn peek_next(&self) -> u64 {
142 self.next.load(Ordering::Relaxed)
143 }
144}
145
146impl Default for CallIdAllocator {
147 fn default() -> Self {
148 Self::new()
149 }
150}
151
152impl Default for PromiseIdAllocator {
153 fn default() -> Self {
154 Self::new()
155 }
156}
157
158impl Default for CapIdAllocator {
159 fn default() -> Self {
160 Self::new()
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167 use std::collections::HashSet;
168 use std::sync::Arc;
169 use std::thread;
170
171 #[test]
172 fn test_id_creation_and_conversion() {
173 let call_id = CallId::new(42);
174 assert_eq!(call_id.as_u64(), 42);
175 assert_eq!(format!("{}", call_id), "CallId(42)");
176
177 let promise_id = PromiseId::new(100);
178 assert_eq!(promise_id.as_u64(), 100);
179 assert_eq!(format!("{}", promise_id), "PromiseId(100)");
180
181 let cap_id = CapId::new(999);
182 assert_eq!(cap_id.as_u64(), 999);
183 assert_eq!(format!("{}", cap_id), "CapId(999)");
184 }
185
186 #[test]
187 fn test_id_from_u64() {
188 let call_id: CallId = 42u64.into();
189 assert_eq!(call_id.as_u64(), 42);
190
191 let promise_id: PromiseId = 100u64.into();
192 assert_eq!(promise_id.as_u64(), 100);
193
194 let cap_id: CapId = 999u64.into();
195 assert_eq!(cap_id.as_u64(), 999);
196 }
197
198 #[test]
199 fn test_id_equality_and_hash() {
200 let id1 = CallId::new(42);
201 let id2 = CallId::new(42);
202 let id3 = CallId::new(43);
203
204 assert_eq!(id1, id2);
205 assert_ne!(id1, id3);
206
207 let mut set = HashSet::new();
208 set.insert(id1);
209 assert!(set.contains(&id2));
210 assert!(!set.contains(&id3));
211 }
212
213 #[test]
214 fn test_allocator_monotonic() {
215 let allocator = CallIdAllocator::new();
216
217 let id1 = allocator.allocate();
218 let id2 = allocator.allocate();
219 let id3 = allocator.allocate();
220
221 assert_eq!(id1.as_u64(), 1);
222 assert_eq!(id2.as_u64(), 2);
223 assert_eq!(id3.as_u64(), 3);
224 assert_eq!(allocator.peek_next(), 4);
225 }
226
227 #[test]
228 fn test_allocator_thread_safety() {
229 let allocator = Arc::new(CallIdAllocator::new());
230 let mut handles = vec![];
231 let num_threads = 10;
232 let ids_per_thread = 100;
233
234 for _ in 0..num_threads {
235 let alloc = Arc::clone(&allocator);
236 let handle = thread::spawn(move || {
237 let mut ids = vec![];
238 for _ in 0..ids_per_thread {
239 ids.push(alloc.allocate().as_u64());
240 }
241 ids
242 });
243 handles.push(handle);
244 }
245
246 let mut all_ids = HashSet::new();
247 for handle in handles {
248 let ids = handle.join().unwrap();
249 for id in ids {
250 assert!(all_ids.insert(id), "Duplicate ID found: {}", id);
251 }
252 }
253
254 assert_eq!(all_ids.len(), num_threads * ids_per_thread);
255 assert_eq!(
256 allocator.peek_next(),
257 (num_threads * ids_per_thread + 1) as u64
258 );
259 }
260
261 #[test]
262 fn test_serialization_deserialization() {
263 let call_id = CallId::new(42);
264 let json = serde_json::to_string(&call_id).unwrap();
265 assert_eq!(json, "42");
266
267 let deserialized: CallId = serde_json::from_str(&json).unwrap();
268 assert_eq!(deserialized, call_id);
269
270 let promise_id = PromiseId::new(100);
271 let json = serde_json::to_string(&promise_id).unwrap();
272 assert_eq!(json, "100");
273
274 let deserialized: PromiseId = serde_json::from_str(&json).unwrap();
275 assert_eq!(deserialized, promise_id);
276
277 let cap_id = CapId::new(999);
278 let json = serde_json::to_string(&cap_id).unwrap();
279 assert_eq!(json, "999");
280
281 let deserialized: CapId = serde_json::from_str(&json).unwrap();
282 assert_eq!(deserialized, cap_id);
283 }
284
285 #[test]
286 fn test_multiple_allocators_independence() {
287 let call_allocator = CallIdAllocator::new();
288 let promise_allocator = PromiseIdAllocator::new();
289 let cap_allocator = CapIdAllocator::new();
290
291 let call1 = call_allocator.allocate();
292 let promise1 = promise_allocator.allocate();
293 let cap1 = cap_allocator.allocate();
294
295 assert_eq!(call1.as_u64(), 1);
296 assert_eq!(promise1.as_u64(), 1);
297 assert_eq!(cap1.as_u64(), 1);
298
299 let call2 = call_allocator.allocate();
300 let promise2 = promise_allocator.allocate();
301 let cap2 = cap_allocator.allocate();
302
303 assert_eq!(call2.as_u64(), 2);
304 assert_eq!(promise2.as_u64(), 2);
305 assert_eq!(cap2.as_u64(), 2);
306 }
307}