brainwires_proxy/
request_id.rs1use std::fmt;
2use std::sync::atomic::{AtomicU64, Ordering};
3
4static COUNTER: AtomicU64 = AtomicU64::new(1);
5
6#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
8pub struct RequestId {
9 seq: u64,
10 uuid: uuid::Uuid,
11}
12
13impl RequestId {
14 pub fn new() -> Self {
16 Self {
17 seq: COUNTER.fetch_add(1, Ordering::Relaxed),
18 uuid: uuid::Uuid::new_v4(),
19 }
20 }
21
22 pub fn seq(&self) -> u64 {
24 self.seq
25 }
26
27 pub fn uuid(&self) -> uuid::Uuid {
29 self.uuid
30 }
31}
32
33impl Default for RequestId {
34 fn default() -> Self {
35 Self::new()
36 }
37}
38
39impl fmt::Display for RequestId {
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 write!(f, "{}-{}", self.seq, &self.uuid.to_string()[..8])
42 }
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48
49 #[test]
50 fn ids_are_unique() {
51 let a = RequestId::new();
52 let b = RequestId::new();
53 assert_ne!(a, b);
54 assert_ne!(a.seq(), b.seq());
55 assert_ne!(a.uuid(), b.uuid());
56 }
57
58 #[test]
59 fn seq_is_monotonic() {
60 let a = RequestId::new();
61 let b = RequestId::new();
62 let c = RequestId::new();
63 assert!(a.seq() < b.seq());
64 assert!(b.seq() < c.seq());
65 }
66
67 #[test]
68 fn display_format() {
69 let id = RequestId::new();
70 let s = id.to_string();
71 assert!(s.contains('-'));
73 let parts: Vec<&str> = s.splitn(2, '-').collect();
74 assert_eq!(parts.len(), 2);
75 assert!(parts[0].parse::<u64>().is_ok());
76 assert_eq!(parts[1].len(), 8);
77 }
78
79 #[test]
80 fn serde_roundtrip() {
81 let id = RequestId::new();
82 let json = serde_json::to_string(&id).unwrap();
83 let deserialized: RequestId = serde_json::from_str(&json).unwrap();
84 assert_eq!(id, deserialized);
85 }
86}