Skip to main content

rtc_shared/
serde.rs

1/// Serializes a `tokio::time::Instant` to an approximation of epoch time in the form
2/// of an `f64` where the integer portion is seconds and the decimal portion is milliseconds.
3/// For instance, `Monday, May 30, 2022 10:45:26.456 PM UTC` converts to `1653950726.456`.
4///
5/// Note that an `Instant` is not connected to real world time, so this conversion is
6/// approximate.
7pub mod instant_to_epoch {
8    use serde::{Deserialize, Deserializer, Serialize, Serializer};
9    use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
10
11    /// Serializes an [`Instant`] as a duration relative to the process's reference instant.
12    ///
13    /// [`Instant`] has no absolute representation, so this encodes the offset instead. Use
14    /// with `#[serde(with = "...")]`.
15    ///
16    /// # Errors
17    ///
18    /// Propagates any failure from the underlying serializer.
19    pub fn serialize<S>(instant: &Instant, serializer: S) -> Result<S::Ok, S::Error>
20    where
21        S: Serializer,
22    {
23        let system_now = SystemTime::now();
24        let instant_now = Instant::now();
25        let approx = system_now - (instant_now - *instant);
26        let epoch = approx
27            .duration_since(UNIX_EPOCH)
28            .expect("Time went backwards");
29
30        let epoch_s = epoch.as_millis() as f64 / 1000.0;
31
32        epoch_s.serialize(serializer)
33    }
34
35    /// Deserializes an [`Instant`] from the relative offset written by [`serialize`].
36    ///
37    /// # Errors
38    ///
39    /// Propagates any failure from the underlying deserializer.
40    pub fn deserialize<'de, D>(deserializer: D) -> Result<Instant, D::Error>
41    where
42        D: Deserializer<'de>,
43    {
44        let epoch_s = f64::deserialize(deserializer)?;
45        let epoch_duration = Duration::from_secs_f64(epoch_s);
46
47        let system_now = SystemTime::now();
48        let instant_now = Instant::now();
49
50        let duration_since_approx = system_now
51            .duration_since(UNIX_EPOCH + epoch_duration)
52            .expect("Time went backwards");
53        let instant = instant_now - duration_since_approx;
54
55        Ok(instant)
56    }
57}