/rust/registry/src/index.crates.io-1949cf8c6b5b557f/jiff-0.2.16/src/fmt/serde.rs
Line | Count | Source |
1 | | /*! |
2 | | This module provides helpers to use with [Serde]. |
3 | | |
4 | | Some helpers, like those for `Timestamp`, are exposed as modules meant |
5 | | to be used with Serde's [`with` attribute]. Others, like for `Span` and |
6 | | `SignedDuration`, only provide serialization helpers to be used with Serde's |
7 | | [`serialize_with` attribute]. |
8 | | |
9 | | # Module hierarchy |
10 | | |
11 | | The available helpers can be more quickly understood by looking at a fully |
12 | | rendered tree of this module's hierarchy. Only the leaves of the tree are |
13 | | usable with Serde's attributes. For each leaf, the full path is spelled out for |
14 | | easy copy & paste. |
15 | | |
16 | | * [`duration`] |
17 | | * [`friendly`](self::duration::friendly) |
18 | | * [`compact`](self::duration::friendly::compact) |
19 | | * [`jiff::fmt::serde::duration::friendly::compact::required`](self::duration::friendly::compact::required) |
20 | | * [`jiff::fmt::serde::duration::friendly::compact::optional`](self::duration::friendly::compact::optional) |
21 | | * [`span`] |
22 | | * [`friendly`](self::span::friendly) |
23 | | * [`compact`](self::span::friendly::compact) |
24 | | * [`jiff::fmt::serde::span::friendly::compact::required`](self::span::friendly::compact::required) |
25 | | * [`jiff::fmt::serde::span::friendly::compact::optional`](self::span::friendly::compact::optional) |
26 | | * [`timestamp`] |
27 | | * [`second`](self::timestamp::second) |
28 | | * [`jiff::fmt::serde::timestamp::second::required`](self::timestamp::second::required) |
29 | | * [`jiff::fmt::serde::timestamp::second::optional`](self::timestamp::second::optional) |
30 | | * [`millisecond`](self::timestamp::millisecond) |
31 | | * [`jiff::fmt::serde::timestamp::millisecond::required`](self::timestamp::millisecond::required) |
32 | | * [`jiff::fmt::serde::timestamp::millisecond::optional`](self::timestamp::millisecond::optional) |
33 | | * [`microsecond`](self::timestamp::millisecond) |
34 | | * [`jiff::fmt::serde::timestamp::microsecond::required`](self::timestamp::microsecond::required) |
35 | | * [`jiff::fmt::serde::timestamp::microsecond::optional`](self::timestamp::microsecond::optional) |
36 | | * [`nanosecond`](self::timestamp::millisecond) |
37 | | * [`jiff::fmt::serde::timestamp::nanosecond::required`](self::timestamp::nanosecond::required) |
38 | | * [`jiff::fmt::serde::timestamp::nanosecond::optional`](self::timestamp::nanosecond::optional) |
39 | | * [`tz`] |
40 | | * [`jiff::fmt::serde::tz::required`](self::tz::required) |
41 | | * [`jiff::fmt::serde::tz::optional`](self::tz::optional) |
42 | | * [`unsigned_duration`] |
43 | | * [`friendly`](self::unsigned_duration::friendly) |
44 | | * [`compact`](self::unsigned_duration::friendly::compact) |
45 | | * [`jiff::fmt::serde::unsigned_duration::friendly::compact::required`](self::unsigned_duration::friendly::compact::required) |
46 | | * [`jiff::fmt::serde::unsigned_duration::friendly::compact::optional`](self::unsigned_duration::friendly::compact::optional) |
47 | | * [`required`](self::unsigned_duration::required) |
48 | | * [`optional`](self::unsigned_duration::optional) |
49 | | |
50 | | # Example: timestamps as an integer |
51 | | |
52 | | This example shows how to deserialize an integer number of seconds since the |
53 | | Unix epoch into a [`Timestamp`](crate::Timestamp). And the reverse operation |
54 | | for serialization: |
55 | | |
56 | | ``` |
57 | | use jiff::Timestamp; |
58 | | |
59 | | #[derive(Debug, serde::Deserialize, serde::Serialize)] |
60 | | struct Record { |
61 | | #[serde(with = "jiff::fmt::serde::timestamp::second::required")] |
62 | | timestamp: Timestamp, |
63 | | } |
64 | | |
65 | | let json = r#"{"timestamp":1517644800}"#; |
66 | | let got: Record = serde_json::from_str(&json)?; |
67 | | assert_eq!(got.timestamp, Timestamp::from_second(1517644800)?); |
68 | | assert_eq!(serde_json::to_string(&got)?, json); |
69 | | |
70 | | # Ok::<(), Box<dyn std::error::Error>>(()) |
71 | | ``` |
72 | | |
73 | | # Example: optional timestamp support |
74 | | |
75 | | And this example shows how to use an `Option<Timestamp>` instead of a |
76 | | `Timestamp`. Note that in this case, we show how to roundtrip the number of |
77 | | **milliseconds** since the Unix epoch: |
78 | | |
79 | | ``` |
80 | | use jiff::Timestamp; |
81 | | |
82 | | #[derive(Debug, serde::Deserialize, serde::Serialize)] |
83 | | struct Record { |
84 | | #[serde(with = "jiff::fmt::serde::timestamp::millisecond::optional")] |
85 | | timestamp: Option<Timestamp>, |
86 | | } |
87 | | |
88 | | let json = r#"{"timestamp":1517644800123}"#; |
89 | | let got: Record = serde_json::from_str(&json)?; |
90 | | assert_eq!(got.timestamp, Some(Timestamp::from_millisecond(1517644800_123)?)); |
91 | | assert_eq!(serde_json::to_string(&got)?, json); |
92 | | |
93 | | # Ok::<(), Box<dyn std::error::Error>>(()) |
94 | | ``` |
95 | | |
96 | | # Example: the "friendly" duration format |
97 | | |
98 | | The [`Span`](crate::Span) and [`SignedDuration`](crate::SignedDuration) types |
99 | | in this crate both implement Serde's `Serialize` and `Deserialize` traits. For |
100 | | `Serialize`, they both use the [ISO 8601 Temporal duration format], but for |
101 | | `Deserialize`, they both support the ISO 8601 Temporal duration format and |
102 | | the ["friendly" duration format] simultaneously. In order to serialize either |
103 | | type in the "friendly" format, you can either define your own serialization |
104 | | functions or use one of the convenience routines provided by this module. For |
105 | | example: |
106 | | |
107 | | ``` |
108 | | use jiff::{ToSpan, Span}; |
109 | | |
110 | | #[derive(Debug, serde::Deserialize, serde::Serialize)] |
111 | | struct Record { |
112 | | #[serde( |
113 | | serialize_with = "jiff::fmt::serde::span::friendly::compact::required" |
114 | | )] |
115 | | span: Span, |
116 | | } |
117 | | |
118 | | let json = r#"{"span":"1 year 2 months 36 hours 1100ms"}"#; |
119 | | let got: Record = serde_json::from_str(&json)?; |
120 | | assert_eq!( |
121 | | got.span, |
122 | | 1.year().months(2).hours(36).milliseconds(1100).fieldwise(), |
123 | | ); |
124 | | |
125 | | let expected = r#"{"span":"1y 2mo 36h 1100ms"}"#; |
126 | | assert_eq!(serde_json::to_string(&got).unwrap(), expected); |
127 | | |
128 | | # Ok::<(), Box<dyn std::error::Error>>(()) |
129 | | ``` |
130 | | |
131 | | [Serde]: https://serde.rs/ |
132 | | [`with` attribute]: https://serde.rs/field-attrs.html#with |
133 | | [`serialize_with` attribute]: https://serde.rs/field-attrs.html#serialize_with |
134 | | [ISO 8601 Temporal duration format]: crate::fmt::temporal |
135 | | ["friendly" duration format]: crate::fmt::friendly |
136 | | */ |
137 | | |
138 | | /// Convenience routines for serializing |
139 | | /// [`SignedDuration`](crate::SignedDuration) values. |
140 | | /// |
141 | | /// These convenience routines exist because the `Serialize` implementation for |
142 | | /// `SignedDuration` always uses the ISO 8601 duration format. These routines |
143 | | /// provide a way to use the "[friendly](crate::fmt::friendly)" format. |
144 | | /// |
145 | | /// Only serialization routines are provided because a `SignedDuration`'s |
146 | | /// `Deserialize` implementation automatically handles both the ISO 8601 |
147 | | /// duration format and the "friendly" format. |
148 | | /// |
149 | | /// # Advice |
150 | | /// |
151 | | /// The `Serialize` implementation uses ISO 8601 because it is a widely |
152 | | /// accepted interchange format for communicating durations. If you need to |
153 | | /// inter-operate with other systems, it is almost certainly the correct |
154 | | /// choice. |
155 | | /// |
156 | | /// The "friendly" format does not adhere to any universal specified format. |
157 | | /// However, it is perhaps easier to read. Beyond that, its utility for |
158 | | /// `SignedDuration` is somewhat less compared to [`Span`](crate::Span), since |
159 | | /// for `Span`, the friendly format preserves all components of the `Span` |
160 | | /// faithfully. But a `SignedDuration` is just a 96-bit integer of nanoseconds, |
161 | | /// so there are no individual components to preserve. Still, even with a |
162 | | /// `SignedDuration`, you might prefer the friendly format. |
163 | | /// |
164 | | /// # Available routines |
165 | | /// |
166 | | /// A [`SpanPrinter`](crate::fmt::friendly::SpanPrinter) has a lot of different |
167 | | /// configuration options. The convenience routines provided by this module |
168 | | /// only cover a small space of those options since it isn't feasible to |
169 | | /// provide a convenience routine for every possible set of configuration |
170 | | /// options. |
171 | | /// |
172 | | /// While more convenience routines could be added (please file an issue), only |
173 | | /// the most common or popular such routines can be feasibly added. So in the |
174 | | /// case where a convenience routine isn't available for the configuration you |
175 | | /// want, you can very easily define your own `serialize_with` routine. |
176 | | /// |
177 | | /// The recommended approach is to define a function and a type that |
178 | | /// implements the `std::fmt::Display` trait. This way, if a serializer can |
179 | | /// efficiently support `Display` implementations, then an allocation can be |
180 | | /// avoided. |
181 | | /// |
182 | | /// ``` |
183 | | /// use jiff::SignedDuration; |
184 | | /// |
185 | | /// #[derive(Debug, serde::Deserialize, serde::Serialize)] |
186 | | /// struct Data { |
187 | | /// #[serde(serialize_with = "custom_friendly")] |
188 | | /// duration: SignedDuration, |
189 | | /// } |
190 | | /// |
191 | | /// let json = r#"{"duration": "36 hours 1100ms"}"#; |
192 | | /// let got: Data = serde_json::from_str(&json).unwrap(); |
193 | | /// assert_eq!(got.duration, SignedDuration::new(36 * 60 * 60 + 1, 100_000_000)); |
194 | | /// |
195 | | /// let expected = r#"{"duration":"36:00:01.100"}"#; |
196 | | /// assert_eq!(serde_json::to_string(&got).unwrap(), expected); |
197 | | /// |
198 | | /// fn custom_friendly<S: serde::Serializer>( |
199 | | /// duration: &SignedDuration, |
200 | | /// se: S, |
201 | | /// ) -> Result<S::Ok, S::Error> { |
202 | | /// struct Custom<'a>(&'a SignedDuration); |
203 | | /// |
204 | | /// impl<'a> std::fmt::Display for Custom<'a> { |
205 | | /// fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
206 | | /// use jiff::fmt::{friendly::SpanPrinter, StdFmtWrite}; |
207 | | /// |
208 | | /// static PRINTER: SpanPrinter = SpanPrinter::new() |
209 | | /// .hours_minutes_seconds(true) |
210 | | /// .precision(Some(3)); |
211 | | /// |
212 | | /// PRINTER |
213 | | /// .print_duration(self.0, StdFmtWrite(f)) |
214 | | /// .map_err(|_| core::fmt::Error) |
215 | | /// } |
216 | | /// } |
217 | | /// |
218 | | /// se.collect_str(&Custom(duration)) |
219 | | /// } |
220 | | /// ``` |
221 | | /// |
222 | | /// Recall from above that you only need a custom serialization routine |
223 | | /// for this. Namely, deserialization automatically supports parsing all |
224 | | /// configuration options for serialization unconditionally. |
225 | | pub mod duration { |
226 | | /// Serialize a `SignedDuration` in the [`friendly`](crate::fmt::friendly) duration |
227 | | /// format. |
228 | | pub mod friendly { |
229 | | /// Serialize a `SignedDuration` in the |
230 | | /// [`friendly`](crate::fmt::friendly) duration format using compact |
231 | | /// designators. |
232 | | pub mod compact { |
233 | | use crate::fmt::{friendly, StdFmtWrite}; |
234 | | |
235 | | struct CompactDuration<'a>(&'a crate::SignedDuration); |
236 | | |
237 | | impl<'a> core::fmt::Display for CompactDuration<'a> { |
238 | 0 | fn fmt( |
239 | 0 | &self, |
240 | 0 | f: &mut core::fmt::Formatter, |
241 | 0 | ) -> core::fmt::Result { |
242 | | static PRINTER: friendly::SpanPrinter = |
243 | | friendly::SpanPrinter::new() |
244 | | .designator(friendly::Designator::Compact); |
245 | 0 | PRINTER |
246 | 0 | .print_duration(self.0, StdFmtWrite(f)) |
247 | 0 | .map_err(|_| core::fmt::Error) |
248 | 0 | } |
249 | | } |
250 | | |
251 | | /// Serialize a required `SignedDuration` in the [`friendly`] |
252 | | /// duration format using compact designators. |
253 | | #[inline] |
254 | 0 | pub fn required<S: serde_core::Serializer>( |
255 | 0 | duration: &crate::SignedDuration, |
256 | 0 | se: S, |
257 | 0 | ) -> Result<S::Ok, S::Error> { |
258 | 0 | se.collect_str(&CompactDuration(duration)) |
259 | 0 | } |
260 | | |
261 | | /// Serialize an optional `SignedDuration` in the [`friendly`] |
262 | | /// duration format using compact designators. |
263 | | #[inline] |
264 | 0 | pub fn optional<S: serde_core::Serializer>( |
265 | 0 | duration: &Option<crate::SignedDuration>, |
266 | 0 | se: S, |
267 | 0 | ) -> Result<S::Ok, S::Error> { |
268 | 0 | match *duration { |
269 | 0 | None => se.serialize_none(), |
270 | 0 | Some(ref duration) => required(duration, se), |
271 | | } |
272 | 0 | } |
273 | | } |
274 | | } |
275 | | } |
276 | | |
277 | | /// Convenience routines for serializing [`Span`](crate::Span) values. |
278 | | /// |
279 | | /// These convenience routines exist because the `Serialize` implementation for |
280 | | /// `Span` always uses the ISO 8601 duration format. These routines provide a |
281 | | /// way to use the "[friendly](crate::fmt::friendly)" format. |
282 | | /// |
283 | | /// Only serialization routines are provided because a `Span`'s `Deserialize` |
284 | | /// implementation automatically handles both the ISO 8601 duration format and |
285 | | /// the "friendly" format. |
286 | | /// |
287 | | /// # Advice |
288 | | /// |
289 | | /// The `Serialize` implementation uses ISO 8601 because it is a widely |
290 | | /// accepted interchange format for communicating durations. If you need to |
291 | | /// inter-operate with other systems, it is almost certainly the correct choice. |
292 | | /// |
293 | | /// The "friendly" format does not adhere to any universal specified format. |
294 | | /// However, it is perhaps easier to read, and crucially, unambiguously |
295 | | /// represents all components of a `Span` faithfully. (In contrast, the ISO |
296 | | /// 8601 format always normalizes sub-second durations into fractional seconds, |
297 | | /// which means durations like `1100ms` and `1s100ms` are always considered |
298 | | /// equivalent.) |
299 | | /// |
300 | | /// # Available routines |
301 | | /// |
302 | | /// A [`SpanPrinter`](crate::fmt::friendly::SpanPrinter) has a lot of different |
303 | | /// configuration options. The convenience routines provided by this module |
304 | | /// only cover a small space of those options since it isn't feasible to |
305 | | /// provide a convenience routine for every possible set of configuration |
306 | | /// options. |
307 | | /// |
308 | | /// While more convenience routines could be added (please file an issue), only |
309 | | /// the most common or popular such routines can be feasibly added. So in the |
310 | | /// case where a convenience routine isn't available for the configuration you |
311 | | /// want, you can very easily define your own `serialize_with` routine. |
312 | | /// |
313 | | /// The recommended approach is to define a function and a type that |
314 | | /// implements the `std::fmt::Display` trait. This way, if a serializer can |
315 | | /// efficiently support `Display` implementations, then an allocation can be |
316 | | /// avoided. |
317 | | /// |
318 | | /// ``` |
319 | | /// use jiff::{Span, ToSpan}; |
320 | | /// |
321 | | /// #[derive(Debug, serde::Deserialize, serde::Serialize)] |
322 | | /// struct Data { |
323 | | /// #[serde(serialize_with = "custom_friendly")] |
324 | | /// duration: Span, |
325 | | /// } |
326 | | /// |
327 | | /// let json = r#"{"duration": "1 year 2 months 36 hours 1100ms"}"#; |
328 | | /// let got: Data = serde_json::from_str(&json).unwrap(); |
329 | | /// assert_eq!( |
330 | | /// got.duration, |
331 | | /// 1.year().months(2).hours(36).milliseconds(1100).fieldwise(), |
332 | | /// ); |
333 | | /// |
334 | | /// let expected = r#"{"duration":"1 year, 2 months, 36:00:01.100"}"#; |
335 | | /// assert_eq!(serde_json::to_string(&got).unwrap(), expected); |
336 | | /// |
337 | | /// fn custom_friendly<S: serde::Serializer>( |
338 | | /// span: &Span, |
339 | | /// se: S, |
340 | | /// ) -> Result<S::Ok, S::Error> { |
341 | | /// struct Custom<'a>(&'a Span); |
342 | | /// |
343 | | /// impl<'a> std::fmt::Display for Custom<'a> { |
344 | | /// fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
345 | | /// use jiff::fmt::{ |
346 | | /// friendly::{Designator, Spacing, SpanPrinter}, |
347 | | /// StdFmtWrite, |
348 | | /// }; |
349 | | /// |
350 | | /// static PRINTER: SpanPrinter = SpanPrinter::new() |
351 | | /// .designator(Designator::Verbose) |
352 | | /// .comma_after_designator(true) |
353 | | /// .spacing(Spacing::BetweenUnitsAndDesignators) |
354 | | /// .hours_minutes_seconds(true) |
355 | | /// .precision(Some(3)); |
356 | | /// |
357 | | /// PRINTER |
358 | | /// .print_span(self.0, StdFmtWrite(f)) |
359 | | /// .map_err(|_| core::fmt::Error) |
360 | | /// } |
361 | | /// } |
362 | | /// |
363 | | /// se.collect_str(&Custom(span)) |
364 | | /// } |
365 | | /// ``` |
366 | | /// |
367 | | /// Recall from above that you only need a custom serialization routine |
368 | | /// for this. Namely, deserialization automatically supports parsing all |
369 | | /// configuration options for serialization unconditionally. |
370 | | pub mod span { |
371 | | /// Serialize a `Span` in the [`friendly`](crate::fmt::friendly) duration |
372 | | /// format. |
373 | | pub mod friendly { |
374 | | /// Serialize a `Span` in the [`friendly`](crate::fmt::friendly) |
375 | | /// duration format using compact designators. |
376 | | pub mod compact { |
377 | | use crate::fmt::{friendly, StdFmtWrite}; |
378 | | |
379 | | struct CompactSpan<'a>(&'a crate::Span); |
380 | | |
381 | | impl<'a> core::fmt::Display for CompactSpan<'a> { |
382 | 0 | fn fmt( |
383 | 0 | &self, |
384 | 0 | f: &mut core::fmt::Formatter, |
385 | 0 | ) -> core::fmt::Result { |
386 | | static PRINTER: friendly::SpanPrinter = |
387 | | friendly::SpanPrinter::new() |
388 | | .designator(friendly::Designator::Compact); |
389 | 0 | PRINTER |
390 | 0 | .print_span(self.0, StdFmtWrite(f)) |
391 | 0 | .map_err(|_| core::fmt::Error) |
392 | 0 | } |
393 | | } |
394 | | |
395 | | /// Serialize a required `Span` in the [`friendly`] duration format |
396 | | /// using compact designators. |
397 | | #[inline] |
398 | 0 | pub fn required<S: serde_core::Serializer>( |
399 | 0 | span: &crate::Span, |
400 | 0 | se: S, |
401 | 0 | ) -> Result<S::Ok, S::Error> { |
402 | 0 | se.collect_str(&CompactSpan(span)) |
403 | 0 | } |
404 | | |
405 | | /// Serialize an optional `Span` in the [`friendly`] duration |
406 | | /// format using compact designators. |
407 | | #[inline] |
408 | 0 | pub fn optional<S: serde_core::Serializer>( |
409 | 0 | span: &Option<crate::Span>, |
410 | 0 | se: S, |
411 | 0 | ) -> Result<S::Ok, S::Error> { |
412 | 0 | match *span { |
413 | 0 | None => se.serialize_none(), |
414 | 0 | Some(ref span) => required(span, se), |
415 | | } |
416 | 0 | } |
417 | | } |
418 | | } |
419 | | } |
420 | | |
421 | | /// Convenience routines for (de)serializing [`Timestamp`](crate::Timestamp) as |
422 | | /// raw integer values. |
423 | | /// |
424 | | /// At present, the helpers are limited to serializing and deserializing |
425 | | /// [`Timestamp`](crate::Timestamp) values as an integer number of seconds, |
426 | | /// milliseconds, microseconds or nanoseconds. |
427 | | /// |
428 | | /// # Advice |
429 | | /// |
430 | | /// In general, these helpers should only be used to interface with "legacy" |
431 | | /// APIs that transmit times as integer number of seconds (or milliseconds or |
432 | | /// whatever). If you're designing a new API and need to transmit instants in |
433 | | /// time that don't care about time zones, then you should use `Timestamp` |
434 | | /// directly. It will automatically use RFC 3339. (And if you do want to |
435 | | /// include the time zone, then using [`Zoned`](crate::Zoned) directly will |
436 | | /// work as well by utilizing the RFC 9557 extension to RFC 3339.) |
437 | | pub mod timestamp { |
438 | | use serde_core::de; |
439 | | |
440 | | /// A generic visitor for `Option<Timestamp>`. |
441 | | struct OptionalVisitor<V>(V); |
442 | | |
443 | | impl<'de, V: de::Visitor<'de, Value = crate::Timestamp>> de::Visitor<'de> |
444 | | for OptionalVisitor<V> |
445 | | { |
446 | | type Value = Option<crate::Timestamp>; |
447 | | |
448 | 0 | fn expecting( |
449 | 0 | &self, |
450 | 0 | f: &mut core::fmt::Formatter, |
451 | 0 | ) -> core::fmt::Result { |
452 | 0 | f.write_str( |
453 | 0 | "an integer number of seconds from the Unix epoch or `None`", |
454 | | ) |
455 | 0 | } |
456 | | |
457 | | #[inline] |
458 | 0 | fn visit_some<D: de::Deserializer<'de>>( |
459 | 0 | self, |
460 | 0 | de: D, |
461 | 0 | ) -> Result<Option<crate::Timestamp>, D::Error> { |
462 | 0 | de.deserialize_i64(self.0).map(Some) |
463 | 0 | } |
464 | | |
465 | | #[inline] |
466 | 0 | fn visit_none<E: de::Error>( |
467 | 0 | self, |
468 | 0 | ) -> Result<Option<crate::Timestamp>, E> { |
469 | 0 | Ok(None) |
470 | 0 | } |
471 | | } |
472 | | |
473 | | /// (De)serialize an integer number of seconds from the Unix epoch. |
474 | | pub mod second { |
475 | | use serde_core::de; |
476 | | |
477 | | struct Visitor; |
478 | | |
479 | | impl<'de> de::Visitor<'de> for Visitor { |
480 | | type Value = crate::Timestamp; |
481 | | |
482 | 0 | fn expecting( |
483 | 0 | &self, |
484 | 0 | f: &mut core::fmt::Formatter, |
485 | 0 | ) -> core::fmt::Result { |
486 | 0 | f.write_str("an integer number of seconds from the Unix epoch") |
487 | 0 | } |
488 | | |
489 | | #[inline] |
490 | 0 | fn visit_i8<E: de::Error>( |
491 | 0 | self, |
492 | 0 | v: i8, |
493 | 0 | ) -> Result<crate::Timestamp, E> { |
494 | 0 | self.visit_i64(i64::from(v)) |
495 | 0 | } |
496 | | |
497 | | #[inline] |
498 | 0 | fn visit_u8<E: de::Error>( |
499 | 0 | self, |
500 | 0 | v: u8, |
501 | 0 | ) -> Result<crate::Timestamp, E> { |
502 | 0 | self.visit_i64(i64::from(v)) |
503 | 0 | } |
504 | | |
505 | | #[inline] |
506 | 0 | fn visit_i16<E: de::Error>( |
507 | 0 | self, |
508 | 0 | v: i16, |
509 | 0 | ) -> Result<crate::Timestamp, E> { |
510 | 0 | self.visit_i64(i64::from(v)) |
511 | 0 | } |
512 | | |
513 | | #[inline] |
514 | 0 | fn visit_u16<E: de::Error>( |
515 | 0 | self, |
516 | 0 | v: u16, |
517 | 0 | ) -> Result<crate::Timestamp, E> { |
518 | 0 | self.visit_i64(i64::from(v)) |
519 | 0 | } |
520 | | |
521 | | #[inline] |
522 | 0 | fn visit_i32<E: de::Error>( |
523 | 0 | self, |
524 | 0 | v: i32, |
525 | 0 | ) -> Result<crate::Timestamp, E> { |
526 | 0 | self.visit_i64(i64::from(v)) |
527 | 0 | } |
528 | | |
529 | | #[inline] |
530 | 0 | fn visit_u32<E: de::Error>( |
531 | 0 | self, |
532 | 0 | v: u32, |
533 | 0 | ) -> Result<crate::Timestamp, E> { |
534 | 0 | self.visit_i64(i64::from(v)) |
535 | 0 | } |
536 | | |
537 | | #[inline] |
538 | 0 | fn visit_i64<E: de::Error>( |
539 | 0 | self, |
540 | 0 | v: i64, |
541 | 0 | ) -> Result<crate::Timestamp, E> { |
542 | 0 | crate::Timestamp::from_second(v).map_err(de::Error::custom) |
543 | 0 | } |
544 | | |
545 | | #[inline] |
546 | 0 | fn visit_u64<E: de::Error>( |
547 | 0 | self, |
548 | 0 | v: u64, |
549 | 0 | ) -> Result<crate::Timestamp, E> { |
550 | 0 | let v = i64::try_from(v).map_err(|_| { |
551 | 0 | de::Error::custom(format_args!( |
552 | 0 | "got unsigned integer {v} seconds, \ |
553 | 0 | which is too big to fit in a Jiff `Timestamp`", |
554 | | )) |
555 | 0 | })?; |
556 | 0 | self.visit_i64(v) |
557 | 0 | } |
558 | | |
559 | | #[inline] |
560 | 0 | fn visit_i128<E: de::Error>( |
561 | 0 | self, |
562 | 0 | v: i128, |
563 | 0 | ) -> Result<crate::Timestamp, E> { |
564 | 0 | let v = i64::try_from(v).map_err(|_| { |
565 | 0 | de::Error::custom(format_args!( |
566 | 0 | "got signed integer {v} seconds, \ |
567 | 0 | which is too big to fit in a Jiff `Timestamp`", |
568 | | )) |
569 | 0 | })?; |
570 | 0 | self.visit_i64(v) |
571 | 0 | } |
572 | | |
573 | | #[inline] |
574 | 0 | fn visit_u128<E: de::Error>( |
575 | 0 | self, |
576 | 0 | v: u128, |
577 | 0 | ) -> Result<crate::Timestamp, E> { |
578 | 0 | let v = i64::try_from(v).map_err(|_| { |
579 | 0 | de::Error::custom(format_args!( |
580 | 0 | "got unsigned integer {v} seconds, \ |
581 | 0 | which is too big to fit in a Jiff `Timestamp`", |
582 | | )) |
583 | 0 | })?; |
584 | 0 | self.visit_i64(v) |
585 | 0 | } |
586 | | } |
587 | | |
588 | | /// (De)serialize a required integer number of seconds from the Unix |
589 | | /// epoch. |
590 | | pub mod required { |
591 | | /// Serialize a required integer number of seconds since the Unix |
592 | | /// epoch. |
593 | | #[inline] |
594 | 0 | pub fn serialize<S: serde_core::Serializer>( |
595 | 0 | timestamp: &crate::Timestamp, |
596 | 0 | se: S, |
597 | 0 | ) -> Result<S::Ok, S::Error> { |
598 | 0 | se.serialize_i64(timestamp.as_second()) |
599 | 0 | } |
600 | | |
601 | | /// Deserialize a required integer number of seconds since the |
602 | | /// Unix epoch. |
603 | | #[inline] |
604 | 0 | pub fn deserialize<'de, D: serde_core::Deserializer<'de>>( |
605 | 0 | de: D, |
606 | 0 | ) -> Result<crate::Timestamp, D::Error> { |
607 | 0 | de.deserialize_i64(super::Visitor) |
608 | 0 | } |
609 | | } |
610 | | |
611 | | /// (De)serialize an optional integer number of seconds from the Unix |
612 | | /// epoch. |
613 | | pub mod optional { |
614 | | /// Serialize an optional integer number of seconds since the Unix |
615 | | /// epoch. |
616 | | #[inline] |
617 | 0 | pub fn serialize<S: serde_core::Serializer>( |
618 | 0 | timestamp: &Option<crate::Timestamp>, |
619 | 0 | se: S, |
620 | 0 | ) -> Result<S::Ok, S::Error> { |
621 | 0 | match *timestamp { |
622 | 0 | None => se.serialize_none(), |
623 | 0 | Some(ref ts) => super::required::serialize(ts, se), |
624 | | } |
625 | 0 | } |
626 | | |
627 | | /// Deserialize an optional integer number of seconds since the |
628 | | /// Unix epoch. |
629 | | #[inline] |
630 | 0 | pub fn deserialize<'de, D: serde_core::Deserializer<'de>>( |
631 | 0 | de: D, |
632 | 0 | ) -> Result<Option<crate::Timestamp>, D::Error> { |
633 | 0 | de.deserialize_option(super::super::OptionalVisitor( |
634 | 0 | super::Visitor, |
635 | 0 | )) |
636 | 0 | } |
637 | | } |
638 | | } |
639 | | |
640 | | /// (De)serialize an integer number of milliseconds from the Unix epoch. |
641 | | pub mod millisecond { |
642 | | use serde_core::de; |
643 | | |
644 | | struct Visitor; |
645 | | |
646 | | impl<'de> de::Visitor<'de> for Visitor { |
647 | | type Value = crate::Timestamp; |
648 | | |
649 | 0 | fn expecting( |
650 | 0 | &self, |
651 | 0 | f: &mut core::fmt::Formatter, |
652 | 0 | ) -> core::fmt::Result { |
653 | 0 | f.write_str( |
654 | 0 | "an integer number of milliseconds from the Unix epoch", |
655 | | ) |
656 | 0 | } |
657 | | |
658 | | #[inline] |
659 | 0 | fn visit_i8<E: de::Error>( |
660 | 0 | self, |
661 | 0 | v: i8, |
662 | 0 | ) -> Result<crate::Timestamp, E> { |
663 | 0 | self.visit_i64(i64::from(v)) |
664 | 0 | } |
665 | | |
666 | | #[inline] |
667 | 0 | fn visit_u8<E: de::Error>( |
668 | 0 | self, |
669 | 0 | v: u8, |
670 | 0 | ) -> Result<crate::Timestamp, E> { |
671 | 0 | self.visit_i64(i64::from(v)) |
672 | 0 | } |
673 | | |
674 | | #[inline] |
675 | 0 | fn visit_i16<E: de::Error>( |
676 | 0 | self, |
677 | 0 | v: i16, |
678 | 0 | ) -> Result<crate::Timestamp, E> { |
679 | 0 | self.visit_i64(i64::from(v)) |
680 | 0 | } |
681 | | |
682 | | #[inline] |
683 | 0 | fn visit_u16<E: de::Error>( |
684 | 0 | self, |
685 | 0 | v: u16, |
686 | 0 | ) -> Result<crate::Timestamp, E> { |
687 | 0 | self.visit_i64(i64::from(v)) |
688 | 0 | } |
689 | | |
690 | | #[inline] |
691 | 0 | fn visit_i32<E: de::Error>( |
692 | 0 | self, |
693 | 0 | v: i32, |
694 | 0 | ) -> Result<crate::Timestamp, E> { |
695 | 0 | self.visit_i64(i64::from(v)) |
696 | 0 | } |
697 | | |
698 | | #[inline] |
699 | 0 | fn visit_u32<E: de::Error>( |
700 | 0 | self, |
701 | 0 | v: u32, |
702 | 0 | ) -> Result<crate::Timestamp, E> { |
703 | 0 | self.visit_i64(i64::from(v)) |
704 | 0 | } |
705 | | |
706 | | #[inline] |
707 | 0 | fn visit_i64<E: de::Error>( |
708 | 0 | self, |
709 | 0 | v: i64, |
710 | 0 | ) -> Result<crate::Timestamp, E> { |
711 | 0 | crate::Timestamp::from_millisecond(v) |
712 | 0 | .map_err(de::Error::custom) |
713 | 0 | } |
714 | | |
715 | | #[inline] |
716 | 0 | fn visit_u64<E: de::Error>( |
717 | 0 | self, |
718 | 0 | v: u64, |
719 | 0 | ) -> Result<crate::Timestamp, E> { |
720 | 0 | let v = i64::try_from(v).map_err(|_| { |
721 | 0 | de::Error::custom(format_args!( |
722 | 0 | "got unsigned integer {v} milliseconds, \ |
723 | 0 | which is too big to fit in a Jiff `Timestamp`", |
724 | | )) |
725 | 0 | })?; |
726 | 0 | self.visit_i64(v) |
727 | 0 | } |
728 | | |
729 | | #[inline] |
730 | 0 | fn visit_i128<E: de::Error>( |
731 | 0 | self, |
732 | 0 | v: i128, |
733 | 0 | ) -> Result<crate::Timestamp, E> { |
734 | 0 | let v = i64::try_from(v).map_err(|_| { |
735 | 0 | de::Error::custom(format_args!( |
736 | 0 | "got signed integer {v} milliseconds, \ |
737 | 0 | which is too big to fit in a Jiff `Timestamp`", |
738 | | )) |
739 | 0 | })?; |
740 | 0 | self.visit_i64(v) |
741 | 0 | } |
742 | | |
743 | | #[inline] |
744 | 0 | fn visit_u128<E: de::Error>( |
745 | 0 | self, |
746 | 0 | v: u128, |
747 | 0 | ) -> Result<crate::Timestamp, E> { |
748 | 0 | let v = i64::try_from(v).map_err(|_| { |
749 | 0 | de::Error::custom(format_args!( |
750 | 0 | "got unsigned integer {v} milliseconds, \ |
751 | 0 | which is too big to fit in a Jiff `Timestamp`", |
752 | | )) |
753 | 0 | })?; |
754 | 0 | self.visit_i64(v) |
755 | 0 | } |
756 | | } |
757 | | |
758 | | /// (De)serialize a required integer number of milliseconds from the |
759 | | /// Unix epoch. |
760 | | pub mod required { |
761 | | /// Serialize a required integer number of milliseconds since the |
762 | | /// Unix epoch. |
763 | | #[inline] |
764 | 0 | pub fn serialize<S: serde_core::Serializer>( |
765 | 0 | timestamp: &crate::Timestamp, |
766 | 0 | se: S, |
767 | 0 | ) -> Result<S::Ok, S::Error> { |
768 | 0 | se.serialize_i64(timestamp.as_millisecond()) |
769 | 0 | } |
770 | | |
771 | | /// Deserialize a required integer number of milliseconds since the |
772 | | /// Unix epoch. |
773 | | #[inline] |
774 | 0 | pub fn deserialize<'de, D: serde_core::Deserializer<'de>>( |
775 | 0 | de: D, |
776 | 0 | ) -> Result<crate::Timestamp, D::Error> { |
777 | 0 | de.deserialize_i64(super::Visitor) |
778 | 0 | } |
779 | | } |
780 | | |
781 | | /// (De)serialize an optional integer number of milliseconds from the |
782 | | /// Unix epoch. |
783 | | pub mod optional { |
784 | | /// Serialize an optional integer number of milliseconds since the |
785 | | /// Unix epoch. |
786 | | #[inline] |
787 | 0 | pub fn serialize<S: serde_core::Serializer>( |
788 | 0 | timestamp: &Option<crate::Timestamp>, |
789 | 0 | se: S, |
790 | 0 | ) -> Result<S::Ok, S::Error> { |
791 | 0 | match *timestamp { |
792 | 0 | None => se.serialize_none(), |
793 | 0 | Some(ref ts) => super::required::serialize(ts, se), |
794 | | } |
795 | 0 | } |
796 | | |
797 | | /// Deserialize an optional integer number of milliseconds since |
798 | | /// the Unix epoch. |
799 | | #[inline] |
800 | 0 | pub fn deserialize<'de, D: serde_core::Deserializer<'de>>( |
801 | 0 | de: D, |
802 | 0 | ) -> Result<Option<crate::Timestamp>, D::Error> { |
803 | 0 | de.deserialize_option(super::super::OptionalVisitor( |
804 | 0 | super::Visitor, |
805 | 0 | )) |
806 | 0 | } |
807 | | } |
808 | | } |
809 | | |
810 | | /// (De)serialize an integer number of microseconds from the Unix epoch. |
811 | | pub mod microsecond { |
812 | | use serde_core::de; |
813 | | |
814 | | struct Visitor; |
815 | | |
816 | | impl<'de> de::Visitor<'de> for Visitor { |
817 | | type Value = crate::Timestamp; |
818 | | |
819 | 0 | fn expecting( |
820 | 0 | &self, |
821 | 0 | f: &mut core::fmt::Formatter, |
822 | 0 | ) -> core::fmt::Result { |
823 | 0 | f.write_str( |
824 | 0 | "an integer number of microseconds from the Unix epoch", |
825 | | ) |
826 | 0 | } |
827 | | |
828 | | #[inline] |
829 | 0 | fn visit_i8<E: de::Error>( |
830 | 0 | self, |
831 | 0 | v: i8, |
832 | 0 | ) -> Result<crate::Timestamp, E> { |
833 | 0 | self.visit_i64(i64::from(v)) |
834 | 0 | } |
835 | | |
836 | | #[inline] |
837 | 0 | fn visit_u8<E: de::Error>( |
838 | 0 | self, |
839 | 0 | v: u8, |
840 | 0 | ) -> Result<crate::Timestamp, E> { |
841 | 0 | self.visit_i64(i64::from(v)) |
842 | 0 | } |
843 | | |
844 | | #[inline] |
845 | 0 | fn visit_i16<E: de::Error>( |
846 | 0 | self, |
847 | 0 | v: i16, |
848 | 0 | ) -> Result<crate::Timestamp, E> { |
849 | 0 | self.visit_i64(i64::from(v)) |
850 | 0 | } |
851 | | |
852 | | #[inline] |
853 | 0 | fn visit_u16<E: de::Error>( |
854 | 0 | self, |
855 | 0 | v: u16, |
856 | 0 | ) -> Result<crate::Timestamp, E> { |
857 | 0 | self.visit_i64(i64::from(v)) |
858 | 0 | } |
859 | | |
860 | | #[inline] |
861 | 0 | fn visit_i32<E: de::Error>( |
862 | 0 | self, |
863 | 0 | v: i32, |
864 | 0 | ) -> Result<crate::Timestamp, E> { |
865 | 0 | self.visit_i64(i64::from(v)) |
866 | 0 | } |
867 | | |
868 | | #[inline] |
869 | 0 | fn visit_u32<E: de::Error>( |
870 | 0 | self, |
871 | 0 | v: u32, |
872 | 0 | ) -> Result<crate::Timestamp, E> { |
873 | 0 | self.visit_i64(i64::from(v)) |
874 | 0 | } |
875 | | |
876 | | #[inline] |
877 | 0 | fn visit_i64<E: de::Error>( |
878 | 0 | self, |
879 | 0 | v: i64, |
880 | 0 | ) -> Result<crate::Timestamp, E> { |
881 | 0 | crate::Timestamp::from_microsecond(v) |
882 | 0 | .map_err(de::Error::custom) |
883 | 0 | } |
884 | | |
885 | | #[inline] |
886 | 0 | fn visit_u64<E: de::Error>( |
887 | 0 | self, |
888 | 0 | v: u64, |
889 | 0 | ) -> Result<crate::Timestamp, E> { |
890 | 0 | let v = i64::try_from(v).map_err(|_| { |
891 | 0 | de::Error::custom(format_args!( |
892 | 0 | "got unsigned integer {v} microseconds, \ |
893 | 0 | which is too big to fit in a Jiff `Timestamp`", |
894 | | )) |
895 | 0 | })?; |
896 | 0 | self.visit_i64(v) |
897 | 0 | } |
898 | | |
899 | | #[inline] |
900 | 0 | fn visit_i128<E: de::Error>( |
901 | 0 | self, |
902 | 0 | v: i128, |
903 | 0 | ) -> Result<crate::Timestamp, E> { |
904 | 0 | let v = i64::try_from(v).map_err(|_| { |
905 | 0 | de::Error::custom(format_args!( |
906 | 0 | "got signed integer {v} microseconds, \ |
907 | 0 | which is too big to fit in a Jiff `Timestamp`", |
908 | | )) |
909 | 0 | })?; |
910 | 0 | self.visit_i64(v) |
911 | 0 | } |
912 | | |
913 | | #[inline] |
914 | 0 | fn visit_u128<E: de::Error>( |
915 | 0 | self, |
916 | 0 | v: u128, |
917 | 0 | ) -> Result<crate::Timestamp, E> { |
918 | 0 | let v = i64::try_from(v).map_err(|_| { |
919 | 0 | de::Error::custom(format_args!( |
920 | 0 | "got unsigned integer {v} microseconds, \ |
921 | 0 | which is too big to fit in a Jiff `Timestamp`", |
922 | | )) |
923 | 0 | })?; |
924 | 0 | self.visit_i64(v) |
925 | 0 | } |
926 | | } |
927 | | |
928 | | /// (De)serialize a required integer number of microseconds from the |
929 | | /// Unix epoch. |
930 | | pub mod required { |
931 | | /// Serialize a required integer number of microseconds since the |
932 | | /// Unix epoch. |
933 | | #[inline] |
934 | 0 | pub fn serialize<S: serde_core::Serializer>( |
935 | 0 | timestamp: &crate::Timestamp, |
936 | 0 | se: S, |
937 | 0 | ) -> Result<S::Ok, S::Error> { |
938 | 0 | se.serialize_i64(timestamp.as_microsecond()) |
939 | 0 | } |
940 | | |
941 | | /// Deserialize a required integer number of microseconds since the |
942 | | /// Unix epoch. |
943 | | #[inline] |
944 | 0 | pub fn deserialize<'de, D: serde_core::Deserializer<'de>>( |
945 | 0 | de: D, |
946 | 0 | ) -> Result<crate::Timestamp, D::Error> { |
947 | 0 | de.deserialize_i64(super::Visitor) |
948 | 0 | } |
949 | | } |
950 | | |
951 | | /// (De)serialize an optional integer number of microseconds from the |
952 | | /// Unix epoch. |
953 | | pub mod optional { |
954 | | /// Serialize an optional integer number of microseconds since the |
955 | | /// Unix epoch. |
956 | | #[inline] |
957 | 0 | pub fn serialize<S: serde_core::Serializer>( |
958 | 0 | timestamp: &Option<crate::Timestamp>, |
959 | 0 | se: S, |
960 | 0 | ) -> Result<S::Ok, S::Error> { |
961 | 0 | match *timestamp { |
962 | 0 | None => se.serialize_none(), |
963 | 0 | Some(ref ts) => super::required::serialize(ts, se), |
964 | | } |
965 | 0 | } |
966 | | |
967 | | /// Deserialize an optional integer number of microseconds since |
968 | | /// the Unix epoch. |
969 | | #[inline] |
970 | 0 | pub fn deserialize<'de, D: serde_core::Deserializer<'de>>( |
971 | 0 | de: D, |
972 | 0 | ) -> Result<Option<crate::Timestamp>, D::Error> { |
973 | 0 | de.deserialize_option(super::super::OptionalVisitor( |
974 | 0 | super::Visitor, |
975 | 0 | )) |
976 | 0 | } |
977 | | } |
978 | | } |
979 | | |
980 | | /// (De)serialize an integer number of nanoseconds from the Unix epoch. |
981 | | pub mod nanosecond { |
982 | | use serde_core::de; |
983 | | |
984 | | struct Visitor; |
985 | | |
986 | | impl<'de> de::Visitor<'de> for Visitor { |
987 | | type Value = crate::Timestamp; |
988 | | |
989 | 0 | fn expecting( |
990 | 0 | &self, |
991 | 0 | f: &mut core::fmt::Formatter, |
992 | 0 | ) -> core::fmt::Result { |
993 | 0 | f.write_str( |
994 | 0 | "an integer number of nanoseconds from the Unix epoch", |
995 | | ) |
996 | 0 | } |
997 | | |
998 | | #[inline] |
999 | 0 | fn visit_i64<E: de::Error>( |
1000 | 0 | self, |
1001 | 0 | v: i64, |
1002 | 0 | ) -> Result<crate::Timestamp, E> { |
1003 | 0 | self.visit_i128(i128::from(v)) |
1004 | 0 | } |
1005 | | |
1006 | | #[inline] |
1007 | 0 | fn visit_u64<E: de::Error>( |
1008 | 0 | self, |
1009 | 0 | v: u64, |
1010 | 0 | ) -> Result<crate::Timestamp, E> { |
1011 | 0 | self.visit_u128(u128::from(v)) |
1012 | 0 | } |
1013 | | |
1014 | | #[inline] |
1015 | 0 | fn visit_i128<E: de::Error>( |
1016 | 0 | self, |
1017 | 0 | v: i128, |
1018 | 0 | ) -> Result<crate::Timestamp, E> { |
1019 | 0 | crate::Timestamp::from_nanosecond(v).map_err(de::Error::custom) |
1020 | 0 | } |
1021 | | |
1022 | | #[inline] |
1023 | 0 | fn visit_u128<E: de::Error>( |
1024 | 0 | self, |
1025 | 0 | v: u128, |
1026 | 0 | ) -> Result<crate::Timestamp, E> { |
1027 | 0 | let v = i128::try_from(v).map_err(|_| { |
1028 | 0 | de::Error::custom(format_args!( |
1029 | 0 | "got unsigned integer {v} nanoseconds, \ |
1030 | 0 | which is too big to fit in a Jiff `Timestamp`", |
1031 | | )) |
1032 | 0 | })?; |
1033 | 0 | self.visit_i128(v) |
1034 | 0 | } |
1035 | | } |
1036 | | |
1037 | | /// (De)serialize a required integer number of nanoseconds from the |
1038 | | /// Unix epoch. |
1039 | | pub mod required { |
1040 | | /// Serialize a required integer number of nanoseconds since the |
1041 | | /// Unix epoch. |
1042 | | #[inline] |
1043 | 0 | pub fn serialize<S: serde_core::Serializer>( |
1044 | 0 | timestamp: &crate::Timestamp, |
1045 | 0 | se: S, |
1046 | 0 | ) -> Result<S::Ok, S::Error> { |
1047 | 0 | se.serialize_i128(timestamp.as_nanosecond()) |
1048 | 0 | } |
1049 | | |
1050 | | /// Deserialize a required integer number of nanoseconds since the |
1051 | | /// Unix epoch. |
1052 | | #[inline] |
1053 | 0 | pub fn deserialize<'de, D: serde_core::Deserializer<'de>>( |
1054 | 0 | de: D, |
1055 | 0 | ) -> Result<crate::Timestamp, D::Error> { |
1056 | 0 | de.deserialize_i128(super::Visitor) |
1057 | 0 | } |
1058 | | } |
1059 | | |
1060 | | /// (De)serialize an optional integer number of nanoseconds from the |
1061 | | /// Unix epoch. |
1062 | | pub mod optional { |
1063 | | /// Serialize an optional integer number of nanoseconds since the |
1064 | | /// Unix epoch. |
1065 | | #[inline] |
1066 | 0 | pub fn serialize<S: serde_core::Serializer>( |
1067 | 0 | timestamp: &Option<crate::Timestamp>, |
1068 | 0 | se: S, |
1069 | 0 | ) -> Result<S::Ok, S::Error> { |
1070 | 0 | match *timestamp { |
1071 | 0 | None => se.serialize_none(), |
1072 | 0 | Some(ref ts) => super::required::serialize(ts, se), |
1073 | | } |
1074 | 0 | } |
1075 | | |
1076 | | /// Deserialize an optional integer number of nanoseconds since the |
1077 | | /// Unix epoch. |
1078 | | #[inline] |
1079 | 0 | pub fn deserialize<'de, D: serde_core::Deserializer<'de>>( |
1080 | 0 | de: D, |
1081 | 0 | ) -> Result<Option<crate::Timestamp>, D::Error> { |
1082 | 0 | de.deserialize_option(super::super::OptionalVisitor( |
1083 | 0 | super::Visitor, |
1084 | 0 | )) |
1085 | 0 | } |
1086 | | } |
1087 | | } |
1088 | | } |
1089 | | |
1090 | | /// Convenience routines for (de)serializing [`TimeZone`](crate::tz::TimeZone) |
1091 | | /// values. |
1092 | | /// |
1093 | | /// The `required` and `optional` sub-modules each provide serialization and |
1094 | | /// deserialization routines. They are meant to be used with Serde's |
1095 | | /// [`with` attribute]. |
1096 | | /// |
1097 | | /// # Advice |
1098 | | /// |
1099 | | /// Serializing time zones is useful when you want to accept user configuration |
1100 | | /// selecting a time zone to use. This might be beneficial when one cannot rely |
1101 | | /// on a system's time zone. |
1102 | | /// |
1103 | | /// Note that when deserializing time zones that are IANA time zone |
1104 | | /// identifiers, Jiff will automatically use the implicit global database to |
1105 | | /// resolve the identifier to an actual time zone. If you do not want to use |
1106 | | /// Jiff's global time zone database for this, you'll need to write your own |
1107 | | /// Serde integration. |
1108 | | /// |
1109 | | /// [`with` attribute]: https://serde.rs/field-attrs.html#with |
1110 | | /// |
1111 | | /// # Example |
1112 | | /// |
1113 | | /// ``` |
1114 | | /// use jiff::tz::TimeZone; |
1115 | | /// |
1116 | | /// #[derive(Debug, serde::Deserialize, serde::Serialize)] |
1117 | | /// struct Record { |
1118 | | /// #[serde(with = "jiff::fmt::serde::tz::required")] |
1119 | | /// tz: TimeZone, |
1120 | | /// } |
1121 | | /// |
1122 | | /// let json = r#"{"tz":"America/Nuuk"}"#; |
1123 | | /// let got: Record = serde_json::from_str(&json)?; |
1124 | | /// assert_eq!(got.tz, TimeZone::get("America/Nuuk")?); |
1125 | | /// assert_eq!(serde_json::to_string(&got)?, json); |
1126 | | /// |
1127 | | /// # Ok::<(), Box<dyn std::error::Error>>(()) |
1128 | | /// ``` |
1129 | | /// |
1130 | | /// # Example: serializing an unknown `TimeZone` works |
1131 | | /// |
1132 | | /// For example, when a time zone was created from |
1133 | | /// [`TimeZone::system`](crate::tz::TimeZone::system) and a system configured |
1134 | | /// time zone could not be found. One can artificially create this situation |
1135 | | /// with [`TimeZone::unknown`](crate::tz::TimeZone::unknown): |
1136 | | /// |
1137 | | /// ``` |
1138 | | /// use jiff::tz::TimeZone; |
1139 | | /// |
1140 | | /// #[derive(Debug, serde::Deserialize, serde::Serialize)] |
1141 | | /// struct Record { |
1142 | | /// #[serde(with = "jiff::fmt::serde::tz::required")] |
1143 | | /// tz: TimeZone, |
1144 | | /// } |
1145 | | /// |
1146 | | /// let record = Record { tz: TimeZone::unknown() }; |
1147 | | /// assert_eq!( |
1148 | | /// serde_json::to_string(&record)?, |
1149 | | /// r#"{"tz":"Etc/Unknown"}"#, |
1150 | | /// ); |
1151 | | /// |
1152 | | /// # Ok::<(), Box<dyn std::error::Error>>(()) |
1153 | | /// ``` |
1154 | | /// |
1155 | | /// And it deserializes as well: |
1156 | | /// |
1157 | | /// ``` |
1158 | | /// use jiff::tz::TimeZone; |
1159 | | /// |
1160 | | /// #[derive(Debug, serde::Deserialize, serde::Serialize)] |
1161 | | /// struct Record { |
1162 | | /// #[serde(with = "jiff::fmt::serde::tz::required")] |
1163 | | /// tz: TimeZone, |
1164 | | /// } |
1165 | | /// |
1166 | | /// let json = r#"{"tz":"Etc/Unknown"}"#; |
1167 | | /// let got: Record = serde_json::from_str(&json)?; |
1168 | | /// assert!(got.tz.is_unknown()); |
1169 | | /// |
1170 | | /// # Ok::<(), Box<dyn std::error::Error>>(()) |
1171 | | /// ``` |
1172 | | /// |
1173 | | /// An unknown time zone is "allowed" to percolate through Jiff because it's |
1174 | | /// usually not desirable to return an error and completely fail if a system |
1175 | | /// time zone could not be detected. On the other hand, by using a special |
1176 | | /// `Etc/Unknown` identifier for this case, it still surfaces the fact that |
1177 | | /// something has gone wrong. |
1178 | | pub mod tz { |
1179 | | use serde_core::de; |
1180 | | |
1181 | | use crate::fmt::{temporal, StdFmtWrite}; |
1182 | | |
1183 | | struct TemporalTimeZone<'a>(&'a crate::tz::TimeZone); |
1184 | | |
1185 | | impl<'a> core::fmt::Display for TemporalTimeZone<'a> { |
1186 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { |
1187 | | static PRINTER: temporal::DateTimePrinter = |
1188 | | temporal::DateTimePrinter::new(); |
1189 | 0 | PRINTER |
1190 | 0 | .print_time_zone(self.0, StdFmtWrite(f)) |
1191 | 0 | .map_err(|_| core::fmt::Error) |
1192 | 0 | } |
1193 | | } |
1194 | | |
1195 | | /// A required visitor for `TimeZone`. |
1196 | | struct Visitor; |
1197 | | |
1198 | | impl<'de> de::Visitor<'de> for Visitor { |
1199 | | type Value = crate::tz::TimeZone; |
1200 | | |
1201 | 0 | fn expecting( |
1202 | 0 | &self, |
1203 | 0 | f: &mut core::fmt::Formatter, |
1204 | 0 | ) -> core::fmt::Result { |
1205 | 0 | f.write_str( |
1206 | 0 | "a string representing a time zone via an \ |
1207 | 0 | IANA time zone identifier, fixed offset from UTC \ |
1208 | 0 | or a POSIX time zone string", |
1209 | | ) |
1210 | 0 | } |
1211 | | |
1212 | | #[inline] |
1213 | 0 | fn visit_bytes<E: de::Error>( |
1214 | 0 | self, |
1215 | 0 | value: &[u8], |
1216 | 0 | ) -> Result<crate::tz::TimeZone, E> { |
1217 | | static PARSER: temporal::DateTimeParser = |
1218 | | temporal::DateTimeParser::new(); |
1219 | 0 | PARSER.parse_time_zone(value).map_err(de::Error::custom) |
1220 | 0 | } |
1221 | | |
1222 | | #[inline] |
1223 | 0 | fn visit_str<E: de::Error>( |
1224 | 0 | self, |
1225 | 0 | value: &str, |
1226 | 0 | ) -> Result<crate::tz::TimeZone, E> { |
1227 | 0 | self.visit_bytes(value.as_bytes()) |
1228 | 0 | } |
1229 | | } |
1230 | | |
1231 | | /// A generic optional visitor for `TimeZone`. |
1232 | | struct OptionalVisitor<V>(V); |
1233 | | |
1234 | | impl<'de, V: de::Visitor<'de, Value = crate::tz::TimeZone>> |
1235 | | de::Visitor<'de> for OptionalVisitor<V> |
1236 | | { |
1237 | | type Value = Option<crate::tz::TimeZone>; |
1238 | | |
1239 | 0 | fn expecting( |
1240 | 0 | &self, |
1241 | 0 | f: &mut core::fmt::Formatter, |
1242 | 0 | ) -> core::fmt::Result { |
1243 | 0 | f.write_str( |
1244 | 0 | "a string representing a time zone via an \ |
1245 | 0 | IANA time zone identifier, fixed offset from UTC \ |
1246 | 0 | or a POSIX time zone string", |
1247 | | ) |
1248 | 0 | } |
1249 | | |
1250 | | #[inline] |
1251 | 0 | fn visit_some<D: de::Deserializer<'de>>( |
1252 | 0 | self, |
1253 | 0 | de: D, |
1254 | 0 | ) -> Result<Option<crate::tz::TimeZone>, D::Error> { |
1255 | 0 | de.deserialize_str(self.0).map(Some) |
1256 | 0 | } |
1257 | | |
1258 | | #[inline] |
1259 | 0 | fn visit_none<E: de::Error>( |
1260 | 0 | self, |
1261 | 0 | ) -> Result<Option<crate::tz::TimeZone>, E> { |
1262 | 0 | Ok(None) |
1263 | 0 | } |
1264 | | } |
1265 | | |
1266 | | /// (De)serialize a required [`TimeZone`](crate::tz::TimeZone). |
1267 | | pub mod required { |
1268 | | /// Serialize a required [`TimeZone`](crate::tz::TimeZone). |
1269 | | /// |
1270 | | /// This will result in an IANA time zone identifier, fixed offset or a |
1271 | | /// POSIX time zone string. |
1272 | | /// |
1273 | | /// This can return an error in some cases when the `TimeZone` has no |
1274 | | /// succinct string representation. For example, when the `TimeZone` is |
1275 | | /// derived from a system `/etc/localtime` for which no IANA time zone |
1276 | | /// identifier could be found. |
1277 | | #[inline] |
1278 | 0 | pub fn serialize<S: serde_core::Serializer>( |
1279 | 0 | tz: &crate::tz::TimeZone, |
1280 | 0 | se: S, |
1281 | 0 | ) -> Result<S::Ok, S::Error> { |
1282 | 0 | if !tz.has_succinct_serialization() { |
1283 | 0 | return Err(<S::Error as serde_core::ser::Error>::custom( |
1284 | 0 | "time zones without IANA identifiers that aren't either \ |
1285 | 0 | fixed offsets or a POSIX time zone can't be serialized \ |
1286 | 0 | (this typically occurs when this is a system time zone \ |
1287 | 0 | derived from `/etc/localtime` on Unix systems that \ |
1288 | 0 | isn't symlinked to an entry in `/usr/share/zoneinfo)", |
1289 | 0 | )); |
1290 | 0 | } |
1291 | 0 | se.collect_str(&super::TemporalTimeZone(tz)) |
1292 | 0 | } |
1293 | | |
1294 | | /// Deserialize a required [`TimeZone`](crate::tz::TimeZone). |
1295 | | /// |
1296 | | /// This will attempt to parse an IANA time zone identifier, a fixed |
1297 | | /// offset or a POSIX time zone string. |
1298 | | #[inline] |
1299 | 0 | pub fn deserialize<'de, D: serde_core::Deserializer<'de>>( |
1300 | 0 | de: D, |
1301 | 0 | ) -> Result<crate::tz::TimeZone, D::Error> { |
1302 | 0 | de.deserialize_str(super::Visitor) |
1303 | 0 | } |
1304 | | } |
1305 | | |
1306 | | /// (De)serialize an optional [`TimeZone`](crate::tz::TimeZone). |
1307 | | pub mod optional { |
1308 | | /// Serialize an optional [`TimeZone`](crate::tz::TimeZone). |
1309 | | /// |
1310 | | /// This will result in an IANA time zone identifier, fixed offset or a |
1311 | | /// POSIX time zone string. |
1312 | | /// |
1313 | | /// This can return an error in some cases when the `TimeZone` has no |
1314 | | /// succinct string representation. For example, when the `TimeZone` is |
1315 | | /// derived from a system `/etc/localtime` for which no IANA time zone |
1316 | | /// identifier could be found. |
1317 | | #[inline] |
1318 | 0 | pub fn serialize<S: serde_core::Serializer>( |
1319 | 0 | tz: &Option<crate::tz::TimeZone>, |
1320 | 0 | se: S, |
1321 | 0 | ) -> Result<S::Ok, S::Error> { |
1322 | 0 | match *tz { |
1323 | 0 | None => se.serialize_none(), |
1324 | 0 | Some(ref tz) => super::required::serialize(tz, se), |
1325 | | } |
1326 | 0 | } |
1327 | | |
1328 | | /// Deserialize an optional [`TimeZone`](crate::tz::TimeZone). |
1329 | | /// |
1330 | | /// This will attempt to parse an IANA time zone identifier, a fixed |
1331 | | /// offset or a POSIX time zone string. |
1332 | | #[inline] |
1333 | 0 | pub fn deserialize<'de, D: serde_core::Deserializer<'de>>( |
1334 | 0 | de: D, |
1335 | 0 | ) -> Result<Option<crate::tz::TimeZone>, D::Error> { |
1336 | 0 | de.deserialize_option(super::OptionalVisitor(super::Visitor)) |
1337 | 0 | } |
1338 | | } |
1339 | | } |
1340 | | |
1341 | | /// Convenience routines for serializing [`std::time::Duration`] values. |
1342 | | /// |
1343 | | /// The principal helpers in this module are the |
1344 | | /// [`required`](crate::fmt::serde::unsigned_duration::required) |
1345 | | /// and |
1346 | | /// [`optional`](crate::fmt::serde::unsigned_duration::optional) sub-modules. |
1347 | | /// Either may be used with Serde's `with` attribute. Each sub-module |
1348 | | /// provides both a serialization and a deserialization routine for |
1349 | | /// [`std::time::Duration`]. Deserialization supports either ISO 8601 or the |
1350 | | /// "[friendly](crate::fmt::friendly)" format. Serialization always uses ISO |
1351 | | /// 8601 for reasons of increased interoperability. These helpers are meant to |
1352 | | /// approximate the `Deserialize` and `Serialize` trait implementations for |
1353 | | /// Jiff's own [`SignedDuration`](crate::SignedDuration). |
1354 | | /// |
1355 | | /// If you want to serialize a `std::time::Duration` using the |
1356 | | /// [friendly](crate::fmt::friendly), then you can make use of the |
1357 | | /// helpers in |
1358 | | /// [`friendly::compact`](crate::fmt::serde::unsigned_duration::friendly::compact), |
1359 | | /// also via Serde's `with` attribute. These helpers change their serialization |
1360 | | /// to the "friendly" format using compact unit designators. Their deserialization |
1361 | | /// remains the same as the top-level helpers (that is, both ISO 8601 and |
1362 | | /// friendly formatted duration strings are parsed). |
1363 | | /// |
1364 | | /// Unlike Jiff's own [`SignedDuration`](crate::SignedDuration), deserializing |
1365 | | /// a `std::time::Duration` does not support negative durations. If a negative |
1366 | | /// duration is found, then deserialization will fail. Moreover, as an unsigned |
1367 | | /// type, a `std::time::Duration` can represent larger durations than a |
1368 | | /// `SignedDuration`. This means that a `SignedDuration` cannot deserialize |
1369 | | /// all valid values of a `std::time::Duration`. In other words, be careful not |
1370 | | /// to mix them. |
1371 | | /// |
1372 | | /// # Example: maximally interoperable serialization |
1373 | | /// |
1374 | | /// This example shows how to achieve Serde integration for `std::time::Duration` |
1375 | | /// in a way that mirrors [`SignedDuration`](crate::SignedDuration). In |
1376 | | /// particular, this supports deserializing ISO 8601 or "friendly" format |
1377 | | /// duration strings. In order to be maximally interoperable, this serializes |
1378 | | /// only in the ISO 8601 format. |
1379 | | /// |
1380 | | /// ``` |
1381 | | /// use std::time::Duration; |
1382 | | /// |
1383 | | /// use serde::{Deserialize, Serialize}; |
1384 | | /// |
1385 | | /// #[derive(Debug, PartialEq, Serialize, Deserialize)] |
1386 | | /// struct Task { |
1387 | | /// name: String, |
1388 | | /// #[serde(with = "jiff::fmt::serde::unsigned_duration::required")] |
1389 | | /// timeout: Duration, |
1390 | | /// #[serde(with = "jiff::fmt::serde::unsigned_duration::optional")] |
1391 | | /// retry_delay: Option<Duration>, |
1392 | | /// } |
1393 | | /// |
1394 | | /// let task = Task { |
1395 | | /// name: "Task 1".to_string(), |
1396 | | /// // 1 hour 30 minutes |
1397 | | /// timeout: Duration::from_secs(60 * 60 + 30 * 60), |
1398 | | /// // 2 seconds 500 milliseconds |
1399 | | /// retry_delay: Some(Duration::from_millis(2500)), |
1400 | | /// }; |
1401 | | /// |
1402 | | /// let expected_json = r#"{"name":"Task 1","timeout":"PT1H30M","retry_delay":"PT2.5S"}"#; |
1403 | | /// let actual_json = serde_json::to_string(&task)?; |
1404 | | /// assert_eq!(actual_json, expected_json); |
1405 | | /// |
1406 | | /// let deserialized_task: Task = serde_json::from_str(&actual_json)?; |
1407 | | /// assert_eq!(deserialized_task, task); |
1408 | | /// |
1409 | | /// // Example with None for optional field |
1410 | | /// let task_no_retry = Task { |
1411 | | /// name: "Task 2".to_string(), |
1412 | | /// timeout: Duration::from_secs(5), |
1413 | | /// retry_delay: None, |
1414 | | /// }; |
1415 | | /// let expected_json_no_retry = r#"{"name":"Task 2","timeout":"PT5S","retry_delay":null}"#; |
1416 | | /// let actual_json_no_retry = serde_json::to_string(&task_no_retry)?; |
1417 | | /// assert_eq!(actual_json_no_retry, expected_json_no_retry); |
1418 | | /// |
1419 | | /// let deserialized_task_no_retry: Task = serde_json::from_str(&actual_json_no_retry)?; |
1420 | | /// assert_eq!(deserialized_task_no_retry, task_no_retry); |
1421 | | /// |
1422 | | /// # Ok::<(), Box<dyn std::error::Error>>(()) |
1423 | | /// ``` |
1424 | | /// |
1425 | | /// # Example: Round-tripping `std::time::Duration` |
1426 | | /// |
1427 | | /// This example demonstrates how to serialize and deserialize a |
1428 | | /// `std::time::Duration` field using the helpers from this module. In |
1429 | | /// particular, this serializes durations in the more human readable |
1430 | | /// "friendly" format, but can still deserialize ISO 8601 duration strings. |
1431 | | /// |
1432 | | /// ``` |
1433 | | /// use std::time::Duration; |
1434 | | /// |
1435 | | /// use serde::{Deserialize, Serialize}; |
1436 | | /// |
1437 | | /// #[derive(Debug, PartialEq, Serialize, Deserialize)] |
1438 | | /// struct Task { |
1439 | | /// name: String, |
1440 | | /// #[serde(with = "jiff::fmt::serde::unsigned_duration::friendly::compact::required")] |
1441 | | /// timeout: Duration, |
1442 | | /// #[serde(with = "jiff::fmt::serde::unsigned_duration::friendly::compact::optional")] |
1443 | | /// retry_delay: Option<Duration>, |
1444 | | /// } |
1445 | | /// |
1446 | | /// let task = Task { |
1447 | | /// name: "Task 1".to_string(), |
1448 | | /// // 1 hour 30 minutes |
1449 | | /// timeout: Duration::from_secs(60 * 60 + 30 * 60), |
1450 | | /// // 2 seconds 500 milliseconds |
1451 | | /// retry_delay: Some(Duration::from_millis(2500)), |
1452 | | /// }; |
1453 | | /// |
1454 | | /// let expected_json = r#"{"name":"Task 1","timeout":"1h 30m","retry_delay":"2s 500ms"}"#; |
1455 | | /// let actual_json = serde_json::to_string(&task)?; |
1456 | | /// assert_eq!(actual_json, expected_json); |
1457 | | /// |
1458 | | /// let deserialized_task: Task = serde_json::from_str(&actual_json)?; |
1459 | | /// assert_eq!(deserialized_task, task); |
1460 | | /// |
1461 | | /// // Example with None for optional field |
1462 | | /// let task_no_retry = Task { |
1463 | | /// name: "Task 2".to_string(), |
1464 | | /// timeout: Duration::from_secs(5), |
1465 | | /// retry_delay: None, |
1466 | | /// }; |
1467 | | /// let expected_json_no_retry = r#"{"name":"Task 2","timeout":"5s","retry_delay":null}"#; |
1468 | | /// let actual_json_no_retry = serde_json::to_string(&task_no_retry)?; |
1469 | | /// assert_eq!(actual_json_no_retry, expected_json_no_retry); |
1470 | | /// |
1471 | | /// let deserialized_task_no_retry: Task = serde_json::from_str(&actual_json_no_retry)?; |
1472 | | /// assert_eq!(deserialized_task_no_retry, task_no_retry); |
1473 | | /// |
1474 | | /// # Ok::<(), Box<dyn std::error::Error>>(()) |
1475 | | /// ``` |
1476 | | /// |
1477 | | /// # Example: custom "friendly" format options |
1478 | | /// |
1479 | | /// When using |
1480 | | /// [`friendly::compact`](crate::fmt::serde::unsigned_duration::friendly::compact), |
1481 | | /// the serialization implementation uses a fixed friendly format |
1482 | | /// configuration. To use your own configuration, you'll need to write your own |
1483 | | /// serialization function: |
1484 | | /// |
1485 | | /// ``` |
1486 | | /// use std::time::Duration; |
1487 | | /// |
1488 | | /// #[derive(Debug, serde::Deserialize, serde::Serialize)] |
1489 | | /// struct Data { |
1490 | | /// #[serde(serialize_with = "custom_friendly")] |
1491 | | /// // We can reuse an existing deserialization helper so that you |
1492 | | /// // don't have to write your own. |
1493 | | /// #[serde(deserialize_with = "jiff::fmt::serde::unsigned_duration::required::deserialize")] |
1494 | | /// duration: Duration, |
1495 | | /// } |
1496 | | /// |
1497 | | /// let json = r#"{"duration": "36 hours 1100ms"}"#; |
1498 | | /// let got: Data = serde_json::from_str(&json).unwrap(); |
1499 | | /// assert_eq!(got.duration, Duration::new(36 * 60 * 60 + 1, 100_000_000)); |
1500 | | /// |
1501 | | /// let expected = r#"{"duration":"36:00:01.100"}"#; |
1502 | | /// assert_eq!(serde_json::to_string(&got).unwrap(), expected); |
1503 | | /// |
1504 | | /// fn custom_friendly<S: serde::Serializer>( |
1505 | | /// duration: &Duration, |
1506 | | /// se: S, |
1507 | | /// ) -> Result<S::Ok, S::Error> { |
1508 | | /// struct Custom<'a>(&'a Duration); |
1509 | | /// |
1510 | | /// impl<'a> std::fmt::Display for Custom<'a> { |
1511 | | /// fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
1512 | | /// use jiff::fmt::{friendly::SpanPrinter, StdFmtWrite}; |
1513 | | /// |
1514 | | /// static PRINTER: SpanPrinter = SpanPrinter::new() |
1515 | | /// .hours_minutes_seconds(true) |
1516 | | /// .precision(Some(3)); |
1517 | | /// |
1518 | | /// PRINTER |
1519 | | /// .print_unsigned_duration(self.0, StdFmtWrite(f)) |
1520 | | /// .map_err(|_| core::fmt::Error) |
1521 | | /// } |
1522 | | /// } |
1523 | | /// |
1524 | | /// se.collect_str(&Custom(duration)) |
1525 | | /// } |
1526 | | /// ``` |
1527 | | pub mod unsigned_duration { |
1528 | | /// (De)serialize a `std::time::Duration` |
1529 | | /// in the [`friendly`](crate::fmt::friendly) duration format. |
1530 | | /// |
1531 | | /// Note that these will still deserialize ISO 8601 duration strings. |
1532 | | /// The main feature of this module is that serialization will use the |
1533 | | /// friendly format instead of the ISO 8601 format. |
1534 | | pub mod friendly { |
1535 | | /// (De)serialize a `std::time::Duration` |
1536 | | /// in the [`friendly`](crate::fmt::friendly) duration format using |
1537 | | /// compact designators. |
1538 | | /// |
1539 | | /// Note that these will still deserialize ISO 8601 duration strings. |
1540 | | /// The main feature of this module is that serialization will use the |
1541 | | /// friendly format instead of the ISO 8601 format. |
1542 | | pub mod compact { |
1543 | | /// (De)serialize a required `std::time::Duration` |
1544 | | /// in the [`friendly`](crate::fmt::friendly) duration format using |
1545 | | /// compact designators. |
1546 | | /// |
1547 | | /// Note that this will still deserialize ISO 8601 duration |
1548 | | /// strings. The main feature of this module is that serialization |
1549 | | /// will use the friendly format instead of the ISO 8601 format. |
1550 | | /// |
1551 | | /// This is meant to be used with Serde's `with` attribute. |
1552 | | pub mod required { |
1553 | | /// Serialize a required "friendly" duration from a |
1554 | | /// [`std::time::Duration`]. |
1555 | | #[inline] |
1556 | 0 | pub fn serialize<S: serde_core::Serializer>( |
1557 | 0 | duration: &core::time::Duration, |
1558 | 0 | se: S, |
1559 | 0 | ) -> Result<S::Ok, S::Error> { |
1560 | 0 | se.collect_str(&super::DisplayFriendlyCompact(duration)) |
1561 | 0 | } |
1562 | | |
1563 | | /// Deserialize a required ISO 8601 or friendly duration from a |
1564 | | /// [`std::time::Duration`]. |
1565 | | #[inline] |
1566 | 0 | pub fn deserialize<'de, D: serde_core::Deserializer<'de>>( |
1567 | 0 | de: D, |
1568 | 0 | ) -> Result<core::time::Duration, D::Error> { |
1569 | 0 | super::super::super::required::deserialize(de) |
1570 | 0 | } |
1571 | | } |
1572 | | |
1573 | | /// (De)serialize an optional `std::time::Duration` |
1574 | | /// in the [`friendly`](crate::fmt::friendly) duration format using |
1575 | | /// compact designators. |
1576 | | /// |
1577 | | /// Note that this will still deserialize ISO 8601 duration |
1578 | | /// strings. The main feature of this module is that serialization |
1579 | | /// will use the friendly format instead of the ISO 8601 format. |
1580 | | /// |
1581 | | /// This is meant to be used with Serde's `with` attribute. |
1582 | | pub mod optional { |
1583 | | /// Serialize an optional "friendly" duration from a |
1584 | | /// [`std::time::Duration`]. |
1585 | | #[inline] |
1586 | 0 | pub fn serialize<S: serde_core::Serializer>( |
1587 | 0 | duration: &Option<core::time::Duration>, |
1588 | 0 | se: S, |
1589 | 0 | ) -> Result<S::Ok, S::Error> { |
1590 | 0 | match *duration { |
1591 | 0 | None => se.serialize_none(), |
1592 | 0 | Some(ref duration) => { |
1593 | 0 | super::required::serialize(duration, se) |
1594 | | } |
1595 | | } |
1596 | 0 | } |
1597 | | |
1598 | | /// Deserialize a required ISO 8601 or friendly duration from a |
1599 | | /// [`std::time::Duration`]. |
1600 | | #[inline] |
1601 | 0 | pub fn deserialize<'de, D: serde_core::Deserializer<'de>>( |
1602 | 0 | de: D, |
1603 | 0 | ) -> Result<Option<core::time::Duration>, D::Error> |
1604 | | { |
1605 | 0 | super::super::super::optional::deserialize(de) |
1606 | 0 | } |
1607 | | } |
1608 | | |
1609 | | /// A helper for printing a `std::time::Duration` in the friendly |
1610 | | /// format using compact unit designators. |
1611 | | struct DisplayFriendlyCompact<'a>(&'a core::time::Duration); |
1612 | | |
1613 | | impl<'a> core::fmt::Display for DisplayFriendlyCompact<'a> { |
1614 | 0 | fn fmt( |
1615 | 0 | &self, |
1616 | 0 | f: &mut core::fmt::Formatter, |
1617 | 0 | ) -> core::fmt::Result { |
1618 | | use crate::fmt::{ |
1619 | | friendly::{Designator, SpanPrinter}, |
1620 | | StdFmtWrite, |
1621 | | }; |
1622 | | |
1623 | | static PRINTER: SpanPrinter = |
1624 | | SpanPrinter::new().designator(Designator::Compact); |
1625 | 0 | PRINTER |
1626 | 0 | .print_unsigned_duration(self.0, StdFmtWrite(f)) |
1627 | 0 | .map_err(|_| core::fmt::Error) |
1628 | 0 | } |
1629 | | } |
1630 | | } |
1631 | | } |
1632 | | |
1633 | | /// (De)serialize a required ISO 8601 or friendly duration from a |
1634 | | /// [`std::time::Duration`]. |
1635 | | /// |
1636 | | /// This is meant to be used with Serde's `with` attribute. |
1637 | | pub mod required { |
1638 | | pub(super) struct Visitor; |
1639 | | |
1640 | | impl<'de> serde_core::de::Visitor<'de> for Visitor { |
1641 | | type Value = core::time::Duration; |
1642 | | |
1643 | 0 | fn expecting( |
1644 | 0 | &self, |
1645 | 0 | f: &mut core::fmt::Formatter, |
1646 | 0 | ) -> core::fmt::Result { |
1647 | 0 | f.write_str("an unsigned duration string") |
1648 | 0 | } |
1649 | | |
1650 | | #[inline] |
1651 | 0 | fn visit_bytes<E: serde_core::de::Error>( |
1652 | 0 | self, |
1653 | 0 | value: &[u8], |
1654 | 0 | ) -> Result<core::time::Duration, E> { |
1655 | 0 | super::parse_iso_or_friendly(value) |
1656 | 0 | .map_err(serde_core::de::Error::custom) |
1657 | 0 | } |
1658 | | |
1659 | | #[inline] |
1660 | 0 | fn visit_str<E: serde_core::de::Error>( |
1661 | 0 | self, |
1662 | 0 | value: &str, |
1663 | 0 | ) -> Result<core::time::Duration, E> { |
1664 | 0 | self.visit_bytes(value.as_bytes()) |
1665 | 0 | } |
1666 | | } |
1667 | | |
1668 | | /// Serialize a required ISO 8601 duration from a |
1669 | | /// [`std::time::Duration`]. |
1670 | | #[inline] |
1671 | 0 | pub fn serialize<S: serde_core::Serializer>( |
1672 | 0 | duration: &core::time::Duration, |
1673 | 0 | se: S, |
1674 | 0 | ) -> Result<S::Ok, S::Error> { |
1675 | 0 | se.collect_str(&super::DisplayISO8601(duration)) |
1676 | 0 | } |
1677 | | |
1678 | | /// Deserialize a required ISO 8601 or friendly duration from a |
1679 | | /// [`std::time::Duration`]. |
1680 | | #[inline] |
1681 | 0 | pub fn deserialize<'de, D: serde_core::Deserializer<'de>>( |
1682 | 0 | de: D, |
1683 | 0 | ) -> Result<core::time::Duration, D::Error> { |
1684 | 0 | de.deserialize_str(Visitor) |
1685 | 0 | } |
1686 | | } |
1687 | | |
1688 | | /// (De)serialize an optional ISO 8601 or friendly duration from a |
1689 | | /// [`std::time::Duration`]. |
1690 | | /// |
1691 | | /// This is meant to be used with Serde's `with` attribute. |
1692 | | pub mod optional { |
1693 | | struct Visitor<V>(V); |
1694 | | |
1695 | | impl< |
1696 | | 'de, |
1697 | | V: serde_core::de::Visitor<'de, Value = core::time::Duration>, |
1698 | | > serde_core::de::Visitor<'de> for Visitor<V> |
1699 | | { |
1700 | | type Value = Option<core::time::Duration>; |
1701 | | |
1702 | 0 | fn expecting( |
1703 | 0 | &self, |
1704 | 0 | f: &mut core::fmt::Formatter, |
1705 | 0 | ) -> core::fmt::Result { |
1706 | 0 | f.write_str("an unsigned duration string") |
1707 | 0 | } |
1708 | | |
1709 | | #[inline] |
1710 | 0 | fn visit_some<D: serde_core::de::Deserializer<'de>>( |
1711 | 0 | self, |
1712 | 0 | de: D, |
1713 | 0 | ) -> Result<Option<core::time::Duration>, D::Error> { |
1714 | 0 | de.deserialize_str(self.0).map(Some) |
1715 | 0 | } |
1716 | | |
1717 | | #[inline] |
1718 | 0 | fn visit_none<E: serde_core::de::Error>( |
1719 | 0 | self, |
1720 | 0 | ) -> Result<Option<core::time::Duration>, E> { |
1721 | 0 | Ok(None) |
1722 | 0 | } |
1723 | | } |
1724 | | |
1725 | | /// Serialize an optional ISO 8601 duration from a |
1726 | | /// [`std::time::Duration`]. |
1727 | | #[inline] |
1728 | 0 | pub fn serialize<S: serde_core::Serializer>( |
1729 | 0 | duration: &Option<core::time::Duration>, |
1730 | 0 | se: S, |
1731 | 0 | ) -> Result<S::Ok, S::Error> { |
1732 | 0 | match *duration { |
1733 | 0 | None => se.serialize_none(), |
1734 | 0 | Some(ref duration) => super::required::serialize(duration, se), |
1735 | | } |
1736 | 0 | } |
1737 | | |
1738 | | /// Deserialize an optional ISO 8601 or friendly duration from a |
1739 | | /// [`std::time::Duration`]. |
1740 | | #[inline] |
1741 | 0 | pub fn deserialize<'de, D: serde_core::Deserializer<'de>>( |
1742 | 0 | de: D, |
1743 | 0 | ) -> Result<Option<core::time::Duration>, D::Error> { |
1744 | 0 | de.deserialize_option(Visitor(super::required::Visitor)) |
1745 | 0 | } |
1746 | | } |
1747 | | |
1748 | | /// A helper for printing a `std::time::Duration` in ISO 8601 format. |
1749 | | struct DisplayISO8601<'a>(&'a core::time::Duration); |
1750 | | |
1751 | | impl<'a> core::fmt::Display for DisplayISO8601<'a> { |
1752 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { |
1753 | | use crate::fmt::temporal::SpanPrinter; |
1754 | | |
1755 | | static PRINTER: SpanPrinter = SpanPrinter::new(); |
1756 | 0 | PRINTER |
1757 | 0 | .print_unsigned_duration(self.0, crate::fmt::StdFmtWrite(f)) |
1758 | 0 | .map_err(|_| core::fmt::Error) |
1759 | 0 | } |
1760 | | } |
1761 | | |
1762 | | /// A common parsing function that works in bytes. |
1763 | | /// |
1764 | | /// Specifically, this parses either an ISO 8601 duration into |
1765 | | /// a `std::time::Duration` or a "friendly" duration into a |
1766 | | /// `std::time::Duration`. It also tries to give decent error messages. |
1767 | | /// |
1768 | | /// This works because the friendly and ISO 8601 formats have |
1769 | | /// non-overlapping prefixes. Both can start with a `+` or `-`, but aside |
1770 | | /// from that, an ISO 8601 duration _always_ has to start with a `P` or |
1771 | | /// `p`. We can utilize this property to very quickly determine how to |
1772 | | /// parse the input. We just need to handle the possibly ambiguous case |
1773 | | /// with a leading sign a little carefully in order to ensure good error |
1774 | | /// messages. |
1775 | | /// |
1776 | | /// (We do the same thing for `Span` and `SignedDuration`.) |
1777 | | #[cfg_attr(feature = "perf-inline", inline(always))] |
1778 | 0 | fn parse_iso_or_friendly( |
1779 | 0 | bytes: &[u8], |
1780 | 0 | ) -> Result<core::time::Duration, crate::Error> { |
1781 | 0 | if bytes.is_empty() { |
1782 | 0 | return Err(crate::error::err!( |
1783 | 0 | "an empty string is not a valid `std::time::Duration`, \ |
1784 | 0 | expected either a ISO 8601 or Jiff's 'friendly' \ |
1785 | 0 | format", |
1786 | 0 | )); |
1787 | 0 | } |
1788 | 0 | let mut first = bytes[0]; |
1789 | | // N.B. Unsigned durations don't support negative durations (of |
1790 | | // course), but we still check for it here so that we can defer to |
1791 | | // the dedicated parsers. They will provide their own error messages. |
1792 | 0 | if first == b'+' || first == b'-' { |
1793 | 0 | if bytes.len() == 1 { |
1794 | 0 | return Err(crate::error::err!( |
1795 | 0 | "found nothing after sign `{sign}`, \ |
1796 | 0 | which is not a valid `std::time::Duration`, \ |
1797 | 0 | expected either a ISO 8601 or Jiff's 'friendly' \ |
1798 | 0 | format", |
1799 | 0 | sign = crate::util::escape::Byte(first), |
1800 | 0 | )); |
1801 | 0 | } |
1802 | 0 | first = bytes[1]; |
1803 | 0 | } |
1804 | 0 | let dur = if first == b'P' || first == b'p' { |
1805 | 0 | crate::fmt::temporal::DEFAULT_SPAN_PARSER |
1806 | 0 | .parse_unsigned_duration(bytes) |
1807 | | } else { |
1808 | 0 | crate::fmt::friendly::DEFAULT_SPAN_PARSER |
1809 | 0 | .parse_unsigned_duration(bytes) |
1810 | 0 | }?; |
1811 | 0 | Ok(dur) |
1812 | 0 | } |
1813 | | } |
1814 | | |
1815 | | #[cfg(test)] |
1816 | | mod tests { |
1817 | | use crate::{ |
1818 | | span::span_eq, SignedDuration, Span, SpanFieldwise, Timestamp, ToSpan, |
1819 | | }; |
1820 | | use core::time::Duration as UnsignedDuration; |
1821 | | |
1822 | | #[test] |
1823 | | fn duration_friendly_compact_required() { |
1824 | | #[derive(Debug, serde::Deserialize, serde::Serialize)] |
1825 | | struct Data { |
1826 | | #[serde( |
1827 | | serialize_with = "crate::fmt::serde::duration::friendly::compact::required" |
1828 | | )] |
1829 | | duration: SignedDuration, |
1830 | | } |
1831 | | |
1832 | | let json = r#"{"duration":"36 hours 1100ms"}"#; |
1833 | | let got: Data = serde_json::from_str(&json).unwrap(); |
1834 | | assert_eq!( |
1835 | | got.duration, |
1836 | | SignedDuration::new(36 * 60 * 60 + 1, 100_000_000) |
1837 | | ); |
1838 | | |
1839 | | let expected = r#"{"duration":"36h 1s 100ms"}"#; |
1840 | | assert_eq!(serde_json::to_string(&got).unwrap(), expected); |
1841 | | } |
1842 | | |
1843 | | #[test] |
1844 | | fn duration_friendly_compact_optional() { |
1845 | | #[derive(Debug, serde::Deserialize, serde::Serialize)] |
1846 | | struct Data { |
1847 | | #[serde( |
1848 | | serialize_with = "crate::fmt::serde::duration::friendly::compact::optional" |
1849 | | )] |
1850 | | duration: Option<SignedDuration>, |
1851 | | } |
1852 | | |
1853 | | let json = r#"{"duration":"36 hours 1100ms"}"#; |
1854 | | let got: Data = serde_json::from_str(&json).unwrap(); |
1855 | | assert_eq!( |
1856 | | got.duration, |
1857 | | Some(SignedDuration::new(36 * 60 * 60 + 1, 100_000_000)) |
1858 | | ); |
1859 | | |
1860 | | let expected = r#"{"duration":"36h 1s 100ms"}"#; |
1861 | | assert_eq!(serde_json::to_string(&got).unwrap(), expected); |
1862 | | } |
1863 | | |
1864 | | #[test] |
1865 | | fn unsigned_duration_required() { |
1866 | | #[derive(Debug, serde::Deserialize, serde::Serialize)] |
1867 | | struct Data { |
1868 | | #[serde(with = "crate::fmt::serde::unsigned_duration::required")] |
1869 | | duration: UnsignedDuration, |
1870 | | } |
1871 | | |
1872 | | let json = r#"{"duration":"PT36H1.1S"}"#; |
1873 | | let got: Data = serde_json::from_str(&json).unwrap(); |
1874 | | assert_eq!( |
1875 | | got.duration, |
1876 | | UnsignedDuration::new(36 * 60 * 60 + 1, 100_000_000) |
1877 | | ); |
1878 | | assert_eq!(serde_json::to_string(&got).unwrap(), json); |
1879 | | |
1880 | | // Check that we can parse a number of seconds that exceeds |
1881 | | // `i64::MAX`. In this case, precisely `u64::MAX`. |
1882 | | let json = r#"{"duration":"PT18446744073709551615S"}"#; |
1883 | | let got: Data = serde_json::from_str(&json).unwrap(); |
1884 | | assert_eq!( |
1885 | | got.duration, |
1886 | | UnsignedDuration::new(18446744073709551615, 0) |
1887 | | ); |
1888 | | // Printing ISO 8601 durations balances up to hours, so |
1889 | | // it won't match the one we parsed. But the actual duration |
1890 | | // value is equivalent. |
1891 | | let expected = r#"{"duration":"PT5124095576030431H15S"}"#; |
1892 | | assert_eq!(serde_json::to_string(&got).unwrap(), expected); |
1893 | | } |
1894 | | |
1895 | | #[test] |
1896 | | fn unsigned_duration_optional() { |
1897 | | #[derive(Debug, serde::Deserialize, serde::Serialize)] |
1898 | | struct Data { |
1899 | | #[serde(with = "crate::fmt::serde::unsigned_duration::optional")] |
1900 | | duration: Option<UnsignedDuration>, |
1901 | | } |
1902 | | |
1903 | | let json = r#"{"duration":"PT36H1.1S"}"#; |
1904 | | let got: Data = serde_json::from_str(&json).unwrap(); |
1905 | | assert_eq!( |
1906 | | got.duration, |
1907 | | Some(UnsignedDuration::new(36 * 60 * 60 + 1, 100_000_000)) |
1908 | | ); |
1909 | | assert_eq!(serde_json::to_string(&got).unwrap(), json); |
1910 | | |
1911 | | let json = r#"{"duration":null}"#; |
1912 | | let got: Data = serde_json::from_str(&json).unwrap(); |
1913 | | assert_eq!(got.duration, None,); |
1914 | | assert_eq!(serde_json::to_string(&got).unwrap(), json); |
1915 | | } |
1916 | | |
1917 | | #[test] |
1918 | | fn unsigned_duration_compact_required() { |
1919 | | #[derive(Debug, serde::Deserialize, serde::Serialize)] |
1920 | | struct Data { |
1921 | | #[serde( |
1922 | | with = "crate::fmt::serde::unsigned_duration::friendly::compact::required" |
1923 | | )] |
1924 | | duration: UnsignedDuration, |
1925 | | } |
1926 | | |
1927 | | let json = r#"{"duration":"36h 1s 100ms"}"#; |
1928 | | let got: Data = serde_json::from_str(&json).unwrap(); |
1929 | | assert_eq!( |
1930 | | got.duration, |
1931 | | UnsignedDuration::new(36 * 60 * 60 + 1, 100_000_000) |
1932 | | ); |
1933 | | assert_eq!(serde_json::to_string(&got).unwrap(), json); |
1934 | | } |
1935 | | |
1936 | | #[test] |
1937 | | fn unsigned_duration_compact_optional() { |
1938 | | #[derive(Debug, serde::Deserialize, serde::Serialize)] |
1939 | | struct Data { |
1940 | | #[serde( |
1941 | | with = "crate::fmt::serde::unsigned_duration::friendly::compact::optional" |
1942 | | )] |
1943 | | duration: Option<UnsignedDuration>, |
1944 | | } |
1945 | | |
1946 | | let json = r#"{"duration":"36h 1s 100ms"}"#; |
1947 | | let got: Data = serde_json::from_str(&json).unwrap(); |
1948 | | assert_eq!( |
1949 | | got.duration, |
1950 | | Some(UnsignedDuration::new(36 * 60 * 60 + 1, 100_000_000)) |
1951 | | ); |
1952 | | assert_eq!(serde_json::to_string(&got).unwrap(), json); |
1953 | | } |
1954 | | |
1955 | | #[test] |
1956 | | fn span_friendly_compact_required() { |
1957 | | #[derive(Debug, serde::Deserialize, serde::Serialize)] |
1958 | | struct Data { |
1959 | | #[serde( |
1960 | | serialize_with = "crate::fmt::serde::span::friendly::compact::required" |
1961 | | )] |
1962 | | span: Span, |
1963 | | } |
1964 | | |
1965 | | let json = r#"{"span":"1 year 2 months 36 hours 1100ms"}"#; |
1966 | | let got: Data = serde_json::from_str(&json).unwrap(); |
1967 | | span_eq!(got.span, 1.year().months(2).hours(36).milliseconds(1100)); |
1968 | | |
1969 | | let expected = r#"{"span":"1y 2mo 36h 1100ms"}"#; |
1970 | | assert_eq!(serde_json::to_string(&got).unwrap(), expected); |
1971 | | } |
1972 | | |
1973 | | #[test] |
1974 | | fn span_friendly_compact_optional() { |
1975 | | #[derive(Debug, serde::Deserialize, serde::Serialize)] |
1976 | | struct Data { |
1977 | | #[serde( |
1978 | | serialize_with = "crate::fmt::serde::span::friendly::compact::optional" |
1979 | | )] |
1980 | | span: Option<Span>, |
1981 | | } |
1982 | | |
1983 | | let json = r#"{"span":"1 year 2 months 36 hours 1100ms"}"#; |
1984 | | let got: Data = serde_json::from_str(&json).unwrap(); |
1985 | | assert_eq!( |
1986 | | got.span.map(SpanFieldwise), |
1987 | | Some(1.year().months(2).hours(36).milliseconds(1100).fieldwise()) |
1988 | | ); |
1989 | | |
1990 | | let expected = r#"{"span":"1y 2mo 36h 1100ms"}"#; |
1991 | | assert_eq!(serde_json::to_string(&got).unwrap(), expected); |
1992 | | } |
1993 | | |
1994 | | #[test] |
1995 | | fn timestamp_second_required() { |
1996 | | #[derive(Debug, serde::Deserialize, serde::Serialize)] |
1997 | | struct Data { |
1998 | | #[serde(with = "crate::fmt::serde::timestamp::second::required")] |
1999 | | ts: Timestamp, |
2000 | | } |
2001 | | |
2002 | | let json = r#"{"ts":1517644800}"#; |
2003 | | let got: Data = serde_json::from_str(&json).unwrap(); |
2004 | | assert_eq!(got.ts, Timestamp::from_second(1517644800).unwrap()); |
2005 | | assert_eq!(serde_json::to_string(&got).unwrap(), json); |
2006 | | } |
2007 | | |
2008 | | #[test] |
2009 | | fn timestamp_second_optional() { |
2010 | | #[derive(Debug, serde::Deserialize, serde::Serialize)] |
2011 | | struct Data { |
2012 | | #[serde(with = "crate::fmt::serde::timestamp::second::optional")] |
2013 | | ts: Option<Timestamp>, |
2014 | | } |
2015 | | |
2016 | | let json = r#"{"ts":1517644800}"#; |
2017 | | let got: Data = serde_json::from_str(&json).unwrap(); |
2018 | | assert_eq!(got.ts, Some(Timestamp::from_second(1517644800).unwrap())); |
2019 | | assert_eq!(serde_json::to_string(&got).unwrap(), json); |
2020 | | } |
2021 | | |
2022 | | #[test] |
2023 | | fn timestamp_millisecond_required() { |
2024 | | #[derive(Debug, serde::Deserialize, serde::Serialize)] |
2025 | | struct Data { |
2026 | | #[serde( |
2027 | | with = "crate::fmt::serde::timestamp::millisecond::required" |
2028 | | )] |
2029 | | ts: Timestamp, |
2030 | | } |
2031 | | |
2032 | | let json = r#"{"ts":1517644800000}"#; |
2033 | | let got: Data = serde_json::from_str(&json).unwrap(); |
2034 | | assert_eq!( |
2035 | | got.ts, |
2036 | | Timestamp::from_millisecond(1517644800_000).unwrap() |
2037 | | ); |
2038 | | assert_eq!(serde_json::to_string(&got).unwrap(), json); |
2039 | | |
2040 | | let json = r#"{"ts":1517644800123}"#; |
2041 | | let got: Data = serde_json::from_str(&json).unwrap(); |
2042 | | assert_eq!( |
2043 | | got.ts, |
2044 | | Timestamp::from_millisecond(1517644800_123).unwrap() |
2045 | | ); |
2046 | | assert_eq!(serde_json::to_string(&got).unwrap(), json); |
2047 | | } |
2048 | | |
2049 | | #[test] |
2050 | | fn timestamp_millisecond_optional() { |
2051 | | #[derive(Debug, serde::Deserialize, serde::Serialize)] |
2052 | | struct Data { |
2053 | | #[serde( |
2054 | | with = "crate::fmt::serde::timestamp::millisecond::optional" |
2055 | | )] |
2056 | | ts: Option<Timestamp>, |
2057 | | } |
2058 | | |
2059 | | let json = r#"{"ts":1517644800000}"#; |
2060 | | let got: Data = serde_json::from_str(&json).unwrap(); |
2061 | | assert_eq!( |
2062 | | got.ts, |
2063 | | Some(Timestamp::from_millisecond(1517644800_000).unwrap()) |
2064 | | ); |
2065 | | assert_eq!(serde_json::to_string(&got).unwrap(), json); |
2066 | | |
2067 | | let json = r#"{"ts":1517644800123}"#; |
2068 | | let got: Data = serde_json::from_str(&json).unwrap(); |
2069 | | assert_eq!( |
2070 | | got.ts, |
2071 | | Some(Timestamp::from_millisecond(1517644800_123).unwrap()) |
2072 | | ); |
2073 | | assert_eq!(serde_json::to_string(&got).unwrap(), json); |
2074 | | } |
2075 | | |
2076 | | #[test] |
2077 | | fn timestamp_microsecond_required() { |
2078 | | #[derive(Debug, serde::Deserialize, serde::Serialize)] |
2079 | | struct Data { |
2080 | | #[serde( |
2081 | | with = "crate::fmt::serde::timestamp::microsecond::required" |
2082 | | )] |
2083 | | ts: Timestamp, |
2084 | | } |
2085 | | |
2086 | | let json = r#"{"ts":1517644800000000}"#; |
2087 | | let got: Data = serde_json::from_str(&json).unwrap(); |
2088 | | assert_eq!( |
2089 | | got.ts, |
2090 | | Timestamp::from_microsecond(1517644800_000000).unwrap() |
2091 | | ); |
2092 | | assert_eq!(serde_json::to_string(&got).unwrap(), json); |
2093 | | |
2094 | | let json = r#"{"ts":1517644800123456}"#; |
2095 | | let got: Data = serde_json::from_str(&json).unwrap(); |
2096 | | assert_eq!( |
2097 | | got.ts, |
2098 | | Timestamp::from_microsecond(1517644800_123456).unwrap() |
2099 | | ); |
2100 | | assert_eq!(serde_json::to_string(&got).unwrap(), json); |
2101 | | } |
2102 | | |
2103 | | #[test] |
2104 | | fn timestamp_microsecond_optional() { |
2105 | | #[derive(Debug, serde::Deserialize, serde::Serialize)] |
2106 | | struct Data { |
2107 | | #[serde( |
2108 | | with = "crate::fmt::serde::timestamp::microsecond::optional" |
2109 | | )] |
2110 | | ts: Option<Timestamp>, |
2111 | | } |
2112 | | |
2113 | | let json = r#"{"ts":1517644800000000}"#; |
2114 | | let got: Data = serde_json::from_str(&json).unwrap(); |
2115 | | assert_eq!( |
2116 | | got.ts, |
2117 | | Some(Timestamp::from_microsecond(1517644800_000000).unwrap()) |
2118 | | ); |
2119 | | assert_eq!(serde_json::to_string(&got).unwrap(), json); |
2120 | | |
2121 | | let json = r#"{"ts":1517644800123456}"#; |
2122 | | let got: Data = serde_json::from_str(&json).unwrap(); |
2123 | | assert_eq!( |
2124 | | got.ts, |
2125 | | Some(Timestamp::from_microsecond(1517644800_123456).unwrap()) |
2126 | | ); |
2127 | | assert_eq!(serde_json::to_string(&got).unwrap(), json); |
2128 | | } |
2129 | | |
2130 | | #[test] |
2131 | | fn timestamp_nanosecond_required() { |
2132 | | #[derive(Debug, serde::Deserialize, serde::Serialize)] |
2133 | | struct Data { |
2134 | | #[serde( |
2135 | | with = "crate::fmt::serde::timestamp::nanosecond::required" |
2136 | | )] |
2137 | | ts: Timestamp, |
2138 | | } |
2139 | | |
2140 | | let json = r#"{"ts":1517644800000000000}"#; |
2141 | | let got: Data = serde_json::from_str(&json).unwrap(); |
2142 | | assert_eq!( |
2143 | | got.ts, |
2144 | | Timestamp::from_nanosecond(1517644800_000000000).unwrap() |
2145 | | ); |
2146 | | assert_eq!(serde_json::to_string(&got).unwrap(), json); |
2147 | | |
2148 | | let json = r#"{"ts":1517644800123456789}"#; |
2149 | | let got: Data = serde_json::from_str(&json).unwrap(); |
2150 | | assert_eq!( |
2151 | | got.ts, |
2152 | | Timestamp::from_nanosecond(1517644800_123456789).unwrap() |
2153 | | ); |
2154 | | assert_eq!(serde_json::to_string(&got).unwrap(), json); |
2155 | | } |
2156 | | |
2157 | | #[test] |
2158 | | fn timestamp_nanosecond_optional() { |
2159 | | #[derive(Debug, serde::Deserialize, serde::Serialize)] |
2160 | | struct Data { |
2161 | | #[serde( |
2162 | | with = "crate::fmt::serde::timestamp::nanosecond::optional" |
2163 | | )] |
2164 | | ts: Option<Timestamp>, |
2165 | | } |
2166 | | |
2167 | | let json = r#"{"ts":1517644800000000000}"#; |
2168 | | let got: Data = serde_json::from_str(&json).unwrap(); |
2169 | | assert_eq!( |
2170 | | got.ts, |
2171 | | Some(Timestamp::from_nanosecond(1517644800_000000000).unwrap()) |
2172 | | ); |
2173 | | assert_eq!(serde_json::to_string(&got).unwrap(), json); |
2174 | | |
2175 | | let json = r#"{"ts":1517644800123456789}"#; |
2176 | | let got: Data = serde_json::from_str(&json).unwrap(); |
2177 | | assert_eq!( |
2178 | | got.ts, |
2179 | | Some(Timestamp::from_nanosecond(1517644800_123456789).unwrap()) |
2180 | | ); |
2181 | | assert_eq!(serde_json::to_string(&got).unwrap(), json); |
2182 | | } |
2183 | | } |