sfo_cmd_server/
tunnel_id.rs1use bucky_raw_codec::{RawDecode, RawEncode};
2use std::hash::{Hash, Hasher};
3use std::sync::atomic::{AtomicU32, Ordering};
4use std::time::{Duration, SystemTime, UNIX_EPOCH};
5
6#[derive(Clone, Copy, Ord, PartialEq, Eq, Debug, RawEncode, RawDecode)]
7pub struct TunnelId(u32);
8
9impl TunnelId {
10 pub fn value(&self) -> u32 {
11 self.0
12 }
13
14 fn now(_now: u64) -> u32 {
15 let now = SystemTime::now()
16 .duration_since(SystemTime::UNIX_EPOCH)
17 .unwrap()
18 .as_secs() as u32;
19 let since_2021 = Duration::from_secs((50 * 365 + 9) * 24 * 3600).as_secs() as u32;
20 (now - since_2021) * 10
22 }
23
24 }
28
29impl PartialOrd for TunnelId {
30 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
31 if self.0 == 0 || other.0 == 0 {
32 self.0.partial_cmp(&other.0)
33 } else if (std::cmp::max(self.0, other.0) - std::cmp::min(self.0, other.0)) > (u32::MAX / 2)
34 {
35 Some(if self.0 > other.0 {
36 std::cmp::Ordering::Less
37 } else {
38 std::cmp::Ordering::Greater
39 })
40 } else {
41 self.0.partial_cmp(&other.0)
42 }
43 }
44}
45
46impl Default for TunnelId {
47 fn default() -> Self {
48 Self(0)
49 }
50}
51
52impl From<u32> for TunnelId {
53 fn from(v: u32) -> Self {
54 Self(v)
55 }
56}
57
58impl Hash for TunnelId {
59 fn hash<H: Hasher>(&self, state: &mut H) {
60 state.write_u32(self.0)
61 }
62}
63
64pub struct TunnelIdGenerator {
65 cur: AtomicU32,
66}
67
68impl From<TunnelId> for TunnelIdGenerator {
69 fn from(init: TunnelId) -> Self {
70 Self {
71 cur: AtomicU32::new(init.value()),
72 }
73 }
74}
75
76impl TunnelIdGenerator {
77 pub fn new() -> Self {
78 let now = TunnelId::now(
79 SystemTime::now()
80 .duration_since(UNIX_EPOCH)
81 .unwrap()
82 .as_millis() as u64,
83 );
84 Self {
85 cur: AtomicU32::new(now),
86 }
87 }
88
89 pub fn generate(&self) -> TunnelId {
90 let v = self.cur.fetch_add(1, Ordering::SeqCst);
91 if v == 0 {
92 TunnelId(self.cur.fetch_add(1, Ordering::SeqCst))
93 } else {
94 TunnelId(v)
95 }
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::{TunnelId, TunnelIdGenerator};
102
103 #[test]
104 fn generator_skips_zero_and_increments() {
105 let generator = TunnelIdGenerator::from(TunnelId::from(0));
106 let first = generator.generate();
107 let second = generator.generate();
108 let third = generator.generate();
109
110 assert_eq!(first.value(), 1);
111 assert_eq!(second.value(), 2);
112 assert_eq!(third.value(), 3);
113 }
114
115 #[test]
116 fn partial_ord_wrap_around_behavior() {
117 let near_max = TunnelId::from(u32::MAX - 10);
118 let small = TunnelId::from(10);
119 assert!(near_max < small);
120 assert!(small > near_max);
121 }
122
123 #[test]
124 fn partial_ord_zero_follows_natural_order() {
125 let zero = TunnelId::from(0);
126 let one = TunnelId::from(1);
127 assert!(zero < one);
128 assert!(one > zero);
129 }
130}