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