Skip to main content

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