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.duration_since(SystemTime::UNIX_EPOCH).or(Err(Error::Overflow))?;
70
71 if time > Duration::from_secs(253402300799) {
72 Err(Error::Overflow)
73 } else if time.subsec_nanos() == 0 {
74 Ok(Self(Inner::Int(time.as_secs())))
75 } else {
76 Ok(Self(Inner::Float(time.as_secs_f64())))
77 }
78 }
79}
80
81fn from_int<T: TryInto<u64>>(value: T) -> Result<EpochTime> {
82 let value = value.try_into().or(Err(Error::Overflow))?;
83
84 if (0..=253402300799).contains(&value) {
85 Ok(EpochTime(Inner::Int(value)))
86 } else {
87 Err(Error::Overflow)
88 }
89}
90
91impl TryFrom<u8> for EpochTime {
92 type Error = Error;
93 fn try_from(value: u8) -> Result<Self> {
94 from_int(value)
95 }
96}
97impl TryFrom<u16> for EpochTime {
98 type Error = Error;
99 fn try_from(value: u16) -> Result<Self> {
100 from_int(value)
101 }
102}
103impl TryFrom<u32> for EpochTime {
104 type Error = Error;
105 fn try_from(value: u32) -> Result<Self> {
106 from_int(value)
107 }
108}
109impl TryFrom<u64> for EpochTime {
110 type Error = Error;
111 fn try_from(value: u64) -> Result<Self> {
112 from_int(value)
113 }
114}
115impl TryFrom<u128> for EpochTime {
116 type Error = Error;
117 fn try_from(value: u128) -> Result<Self> {
118 from_int(value)
119 }
120}
121impl TryFrom<usize> for EpochTime {
122 type Error = Error;
123 fn try_from(value: usize) -> Result<Self> {
124 from_int(value)
125 }
126}
127impl TryFrom<i8> for EpochTime {
128 type Error = Error;
129 fn try_from(value: i8) -> Result<Self> {
130 from_int(value)
131 }
132}
133impl TryFrom<i16> for EpochTime {
134 type Error = Error;
135 fn try_from(value: i16) -> Result<Self> {
136 from_int(value)
137 }
138}
139impl TryFrom<i32> for EpochTime {
140 type Error = Error;
141 fn try_from(value: i32) -> Result<Self> {
142 from_int(value)
143 }
144}
145impl TryFrom<i64> for EpochTime {
146 type Error = Error;
147 fn try_from(value: i64) -> Result<Self> {
148 from_int(value)
149 }
150}
151impl TryFrom<i128> for EpochTime {
152 type Error = Error;
153 fn try_from(value: i128) -> Result<Self> {
154 from_int(value)
155 }
156}
157impl TryFrom<isize> for EpochTime {
158 type Error = Error;
159 fn try_from(value: isize) -> Result<Self> {
160 from_int(value)
161 }
162}
163
164impl TryFrom<f32> for EpochTime {
165 type Error = Error;
166
167 fn try_from(value: f32) -> Result<Self> {
168 Self::try_from(f64::from(value))
169 }
170}
171impl TryFrom<f64> for EpochTime {
172 type Error = Error;
173
174 fn try_from(value: f64) -> Result<Self> {
175 if value.is_finite() && (0.0..=253402300799.0).contains(&value) {
176 Ok(Self(Inner::Float(value)))
177 } else {
178 Err(Error::Overflow)
179 }
180 }
181}