Skip to main content

endpoint_libs/libs/
utils.rs

1use eyre::Result;
2
3pub fn get_log_id() -> u64 {
4    chrono::Utc::now().timestamp_micros() as _
5}
6
7/// A connection id unique within this process.
8///
9/// It was the clock in microseconds, cut to 32 bits, which gives two
10/// connections accepted in the same microsecond the same id. With one accept
11/// loop that took two accepts inside a microsecond; with a shard per core it
12/// is two shards accepting at once, and the second insert into the shared
13/// connection table replaced the first. A counter cannot repeat until it wraps.
14/// It starts from the clock so ids still differ across restarts in logs.
15pub fn get_conn_id() -> u32 {
16    use std::sync::OnceLock;
17    use std::sync::atomic::{AtomicU32, Ordering};
18    static NEXT: OnceLock<AtomicU32> = OnceLock::new();
19    NEXT.get_or_init(|| AtomicU32::new(chrono::Utc::now().timestamp_micros() as u32))
20        .fetch_add(1, Ordering::Relaxed)
21}
22
23#[cfg(test)]
24mod conn_id_tests {
25    #[test]
26    fn ids_from_many_threads_never_repeat() {
27        let ids: Vec<u32> = std::thread::scope(|scope| {
28            let workers: Vec<_> = (0..8)
29                .map(|_| {
30                    scope.spawn(|| {
31                        (0..10_000)
32                            .map(|_| super::get_conn_id())
33                            .collect::<Vec<_>>()
34                    })
35                })
36                .collect();
37            workers
38                .into_iter()
39                .flat_map(|worker| worker.join().unwrap())
40                .collect()
41        });
42        let unique: std::collections::HashSet<u32> = ids.iter().copied().collect();
43        assert_eq!(unique.len(), ids.len());
44    }
45}
46
47pub fn get_time_milliseconds() -> i64 {
48    chrono::Utc::now().timestamp_millis()
49}
50pub fn get_time_micros() -> i64 {
51    chrono::Utc::now().timestamp_micros()
52}
53pub fn hex_decode(s: &[u8]) -> Result<Vec<u8>> {
54    if s.starts_with(b"0x") {
55        Ok(hex::decode(&s[2..])?)
56    } else {
57        Ok(hex::decode(s)?)
58    }
59}
60
61/// Aligns the precision of one `f64` value to match another `f64` value.
62pub fn align_precision(a: f64, b: f64) -> f64 {
63    let precision_b = count_dp(b);
64    let precision_a = format!("{:.0$}", { precision_b });
65    let aligned_a = format!("{:.*}", precision_a.parse::<usize>().unwrap(), a);
66    aligned_a.parse().unwrap()
67}
68
69pub fn count_dp(num: f64) -> usize {
70    // Convert the f64 to a string representation
71    let num_str = format!("{num}");
72
73    // Find the position of the decimal point
74    if let Some(decimal_index) = num_str.find('.') {
75        // Count the number of characters after the decimal point
76        num_str.len() - decimal_index - 1
77    } else {
78        // If there is no decimal point, return 0
79        0
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn test_count_dp() {
89        assert_eq!(count_dp(1.5), 1);
90        assert_eq!(count_dp(1.1), 1);
91    }
92
93    #[test]
94    fn test_align_precision() {
95        let a = 123.456789;
96        let b = 78.9;
97        let aligned_a = align_precision(a, b);
98        assert_eq!(aligned_a, 123.5);
99
100        let a = 2.37;
101        let b = 631.3;
102        let aligned_a = align_precision(a, b);
103        assert_eq!(aligned_a, 2.4);
104    }
105}