1#![warn(clippy::as_conversions)]
14
15use crate::{
16 formats::{Flexible, Format, Strict, Strictness},
17 prelude::*,
18};
19#[cfg(feature = "std")]
20use ::time_0_3::format_description::well_known::{
21 iso8601::EncodedConfig, Iso8601, Rfc2822, Rfc3339,
22};
23use ::time_0_3::{Duration as Time03Duration, OffsetDateTime, PrimitiveDateTime};
24
25fn unix_epoch_primitive() -> PrimitiveDateTime {
27 PrimitiveDateTime::new(
28 ::time_0_3::Date::from_ordinal_date(1970, 1).unwrap(),
29 ::time_0_3::Time::from_hms_nano(0, 0, 0, 0).unwrap(),
30 )
31}
32
33fn duration_into_duration_signed(dur: &Time03Duration) -> DurationSigned {
35 let std_dur = Duration::new(
36 dur.whole_seconds().unsigned_abs(),
37 dur.subsec_nanoseconds().unsigned_abs(),
38 );
39
40 DurationSigned::with_duration(
41 if dur.is_negative() {
43 Sign::Negative
44 } else {
45 Sign::Positive
46 },
47 std_dur,
48 )
49}
50
51fn duration_from_duration_signed<'de, D>(sdur: DurationSigned) -> Result<Time03Duration, D::Error>
53where
54 D: Deserializer<'de>,
55{
56 let mut dur: Time03Duration = match sdur.duration.try_into() {
57 Ok(dur) => dur,
58 Err(msg) => {
59 return Err(DeError::custom(format_args!(
60 "Duration is outside of the representable range: {msg}"
61 )))
62 }
63 };
64 if sdur.sign.is_negative() {
65 dur = -dur;
66 }
67 Ok(dur)
68}
69
70macro_rules! use_duration_signed_ser {
71 (
72 $main_trait:ident $internal_trait:ident =>
73 {
74 $ty:ty; $converter:ident =>
75 $({
76 $format:ty, $strictness:ty =>
77 $($tbound:ident: $bound:ident $(,)?)*
78 })*
79 }
80 ) => {
81 $(
82 impl<$($tbound ,)*> SerializeAs<$ty> for $main_trait<$format, $strictness>
83 where
84 $($tbound: $bound,)*
85 {
86 fn serialize_as<S>(source: &$ty, serializer: S) -> Result<S::Ok, S::Error>
87 where
88 S: Serializer,
89 {
90 let dur: DurationSigned = $converter(source);
91 $internal_trait::<$format, $strictness>::serialize_as(
92 &dur,
93 serializer,
94 )
95 }
96 }
97 )*
98 };
99 (
100 $( $main_trait:ident $internal_trait:ident, )+ => $rest:tt
101 ) => {
102 $( use_duration_signed_ser!($main_trait $internal_trait => $rest); )+
103 };
104}
105
106fn offset_datetime_to_duration(source: &OffsetDateTime) -> DurationSigned {
107 duration_into_duration_signed(&(*source - OffsetDateTime::UNIX_EPOCH))
108}
109
110fn primitive_datetime_to_duration(source: &PrimitiveDateTime) -> DurationSigned {
111 duration_into_duration_signed(&(*source - unix_epoch_primitive()))
112}
113
114use_duration_signed_ser!(
115 DurationSeconds DurationSeconds,
116 DurationMilliSeconds DurationMilliSeconds,
117 DurationMicroSeconds DurationMicroSeconds,
118 DurationNanoSeconds DurationNanoSeconds,
119 => {
120 Time03Duration; duration_into_duration_signed =>
121 {i64, STRICTNESS => STRICTNESS: Strictness}
122 }
123);
124#[cfg(feature = "alloc")]
125use_duration_signed_ser!(
126 DurationSeconds DurationSeconds,
127 DurationMilliSeconds DurationMilliSeconds,
128 DurationMicroSeconds DurationMicroSeconds,
129 DurationNanoSeconds DurationNanoSeconds,
130 => {
131 Time03Duration; duration_into_duration_signed =>
132 {String, STRICTNESS => STRICTNESS: Strictness}
133 }
134);
135#[cfg(feature = "std")]
136use_duration_signed_ser!(
137 DurationSeconds DurationSeconds,
138 DurationMilliSeconds DurationMilliSeconds,
139 DurationMicroSeconds DurationMicroSeconds,
140 DurationNanoSeconds DurationNanoSeconds,
141 => {
142 Time03Duration; duration_into_duration_signed =>
143 {f64, STRICTNESS => STRICTNESS: Strictness}
144 }
145);
146use_duration_signed_ser!(
147 TimestampSeconds DurationSeconds,
148 TimestampMilliSeconds DurationMilliSeconds,
149 TimestampMicroSeconds DurationMicroSeconds,
150 TimestampNanoSeconds DurationNanoSeconds,
151 => {
152 OffsetDateTime; offset_datetime_to_duration =>
153 {i64, STRICTNESS => STRICTNESS: Strictness}
154 }
155);
156#[cfg(feature = "alloc")]
157use_duration_signed_ser!(
158 TimestampSeconds DurationSeconds,
159 TimestampMilliSeconds DurationMilliSeconds,
160 TimestampMicroSeconds DurationMicroSeconds,
161 TimestampNanoSeconds DurationNanoSeconds,
162 => {
163 OffsetDateTime; offset_datetime_to_duration =>
164 {String, STRICTNESS => STRICTNESS: Strictness}
165 }
166);
167#[cfg(feature = "std")]
168use_duration_signed_ser!(
169 TimestampSeconds DurationSeconds,
170 TimestampMilliSeconds DurationMilliSeconds,
171 TimestampMicroSeconds DurationMicroSeconds,
172 TimestampNanoSeconds DurationNanoSeconds,
173 => {
174 OffsetDateTime; offset_datetime_to_duration =>
175 {f64, STRICTNESS => STRICTNESS: Strictness}
176 }
177);
178use_duration_signed_ser!(
179 TimestampSeconds DurationSeconds,
180 TimestampMilliSeconds DurationMilliSeconds,
181 TimestampMicroSeconds DurationMicroSeconds,
182 TimestampNanoSeconds DurationNanoSeconds,
183 => {
184 PrimitiveDateTime; primitive_datetime_to_duration =>
185 {i64, STRICTNESS => STRICTNESS: Strictness}
186 }
187);
188#[cfg(feature = "alloc")]
189use_duration_signed_ser!(
190 TimestampSeconds DurationSeconds,
191 TimestampMilliSeconds DurationMilliSeconds,
192 TimestampMicroSeconds DurationMicroSeconds,
193 TimestampNanoSeconds DurationNanoSeconds,
194 => {
195 PrimitiveDateTime; primitive_datetime_to_duration =>
196 {String, STRICTNESS => STRICTNESS: Strictness}
197 }
198);
199#[cfg(feature = "std")]
200use_duration_signed_ser!(
201 TimestampSeconds DurationSeconds,
202 TimestampMilliSeconds DurationMilliSeconds,
203 TimestampMicroSeconds DurationMicroSeconds,
204 TimestampNanoSeconds DurationNanoSeconds,
205 => {
206 PrimitiveDateTime; primitive_datetime_to_duration =>
207 {f64, STRICTNESS => STRICTNESS: Strictness}
208 }
209);
210
211#[cfg(feature = "alloc")]
213use_duration_signed_ser!(
214 DurationSecondsWithFrac DurationSecondsWithFrac,
215 DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
216 DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
217 DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
218 => {
219 Time03Duration; duration_into_duration_signed =>
220 {String, STRICTNESS => STRICTNESS: Strictness}
221 }
222);
223#[cfg(feature = "std")]
224use_duration_signed_ser!(
225 DurationSecondsWithFrac DurationSecondsWithFrac,
226 DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
227 DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
228 DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
229 => {
230 Time03Duration; duration_into_duration_signed =>
231 {f64, STRICTNESS => STRICTNESS: Strictness}
232 }
233);
234#[cfg(feature = "alloc")]
235use_duration_signed_ser!(
236 TimestampSecondsWithFrac DurationSecondsWithFrac,
237 TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
238 TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
239 TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
240 => {
241 OffsetDateTime; offset_datetime_to_duration =>
242 {String, STRICTNESS => STRICTNESS: Strictness}
243 }
244);
245#[cfg(feature = "std")]
246use_duration_signed_ser!(
247 TimestampSecondsWithFrac DurationSecondsWithFrac,
248 TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
249 TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
250 TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
251 => {
252 OffsetDateTime; offset_datetime_to_duration =>
253 {f64, STRICTNESS => STRICTNESS: Strictness}
254 }
255);
256#[cfg(feature = "alloc")]
257use_duration_signed_ser!(
258 TimestampSecondsWithFrac DurationSecondsWithFrac,
259 TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
260 TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
261 TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
262 => {
263 PrimitiveDateTime; primitive_datetime_to_duration =>
264 {String, STRICTNESS => STRICTNESS: Strictness}
265 }
266);
267#[cfg(feature = "std")]
268use_duration_signed_ser!(
269 TimestampSecondsWithFrac DurationSecondsWithFrac,
270 TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
271 TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
272 TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
273 => {
274 PrimitiveDateTime; primitive_datetime_to_duration =>
275 {f64, STRICTNESS => STRICTNESS: Strictness}
276 }
277);
278
279macro_rules! use_duration_signed_de {
280 (
281 $main_trait:ident $internal_trait:ident =>
282 {
283 $ty:ty; $converter:ident =>
284 $({
285 $format:ty, $strictness:ty =>
286 $($tbound:ident: $bound:ident)*
287 })*
288 }
289 ) =>{
290 $(
291 impl<'de, $($tbound,)*> DeserializeAs<'de, $ty> for $main_trait<$format, $strictness>
292 where
293 $($tbound: $bound,)*
294 {
295 fn deserialize_as<D>(deserializer: D) -> Result<$ty, D::Error>
296 where
297 D: Deserializer<'de>,
298 {
299 let dur: DurationSigned = $internal_trait::<$format, $strictness>::deserialize_as(deserializer)?;
300 $converter::<D>(dur)
301 }
302 }
303 )*
304 };
305 (
306 $( $main_trait:ident $internal_trait:ident, )+ => $rest:tt
307 ) => {
308 $( use_duration_signed_de!($main_trait $internal_trait => $rest); )+
309 };
310}
311
312fn duration_to_offset_datetime<'de, D>(dur: DurationSigned) -> Result<OffsetDateTime, D::Error>
313where
314 D: Deserializer<'de>,
315{
316 Ok(OffsetDateTime::UNIX_EPOCH + duration_from_duration_signed::<D>(dur)?)
317}
318
319fn duration_to_primitive_datetime<'de, D>(
320 dur: DurationSigned,
321) -> Result<PrimitiveDateTime, D::Error>
322where
323 D: Deserializer<'de>,
324{
325 Ok(unix_epoch_primitive() + duration_from_duration_signed::<D>(dur)?)
326}
327
328use_duration_signed_de!(
330 DurationSeconds DurationSeconds,
331 DurationMilliSeconds DurationMilliSeconds,
332 DurationMicroSeconds DurationMicroSeconds,
333 DurationNanoSeconds DurationNanoSeconds,
334 => {
335 Time03Duration; duration_from_duration_signed =>
336 {i64, Strict =>}
337 {FORMAT, Flexible => FORMAT: Format}
338 }
339);
340#[cfg(feature = "alloc")]
341use_duration_signed_de!(
342 DurationSeconds DurationSeconds,
343 DurationMilliSeconds DurationMilliSeconds,
344 DurationMicroSeconds DurationMicroSeconds,
345 DurationNanoSeconds DurationNanoSeconds,
346 => {
347 Time03Duration; duration_from_duration_signed =>
348 {String, Strict =>}
349 }
350);
351#[cfg(feature = "std")]
352use_duration_signed_de!(
353 DurationSeconds DurationSeconds,
354 DurationMilliSeconds DurationMilliSeconds,
355 DurationMicroSeconds DurationMicroSeconds,
356 DurationNanoSeconds DurationNanoSeconds,
357 => {
358 Time03Duration; duration_from_duration_signed =>
359 {f64, Strict =>}
360 }
361);
362use_duration_signed_de!(
363 TimestampSeconds DurationSeconds,
364 TimestampMilliSeconds DurationMilliSeconds,
365 TimestampMicroSeconds DurationMicroSeconds,
366 TimestampNanoSeconds DurationNanoSeconds,
367 => {
368 OffsetDateTime; duration_to_offset_datetime =>
369 {i64, Strict =>}
370 {FORMAT, Flexible => FORMAT: Format}
371 }
372);
373#[cfg(feature = "alloc")]
374use_duration_signed_de!(
375 TimestampSeconds DurationSeconds,
376 TimestampMilliSeconds DurationMilliSeconds,
377 TimestampMicroSeconds DurationMicroSeconds,
378 TimestampNanoSeconds DurationNanoSeconds,
379 => {
380 OffsetDateTime; duration_to_offset_datetime =>
381 {String, Strict =>}
382 }
383);
384#[cfg(feature = "std")]
385use_duration_signed_de!(
386 TimestampSeconds DurationSeconds,
387 TimestampMilliSeconds DurationMilliSeconds,
388 TimestampMicroSeconds DurationMicroSeconds,
389 TimestampNanoSeconds DurationNanoSeconds,
390 => {
391 OffsetDateTime; duration_to_offset_datetime =>
392 {f64, Strict =>}
393 }
394);
395use_duration_signed_de!(
396 TimestampSeconds DurationSeconds,
397 TimestampMilliSeconds DurationMilliSeconds,
398 TimestampMicroSeconds DurationMicroSeconds,
399 TimestampNanoSeconds DurationNanoSeconds,
400 => {
401 PrimitiveDateTime; duration_to_primitive_datetime =>
402 {i64, Strict =>}
403 {FORMAT, Flexible => FORMAT: Format}
404 }
405);
406#[cfg(feature = "alloc")]
407use_duration_signed_de!(
408 TimestampSeconds DurationSeconds,
409 TimestampMilliSeconds DurationMilliSeconds,
410 TimestampMicroSeconds DurationMicroSeconds,
411 TimestampNanoSeconds DurationNanoSeconds,
412 => {
413 PrimitiveDateTime; duration_to_primitive_datetime =>
414 {String, Strict =>}
415 }
416);
417#[cfg(feature = "std")]
418use_duration_signed_de!(
419 TimestampSeconds DurationSeconds,
420 TimestampMilliSeconds DurationMilliSeconds,
421 TimestampMicroSeconds DurationMicroSeconds,
422 TimestampNanoSeconds DurationNanoSeconds,
423 => {
424 PrimitiveDateTime; duration_to_primitive_datetime =>
425 {f64, Strict =>}
426 }
427);
428
429use_duration_signed_de!(
431 DurationSecondsWithFrac DurationSecondsWithFrac,
432 DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
433 DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
434 DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
435 => {
436 Time03Duration; duration_from_duration_signed =>
437 {FORMAT, Flexible => FORMAT: Format}
438 }
439);
440#[cfg(feature = "alloc")]
441use_duration_signed_de!(
442 DurationSecondsWithFrac DurationSecondsWithFrac,
443 DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
444 DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
445 DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
446 => {
447 Time03Duration; duration_from_duration_signed =>
448 {String, Strict =>}
449 }
450);
451#[cfg(feature = "std")]
452use_duration_signed_de!(
453 DurationSecondsWithFrac DurationSecondsWithFrac,
454 DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
455 DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
456 DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
457 => {
458 Time03Duration; duration_from_duration_signed =>
459 {f64, Strict =>}
460 }
461);
462use_duration_signed_de!(
463 TimestampSecondsWithFrac DurationSecondsWithFrac,
464 TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
465 TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
466 TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
467 => {
468 OffsetDateTime; duration_to_offset_datetime =>
469 {FORMAT, Flexible => FORMAT: Format}
470 }
471);
472#[cfg(feature = "alloc")]
473use_duration_signed_de!(
474 TimestampSecondsWithFrac DurationSecondsWithFrac,
475 TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
476 TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
477 TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
478 => {
479 OffsetDateTime; duration_to_offset_datetime =>
480 {String, Strict =>}
481 }
482);
483#[cfg(feature = "std")]
484use_duration_signed_de!(
485 TimestampSecondsWithFrac DurationSecondsWithFrac,
486 TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
487 TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
488 TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
489 => {
490 OffsetDateTime; duration_to_offset_datetime =>
491 {f64, Strict =>}
492 }
493);
494use_duration_signed_de!(
495 TimestampSecondsWithFrac DurationSecondsWithFrac,
496 TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
497 TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
498 TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
499 => {
500 PrimitiveDateTime; duration_to_primitive_datetime =>
501 {FORMAT, Flexible => FORMAT: Format}
502 }
503);
504#[cfg(feature = "alloc")]
505use_duration_signed_de!(
506 TimestampSecondsWithFrac DurationSecondsWithFrac,
507 TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
508 TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
509 TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
510 => {
511 PrimitiveDateTime; duration_to_primitive_datetime =>
512 {String, Strict =>}
513 }
514);
515#[cfg(feature = "std")]
516use_duration_signed_de!(
517 TimestampSecondsWithFrac DurationSecondsWithFrac,
518 TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
519 TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
520 TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
521 => {
522 PrimitiveDateTime; duration_to_primitive_datetime =>
523 {f64, Strict =>}
524 }
525);
526
527#[cfg(feature = "std")]
528impl SerializeAs<OffsetDateTime> for Rfc2822 {
529 fn serialize_as<S>(datetime: &OffsetDateTime, serializer: S) -> Result<S::Ok, S::Error>
530 where
531 S: Serializer,
532 {
533 datetime
534 .format(&Rfc2822)
535 .map_err(S::Error::custom)?
536 .serialize(serializer)
537 }
538}
539
540#[cfg(feature = "std")]
541impl<'de> DeserializeAs<'de, OffsetDateTime> for Rfc2822 {
542 fn deserialize_as<D>(deserializer: D) -> Result<OffsetDateTime, D::Error>
543 where
544 D: Deserializer<'de>,
545 {
546 struct Helper;
547 impl Visitor<'_> for Helper {
548 type Value = OffsetDateTime;
549
550 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
551 formatter.write_str("a RFC2822-formatted `OffsetDateTime`")
552 }
553
554 fn visit_str<E: DeError>(self, value: &str) -> Result<Self::Value, E> {
555 Self::Value::parse(value, &Rfc2822).map_err(E::custom)
556 }
557 }
558
559 deserializer.deserialize_str(Helper)
560 }
561}
562
563#[cfg(feature = "std")]
564impl SerializeAs<OffsetDateTime> for Rfc3339 {
565 fn serialize_as<S>(datetime: &OffsetDateTime, serializer: S) -> Result<S::Ok, S::Error>
566 where
567 S: Serializer,
568 {
569 datetime
570 .format(&Rfc3339)
571 .map_err(S::Error::custom)?
572 .serialize(serializer)
573 }
574}
575
576#[cfg(feature = "std")]
577impl<'de> DeserializeAs<'de, OffsetDateTime> for Rfc3339 {
578 fn deserialize_as<D>(deserializer: D) -> Result<OffsetDateTime, D::Error>
579 where
580 D: Deserializer<'de>,
581 {
582 struct Helper;
583 impl Visitor<'_> for Helper {
584 type Value = OffsetDateTime;
585
586 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
587 formatter.write_str("a RFC3339-formatted `OffsetDateTime`")
588 }
589
590 fn visit_str<E: DeError>(self, value: &str) -> Result<Self::Value, E> {
591 Self::Value::parse(value, &Rfc3339).map_err(E::custom)
592 }
593 }
594
595 deserializer.deserialize_str(Helper)
596 }
597}
598
599#[cfg(feature = "std")]
600impl<const CONFIG: EncodedConfig> SerializeAs<OffsetDateTime> for Iso8601<CONFIG> {
601 fn serialize_as<S>(datetime: &OffsetDateTime, serializer: S) -> Result<S::Ok, S::Error>
602 where
603 S: Serializer,
604 {
605 datetime
606 .format(&Iso8601::<CONFIG>)
607 .map_err(S::Error::custom)?
608 .serialize(serializer)
609 }
610}
611
612#[cfg(feature = "std")]
613impl<'de, const CONFIG: EncodedConfig> DeserializeAs<'de, OffsetDateTime> for Iso8601<CONFIG> {
614 fn deserialize_as<D>(deserializer: D) -> Result<OffsetDateTime, D::Error>
615 where
616 D: Deserializer<'de>,
617 {
618 struct Helper<const CONFIG: EncodedConfig>;
619 impl<const CONFIG: EncodedConfig> Visitor<'_> for Helper<CONFIG> {
620 type Value = OffsetDateTime;
621
622 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
623 formatter.write_str("a ISO8601-formatted `OffsetDateTime`")
624 }
625
626 fn visit_str<E: DeError>(self, value: &str) -> Result<Self::Value, E> {
627 Self::Value::parse(value, &Iso8601::<CONFIG>).map_err(E::custom)
628 }
629 }
630
631 deserializer.deserialize_str(Helper::<CONFIG>)
632 }
633}