nt_time/serde_with/
iso_8601.rs1pub mod option;
46
47use serde::{Deserializer, Serializer, de::Error as _, ser::Error as _};
48use time::serde::iso8601;
49
50use crate::FileTime;
51
52#[allow(clippy::missing_errors_doc)]
53#[inline]
59pub fn serialize<S: Serializer>(ft: &FileTime, serializer: S) -> Result<S::Ok, S::Error> {
60 iso8601::serialize(&(*ft).try_into().map_err(S::Error::custom)?, serializer)
61}
62
63#[allow(clippy::missing_errors_doc)]
64#[inline]
70pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<FileTime, D::Error> {
71 FileTime::try_from(iso8601::deserialize(deserializer)?).map_err(D::Error::custom)
72}
73
74#[cfg(test)]
75mod tests {
76 use serde::{Deserialize, Serialize};
77 use serde_test::{Token, assert_de_tokens_error, assert_tokens};
78
79 use super::*;
80
81 #[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
82 struct Test {
83 #[serde(with = "crate::serde_with::iso_8601")]
84 time: FileTime,
85 }
86
87 #[test]
88 fn serde() {
89 assert_tokens(
90 &Test {
91 time: FileTime::NT_TIME_EPOCH,
92 },
93 &[
94 Token::Struct {
95 name: "Test",
96 len: 1,
97 },
98 Token::Str("time"),
99 Token::BorrowedStr("+001601-01-01T00:00:00.000000000Z"),
100 Token::StructEnd,
101 ],
102 );
103 assert_tokens(
104 &Test {
105 time: FileTime::UNIX_EPOCH,
106 },
107 &[
108 Token::Struct {
109 name: "Test",
110 len: 1,
111 },
112 Token::Str("time"),
113 Token::BorrowedStr("+001970-01-01T00:00:00.000000000Z"),
114 Token::StructEnd,
115 ],
116 );
117 }
118
119 #[cfg(feature = "large-dates")]
120 #[test]
121 fn serde_with_large_dates() {
122 assert_tokens(
123 &Test {
124 time: FileTime::MAX,
125 },
126 &[
127 Token::Struct {
128 name: "Test",
129 len: 1,
130 },
131 Token::Str("time"),
132 Token::BorrowedStr("+060056-05-28T05:36:10.955161500Z"),
133 Token::StructEnd,
134 ],
135 );
136 }
137
138 #[test]
139 fn deserialize_error() {
140 assert_de_tokens_error::<Test>(
141 &[
142 Token::Struct {
143 name: "Test",
144 len: 1,
145 },
146 Token::Str("time"),
147 Token::BorrowedStr("+001600-12-31T23:59:59.999999900Z"),
148 Token::StructEnd,
149 ],
150 "date and time is before `1601-01-01 00:00:00 UTC`",
151 );
152 }
153
154 #[cfg(not(feature = "large-dates"))]
155 #[test]
156 fn deserialize_error_without_large_dates() {
157 assert_de_tokens_error::<Test>(
158 &[
159 Token::Struct {
160 name: "Test",
161 len: 1,
162 },
163 Token::Str("time"),
164 Token::BorrowedStr("+010000-01-01T00:00:00.000000000Z"),
165 Token::StructEnd,
166 ],
167 "unexpected trailing characters; the end of input was expected",
168 );
169 }
170
171 #[cfg(feature = "large-dates")]
172 #[test]
173 fn deserialize_error_with_large_dates() {
174 assert_de_tokens_error::<Test>(
175 &[
176 Token::Struct {
177 name: "Test",
178 len: 1,
179 },
180 Token::Str("time"),
181 Token::BorrowedStr("+060056-05-28T05:36:10.955161600Z"),
182 Token::StructEnd,
183 ],
184 "date and time is after `+60056-05-28 05:36:10.955161500 UTC`",
185 );
186 }
187
188 #[test]
189 fn serialize_json() {
190 assert_eq!(
191 serde_json::to_string(&Test {
192 time: FileTime::NT_TIME_EPOCH
193 })
194 .unwrap(),
195 r#"{"time":"+001601-01-01T00:00:00.000000000Z"}"#
196 );
197 assert_eq!(
198 serde_json::to_string(&Test {
199 time: FileTime::UNIX_EPOCH
200 })
201 .unwrap(),
202 r#"{"time":"+001970-01-01T00:00:00.000000000Z"}"#
203 );
204 }
205
206 #[cfg(feature = "large-dates")]
207 #[test]
208 fn serialize_json_with_large_dates() {
209 assert_eq!(
210 serde_json::to_string(&Test {
211 time: FileTime::MAX
212 })
213 .unwrap(),
214 r#"{"time":"+060056-05-28T05:36:10.955161500Z"}"#
215 );
216 }
217
218 #[test]
219 fn deserialize_json() {
220 assert_eq!(
221 serde_json::from_str::<Test>(r#"{"time":"1601-01-01T00:00:00Z"}"#).unwrap(),
222 Test {
223 time: FileTime::NT_TIME_EPOCH
224 }
225 );
226 assert_eq!(
227 serde_json::from_str::<Test>(r#"{"time":"1970-01-01T00:00:00Z"}"#).unwrap(),
228 Test {
229 time: FileTime::UNIX_EPOCH
230 }
231 );
232 }
233
234 #[cfg(feature = "large-dates")]
235 #[test]
236 fn deserialize_json_with_large_dates() {
237 assert_eq!(
238 serde_json::from_str::<Test>(r#"{"time":"+060056-05-28T05:36:10.955161500Z"}"#)
239 .unwrap(),
240 Test {
241 time: FileTime::MAX
242 }
243 );
244 }
245}