Skip to content

Commit

Permalink
wrap rather than overflow timestamps
Browse files Browse the repository at this point in the history
  • Loading branch information
KodrAus committed Jun 27, 2023
1 parent 7da3f69 commit 646bd98
Showing 1 changed file with 38 additions and 3 deletions.
41 changes: 38 additions & 3 deletions src/timestamp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ impl Timestamp {

/// Construct a `Timestamp` from an RFC4122 timestamp and counter, as used
/// in versions 1 and 6 UUIDs.
///
/// # Overflow
///
/// If conversion from RFC4122 ticks to the internal timestamp format would overflow
/// it will wrap.
pub const fn from_rfc4122(ticks: u64, counter: u16) -> Self {
#[cfg(not(any(feature = "v1", feature = "v6")))]
{
Expand All @@ -89,6 +94,11 @@ impl Timestamp {
}

/// Construct a `Timestamp` from a Unix timestamp, as used in version 7 UUIDs.
///
/// # Overflow
///
/// If conversion from RFC4122 ticks to the internal timestamp format would overflow
/// it will wrap.
pub fn from_unix(context: impl ClockSequence<Output = u16>, seconds: u64, nanos: u32) -> Self {
#[cfg(not(any(feature = "v1", feature = "v6")))]
{
Expand All @@ -110,6 +120,11 @@ impl Timestamp {

/// Get the value of the timestamp as an RFC4122 timestamp and counter,
/// as used in versions 1 and 6 UUIDs.
///
/// # Overflow
///
/// If conversion from RFC4122 ticks to the internal timestamp format would overflow
/// it will wrap.
#[cfg(any(feature = "v1", feature = "v6"))]
pub const fn to_rfc4122(&self) -> (u64, u16) {
(
Expand All @@ -119,21 +134,26 @@ impl Timestamp {
}

/// Get the value of the timestamp as a Unix timestamp, as used in version 7 UUIDs.
///
/// # Overflow
///
/// If conversion from RFC4122 ticks to the internal timestamp format would overflow
/// it will wrap.
pub const fn to_unix(&self) -> (u64, u32) {
(self.seconds, self.nanos)
}

#[cfg(any(feature = "v1", feature = "v6"))]
const fn unix_to_rfc4122_ticks(seconds: u64, nanos: u32) -> u64 {
let ticks = UUID_TICKS_BETWEEN_EPOCHS + seconds * 10_000_000 + nanos as u64 / 100;
let ticks = UUID_TICKS_BETWEEN_EPOCHS.wrapping_add(seconds.wrapping_mul(10_000_000)).wrapping_add(nanos as u64 / 100);

ticks
}

const fn rfc4122_to_unix(ticks: u64) -> (u64, u32) {
(
(ticks - UUID_TICKS_BETWEEN_EPOCHS) / 10_000_000,
((ticks - UUID_TICKS_BETWEEN_EPOCHS) % 10_000_000) as u32 * 100,
ticks.wrapping_sub(UUID_TICKS_BETWEEN_EPOCHS) / 10_000_000,
(ticks.wrapping_sub(UUID_TICKS_BETWEEN_EPOCHS) % 10_000_000) as u32 * 100,
)
}

Expand Down Expand Up @@ -268,6 +288,7 @@ fn now() -> (u64, u32) {

#[wasm_bindgen]
extern "C" {
// NOTE: This signature works around https://bugzilla.mozilla.org/show_bug.cgi?id=1787770
#[wasm_bindgen(js_namespace = Date, catch)]
fn now() -> Result<f64, JsValue>;
}
Expand Down Expand Up @@ -401,3 +422,17 @@ pub mod context {
}
}
}

#[cfg(all(test, any(feature = "v1", feature = "v6")))]
mod tests {
use super::*;

#[test]
fn rfc4122_unix_wraps() {
// Ensure timestamp conversions never panic
Timestamp::unix_to_rfc4122_ticks(u64::MAX, 0);
Timestamp::unix_to_rfc4122_ticks(0, u32::MAX);

Timestamp::rfc4122_to_unix(u64::MAX);
}
}

0 comments on commit 646bd98

Please sign in to comment.