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
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! [`Archive`] implementations for times.

use crate::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize};
use core::{mem::MaybeUninit, time::Duration};

/// An archived [`Duration`](core::time::Duration).
#[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "validation", derive(bytecheck::CheckBytes))]
#[cfg_attr(feature = "strict", repr(C))]
pub struct ArchivedDuration {
    secs: u64,
    nanos: u32,
}

const NANOS_PER_SEC: u32 = 1_000_000_000;
const NANOS_PER_MILLI: u32 = 1_000_000;
const NANOS_PER_MICRO: u32 = 1_000;
const MILLIS_PER_SEC: u64 = 1_000;
const MICROS_PER_SEC: u64 = 1_000_000;

impl ArchivedDuration {
    /// Returns the number of _whole_ seconds contained by this
    /// `ArchivedDuration`.
    ///
    /// The returned value does not include the fractional (nanosecond) part of the duration, which
    /// can be obtained using [`subsec_nanos`].
    ///
    /// [`subsec_nanos`]: ArchivedDuration::subsec_nanos
    #[inline]
    pub const fn as_secs(&self) -> u64 {
        self.secs
    }

    /// Returns the fractional part of this `ArchivedDuration`, in whole milliseconds.
    ///
    /// This method does **not** return the length of the duration when represented by milliseconds.
    /// The returned number always represents a fractional portion of a second (i.e., it is less
    /// than one thousand).
    #[inline]
    pub const fn subsec_millis(&self) -> u32 {
        self.nanos / NANOS_PER_MILLI
    }

    /// Returns the fractional part of this `ArchivedDuration`, in whole microseconds.
    ///
    /// This method does **not** return the length of the duration when represented by microseconds.
    /// The returned number always represents a fractional portion of a second (i.e., it is less
    /// than one million).
    #[inline]
    pub const fn subsec_micros(&self) -> u32 {
        self.nanos / NANOS_PER_MICRO
    }

    /// Returns the fractional part of this `Duration`, in nanoseconds.
    ///
    /// This method does **not** return the length of the duration when represented by nanoseconds.
    /// The returned number always represents a fractional portion of a second (i.e., it is less
    /// than one billion).
    #[inline]
    pub const fn subsec_nanos(&self) -> u32 {
        self.nanos
    }

    /// Returns the total number of whole milliseconds contained by this `ArchivedDuration`.
    #[inline]
    pub const fn as_millis(&self) -> u128 {
        self.secs as u128 * MILLIS_PER_SEC as u128 + (self.nanos / NANOS_PER_MILLI) as u128
    }

    /// Returns the total number of whole microseconds contained by this `ArchivedDuration`.
    #[inline]
    pub const fn as_micros(&self) -> u128 {
        self.secs as u128 * MICROS_PER_SEC as u128 + (self.nanos / NANOS_PER_MICRO) as u128
    }

    /// Returns the total number of nanoseconds contained by this `ArchivedDuration`.
    #[inline]
    pub const fn as_nanos(&self) -> u128 {
        self.secs as u128 * NANOS_PER_SEC as u128 + self.nanos as u128
    }

    /// Returns the number of seconds contained by this `ArchivedDuration` as `f64`.
    ///
    /// The returned value does include the fractional (nanosecond) part of the duration.
    #[inline]
    pub fn as_secs_f64(&self) -> f64 {
        (self.secs as f64) + (self.nanos as f64) / (NANOS_PER_SEC as f64)
    }

    /// Returns the number of seconds contained by this `ArchivedDuration` as `f32`.
    ///
    /// The returned value does include the fractional (nanosecond) part of the duration.
    #[inline]
    pub fn as_secs_f32(&self) -> f32 {
        (self.secs as f32) + (self.nanos as f32) / (NANOS_PER_SEC as f32)
    }
}

impl Archive for Duration {
    type Archived = ArchivedDuration;
    type Resolver = ();

    #[inline]
    fn resolve(&self, pos: usize, _: Self::Resolver, out: &mut MaybeUninit<Self::Archived>) {
        unsafe {
            self.as_secs().resolve(
                pos + offset_of!(ArchivedDuration, secs),
                (),
                project_struct!(out: Self::Archived => secs),
            );
            self.subsec_nanos().resolve(
                pos + offset_of!(ArchivedDuration, nanos),
                (),
                project_struct!(out: Self::Archived => nanos),
            );
        }
    }
}

impl<S: Fallible + ?Sized> Serialize<S> for Duration {
    #[inline]
    fn serialize(&self, _: &mut S) -> Result<Self::Resolver, S::Error> {
        Ok(())
    }
}

impl<D: Fallible + ?Sized> Deserialize<Duration, D> for ArchivedDuration {
    #[inline]
    fn deserialize(&self, _: &mut D) -> Result<Duration, D::Error> {
        Ok(Duration::new(self.secs, self.nanos))
    }
}