1use std::{
2 fmt::{self, Display},
3 str::FromStr,
4};
5
6use serde::Deserialize;
7
8#[derive(Debug, thiserror::Error)]
9pub enum PrecisionError {
10 #[error("invalid precision repr: {0}")]
11 Invalid(String),
12}
13
14#[repr(i32)]
16#[derive(Debug, Copy, Clone, PartialEq, Eq, serde_repr::Serialize_repr)]
17pub enum Precision {
18 Millisecond = 0,
19 Microsecond,
20 Nanosecond,
21}
22
23impl Default for Precision {
24 fn default() -> Self {
25 Self::Millisecond
26 }
27}
28
29impl PartialEq<str> for Precision {
30 fn eq(&self, other: &str) -> bool {
31 self.as_str() == other
32 }
33}
34
35impl PartialEq<&str> for Precision {
36 fn eq(&self, other: &&str) -> bool {
37 self.as_str() == *other
38 }
39}
40
41impl Precision {
42 pub const fn as_str(&self) -> &'static str {
43 use Precision::*;
44 match self {
45 Millisecond => "ms",
46 Microsecond => "us",
47 Nanosecond => "ns",
48 }
49 }
50
51 pub const fn as_u8(&self) -> u8 {
52 match self {
53 Self::Millisecond => 0,
54 Self::Microsecond => 1,
55 Self::Nanosecond => 2,
56 }
57 }
58 pub const fn from_u8(precision: u8) -> Self {
59 match precision {
60 0 => Self::Millisecond,
61 1 => Self::Microsecond,
62 2 => Self::Nanosecond,
63 _ => panic!("precision integer only allow 0/1/2"),
64 }
65 }
66
67 pub const fn to_seconds_format(self) -> chrono::SecondsFormat {
68 match self {
69 Precision::Millisecond => chrono::SecondsFormat::Millis,
70 Precision::Microsecond => chrono::SecondsFormat::Micros,
71 Precision::Nanosecond => chrono::SecondsFormat::Nanos,
72 }
73 }
74}
75
76macro_rules! _impl_from {
77 ($($ty:ty) *) => {
78 $(impl From<$ty> for Precision {
79 fn from(v: $ty) -> Self {
80 Self::from_u8(v as _)
81 }
82 })*
83 }
84}
85
86_impl_from!(i8 i16 i32 i64 isize u8 u16 u32 u64 usize);
87
88impl Display for Precision {
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 write!(f, "{}", self.as_str())
91 }
92}
93
94impl FromStr for Precision {
95 type Err = PrecisionError;
96
97 fn from_str(s: &str) -> Result<Self, Self::Err> {
98 match s {
99 "ms" => Ok(Precision::Millisecond),
100 "us" => Ok(Precision::Microsecond),
101 "ns" => Ok(Precision::Nanosecond),
102 s => Err(PrecisionError::Invalid(s.to_string())),
103 }
104 }
105}
106
107impl<'de> Deserialize<'de> for Precision {
108 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
109 where
110 D: serde::Deserializer<'de>,
111 {
112 struct PrecisionVisitor;
113
114 impl<'de> serde::de::Visitor<'de> for PrecisionVisitor {
115 type Value = Precision;
116
117 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
118 formatter.write_str("expect integer 0/1/2 or string ms/us/ns")
119 }
120
121 fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E>
122 where
123 E: serde::de::Error,
124 {
125 self.visit_i32(v as _)
126 }
127 fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E>
128 where
129 E: serde::de::Error,
130 {
131 self.visit_i32(v as _)
132 }
133
134 fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
135 where
136 E: serde::de::Error,
137 {
138 Precision::try_from(v).map_err(<E as serde::de::Error>::custom)
139 }
140
141 fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
142 where
143 E: serde::de::Error,
144 {
145 self.visit_i32(v as _)
146 }
147
148 fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
149 where
150 E: serde::de::Error,
151 {
152 self.visit_i32(v as _)
153 }
154
155 fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E>
156 where
157 E: serde::de::Error,
158 {
159 self.visit_i32(v as _)
160 }
161
162 fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
163 where
164 E: serde::de::Error,
165 {
166 self.visit_i32(v as _)
167 }
168
169 fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
170 where
171 E: serde::de::Error,
172 {
173 self.visit_i32(v as _)
174 }
175
176 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
177 where
178 E: serde::de::Error,
179 {
180 Precision::from_str(v).map_err(<E as serde::de::Error>::custom)
181 }
182
183 fn visit_none<E>(self) -> Result<Self::Value, E>
184 where
185 E: serde::de::Error,
186 {
187 Ok(Precision::Millisecond)
188 }
189
190 fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
191 where
192 D: serde::Deserializer<'de>,
193 {
194 deserializer.deserialize_any(self)
195 }
196
197 fn visit_unit<E>(self) -> Result<Self::Value, E>
198 where
199 E: serde::de::Error,
200 {
201 Ok(Precision::Millisecond)
202 }
203 }
204
205 deserializer.deserialize_any(PrecisionVisitor)
206 }
207}
208
209#[cfg(test)]
210mod tests {
211 use serde::{
212 de::{
213 value::{I32Deserializer, StrDeserializer, UnitDeserializer},
214 IntoDeserializer,
215 },
216 Deserialize,
217 };
218
219 use super::Precision;
220
221 #[test]
222 fn de() {
223 type SD<'a> = StrDeserializer<'a, serde::de::value::Error>;
224 let precision = Precision::deserialize::<SD>("ms".into_deserializer()).unwrap();
225 assert_eq!(precision, Precision::Millisecond);
226 let precision = Precision::deserialize::<SD>("us".into_deserializer()).unwrap();
227 assert_eq!(precision, Precision::Microsecond);
228 let precision = Precision::deserialize::<SD>("ns".into_deserializer()).unwrap();
229 assert_eq!(precision, Precision::Nanosecond);
230
231 type I32D = I32Deserializer<serde::de::value::Error>;
232 let precision = Precision::deserialize::<I32D>(0.into_deserializer()).unwrap();
233 assert_eq!(precision, Precision::Millisecond);
234 let precision = Precision::deserialize::<I32D>(1.into_deserializer()).unwrap();
235 assert_eq!(precision, Precision::Microsecond);
236 let precision = Precision::deserialize::<I32D>(2.into_deserializer()).unwrap();
237 assert_eq!(precision, Precision::Nanosecond);
238
239 type UnitD = UnitDeserializer<serde::de::value::Error>;
240 let precision = Precision::deserialize::<UnitD>(().into_deserializer()).unwrap();
241 assert_eq!(precision, Precision::Millisecond);
242
243 let json = serde_json::to_string(&precision).unwrap();
244 assert_eq!(json, "0");
245 }
246}