1use crate::siphash::hash_name_u32;
25use serde::{Deserialize, Serialize};
26use std::fmt;
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
32pub struct ServiceId(u32);
33
34impl ServiceId {
35 pub fn from_name(name: &str) -> Self {
45 Self(hash_name_u32(name))
46 }
47
48 pub const fn from_raw(id: u32) -> Self {
50 Self(id)
51 }
52
53 pub const fn as_u32(&self) -> u32 {
55 self.0
56 }
57}
58
59impl From<ServiceId> for u32 {
60 fn from(id: ServiceId) -> u32 {
61 id.0
62 }
63}
64
65impl From<u32> for ServiceId {
66 fn from(id: u32) -> ServiceId {
67 ServiceId(id)
68 }
69}
70
71impl fmt::Display for ServiceId {
72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 write!(f, "ServiceId(0x{:08X})", self.0)
74 }
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
82pub struct InterfaceId(u32);
83
84impl InterfaceId {
85 pub fn from_name(name: &str) -> Self {
95 Self(hash_name_u32(name))
96 }
97
98 pub const fn from_raw(id: u32) -> Self {
100 Self(id)
101 }
102
103 pub const fn as_u32(&self) -> u32 {
105 self.0
106 }
107}
108
109impl From<InterfaceId> for u32 {
110 fn from(id: InterfaceId) -> u32 {
111 id.0
112 }
113}
114
115impl From<u32> for InterfaceId {
116 fn from(id: u32) -> InterfaceId {
117 InterfaceId(id)
118 }
119}
120
121impl fmt::Display for InterfaceId {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 write!(f, "InterfaceId(0x{:08X})", self.0)
124 }
125}
126
127#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
131pub struct MethodId(u32);
132
133impl MethodId {
134 pub fn from_name(name: &str) -> Self {
144 Self(hash_name_u32(name))
145 }
146
147 pub const fn from_raw(id: u32) -> Self {
149 Self(id)
150 }
151
152 pub const fn as_u32(&self) -> u32 {
154 self.0
155 }
156}
157
158impl From<MethodId> for u32 {
159 fn from(id: MethodId) -> u32 {
160 id.0
161 }
162}
163
164impl From<u32> for MethodId {
165 fn from(id: u32) -> MethodId {
166 MethodId(id)
167 }
168}
169
170impl fmt::Display for MethodId {
171 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172 write!(f, "MethodId(0x{:08X})", self.0)
173 }
174}
175
176#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
180pub struct HeaderKeyId(u32);
181
182impl HeaderKeyId {
183 pub fn from_name(name: &str) -> Self {
194 Self(hash_name_u32(name))
195 }
196
197 pub const fn from_raw(id: u32) -> Self {
199 Self(id)
200 }
201
202 pub const fn as_u32(&self) -> u32 {
204 self.0
205 }
206}
207
208impl From<HeaderKeyId> for u32 {
209 fn from(id: HeaderKeyId) -> u32 {
210 id.0
211 }
212}
213
214impl From<u32> for HeaderKeyId {
215 fn from(id: u32) -> HeaderKeyId {
216 HeaderKeyId(id)
217 }
218}
219
220impl fmt::Display for HeaderKeyId {
221 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222 write!(f, "HeaderKeyId(0x{:08X})", self.0)
223 }
224}
225
226#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
230pub struct MetricId(u32);
231
232impl MetricId {
233 pub fn from_name(name: &str) -> Self {
244 Self(hash_name_u32(name))
245 }
246
247 pub const fn from_raw(id: u32) -> Self {
249 Self(id)
250 }
251
252 pub const fn as_u32(&self) -> u32 {
254 self.0
255 }
256}
257
258impl From<MetricId> for u32 {
259 fn from(id: MetricId) -> u32 {
260 id.0
261 }
262}
263
264impl From<u32> for MetricId {
265 fn from(id: u32) -> MetricId {
266 MetricId(id)
267 }
268}
269
270impl fmt::Display for MetricId {
271 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
272 write!(f, "MetricId(0x{:08X})", self.0)
273 }
274}
275
276#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
280pub struct InstanceId(u128);
281
282impl InstanceId {
283 pub fn new_random() -> Self {
285 let uuid = uuid::Uuid::new_v4();
286 Self(u128::from_be_bytes(*uuid.as_bytes()))
287 }
288
289 pub const fn from_raw(id: u128) -> Self {
291 Self(id)
292 }
293
294 pub fn from_bytes(bytes: [u8; 16]) -> Self {
296 Self(u128::from_be_bytes(bytes))
297 }
298
299 pub const fn as_u128(&self) -> u128 {
301 self.0
302 }
303
304 pub fn as_bytes(&self) -> [u8; 16] {
306 self.0.to_be_bytes()
307 }
308}
309
310impl From<InstanceId> for u128 {
311 fn from(id: InstanceId) -> u128 {
312 id.0
313 }
314}
315
316impl From<u128> for InstanceId {
317 fn from(id: u128) -> InstanceId {
318 InstanceId(id)
319 }
320}
321
322impl fmt::Display for InstanceId {
323 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
324 write!(f, "InstanceId(0x{:032X})", self.0)
325 }
326}
327
328pub mod well_known {
333 use super::HeaderKeyId;
334 use once_cell::sync::Lazy;
335
336 pub static TRACE_ID: Lazy<HeaderKeyId> = Lazy::new(|| HeaderKeyId::from_name("trace_id"));
338
339 pub static SPAN_ID: Lazy<HeaderKeyId> = Lazy::new(|| HeaderKeyId::from_name("span_id"));
341
342 pub static REQUEST_ID: Lazy<HeaderKeyId> = Lazy::new(|| HeaderKeyId::from_name("request_id"));
344
345 pub static CALLER_SERVICE: Lazy<HeaderKeyId> =
347 Lazy::new(|| HeaderKeyId::from_name("caller_service"));
348
349 pub static IDEMPOTENCY_KEY: Lazy<HeaderKeyId> =
351 Lazy::new(|| HeaderKeyId::from_name("idempotency_key"));
352}
353
354#[cfg(test)]
355mod tests {
356 use super::*;
357
358 #[test]
359 fn test_service_id() {
360 let id1 = ServiceId::from_name("user-service");
361 let id2 = ServiceId::from_name("user-service");
362 let id3 = ServiceId::from_name("payment-service");
363
364 assert_eq!(id1, id2, "Same name should produce same ID");
365 assert_ne!(id1, id3, "Different names should produce different IDs");
366
367 let raw: u32 = id1.into();
369 let restored = ServiceId::from_raw(raw);
370 assert_eq!(id1, restored);
371 }
372
373 #[test]
374 fn test_interface_id() {
375 let id = InterfaceId::from_name("mensa.user.v2.UserInterface");
376 let raw = id.as_u32();
377 let restored = InterfaceId::from_raw(raw);
378 assert_eq!(id, restored);
379 }
380
381 #[test]
382 fn test_method_id() {
383 let get_user = MethodId::from_name("GetUser");
384 let create_user = MethodId::from_name("CreateUser");
385 assert_ne!(get_user, create_user);
386 }
387
388 #[test]
389 fn test_header_key_id() {
390 let trace_id = HeaderKeyId::from_name("trace_id");
391 let request_id = HeaderKeyId::from_name("request_id");
392 assert_ne!(trace_id, request_id);
393 }
394
395 #[test]
396 fn test_metric_id() {
397 let request_count = MetricId::from_name("request_count");
398 let error_count = MetricId::from_name("error_count");
399 assert_ne!(request_count, error_count);
400 }
401
402 #[test]
403 fn test_instance_id() {
404 let id1 = InstanceId::new_random();
405
406 let bytes = id1.as_bytes();
408 let restored = InstanceId::from_bytes(bytes);
409 assert_eq!(id1, restored);
410
411 assert_eq!(bytes.len(), 16);
413 }
414
415 #[test]
416 fn test_display() {
417 let service_id = ServiceId::from_name("test-service");
418 let display = format!("{}", service_id);
419 assert!(display.starts_with("ServiceId(0x"));
420 }
421
422 #[test]
423 fn test_well_known_headers() {
424 assert_eq!(*well_known::TRACE_ID, HeaderKeyId::from_name("trace_id"));
426 assert_eq!(*well_known::SPAN_ID, HeaderKeyId::from_name("span_id"));
427 assert_eq!(
428 *well_known::REQUEST_ID,
429 HeaderKeyId::from_name("request_id")
430 );
431 assert_eq!(
432 *well_known::CALLER_SERVICE,
433 HeaderKeyId::from_name("caller_service")
434 );
435 assert_eq!(
436 *well_known::IDEMPOTENCY_KEY,
437 HeaderKeyId::from_name("idempotency_key")
438 );
439
440 assert_ne!(*well_known::TRACE_ID, *well_known::SPAN_ID);
442 }
443
444 #[test]
445 fn test_version_sensitivity() {
446 let v1 = InterfaceId::from_name("mensa.user.v1.UserInterface");
447 let v2 = InterfaceId::from_name("mensa.user.v2.UserInterface");
448 assert_ne!(v1, v2, "Different versions should have different IDs");
449 }
450
451 #[test]
452 fn test_ordering() {
453 let id1 = ServiceId::from_name("aaa");
454 let id2 = ServiceId::from_name("bbb");
455 let id3 = ServiceId::from_name("ccc");
456
457 let mut ids = [id3, id1, id2];
459 ids.sort();
460
461 assert_eq!(ids.len(), 3);
463 }
464}