diff rust/hg-core/src/dirstate/entry.rs @ 48192:d2f760c2c91c

dirstate-v2: Separate Rust structs for Timestamp and PackedTimestamp PackedTimestamp is now exclusively for dirstate-v2 serialization purpose. It contains unaligned big-endian integers. Timestamp is used everywhere else and contains native Rust integers. Differential Revision: https://phab.mercurial-scm.org/D11632
author Simon Sapin <simon.sapin@octobus.net>
date Tue, 12 Oct 2021 16:20:05 +0200
parents 1ab4523afe12
children 320de901896a
line wrap: on
line diff
--- a/rust/hg-core/src/dirstate/entry.rs	Mon Oct 11 22:19:42 2021 +0200
+++ b/rust/hg-core/src/dirstate/entry.rs	Tue Oct 12 16:20:05 2021 +0200
@@ -1,6 +1,7 @@
 use crate::errors::HgError;
 use bitflags::bitflags;
 use std::convert::TryFrom;
+use std::time::{SystemTime, UNIX_EPOCH};
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum EntryState {
@@ -28,6 +29,73 @@
     }
 }
 
+#[derive(Copy, Clone, PartialEq)]
+pub struct Timestamp {
+    seconds: i64,
+
+    /// In `0 .. 1_000_000_000`.
+    ///
+    /// This timestamp is after `(seconds, 0)` by this many nanoseconds.
+    nanoseconds: u32,
+}
+
+impl Timestamp {
+    pub fn new(seconds: i64, nanoseconds: u32) -> Self {
+        Self {
+            seconds,
+            nanoseconds,
+        }
+    }
+
+    pub fn seconds(&self) -> i64 {
+        self.seconds
+    }
+
+    pub fn nanoseconds(&self) -> u32 {
+        self.nanoseconds
+    }
+}
+
+impl From<SystemTime> for Timestamp {
+    fn from(system_time: SystemTime) -> Self {
+        // On Unix, `SystemTime` is a wrapper for the `timespec` C struct:
+        // https://www.gnu.org/software/libc/manual/html_node/Time-Types.html#index-struct-timespec
+        // We want to effectively access its fields, but the Rust standard
+        // library does not expose them. The best we can do is:
+        let seconds;
+        let nanoseconds;
+        match system_time.duration_since(UNIX_EPOCH) {
+            Ok(duration) => {
+                seconds = duration.as_secs() as i64;
+                nanoseconds = duration.subsec_nanos();
+            }
+            Err(error) => {
+                // `system_time` is before `UNIX_EPOCH`.
+                // We need to undo this algorithm:
+                // https://github.com/rust-lang/rust/blob/6bed1f0bc3cc50c10aab26d5f94b16a00776b8a5/library/std/src/sys/unix/time.rs#L40-L41
+                let negative = error.duration();
+                let negative_secs = negative.as_secs() as i64;
+                let negative_nanos = negative.subsec_nanos();
+                if negative_nanos == 0 {
+                    seconds = -negative_secs;
+                    nanoseconds = 0;
+                } else {
+                    // For example if `system_time` was 4.3 seconds before
+                    // the Unix epoch we get a Duration that represents
+                    // `(-4, -0.3)` but we want `(-5, +0.7)`:
+                    const NSEC_PER_SEC: u32 = 1_000_000_000;
+                    seconds = -1 - negative_secs;
+                    nanoseconds = NSEC_PER_SEC - negative_nanos;
+                }
+            }
+        };
+        Self {
+            seconds,
+            nanoseconds,
+        }
+    }
+}
+
 pub const V1_RANGEMASK: i32 = 0x7FFFFFFF;
 
 pub const MTIME_UNSET: i32 = -1;