1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use {
    chrono::{
        offset::LocalResult,
        prelude::*,
    },
    async_proto_derive::impl_protocol_for,
    crate::{
        Protocol,
        ReadError,
    },
};

#[derive(Protocol)]
#[async_proto(internal)]
struct NaiveDateProxy {
    num_days_from_ce: i32,
}

impl TryFrom<NaiveDateProxy> for NaiveDate {
    type Error = ReadError;

    fn try_from(NaiveDateProxy { num_days_from_ce }: NaiveDateProxy) -> Result<Self, ReadError> {
        Self::from_num_days_from_ce_opt(num_days_from_ce).ok_or_else(|| ReadError::Custom(format!("out-of-range date")))
    }
}

impl<'a> From<&'a NaiveDate> for NaiveDateProxy {
    fn from(date: &NaiveDate) -> Self {
        Self { num_days_from_ce: date.num_days_from_ce() }
    }
}

#[derive(Protocol)]
#[async_proto(internal)]
struct FixedOffsetProxy {
    east: i32,
}

impl TryFrom<FixedOffsetProxy> for FixedOffset {
    type Error = ReadError;

    fn try_from(FixedOffsetProxy { east }: FixedOffsetProxy) -> Result<Self, ReadError> {
        Self::east_opt(east).ok_or_else(|| ReadError::Custom(format!("FixedOffset::east out of bounds")))
    }
}

impl<'a> From<&'a FixedOffset> for FixedOffsetProxy {
    fn from(offset: &FixedOffset) -> Self {
        Self { east: offset.local_minus_utc() }
    }
}

#[derive(Protocol)]
#[async_proto(internal)]
struct DateTimeProxy<Tz: TimeZone> {
    timezone: Tz,
    timestamp: i64,
    timestamp_subsec_nanos: u32,
}

impl<Tz: TimeZone> TryFrom<DateTimeProxy<Tz>> for DateTime<Tz> {
    type Error = ReadError;

    fn try_from(DateTimeProxy { timezone, timestamp, timestamp_subsec_nanos }: DateTimeProxy<Tz>) -> Result<Self, ReadError> {
        match timezone.timestamp_opt(timestamp, timestamp_subsec_nanos) {
            LocalResult::Single(dt) => Ok(dt),
            LocalResult::None => Err(ReadError::Custom(format!("read a nonexistent timestamp"))),
            LocalResult::Ambiguous(dt1, dt2) => Err(ReadError::Custom(format!("read an ambiguous timestamp that could refer to {:?} or {:?}", dt1, dt2))),
        }
    }
}

impl<'a, Tz: TimeZone> From<&'a DateTime<Tz>> for DateTimeProxy<Tz> {
    fn from(date: &DateTime<Tz>) -> Self {
        Self {
            timezone: date.timezone(),
            timestamp: date.timestamp(),
            timestamp_subsec_nanos: date.timestamp_subsec_nanos(),
        }
    }
}

impl_protocol_for! {
    #[async_proto(attr(cfg_attr(docsrs, doc(cfg(feature = "chrono")))))]
    struct Utc;

    #[async_proto(attr(cfg_attr(docsrs, doc(cfg(feature = "chrono")))))]
    #[async_proto(via = NaiveDateProxy)]
    type NaiveDate;

    #[async_proto(attr(cfg_attr(docsrs, doc(cfg(feature = "chrono")))))]
    #[async_proto(via = FixedOffsetProxy)]
    type FixedOffset;

    #[async_proto(attr(cfg_attr(docsrs, doc(cfg(feature = "chrono")))))]
    #[async_proto(via = DateTimeProxy<Tz>, where(Tz: Protocol + TimeZone + Send + Sync + 'static, Tz::Offset: Sync))]
    type DateTime<Tz: TimeZone>;
}