transformable/impls/
time.rs

1use core::{mem, time::Duration};
2
3use super::Transformable;
4
5const ENCODED_LEN: usize = mem::size_of::<u64>() + mem::size_of::<u32>();
6
7/// Error returned by [`Duration`] when transforming.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9pub enum DurationTransformError {
10  /// The buffer is too small to encode the value.
11  EncodeBufferTooSmall,
12  /// NotEnoughBytes binary data.
13  NotEnoughBytes,
14}
15
16impl core::fmt::Display for DurationTransformError {
17  fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
18    match self {
19      Self::EncodeBufferTooSmall => write!(
20        f,
21        "buffer is too small, use `Transformable::encoded_len` to pre-allocate a buffer with enough space"
22      ),
23      Self::NotEnoughBytes => write!(f, "not enough bytes to decode"),
24    }
25  }
26}
27
28impl core::error::Error for DurationTransformError {}
29
30impl Transformable for Duration {
31  type Error = DurationTransformError;
32
33  fn encode(&self, dst: &mut [u8]) -> Result<usize, Self::Error> {
34    if dst.len() < self.encoded_len() {
35      return Err(Self::Error::EncodeBufferTooSmall);
36    }
37
38    let buf = encode_duration_unchecked(*self);
39    dst[..ENCODED_LEN].copy_from_slice(&buf);
40    Ok(ENCODED_LEN)
41  }
42
43  #[cfg(feature = "std")]
44  #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
45  fn encode_to_writer<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<usize> {
46    let buf = encode_duration_unchecked(*self);
47    let len = buf.len();
48    writer.write_all(&buf).map(|_| len)
49  }
50
51  #[cfg(feature = "async")]
52  #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
53  async fn encode_to_async_writer<W: futures_util::io::AsyncWrite + Send + Unpin>(
54    &self,
55    writer: &mut W,
56  ) -> std::io::Result<usize>
57  where
58    Self::Error: Send + Sync + 'static,
59  {
60    use futures_util::io::AsyncWriteExt;
61
62    let buf = encode_duration_unchecked(*self);
63    let len = buf.len();
64    writer.write_all(&buf).await.map(|_| len)
65  }
66
67  fn encoded_len(&self) -> usize {
68    ENCODED_LEN
69  }
70
71  fn decode(src: &[u8]) -> Result<(usize, Self), Self::Error>
72  where
73    Self: Sized,
74  {
75    if src.len() < ENCODED_LEN {
76      return Err(Self::Error::NotEnoughBytes);
77    }
78
79    Ok(decode_duration_unchecked(src))
80  }
81
82  #[cfg(feature = "std")]
83  #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
84  fn decode_from_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<(usize, Self)>
85  where
86    Self: Sized,
87  {
88    let mut buf = [0; ENCODED_LEN];
89    reader.read_exact(&mut buf)?;
90    Ok(decode_duration_unchecked(&buf))
91  }
92
93  #[cfg(feature = "async")]
94  #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
95  async fn decode_from_async_reader<R: futures_util::io::AsyncRead + Send + Unpin>(
96    reader: &mut R,
97  ) -> std::io::Result<(usize, Self)>
98  where
99    Self: Sized,
100    Self::Error: Send + Sync + 'static,
101  {
102    use futures_util::AsyncReadExt;
103
104    let mut buf = [0; ENCODED_LEN];
105    reader.read_exact(&mut buf).await?;
106    Ok(decode_duration_unchecked(&buf))
107  }
108}
109
110#[inline]
111const fn encode_duration_unchecked(dur: Duration) -> [u8; ENCODED_LEN] {
112  let secs = dur.as_secs().to_be_bytes();
113  let nanos = dur.subsec_nanos().to_be_bytes();
114  [
115    secs[0], secs[1], secs[2], secs[3], secs[4], secs[5], secs[6], secs[7], nanos[0], nanos[1],
116    nanos[2], nanos[3],
117  ]
118}
119
120#[inline]
121const fn decode_duration_unchecked(src: &[u8]) -> (usize, Duration) {
122  let secs = u64::from_be_bytes([
123    src[0], src[1], src[2], src[3], src[4], src[5], src[6], src[7],
124  ]);
125  let nanos = u32::from_be_bytes([src[8], src[9], src[10], src[11]]);
126  (ENCODED_LEN, Duration::new(secs, nanos))
127}
128
129#[cfg(feature = "std")]
130#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
131pub use system_time::*;
132#[cfg(feature = "std")]
133mod system_time;
134
135#[cfg(feature = "std")]
136#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
137pub use instant::*;
138#[cfg(feature = "std")]
139mod instant;
140
141test_transformable!(Duration => test_duration_transformable(Duration::new(10, 1080)));