nt_time/serde_with/unix_time/
microseconds.rs1pub mod option;
39
40use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
41
42use crate::FileTime;
43
44#[allow(clippy::missing_errors_doc)]
45#[inline]
51pub fn serialize<S: Serializer>(ft: &FileTime, serializer: S) -> Result<S::Ok, S::Error> {
52 ft.to_unix_time_micros().serialize(serializer)
53}
54
55#[allow(clippy::missing_errors_doc)]
56#[inline]
62pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<FileTime, D::Error> {
63 FileTime::from_unix_time_micros(<_>::deserialize(deserializer)?).map_err(D::Error::custom)
64}
65
66#[cfg(test)]
67mod tests {
68 use core::time::Duration;
69
70 use serde_test::{
71 Token, assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, assert_tokens,
72 };
73
74 use super::*;
75
76 #[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
77 struct Test {
78 #[serde(with = "crate::serde_with::unix_time::microseconds")]
79 time: FileTime,
80 }
81
82 #[test]
83 fn serde() {
84 assert_tokens(
85 &Test {
86 time: FileTime::NT_TIME_EPOCH,
87 },
88 &[
89 Token::Struct {
90 name: "Test",
91 len: 1,
92 },
93 Token::Str("time"),
94 Token::I64(-11_644_473_600_000_000),
95 Token::StructEnd,
96 ],
97 );
98 assert_tokens(
99 &Test {
100 time: FileTime::UNIX_EPOCH,
101 },
102 &[
103 Token::Struct {
104 name: "Test",
105 len: 1,
106 },
107 Token::Str("time"),
108 Token::I64(i64::default()),
109 Token::StructEnd,
110 ],
111 );
112 }
113
114 #[test]
115 fn serialize() {
116 assert_ser_tokens(
117 &Test {
118 time: FileTime::MAX,
119 },
120 &[
121 Token::Struct {
122 name: "Test",
123 len: 1,
124 },
125 Token::Str("time"),
126 Token::I64(1_833_029_933_770_955_161),
127 Token::StructEnd,
128 ],
129 );
130 }
131
132 #[test]
133 fn deserialize() {
134 assert_de_tokens(
135 &Test {
136 time: FileTime::MAX - Duration::from_nanos(500),
137 },
138 &[
139 Token::Struct {
140 name: "Test",
141 len: 1,
142 },
143 Token::Str("time"),
144 Token::I64(1_833_029_933_770_955_161),
145 Token::StructEnd,
146 ],
147 );
148 }
149
150 #[test]
151 fn deserialize_error() {
152 assert_de_tokens_error::<Test>(
153 &[
154 Token::Struct {
155 name: "Test",
156 len: 1,
157 },
158 Token::Str("time"),
159 Token::I64(-11_644_473_600_000_001),
160 Token::StructEnd,
161 ],
162 "date and time is before `1601-01-01 00:00:00 UTC`",
163 );
164 assert_de_tokens_error::<Test>(
165 &[
166 Token::Struct {
167 name: "Test",
168 len: 1,
169 },
170 Token::Str("time"),
171 Token::I64(1_833_029_933_770_955_162),
172 Token::StructEnd,
173 ],
174 "date and time is after `+60056-05-28 05:36:10.955161500 UTC`",
175 );
176 }
177
178 #[test]
179 fn serialize_json() {
180 assert_eq!(
181 serde_json::to_string(&Test {
182 time: FileTime::NT_TIME_EPOCH
183 })
184 .unwrap(),
185 r#"{"time":-11644473600000000}"#
186 );
187 assert_eq!(
188 serde_json::to_string(&Test {
189 time: FileTime::UNIX_EPOCH
190 })
191 .unwrap(),
192 r#"{"time":0}"#
193 );
194 assert_eq!(
195 serde_json::to_string(&Test {
196 time: FileTime::MAX
197 })
198 .unwrap(),
199 r#"{"time":1833029933770955161}"#
200 );
201 }
202
203 #[cfg(feature = "std")]
204 #[test_strategy::proptest]
205 fn serialize_json_roundtrip(
206 #[strategy(-11_644_473_600_000_000..=1_833_029_933_770_955_161_i64)] ts: i64,
207 ) {
208 use proptest::prop_assert_eq;
209
210 let ft = Test {
211 time: FileTime::from_unix_time_micros(ts).unwrap(),
212 };
213 let json = serde_json::to_string(&ft).unwrap();
214 prop_assert_eq!(json, format!(r#"{{"time":{ts}}}"#));
215 }
216
217 #[test]
218 fn deserialize_json() {
219 assert_eq!(
220 serde_json::from_str::<Test>(r#"{"time":-11644473600000000}"#).unwrap(),
221 Test {
222 time: FileTime::NT_TIME_EPOCH
223 }
224 );
225 assert_eq!(
226 serde_json::from_str::<Test>(r#"{"time":0}"#).unwrap(),
227 Test {
228 time: FileTime::UNIX_EPOCH
229 }
230 );
231 assert_eq!(
232 serde_json::from_str::<Test>(r#"{"time":1833029933770955161}"#).unwrap(),
233 Test {
234 time: FileTime::MAX - Duration::from_nanos(500)
235 }
236 );
237 }
238
239 #[cfg(feature = "std")]
240 #[test_strategy::proptest]
241 fn deserialize_json_roundtrip(
242 #[strategy(-11_644_473_600_000_000..=1_833_029_933_770_955_161_i64)] ts: i64,
243 ) {
244 use proptest::prop_assert_eq;
245
246 let json = format!(r#"{{"time":{ts}}}"#);
247 let ft = serde_json::from_str::<Test>(&json).unwrap();
248 prop_assert_eq!(ft.time, FileTime::from_unix_time_micros(ts).unwrap());
249 }
250}