tlb_ton/
timestamp.rs

1use chrono::{DateTime, Utc};
2use tlb::{
3    Error,
4    bits::{
5        de::{BitReader, BitReaderExt, r#as::BitUnpackAs},
6        ser::{BitWriter, BitWriterExt, r#as::BitPackAs},
7    },
8};
9
10/// Adapter to **de**/**ser**ialize UNIX timestamp as `u32` from [`DateTime`]
11pub struct UnixTimestamp;
12
13#[cfg(feature = "arbitrary")]
14impl UnixTimestamp {
15    #[inline]
16    pub fn arbitrary(u: &mut ::arbitrary::Unstructured) -> ::arbitrary::Result<DateTime<Utc>> {
17        Ok(DateTime::from_timestamp(
18            u.int_in_range(
19                DateTime::UNIX_EPOCH.timestamp()..=DateTime::<Utc>::MAX_UTC.timestamp(),
20            )?,
21            0,
22        )
23        .unwrap_or_else(|| unreachable!()))
24    }
25
26    #[inline]
27    pub fn arbitrary_option(
28        u: &mut ::arbitrary::Unstructured,
29    ) -> ::arbitrary::Result<Option<DateTime<Utc>>> {
30        use arbitrary::Arbitrary;
31
32        Option::<()>::arbitrary(u)?
33            .map(|()| Self::arbitrary(u))
34            .transpose()
35    }
36}
37
38impl BitPackAs<DateTime<Utc>> for UnixTimestamp {
39    #[inline]
40    fn pack_as<W>(source: &DateTime<Utc>, mut writer: W) -> Result<(), W::Error>
41    where
42        W: BitWriter,
43    {
44        let timestamp: u32 = source
45            .timestamp()
46            .try_into()
47            .map_err(|_| Error::custom("timestamp: overflow"))?;
48        writer.pack(timestamp)?;
49        Ok(())
50    }
51}
52
53impl<'de> BitUnpackAs<'de, DateTime<Utc>> for UnixTimestamp {
54    #[inline]
55    fn unpack_as<R>(mut reader: R) -> Result<DateTime<Utc>, R::Error>
56    where
57        R: BitReader<'de>,
58    {
59        let timestamp: u32 = reader.unpack()?;
60        DateTime::from_timestamp(timestamp as i64, 0)
61            .ok_or_else(|| Error::custom("timestamp: overflow"))
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use tlb::bits::{de::r#as::unpack_fully_as, ser::r#as::pack_as};
68
69    use super::*;
70
71    #[test]
72    fn unix_timestamp_serde() {
73        let ts = DateTime::UNIX_EPOCH;
74
75        let packed = pack_as::<_, UnixTimestamp>(ts).unwrap();
76        let got: DateTime<Utc> = unpack_fully_as::<_, UnixTimestamp>(&packed).unwrap();
77
78        assert_eq!(got, ts);
79    }
80}