1use std::time::{Duration, SystemTime};
2
3use crate::{Error, Result, Tag, Value};
4
5#[derive(Debug, Clone, Copy, PartialEq)]
6enum Inner {
7 Int(u64),
8 Float(f64),
9}
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
23pub struct EpochTime(Inner);
24
25impl Eq for Inner {} impl Ord for Inner {
28 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
29 match (self, other) {
30 (Self::Int(a), Self::Int(b)) => a.cmp(b),
31 (Self::Float(a), Self::Float(b)) => a.total_cmp(b),
32 (Self::Int(a), Self::Float(b)) => (*a as f64).total_cmp(b),
35 (Self::Float(a), Self::Int(b)) => a.total_cmp(&(*b as f64)),
36 }
37 }
38}
39
40impl PartialOrd for Inner {
41 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
42 Some(self.cmp(other))
43 }
44}
45
46impl std::hash::Hash for Inner {
47 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
48 core::mem::discriminant(self).hash(state);
49 match self {
50 Inner::Int(x) => x.hash(state),
51 Inner::Float(x) => x.to_bits().hash(state),
52 }
53 }
54}
55
56impl From<EpochTime> for Value {
57 fn from(value: EpochTime) -> Self {
58 match value.0 {
59 Inner::Int(int) => Self::tag(Tag::EPOCH_TIME, int),
60 Inner::Float(float) => Self::tag(Tag::EPOCH_TIME, float),
61 }
62 }
63}
64
65impl TryFrom<SystemTime> for EpochTime {
66 type Error = Error;
67
68 fn try_from(value: SystemTime) -> Result<Self> {
69 let time = value
70 .duration_since(SystemTime::UNIX_EPOCH)
71 .or(Err(Error::InvalidValue))?;
72
73 if time > Duration::from_secs(253402300799) {
74 Err(Error::InvalidValue)
75 } else if time.subsec_nanos() == 0 {
76 Ok(Self(Inner::Int(time.as_secs())))
77 } else {
78 Ok(Self(Inner::Float(time.as_secs_f64())))
79 }
80 }
81}
82
83fn from_int<T: TryInto<u64>>(value: T) -> Result<EpochTime> {
84 let value = value.try_into().or(Err(Error::InvalidValue))?;
85
86 if (0..=253402300799).contains(&value) {
87 Ok(EpochTime(Inner::Int(value)))
88 } else {
89 Err(Error::InvalidValue)
90 }
91}
92
93impl TryFrom<u8> for EpochTime {
94 type Error = Error;
95 fn try_from(value: u8) -> Result<Self> {
96 from_int(value)
97 }
98}
99impl TryFrom<u16> for EpochTime {
100 type Error = Error;
101 fn try_from(value: u16) -> Result<Self> {
102 from_int(value)
103 }
104}
105impl TryFrom<u32> for EpochTime {
106 type Error = Error;
107 fn try_from(value: u32) -> Result<Self> {
108 from_int(value)
109 }
110}
111impl TryFrom<u64> for EpochTime {
112 type Error = Error;
113 fn try_from(value: u64) -> Result<Self> {
114 from_int(value)
115 }
116}
117impl TryFrom<u128> for EpochTime {
118 type Error = Error;
119 fn try_from(value: u128) -> Result<Self> {
120 from_int(value)
121 }
122}
123impl TryFrom<usize> for EpochTime {
124 type Error = Error;
125 fn try_from(value: usize) -> Result<Self> {
126 from_int(value)
127 }
128}
129impl TryFrom<i8> for EpochTime {
130 type Error = Error;
131 fn try_from(value: i8) -> Result<Self> {
132 from_int(value)
133 }
134}
135impl TryFrom<i16> for EpochTime {
136 type Error = Error;
137 fn try_from(value: i16) -> Result<Self> {
138 from_int(value)
139 }
140}
141impl TryFrom<i32> for EpochTime {
142 type Error = Error;
143 fn try_from(value: i32) -> Result<Self> {
144 from_int(value)
145 }
146}
147impl TryFrom<i64> for EpochTime {
148 type Error = Error;
149 fn try_from(value: i64) -> Result<Self> {
150 from_int(value)
151 }
152}
153impl TryFrom<i128> for EpochTime {
154 type Error = Error;
155 fn try_from(value: i128) -> Result<Self> {
156 from_int(value)
157 }
158}
159impl TryFrom<isize> for EpochTime {
160 type Error = Error;
161 fn try_from(value: isize) -> Result<Self> {
162 from_int(value)
163 }
164}
165
166impl TryFrom<f32> for EpochTime {
167 type Error = Error;
168
169 fn try_from(value: f32) -> Result<Self> {
170 Self::try_from(f64::from(value))
171 }
172}
173impl TryFrom<f64> for EpochTime {
174 type Error = Error;
175
176 fn try_from(value: f64) -> Result<Self> {
177 if value.is_finite() && (0.0..=253402300799.0).contains(&value) {
178 Ok(Self(Inner::Float(value)))
179 } else {
180 Err(Error::InvalidValue)
181 }
182 }
183}