endpoint_libs/libs/
utils.rs

1use std::fmt::Write;
2
3use convert_case::{Case, Casing};
4use eyre::{ContextCompat, Result};
5use serde::Serialize;
6
7use crate::model::EndpointSchema;
8
9pub fn get_log_id() -> u64 {
10    chrono::Utc::now().timestamp_micros() as _
11}
12
13pub fn get_conn_id() -> u32 {
14    chrono::Utc::now().timestamp_micros() as _
15}
16
17pub fn encode_header<T: Serialize>(v: T, schema: EndpointSchema) -> Result<String> {
18    let mut s = String::new();
19    write!(s, "0{}", schema.name.to_ascii_lowercase())?;
20    let v = serde_json::to_value(&v)?;
21
22    for (i, f) in schema.parameters.iter().enumerate() {
23        let key = f.name.to_case(Case::Camel);
24        let value = v.get(&key).with_context(|| format!("key: {key}"))?;
25        if value.is_null() {
26            continue;
27        }
28        write!(
29            s,
30            ", {}{}",
31            i + 1,
32            urlencoding::encode(&value.to_string().replace('\"', ""))
33        )?;
34    }
35    Ok(s)
36}
37
38pub fn get_time_milliseconds() -> i64 {
39    chrono::Utc::now().timestamp_millis()
40}
41pub fn get_time_micros() -> i64 {
42    chrono::Utc::now().timestamp_micros()
43}
44pub fn hex_decode(s: &[u8]) -> Result<Vec<u8>> {
45    if s.starts_with(b"0x") {
46        Ok(hex::decode(&s[2..])?)
47    } else {
48        Ok(hex::decode(s)?)
49    }
50}
51
52/// format decimal by specific significant figures
53pub fn decimal_sf(num: rust_decimal::Decimal, sig_figs: usize) -> rust_decimal::Decimal {
54    num.round_sf(sig_figs as _).unwrap()
55}
56
57/// Aligns the precision of one `f64` value to match another `f64` value.
58pub fn align_precision(a: f64, b: f64) -> f64 {
59    let precision_b = count_dp(b);
60    let precision_a = format!("{:.0$}", { precision_b });
61    let aligned_a = format!("{:.*}", precision_a.parse::<usize>().unwrap(), a);
62    aligned_a.parse().unwrap()
63}
64
65pub fn count_dp(num: f64) -> usize {
66    // Convert the f64 to a string representation
67    let num_str = format!("{num}");
68
69    // Find the position of the decimal point
70    if let Some(decimal_index) = num_str.find('.') {
71        // Count the number of characters after the decimal point
72        num_str.len() - decimal_index - 1
73    } else {
74        // If there is no decimal point, return 0
75        0
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    #[test]
84    fn test_count_dp() {
85        assert_eq!(count_dp(1.5), 1);
86        assert_eq!(count_dp(1.1), 1);
87    }
88
89    #[test]
90    fn test_align_precision() {
91        let a = 123.456789;
92        let b = 78.9;
93        let aligned_a = align_precision(a, b);
94        assert_eq!(aligned_a, 123.5);
95
96        let a = 2.37;
97        let b = 631.3;
98        let aligned_a = align_precision(a, b);
99        assert_eq!(aligned_a, 2.4);
100    }
101}