jiff/fmt/
serde.rs

1/*!
2This module provides helpers to use with [Serde].
3
4Some helpers, like those for `Timestamp`, are exposed as modules meant
5to 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
11The available helpers can be more quickly understood by looking at a fully
12rendered tree of this module's hierarchy. Only the leaves of the tree are
13usable with Serde's attributes. For each leaf, the full path is spelled out for
14easy 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
52This example shows how to deserialize an integer number of seconds since the
53Unix epoch into a [`Timestamp`](crate::Timestamp). And the reverse operation
54for serialization:
55
56```
57use jiff::Timestamp;
58
59#[derive(Debug, serde::Deserialize, serde::Serialize)]
60struct Record {
61    #[serde(with = "jiff::fmt::serde::timestamp::second::required")]
62    timestamp: Timestamp,
63}
64
65let json = r#"{"timestamp":1517644800}"#;
66let got: Record = serde_json::from_str(&json)?;
67assert_eq!(got.timestamp, Timestamp::from_second(1517644800)?);
68assert_eq!(serde_json::to_string(&got)?, json);
69
70# Ok::<(), Box<dyn std::error::Error>>(())
71```
72
73# Example: optional timestamp support
74
75And 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```
80use jiff::Timestamp;
81
82#[derive(Debug, serde::Deserialize, serde::Serialize)]
83struct Record {
84    #[serde(with = "jiff::fmt::serde::timestamp::millisecond::optional")]
85    timestamp: Option<Timestamp>,
86}
87
88let json = r#"{"timestamp":1517644800123}"#;
89let got: Record = serde_json::from_str(&json)?;
90assert_eq!(got.timestamp, Some(Timestamp::from_millisecond(1517644800_123)?));
91assert_eq!(serde_json::to_string(&got)?, json);
92
93# Ok::<(), Box<dyn std::error::Error>>(())
94```
95
96# Example: the "friendly" duration format
97
98The [`Span`](crate::Span) and [`SignedDuration`](crate::SignedDuration) types
99in 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
102the ["friendly" duration format] simultaneously. In order to serialize either
103type in the "friendly" format, you can either define your own serialization
104functions or use one of the convenience routines provided by this module. For
105example:
106
107```
108use jiff::{ToSpan, Span};
109
110#[derive(Debug, serde::Deserialize, serde::Serialize)]
111struct Record {
112    #[serde(
113        serialize_with = "jiff::fmt::serde::span::friendly::compact::required"
114    )]
115    span: Span,
116}
117
118let json = r#"{"span":"1 year 2 months 36 hours 1100ms"}"#;
119let got: Record = serde_json::from_str(&json)?;
120assert_eq!(
121    got.span,
122    1.year().months(2).hours(36).milliseconds(1100).fieldwise(),
123);
124
125let expected = r#"{"span":"1y 2mo 36h 1100ms"}"#;
126assert_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.
225pub 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                fn fmt(
239                    &self,
240                    f: &mut core::fmt::Formatter,
241                ) -> core::fmt::Result {
242                    static PRINTER: friendly::SpanPrinter =
243                        friendly::SpanPrinter::new()
244                            .designator(friendly::Designator::Compact);
245                    PRINTER
246                        .print_duration(self.0, StdFmtWrite(f))
247                        .map_err(|_| core::fmt::Error)
248                }
249            }
250
251            /// Serialize a required `SignedDuration` in the [`friendly`]
252            /// duration format using compact designators.
253            #[inline]
254            pub fn required<S: serde_core::Serializer>(
255                duration: &crate::SignedDuration,
256                se: S,
257            ) -> Result<S::Ok, S::Error> {
258                se.collect_str(&CompactDuration(duration))
259            }
260
261            /// Serialize an optional `SignedDuration` in the [`friendly`]
262            /// duration format using compact designators.
263            #[inline]
264            pub fn optional<S: serde_core::Serializer>(
265                duration: &Option<crate::SignedDuration>,
266                se: S,
267            ) -> Result<S::Ok, S::Error> {
268                match *duration {
269                    None => se.serialize_none(),
270                    Some(ref duration) => required(duration, se),
271                }
272            }
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.
370pub 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                fn fmt(
383                    &self,
384                    f: &mut core::fmt::Formatter,
385                ) -> core::fmt::Result {
386                    static PRINTER: friendly::SpanPrinter =
387                        friendly::SpanPrinter::new()
388                            .designator(friendly::Designator::Compact);
389                    PRINTER
390                        .print_span(self.0, StdFmtWrite(f))
391                        .map_err(|_| core::fmt::Error)
392                }
393            }
394
395            /// Serialize a required `Span` in the [`friendly`] duration format
396            /// using compact designators.
397            #[inline]
398            pub fn required<S: serde_core::Serializer>(
399                span: &crate::Span,
400                se: S,
401            ) -> Result<S::Ok, S::Error> {
402                se.collect_str(&CompactSpan(span))
403            }
404
405            /// Serialize an optional `Span` in the [`friendly`] duration
406            /// format using compact designators.
407            #[inline]
408            pub fn optional<S: serde_core::Serializer>(
409                span: &Option<crate::Span>,
410                se: S,
411            ) -> Result<S::Ok, S::Error> {
412                match *span {
413                    None => se.serialize_none(),
414                    Some(ref span) => required(span, se),
415                }
416            }
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.)
437pub 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        fn expecting(
449            &self,
450            f: &mut core::fmt::Formatter,
451        ) -> core::fmt::Result {
452            f.write_str(
453                "an integer number of seconds from the Unix epoch or `None`",
454            )
455        }
456
457        #[inline]
458        fn visit_some<D: de::Deserializer<'de>>(
459            self,
460            de: D,
461        ) -> Result<Option<crate::Timestamp>, D::Error> {
462            de.deserialize_i64(self.0).map(Some)
463        }
464
465        #[inline]
466        fn visit_none<E: de::Error>(
467            self,
468        ) -> Result<Option<crate::Timestamp>, E> {
469            Ok(None)
470        }
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            fn expecting(
483                &self,
484                f: &mut core::fmt::Formatter,
485            ) -> core::fmt::Result {
486                f.write_str("an integer number of seconds from the Unix epoch")
487            }
488
489            #[inline]
490            fn visit_i8<E: de::Error>(
491                self,
492                v: i8,
493            ) -> Result<crate::Timestamp, E> {
494                self.visit_i64(i64::from(v))
495            }
496
497            #[inline]
498            fn visit_u8<E: de::Error>(
499                self,
500                v: u8,
501            ) -> Result<crate::Timestamp, E> {
502                self.visit_i64(i64::from(v))
503            }
504
505            #[inline]
506            fn visit_i16<E: de::Error>(
507                self,
508                v: i16,
509            ) -> Result<crate::Timestamp, E> {
510                self.visit_i64(i64::from(v))
511            }
512
513            #[inline]
514            fn visit_u16<E: de::Error>(
515                self,
516                v: u16,
517            ) -> Result<crate::Timestamp, E> {
518                self.visit_i64(i64::from(v))
519            }
520
521            #[inline]
522            fn visit_i32<E: de::Error>(
523                self,
524                v: i32,
525            ) -> Result<crate::Timestamp, E> {
526                self.visit_i64(i64::from(v))
527            }
528
529            #[inline]
530            fn visit_u32<E: de::Error>(
531                self,
532                v: u32,
533            ) -> Result<crate::Timestamp, E> {
534                self.visit_i64(i64::from(v))
535            }
536
537            #[inline]
538            fn visit_i64<E: de::Error>(
539                self,
540                v: i64,
541            ) -> Result<crate::Timestamp, E> {
542                crate::Timestamp::from_second(v).map_err(de::Error::custom)
543            }
544
545            #[inline]
546            fn visit_u64<E: de::Error>(
547                self,
548                v: u64,
549            ) -> Result<crate::Timestamp, E> {
550                let v = i64::try_from(v).map_err(|_| {
551                    de::Error::custom(format_args!(
552                        "got unsigned integer {v} seconds, \
553                         which is too big to fit in a Jiff `Timestamp`",
554                    ))
555                })?;
556                self.visit_i64(v)
557            }
558
559            #[inline]
560            fn visit_i128<E: de::Error>(
561                self,
562                v: i128,
563            ) -> Result<crate::Timestamp, E> {
564                let v = i64::try_from(v).map_err(|_| {
565                    de::Error::custom(format_args!(
566                        "got signed integer {v} seconds, \
567                         which is too big to fit in a Jiff `Timestamp`",
568                    ))
569                })?;
570                self.visit_i64(v)
571            }
572
573            #[inline]
574            fn visit_u128<E: de::Error>(
575                self,
576                v: u128,
577            ) -> Result<crate::Timestamp, E> {
578                let v = i64::try_from(v).map_err(|_| {
579                    de::Error::custom(format_args!(
580                        "got unsigned integer {v} seconds, \
581                         which is too big to fit in a Jiff `Timestamp`",
582                    ))
583                })?;
584                self.visit_i64(v)
585            }
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            pub fn serialize<S: serde_core::Serializer>(
595                timestamp: &crate::Timestamp,
596                se: S,
597            ) -> Result<S::Ok, S::Error> {
598                se.serialize_i64(timestamp.as_second())
599            }
600
601            /// Deserialize a required integer number of seconds since the
602            /// Unix epoch.
603            #[inline]
604            pub fn deserialize<'de, D: serde_core::Deserializer<'de>>(
605                de: D,
606            ) -> Result<crate::Timestamp, D::Error> {
607                de.deserialize_i64(super::Visitor)
608            }
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            pub fn serialize<S: serde_core::Serializer>(
618                timestamp: &Option<crate::Timestamp>,
619                se: S,
620            ) -> Result<S::Ok, S::Error> {
621                match *timestamp {
622                    None => se.serialize_none(),
623                    Some(ref ts) => super::required::serialize(ts, se),
624                }
625            }
626
627            /// Deserialize an optional integer number of seconds since the
628            /// Unix epoch.
629            #[inline]
630            pub fn deserialize<'de, D: serde_core::Deserializer<'de>>(
631                de: D,
632            ) -> Result<Option<crate::Timestamp>, D::Error> {
633                de.deserialize_option(super::super::OptionalVisitor(
634                    super::Visitor,
635                ))
636            }
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            fn expecting(
650                &self,
651                f: &mut core::fmt::Formatter,
652            ) -> core::fmt::Result {
653                f.write_str(
654                    "an integer number of milliseconds from the Unix epoch",
655                )
656            }
657
658            #[inline]
659            fn visit_i8<E: de::Error>(
660                self,
661                v: i8,
662            ) -> Result<crate::Timestamp, E> {
663                self.visit_i64(i64::from(v))
664            }
665
666            #[inline]
667            fn visit_u8<E: de::Error>(
668                self,
669                v: u8,
670            ) -> Result<crate::Timestamp, E> {
671                self.visit_i64(i64::from(v))
672            }
673
674            #[inline]
675            fn visit_i16<E: de::Error>(
676                self,
677                v: i16,
678            ) -> Result<crate::Timestamp, E> {
679                self.visit_i64(i64::from(v))
680            }
681
682            #[inline]
683            fn visit_u16<E: de::Error>(
684                self,
685                v: u16,
686            ) -> Result<crate::Timestamp, E> {
687                self.visit_i64(i64::from(v))
688            }
689
690            #[inline]
691            fn visit_i32<E: de::Error>(
692                self,
693                v: i32,
694            ) -> Result<crate::Timestamp, E> {
695                self.visit_i64(i64::from(v))
696            }
697
698            #[inline]
699            fn visit_u32<E: de::Error>(
700                self,
701                v: u32,
702            ) -> Result<crate::Timestamp, E> {
703                self.visit_i64(i64::from(v))
704            }
705
706            #[inline]
707            fn visit_i64<E: de::Error>(
708                self,
709                v: i64,
710            ) -> Result<crate::Timestamp, E> {
711                crate::Timestamp::from_millisecond(v)
712                    .map_err(de::Error::custom)
713            }
714
715            #[inline]
716            fn visit_u64<E: de::Error>(
717                self,
718                v: u64,
719            ) -> Result<crate::Timestamp, E> {
720                let v = i64::try_from(v).map_err(|_| {
721                    de::Error::custom(format_args!(
722                        "got unsigned integer {v} milliseconds, \
723                         which is too big to fit in a Jiff `Timestamp`",
724                    ))
725                })?;
726                self.visit_i64(v)
727            }
728
729            #[inline]
730            fn visit_i128<E: de::Error>(
731                self,
732                v: i128,
733            ) -> Result<crate::Timestamp, E> {
734                let v = i64::try_from(v).map_err(|_| {
735                    de::Error::custom(format_args!(
736                        "got signed integer {v} milliseconds, \
737                         which is too big to fit in a Jiff `Timestamp`",
738                    ))
739                })?;
740                self.visit_i64(v)
741            }
742
743            #[inline]
744            fn visit_u128<E: de::Error>(
745                self,
746                v: u128,
747            ) -> Result<crate::Timestamp, E> {
748                let v = i64::try_from(v).map_err(|_| {
749                    de::Error::custom(format_args!(
750                        "got unsigned integer {v} milliseconds, \
751                         which is too big to fit in a Jiff `Timestamp`",
752                    ))
753                })?;
754                self.visit_i64(v)
755            }
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            pub fn serialize<S: serde_core::Serializer>(
765                timestamp: &crate::Timestamp,
766                se: S,
767            ) -> Result<S::Ok, S::Error> {
768                se.serialize_i64(timestamp.as_millisecond())
769            }
770
771            /// Deserialize a required integer number of milliseconds since the
772            /// Unix epoch.
773            #[inline]
774            pub fn deserialize<'de, D: serde_core::Deserializer<'de>>(
775                de: D,
776            ) -> Result<crate::Timestamp, D::Error> {
777                de.deserialize_i64(super::Visitor)
778            }
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            pub fn serialize<S: serde_core::Serializer>(
788                timestamp: &Option<crate::Timestamp>,
789                se: S,
790            ) -> Result<S::Ok, S::Error> {
791                match *timestamp {
792                    None => se.serialize_none(),
793                    Some(ref ts) => super::required::serialize(ts, se),
794                }
795            }
796
797            /// Deserialize an optional integer number of milliseconds since
798            /// the Unix epoch.
799            #[inline]
800            pub fn deserialize<'de, D: serde_core::Deserializer<'de>>(
801                de: D,
802            ) -> Result<Option<crate::Timestamp>, D::Error> {
803                de.deserialize_option(super::super::OptionalVisitor(
804                    super::Visitor,
805                ))
806            }
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            fn expecting(
820                &self,
821                f: &mut core::fmt::Formatter,
822            ) -> core::fmt::Result {
823                f.write_str(
824                    "an integer number of microseconds from the Unix epoch",
825                )
826            }
827
828            #[inline]
829            fn visit_i8<E: de::Error>(
830                self,
831                v: i8,
832            ) -> Result<crate::Timestamp, E> {
833                self.visit_i64(i64::from(v))
834            }
835
836            #[inline]
837            fn visit_u8<E: de::Error>(
838                self,
839                v: u8,
840            ) -> Result<crate::Timestamp, E> {
841                self.visit_i64(i64::from(v))
842            }
843
844            #[inline]
845            fn visit_i16<E: de::Error>(
846                self,
847                v: i16,
848            ) -> Result<crate::Timestamp, E> {
849                self.visit_i64(i64::from(v))
850            }
851
852            #[inline]
853            fn visit_u16<E: de::Error>(
854                self,
855                v: u16,
856            ) -> Result<crate::Timestamp, E> {
857                self.visit_i64(i64::from(v))
858            }
859
860            #[inline]
861            fn visit_i32<E: de::Error>(
862                self,
863                v: i32,
864            ) -> Result<crate::Timestamp, E> {
865                self.visit_i64(i64::from(v))
866            }
867
868            #[inline]
869            fn visit_u32<E: de::Error>(
870                self,
871                v: u32,
872            ) -> Result<crate::Timestamp, E> {
873                self.visit_i64(i64::from(v))
874            }
875
876            #[inline]
877            fn visit_i64<E: de::Error>(
878                self,
879                v: i64,
880            ) -> Result<crate::Timestamp, E> {
881                crate::Timestamp::from_microsecond(v)
882                    .map_err(de::Error::custom)
883            }
884
885            #[inline]
886            fn visit_u64<E: de::Error>(
887                self,
888                v: u64,
889            ) -> Result<crate::Timestamp, E> {
890                let v = i64::try_from(v).map_err(|_| {
891                    de::Error::custom(format_args!(
892                        "got unsigned integer {v} microseconds, \
893                         which is too big to fit in a Jiff `Timestamp`",
894                    ))
895                })?;
896                self.visit_i64(v)
897            }
898
899            #[inline]
900            fn visit_i128<E: de::Error>(
901                self,
902                v: i128,
903            ) -> Result<crate::Timestamp, E> {
904                let v = i64::try_from(v).map_err(|_| {
905                    de::Error::custom(format_args!(
906                        "got signed integer {v} microseconds, \
907                         which is too big to fit in a Jiff `Timestamp`",
908                    ))
909                })?;
910                self.visit_i64(v)
911            }
912
913            #[inline]
914            fn visit_u128<E: de::Error>(
915                self,
916                v: u128,
917            ) -> Result<crate::Timestamp, E> {
918                let v = i64::try_from(v).map_err(|_| {
919                    de::Error::custom(format_args!(
920                        "got unsigned integer {v} microseconds, \
921                         which is too big to fit in a Jiff `Timestamp`",
922                    ))
923                })?;
924                self.visit_i64(v)
925            }
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            pub fn serialize<S: serde_core::Serializer>(
935                timestamp: &crate::Timestamp,
936                se: S,
937            ) -> Result<S::Ok, S::Error> {
938                se.serialize_i64(timestamp.as_microsecond())
939            }
940
941            /// Deserialize a required integer number of microseconds since the
942            /// Unix epoch.
943            #[inline]
944            pub fn deserialize<'de, D: serde_core::Deserializer<'de>>(
945                de: D,
946            ) -> Result<crate::Timestamp, D::Error> {
947                de.deserialize_i64(super::Visitor)
948            }
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            pub fn serialize<S: serde_core::Serializer>(
958                timestamp: &Option<crate::Timestamp>,
959                se: S,
960            ) -> Result<S::Ok, S::Error> {
961                match *timestamp {
962                    None => se.serialize_none(),
963                    Some(ref ts) => super::required::serialize(ts, se),
964                }
965            }
966
967            /// Deserialize an optional integer number of microseconds since
968            /// the Unix epoch.
969            #[inline]
970            pub fn deserialize<'de, D: serde_core::Deserializer<'de>>(
971                de: D,
972            ) -> Result<Option<crate::Timestamp>, D::Error> {
973                de.deserialize_option(super::super::OptionalVisitor(
974                    super::Visitor,
975                ))
976            }
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            fn expecting(
990                &self,
991                f: &mut core::fmt::Formatter,
992            ) -> core::fmt::Result {
993                f.write_str(
994                    "an integer number of nanoseconds from the Unix epoch",
995                )
996            }
997
998            #[inline]
999            fn visit_i64<E: de::Error>(
1000                self,
1001                v: i64,
1002            ) -> Result<crate::Timestamp, E> {
1003                self.visit_i128(i128::from(v))
1004            }
1005
1006            #[inline]
1007            fn visit_u64<E: de::Error>(
1008                self,
1009                v: u64,
1010            ) -> Result<crate::Timestamp, E> {
1011                self.visit_u128(u128::from(v))
1012            }
1013
1014            #[inline]
1015            fn visit_i128<E: de::Error>(
1016                self,
1017                v: i128,
1018            ) -> Result<crate::Timestamp, E> {
1019                crate::Timestamp::from_nanosecond(v).map_err(de::Error::custom)
1020            }
1021
1022            #[inline]
1023            fn visit_u128<E: de::Error>(
1024                self,
1025                v: u128,
1026            ) -> Result<crate::Timestamp, E> {
1027                let v = i128::try_from(v).map_err(|_| {
1028                    de::Error::custom(format_args!(
1029                        "got unsigned integer {v} nanoseconds, \
1030                         which is too big to fit in a Jiff `Timestamp`",
1031                    ))
1032                })?;
1033                self.visit_i128(v)
1034            }
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            pub fn serialize<S: serde_core::Serializer>(
1044                timestamp: &crate::Timestamp,
1045                se: S,
1046            ) -> Result<S::Ok, S::Error> {
1047                se.serialize_i128(timestamp.as_nanosecond())
1048            }
1049
1050            /// Deserialize a required integer number of nanoseconds since the
1051            /// Unix epoch.
1052            #[inline]
1053            pub fn deserialize<'de, D: serde_core::Deserializer<'de>>(
1054                de: D,
1055            ) -> Result<crate::Timestamp, D::Error> {
1056                de.deserialize_i128(super::Visitor)
1057            }
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            pub fn serialize<S: serde_core::Serializer>(
1067                timestamp: &Option<crate::Timestamp>,
1068                se: S,
1069            ) -> Result<S::Ok, S::Error> {
1070                match *timestamp {
1071                    None => se.serialize_none(),
1072                    Some(ref ts) => super::required::serialize(ts, se),
1073                }
1074            }
1075
1076            /// Deserialize an optional integer number of nanoseconds since the
1077            /// Unix epoch.
1078            #[inline]
1079            pub fn deserialize<'de, D: serde_core::Deserializer<'de>>(
1080                de: D,
1081            ) -> Result<Option<crate::Timestamp>, D::Error> {
1082                de.deserialize_option(super::super::OptionalVisitor(
1083                    super::Visitor,
1084                ))
1085            }
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.
1178pub 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        fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
1187            static PRINTER: temporal::DateTimePrinter =
1188                temporal::DateTimePrinter::new();
1189            PRINTER
1190                .print_time_zone(self.0, StdFmtWrite(f))
1191                .map_err(|_| core::fmt::Error)
1192        }
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        fn expecting(
1202            &self,
1203            f: &mut core::fmt::Formatter,
1204        ) -> core::fmt::Result {
1205            f.write_str(
1206                "a string representing a time zone via an \
1207                 IANA time zone identifier, fixed offset from UTC \
1208                 or a POSIX time zone string",
1209            )
1210        }
1211
1212        #[inline]
1213        fn visit_bytes<E: de::Error>(
1214            self,
1215            value: &[u8],
1216        ) -> Result<crate::tz::TimeZone, E> {
1217            static PARSER: temporal::DateTimeParser =
1218                temporal::DateTimeParser::new();
1219            PARSER.parse_time_zone(value).map_err(de::Error::custom)
1220        }
1221
1222        #[inline]
1223        fn visit_str<E: de::Error>(
1224            self,
1225            value: &str,
1226        ) -> Result<crate::tz::TimeZone, E> {
1227            self.visit_bytes(value.as_bytes())
1228        }
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        fn expecting(
1240            &self,
1241            f: &mut core::fmt::Formatter,
1242        ) -> core::fmt::Result {
1243            f.write_str(
1244                "a string representing a time zone via an \
1245                 IANA time zone identifier, fixed offset from UTC \
1246                 or a POSIX time zone string",
1247            )
1248        }
1249
1250        #[inline]
1251        fn visit_some<D: de::Deserializer<'de>>(
1252            self,
1253            de: D,
1254        ) -> Result<Option<crate::tz::TimeZone>, D::Error> {
1255            de.deserialize_str(self.0).map(Some)
1256        }
1257
1258        #[inline]
1259        fn visit_none<E: de::Error>(
1260            self,
1261        ) -> Result<Option<crate::tz::TimeZone>, E> {
1262            Ok(None)
1263        }
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        pub fn serialize<S: serde_core::Serializer>(
1279            tz: &crate::tz::TimeZone,
1280            se: S,
1281        ) -> Result<S::Ok, S::Error> {
1282            if !tz.has_succinct_serialization() {
1283                return Err(<S::Error as serde_core::ser::Error>::custom(
1284                    "time zones without IANA identifiers that aren't either \
1285                     fixed offsets or a POSIX time zone can't be serialized \
1286                     (this typically occurs when this is a system time zone \
1287                      derived from `/etc/localtime` on Unix systems that \
1288                      isn't symlinked to an entry in `/usr/share/zoneinfo)",
1289                ));
1290            }
1291            se.collect_str(&super::TemporalTimeZone(tz))
1292        }
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        pub fn deserialize<'de, D: serde_core::Deserializer<'de>>(
1300            de: D,
1301        ) -> Result<crate::tz::TimeZone, D::Error> {
1302            de.deserialize_str(super::Visitor)
1303        }
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        pub fn serialize<S: serde_core::Serializer>(
1319            tz: &Option<crate::tz::TimeZone>,
1320            se: S,
1321        ) -> Result<S::Ok, S::Error> {
1322            match *tz {
1323                None => se.serialize_none(),
1324                Some(ref tz) => super::required::serialize(tz, se),
1325            }
1326        }
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        pub fn deserialize<'de, D: serde_core::Deserializer<'de>>(
1334            de: D,
1335        ) -> Result<Option<crate::tz::TimeZone>, D::Error> {
1336            de.deserialize_option(super::OptionalVisitor(super::Visitor))
1337        }
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/// ```
1527pub 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                pub fn serialize<S: serde_core::Serializer>(
1557                    duration: &core::time::Duration,
1558                    se: S,
1559                ) -> Result<S::Ok, S::Error> {
1560                    se.collect_str(&super::DisplayFriendlyCompact(duration))
1561                }
1562
1563                /// Deserialize a required ISO 8601 or friendly duration from a
1564                /// [`std::time::Duration`].
1565                #[inline]
1566                pub fn deserialize<'de, D: serde_core::Deserializer<'de>>(
1567                    de: D,
1568                ) -> Result<core::time::Duration, D::Error> {
1569                    super::super::super::required::deserialize(de)
1570                }
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                pub fn serialize<S: serde_core::Serializer>(
1587                    duration: &Option<core::time::Duration>,
1588                    se: S,
1589                ) -> Result<S::Ok, S::Error> {
1590                    match *duration {
1591                        None => se.serialize_none(),
1592                        Some(ref duration) => {
1593                            super::required::serialize(duration, se)
1594                        }
1595                    }
1596                }
1597
1598                /// Deserialize a required ISO 8601 or friendly duration from a
1599                /// [`std::time::Duration`].
1600                #[inline]
1601                pub fn deserialize<'de, D: serde_core::Deserializer<'de>>(
1602                    de: D,
1603                ) -> Result<Option<core::time::Duration>, D::Error>
1604                {
1605                    super::super::super::optional::deserialize(de)
1606                }
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                fn fmt(
1615                    &self,
1616                    f: &mut core::fmt::Formatter,
1617                ) -> 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                    PRINTER
1626                        .print_unsigned_duration(self.0, StdFmtWrite(f))
1627                        .map_err(|_| core::fmt::Error)
1628                }
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            fn expecting(
1644                &self,
1645                f: &mut core::fmt::Formatter,
1646            ) -> core::fmt::Result {
1647                f.write_str("an unsigned duration string")
1648            }
1649
1650            #[inline]
1651            fn visit_bytes<E: serde_core::de::Error>(
1652                self,
1653                value: &[u8],
1654            ) -> Result<core::time::Duration, E> {
1655                super::parse_iso_or_friendly(value)
1656                    .map_err(serde_core::de::Error::custom)
1657            }
1658
1659            #[inline]
1660            fn visit_str<E: serde_core::de::Error>(
1661                self,
1662                value: &str,
1663            ) -> Result<core::time::Duration, E> {
1664                self.visit_bytes(value.as_bytes())
1665            }
1666        }
1667
1668        /// Serialize a required ISO 8601 duration from a
1669        /// [`std::time::Duration`].
1670        #[inline]
1671        pub fn serialize<S: serde_core::Serializer>(
1672            duration: &core::time::Duration,
1673            se: S,
1674        ) -> Result<S::Ok, S::Error> {
1675            se.collect_str(&super::DisplayISO8601(duration))
1676        }
1677
1678        /// Deserialize a required ISO 8601 or friendly duration from a
1679        /// [`std::time::Duration`].
1680        #[inline]
1681        pub fn deserialize<'de, D: serde_core::Deserializer<'de>>(
1682            de: D,
1683        ) -> Result<core::time::Duration, D::Error> {
1684            de.deserialize_str(Visitor)
1685        }
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            fn expecting(
1703                &self,
1704                f: &mut core::fmt::Formatter,
1705            ) -> core::fmt::Result {
1706                f.write_str("an unsigned duration string")
1707            }
1708
1709            #[inline]
1710            fn visit_some<D: serde_core::de::Deserializer<'de>>(
1711                self,
1712                de: D,
1713            ) -> Result<Option<core::time::Duration>, D::Error> {
1714                de.deserialize_str(self.0).map(Some)
1715            }
1716
1717            #[inline]
1718            fn visit_none<E: serde_core::de::Error>(
1719                self,
1720            ) -> Result<Option<core::time::Duration>, E> {
1721                Ok(None)
1722            }
1723        }
1724
1725        /// Serialize an optional ISO 8601 duration from a
1726        /// [`std::time::Duration`].
1727        #[inline]
1728        pub fn serialize<S: serde_core::Serializer>(
1729            duration: &Option<core::time::Duration>,
1730            se: S,
1731        ) -> Result<S::Ok, S::Error> {
1732            match *duration {
1733                None => se.serialize_none(),
1734                Some(ref duration) => super::required::serialize(duration, se),
1735            }
1736        }
1737
1738        /// Deserialize an optional ISO 8601 or friendly duration from a
1739        /// [`std::time::Duration`].
1740        #[inline]
1741        pub fn deserialize<'de, D: serde_core::Deserializer<'de>>(
1742            de: D,
1743        ) -> Result<Option<core::time::Duration>, D::Error> {
1744            de.deserialize_option(Visitor(super::required::Visitor))
1745        }
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        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            PRINTER
1757                .print_unsigned_duration(self.0, crate::fmt::StdFmtWrite(f))
1758                .map_err(|_| core::fmt::Error)
1759        }
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    fn parse_iso_or_friendly(
1779        bytes: &[u8],
1780    ) -> Result<core::time::Duration, crate::Error> {
1781        if bytes.is_empty() {
1782            return Err(crate::error::err!(
1783                "an empty string is not a valid `std::time::Duration`, \
1784                 expected either a ISO 8601 or Jiff's 'friendly' \
1785                 format",
1786            ));
1787        }
1788        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        if first == b'+' || first == b'-' {
1793            if bytes.len() == 1 {
1794                return Err(crate::error::err!(
1795                    "found nothing after sign `{sign}`, \
1796                     which is not a valid `std::time::Duration`, \
1797                     expected either a ISO 8601 or Jiff's 'friendly' \
1798                     format",
1799                    sign = crate::util::escape::Byte(first),
1800                ));
1801            }
1802            first = bytes[1];
1803        }
1804        let dur = if first == b'P' || first == b'p' {
1805            crate::fmt::temporal::DEFAULT_SPAN_PARSER
1806                .parse_unsigned_duration(bytes)
1807        } else {
1808            crate::fmt::friendly::DEFAULT_SPAN_PARSER
1809                .parse_unsigned_duration(bytes)
1810        }?;
1811        Ok(dur)
1812    }
1813}
1814
1815#[cfg(test)]
1816mod 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}