Coverage Report

Created: 2026-03-17 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/jiff-0.2.17/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
        let Some((&byte, tail)) = bytes.split_first() else {
1782
0
            return Err(crate::Error::from(
1783
0
                crate::error::fmt::Error::HybridDurationEmpty,
1784
0
            ));
1785
        };
1786
0
        let mut first = byte;
1787
        // N.B. Unsigned durations don't support negative durations (of
1788
        // course), but we still check for it here so that we can defer to
1789
        // the dedicated parsers. They will provide their own error messages.
1790
0
        if first == b'+' || first == b'-' {
1791
0
            let Some(&byte) = tail.first() else {
1792
0
                return Err(crate::Error::from(
1793
0
                    crate::error::fmt::Error::HybridDurationPrefix {
1794
0
                        sign: first,
1795
0
                    },
1796
0
                ));
1797
            };
1798
0
            first = byte;
1799
0
        }
1800
0
        let dur = if first == b'P' || first == b'p' {
1801
0
            crate::fmt::temporal::DEFAULT_SPAN_PARSER
1802
0
                .parse_unsigned_duration(bytes)
1803
        } else {
1804
0
            crate::fmt::friendly::DEFAULT_SPAN_PARSER
1805
0
                .parse_unsigned_duration(bytes)
1806
0
        }?;
1807
0
        Ok(dur)
1808
0
    }
1809
}
1810
1811
#[cfg(test)]
1812
mod tests {
1813
    use crate::{
1814
        span::span_eq, SignedDuration, Span, SpanFieldwise, Timestamp, ToSpan,
1815
    };
1816
    use core::time::Duration as UnsignedDuration;
1817
1818
    #[test]
1819
    fn duration_friendly_compact_required() {
1820
        #[derive(Debug, serde::Deserialize, serde::Serialize)]
1821
        struct Data {
1822
            #[serde(
1823
                serialize_with = "crate::fmt::serde::duration::friendly::compact::required"
1824
            )]
1825
            duration: SignedDuration,
1826
        }
1827
1828
        let json = r#"{"duration":"36 hours 1100ms"}"#;
1829
        let got: Data = serde_json::from_str(&json).unwrap();
1830
        assert_eq!(
1831
            got.duration,
1832
            SignedDuration::new(36 * 60 * 60 + 1, 100_000_000)
1833
        );
1834
1835
        let expected = r#"{"duration":"36h 1s 100ms"}"#;
1836
        assert_eq!(serde_json::to_string(&got).unwrap(), expected);
1837
    }
1838
1839
    #[test]
1840
    fn duration_friendly_compact_optional() {
1841
        #[derive(Debug, serde::Deserialize, serde::Serialize)]
1842
        struct Data {
1843
            #[serde(
1844
                serialize_with = "crate::fmt::serde::duration::friendly::compact::optional"
1845
            )]
1846
            duration: Option<SignedDuration>,
1847
        }
1848
1849
        let json = r#"{"duration":"36 hours 1100ms"}"#;
1850
        let got: Data = serde_json::from_str(&json).unwrap();
1851
        assert_eq!(
1852
            got.duration,
1853
            Some(SignedDuration::new(36 * 60 * 60 + 1, 100_000_000))
1854
        );
1855
1856
        let expected = r#"{"duration":"36h 1s 100ms"}"#;
1857
        assert_eq!(serde_json::to_string(&got).unwrap(), expected);
1858
    }
1859
1860
    #[test]
1861
    fn unsigned_duration_required() {
1862
        #[derive(Debug, serde::Deserialize, serde::Serialize)]
1863
        struct Data {
1864
            #[serde(with = "crate::fmt::serde::unsigned_duration::required")]
1865
            duration: UnsignedDuration,
1866
        }
1867
1868
        let json = r#"{"duration":"PT36H1.1S"}"#;
1869
        let got: Data = serde_json::from_str(&json).unwrap();
1870
        assert_eq!(
1871
            got.duration,
1872
            UnsignedDuration::new(36 * 60 * 60 + 1, 100_000_000)
1873
        );
1874
        assert_eq!(serde_json::to_string(&got).unwrap(), json);
1875
1876
        // Check that we can parse a number of seconds that exceeds
1877
        // `i64::MAX`. In this case, precisely `u64::MAX`.
1878
        let json = r#"{"duration":"PT18446744073709551615S"}"#;
1879
        let got: Data = serde_json::from_str(&json).unwrap();
1880
        assert_eq!(
1881
            got.duration,
1882
            UnsignedDuration::new(18446744073709551615, 0)
1883
        );
1884
        // Printing ISO 8601 durations balances up to hours, so
1885
        // it won't match the one we parsed. But the actual duration
1886
        // value is equivalent.
1887
        let expected = r#"{"duration":"PT5124095576030431H15S"}"#;
1888
        assert_eq!(serde_json::to_string(&got).unwrap(), expected);
1889
    }
1890
1891
    #[test]
1892
    fn unsigned_duration_optional() {
1893
        #[derive(Debug, serde::Deserialize, serde::Serialize)]
1894
        struct Data {
1895
            #[serde(with = "crate::fmt::serde::unsigned_duration::optional")]
1896
            duration: Option<UnsignedDuration>,
1897
        }
1898
1899
        let json = r#"{"duration":"PT36H1.1S"}"#;
1900
        let got: Data = serde_json::from_str(&json).unwrap();
1901
        assert_eq!(
1902
            got.duration,
1903
            Some(UnsignedDuration::new(36 * 60 * 60 + 1, 100_000_000))
1904
        );
1905
        assert_eq!(serde_json::to_string(&got).unwrap(), json);
1906
1907
        let json = r#"{"duration":null}"#;
1908
        let got: Data = serde_json::from_str(&json).unwrap();
1909
        assert_eq!(got.duration, None,);
1910
        assert_eq!(serde_json::to_string(&got).unwrap(), json);
1911
    }
1912
1913
    #[test]
1914
    fn unsigned_duration_compact_required() {
1915
        #[derive(Debug, serde::Deserialize, serde::Serialize)]
1916
        struct Data {
1917
            #[serde(
1918
                with = "crate::fmt::serde::unsigned_duration::friendly::compact::required"
1919
            )]
1920
            duration: UnsignedDuration,
1921
        }
1922
1923
        let json = r#"{"duration":"36h 1s 100ms"}"#;
1924
        let got: Data = serde_json::from_str(&json).unwrap();
1925
        assert_eq!(
1926
            got.duration,
1927
            UnsignedDuration::new(36 * 60 * 60 + 1, 100_000_000)
1928
        );
1929
        assert_eq!(serde_json::to_string(&got).unwrap(), json);
1930
    }
1931
1932
    #[test]
1933
    fn unsigned_duration_compact_optional() {
1934
        #[derive(Debug, serde::Deserialize, serde::Serialize)]
1935
        struct Data {
1936
            #[serde(
1937
                with = "crate::fmt::serde::unsigned_duration::friendly::compact::optional"
1938
            )]
1939
            duration: Option<UnsignedDuration>,
1940
        }
1941
1942
        let json = r#"{"duration":"36h 1s 100ms"}"#;
1943
        let got: Data = serde_json::from_str(&json).unwrap();
1944
        assert_eq!(
1945
            got.duration,
1946
            Some(UnsignedDuration::new(36 * 60 * 60 + 1, 100_000_000))
1947
        );
1948
        assert_eq!(serde_json::to_string(&got).unwrap(), json);
1949
    }
1950
1951
    #[test]
1952
    fn span_friendly_compact_required() {
1953
        #[derive(Debug, serde::Deserialize, serde::Serialize)]
1954
        struct Data {
1955
            #[serde(
1956
                serialize_with = "crate::fmt::serde::span::friendly::compact::required"
1957
            )]
1958
            span: Span,
1959
        }
1960
1961
        let json = r#"{"span":"1 year 2 months 36 hours 1100ms"}"#;
1962
        let got: Data = serde_json::from_str(&json).unwrap();
1963
        span_eq!(got.span, 1.year().months(2).hours(36).milliseconds(1100));
1964
1965
        let expected = r#"{"span":"1y 2mo 36h 1100ms"}"#;
1966
        assert_eq!(serde_json::to_string(&got).unwrap(), expected);
1967
    }
1968
1969
    #[test]
1970
    fn span_friendly_compact_optional() {
1971
        #[derive(Debug, serde::Deserialize, serde::Serialize)]
1972
        struct Data {
1973
            #[serde(
1974
                serialize_with = "crate::fmt::serde::span::friendly::compact::optional"
1975
            )]
1976
            span: Option<Span>,
1977
        }
1978
1979
        let json = r#"{"span":"1 year 2 months 36 hours 1100ms"}"#;
1980
        let got: Data = serde_json::from_str(&json).unwrap();
1981
        assert_eq!(
1982
            got.span.map(SpanFieldwise),
1983
            Some(1.year().months(2).hours(36).milliseconds(1100).fieldwise())
1984
        );
1985
1986
        let expected = r#"{"span":"1y 2mo 36h 1100ms"}"#;
1987
        assert_eq!(serde_json::to_string(&got).unwrap(), expected);
1988
    }
1989
1990
    #[test]
1991
    fn timestamp_second_required() {
1992
        #[derive(Debug, serde::Deserialize, serde::Serialize)]
1993
        struct Data {
1994
            #[serde(with = "crate::fmt::serde::timestamp::second::required")]
1995
            ts: Timestamp,
1996
        }
1997
1998
        let json = r#"{"ts":1517644800}"#;
1999
        let got: Data = serde_json::from_str(&json).unwrap();
2000
        assert_eq!(got.ts, Timestamp::from_second(1517644800).unwrap());
2001
        assert_eq!(serde_json::to_string(&got).unwrap(), json);
2002
    }
2003
2004
    #[test]
2005
    fn timestamp_second_optional() {
2006
        #[derive(Debug, serde::Deserialize, serde::Serialize)]
2007
        struct Data {
2008
            #[serde(with = "crate::fmt::serde::timestamp::second::optional")]
2009
            ts: Option<Timestamp>,
2010
        }
2011
2012
        let json = r#"{"ts":1517644800}"#;
2013
        let got: Data = serde_json::from_str(&json).unwrap();
2014
        assert_eq!(got.ts, Some(Timestamp::from_second(1517644800).unwrap()));
2015
        assert_eq!(serde_json::to_string(&got).unwrap(), json);
2016
    }
2017
2018
    #[test]
2019
    fn timestamp_millisecond_required() {
2020
        #[derive(Debug, serde::Deserialize, serde::Serialize)]
2021
        struct Data {
2022
            #[serde(
2023
                with = "crate::fmt::serde::timestamp::millisecond::required"
2024
            )]
2025
            ts: Timestamp,
2026
        }
2027
2028
        let json = r#"{"ts":1517644800000}"#;
2029
        let got: Data = serde_json::from_str(&json).unwrap();
2030
        assert_eq!(
2031
            got.ts,
2032
            Timestamp::from_millisecond(1517644800_000).unwrap()
2033
        );
2034
        assert_eq!(serde_json::to_string(&got).unwrap(), json);
2035
2036
        let json = r#"{"ts":1517644800123}"#;
2037
        let got: Data = serde_json::from_str(&json).unwrap();
2038
        assert_eq!(
2039
            got.ts,
2040
            Timestamp::from_millisecond(1517644800_123).unwrap()
2041
        );
2042
        assert_eq!(serde_json::to_string(&got).unwrap(), json);
2043
    }
2044
2045
    #[test]
2046
    fn timestamp_millisecond_optional() {
2047
        #[derive(Debug, serde::Deserialize, serde::Serialize)]
2048
        struct Data {
2049
            #[serde(
2050
                with = "crate::fmt::serde::timestamp::millisecond::optional"
2051
            )]
2052
            ts: Option<Timestamp>,
2053
        }
2054
2055
        let json = r#"{"ts":1517644800000}"#;
2056
        let got: Data = serde_json::from_str(&json).unwrap();
2057
        assert_eq!(
2058
            got.ts,
2059
            Some(Timestamp::from_millisecond(1517644800_000).unwrap())
2060
        );
2061
        assert_eq!(serde_json::to_string(&got).unwrap(), json);
2062
2063
        let json = r#"{"ts":1517644800123}"#;
2064
        let got: Data = serde_json::from_str(&json).unwrap();
2065
        assert_eq!(
2066
            got.ts,
2067
            Some(Timestamp::from_millisecond(1517644800_123).unwrap())
2068
        );
2069
        assert_eq!(serde_json::to_string(&got).unwrap(), json);
2070
    }
2071
2072
    #[test]
2073
    fn timestamp_microsecond_required() {
2074
        #[derive(Debug, serde::Deserialize, serde::Serialize)]
2075
        struct Data {
2076
            #[serde(
2077
                with = "crate::fmt::serde::timestamp::microsecond::required"
2078
            )]
2079
            ts: Timestamp,
2080
        }
2081
2082
        let json = r#"{"ts":1517644800000000}"#;
2083
        let got: Data = serde_json::from_str(&json).unwrap();
2084
        assert_eq!(
2085
            got.ts,
2086
            Timestamp::from_microsecond(1517644800_000000).unwrap()
2087
        );
2088
        assert_eq!(serde_json::to_string(&got).unwrap(), json);
2089
2090
        let json = r#"{"ts":1517644800123456}"#;
2091
        let got: Data = serde_json::from_str(&json).unwrap();
2092
        assert_eq!(
2093
            got.ts,
2094
            Timestamp::from_microsecond(1517644800_123456).unwrap()
2095
        );
2096
        assert_eq!(serde_json::to_string(&got).unwrap(), json);
2097
    }
2098
2099
    #[test]
2100
    fn timestamp_microsecond_optional() {
2101
        #[derive(Debug, serde::Deserialize, serde::Serialize)]
2102
        struct Data {
2103
            #[serde(
2104
                with = "crate::fmt::serde::timestamp::microsecond::optional"
2105
            )]
2106
            ts: Option<Timestamp>,
2107
        }
2108
2109
        let json = r#"{"ts":1517644800000000}"#;
2110
        let got: Data = serde_json::from_str(&json).unwrap();
2111
        assert_eq!(
2112
            got.ts,
2113
            Some(Timestamp::from_microsecond(1517644800_000000).unwrap())
2114
        );
2115
        assert_eq!(serde_json::to_string(&got).unwrap(), json);
2116
2117
        let json = r#"{"ts":1517644800123456}"#;
2118
        let got: Data = serde_json::from_str(&json).unwrap();
2119
        assert_eq!(
2120
            got.ts,
2121
            Some(Timestamp::from_microsecond(1517644800_123456).unwrap())
2122
        );
2123
        assert_eq!(serde_json::to_string(&got).unwrap(), json);
2124
    }
2125
2126
    #[test]
2127
    fn timestamp_nanosecond_required() {
2128
        #[derive(Debug, serde::Deserialize, serde::Serialize)]
2129
        struct Data {
2130
            #[serde(
2131
                with = "crate::fmt::serde::timestamp::nanosecond::required"
2132
            )]
2133
            ts: Timestamp,
2134
        }
2135
2136
        let json = r#"{"ts":1517644800000000000}"#;
2137
        let got: Data = serde_json::from_str(&json).unwrap();
2138
        assert_eq!(
2139
            got.ts,
2140
            Timestamp::from_nanosecond(1517644800_000000000).unwrap()
2141
        );
2142
        assert_eq!(serde_json::to_string(&got).unwrap(), json);
2143
2144
        let json = r#"{"ts":1517644800123456789}"#;
2145
        let got: Data = serde_json::from_str(&json).unwrap();
2146
        assert_eq!(
2147
            got.ts,
2148
            Timestamp::from_nanosecond(1517644800_123456789).unwrap()
2149
        );
2150
        assert_eq!(serde_json::to_string(&got).unwrap(), json);
2151
    }
2152
2153
    #[test]
2154
    fn timestamp_nanosecond_optional() {
2155
        #[derive(Debug, serde::Deserialize, serde::Serialize)]
2156
        struct Data {
2157
            #[serde(
2158
                with = "crate::fmt::serde::timestamp::nanosecond::optional"
2159
            )]
2160
            ts: Option<Timestamp>,
2161
        }
2162
2163
        let json = r#"{"ts":1517644800000000000}"#;
2164
        let got: Data = serde_json::from_str(&json).unwrap();
2165
        assert_eq!(
2166
            got.ts,
2167
            Some(Timestamp::from_nanosecond(1517644800_000000000).unwrap())
2168
        );
2169
        assert_eq!(serde_json::to_string(&got).unwrap(), json);
2170
2171
        let json = r#"{"ts":1517644800123456789}"#;
2172
        let got: Data = serde_json::from_str(&json).unwrap();
2173
        assert_eq!(
2174
            got.ts,
2175
            Some(Timestamp::from_nanosecond(1517644800_123456789).unwrap())
2176
        );
2177
        assert_eq!(serde_json::to_string(&got).unwrap(), json);
2178
    }
2179
}