Coverage Report

Created: 2025-12-31 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}