1use jiff::Timestamp;
2use tlb::{
3 Error,
4 bits::{
5 de::{BitReader, BitReaderExt, BitUnpackAs},
6 ser::{BitPackAs, BitWriter, BitWriterExt},
7 },
8};
9
10pub struct UnixTimestampSeconds;
12
13impl BitPackAs<Timestamp> for UnixTimestampSeconds {
14 type Args = ();
15
16 #[inline]
17 fn pack_as<W>(source: &Timestamp, writer: &mut W, (): Self::Args) -> Result<(), W::Error>
18 where
19 W: BitWriter + ?Sized,
20 {
21 let timestamp: u32 = source
22 .as_second()
23 .try_into()
24 .map_err(|_| Error::custom("timestamp: overflow"))?;
25 writer.pack(timestamp, ())?;
26 Ok(())
27 }
28}
29
30impl<'de> BitUnpackAs<'de, Timestamp> for UnixTimestampSeconds {
31 type Args = ();
32
33 #[inline]
34 fn unpack_as<R>(reader: &mut R, (): Self::Args) -> Result<Timestamp, R::Error>
35 where
36 R: BitReader<'de> + ?Sized,
37 {
38 let timestamp: u32 = reader.unpack(())?;
39 Timestamp::from_second(timestamp as i64).map_err(Error::custom)
40 }
41}
42
43#[cfg(feature = "arbitrary")]
44const _: () = {
45 use arbitrary::{Result, Unstructured};
46 use arbitrary_with::ArbitraryAs;
47
48 impl<'a> ArbitraryAs<'a, Timestamp> for UnixTimestampSeconds {
49 fn arbitrary_as(u: &mut Unstructured<'a>) -> Result<Timestamp> {
50 Ok(Timestamp::from_second(
51 u.int_in_range(Timestamp::UNIX_EPOCH.as_second()..=Timestamp::MAX.as_second())?,
52 )
53 .unwrap_or_else(|_| unreachable!()))
54 }
55 }
56};
57
58#[cfg(test)]
59mod tests {
60
61 use tlb::bits::{de::unpack_fully_as, ser::pack_as};
62
63 use super::*;
64
65 #[test]
66 fn unix_timestamp_serde() {
67 let ts = Timestamp::UNIX_EPOCH;
68
69 let packed = pack_as::<_, UnixTimestampSeconds>(ts, ()).unwrap();
70 let got: Timestamp = unpack_fully_as::<_, UnixTimestampSeconds>(&packed, ()).unwrap();
71
72 assert_eq!(got, ts);
73 }
74}