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}