Skip to main content

hyli_model/
utils.rs

1use alloc::{
2    format,
3    string::{String, ToString},
4    vec::Vec,
5};
6use core::{
7    ops::{Add, Sub},
8    time::Duration,
9};
10
11use borsh::{BorshDeserialize, BorshSerialize};
12use derive_more::Display;
13use serde::{Deserialize, Serialize};
14
15pub mod hex_bytes {
16    use alloc::{string::String, vec::Vec};
17    use serde::{Deserialize, Deserializer, Serializer};
18
19    pub fn serialize<S>(bytes: &Vec<u8>, serializer: S) -> Result<S::Ok, S::Error>
20    where
21        S: Serializer,
22    {
23        serializer.serialize_str(&hex::encode(bytes))
24    }
25
26    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
27    where
28        D: Deserializer<'de>,
29    {
30        let s = String::deserialize(deserializer)?;
31        let normalized = super::normalize_hex_string(&s);
32        hex::decode(&normalized).map_err(serde::de::Error::custom)
33    }
34}
35
36fn normalize_hex_string(s: &str) -> String {
37    let trimmed = s.strip_prefix("0x").unwrap_or(s);
38    if trimmed.len() % 2 == 1 {
39        format!("0{trimmed}")
40    } else {
41        trimmed.to_string()
42    }
43}
44
45pub fn decode_hex_string_checked(s: &str) -> Result<Vec<u8>, hex::FromHexError> {
46    let normalized = normalize_hex_string(s);
47    hex::decode(&normalized)
48}
49
50#[derive(
51    Debug,
52    Clone,
53    Deserialize,
54    Serialize,
55    PartialEq,
56    Eq,
57    BorshDeserialize,
58    BorshSerialize,
59    PartialOrd,
60    Ord,
61    Default,
62    Display,
63    Hash,
64)]
65#[cfg_attr(feature = "full", derive(utoipa::ToSchema))]
66pub struct TimestampMs(pub u128);
67
68impl TimestampMs {
69    pub const ZERO: TimestampMs = TimestampMs(0);
70}
71
72impl Add<Duration> for TimestampMs {
73    type Output = TimestampMs;
74
75    fn add(self, rhs: Duration) -> Self::Output {
76        TimestampMs(self.0 + rhs.as_millis())
77    }
78}
79
80impl Sub<TimestampMs> for TimestampMs {
81    type Output = Duration;
82
83    fn sub(self, rhs: TimestampMs) -> Duration {
84        Duration::from_millis((self.0 - rhs.0) as u64)
85    }
86}
87
88impl Sub<Duration> for TimestampMs {
89    type Output = TimestampMs;
90
91    fn sub(self, rhs: Duration) -> TimestampMs {
92        TimestampMs(self.0 - rhs.as_millis())
93    }
94}