Skip to main content

sfo_cmd_server/
tunnel_id.rs

1use 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        // TODO: 用10年?
21        (now - since_2021) * 10
22    }
23
24    // fn time_bits() -> usize {
25    //     20
26    // }
27}
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}