hail_core 0.3.0

a library for implementing a speedrun timer
Documentation
/*
  Copyright 2024 periwinkle

  This Source Code Form is subject to the terms of the Mozilla Public
  License, v. 2.0. If a copy of the MPL was not distributed with this
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

/// Measurement of a clock.
///
/// Continues measuring time across suspend on platforms where this is available,
/// unlike the standard library's Instant, which only seems to do this on Windows.
///
/// Therefore, we need a custom implementation for Linux systems as well as
/// macOS systems.
///
/// (See <https://github.com/rust-lang/rust/issues/87906>)
pub use platform::HailInstant;

#[cfg(windows)]
mod platform {
    // already behaves how we want on windows, apparently.
    pub type HailInstant = std::time::Instant;
}

// On Linux clock_monotonic doesn't count suspend time. The Linux kernel introduced
// the clock_boottime clockid after 2.6.39. Rust no longer supports pre-3.2 and as such
// I don't care if this doesn't work there.
//
// macOS documentation recommends clock_gettime_nsec_np.
//
// For now I don't support anything else. Could add other *BSDs which seem to do what we want
// with clock_monotonic.

#[cfg(target_os = "linux")]
mod platform {
    use std::time::Duration;
    #[derive(Debug, Clone)]
    pub struct HailInstant(Duration);

    impl HailInstant {
        /// Create an instant corresponding to "now".
        pub fn now() -> Self {
            let mut ts = libc::timespec {
                tv_sec: 0,
                tv_nsec: 0,
            };
            // Always safe, since we have a valid pointer to a timespec.
            if unsafe { libc::clock_gettime(libc::CLOCK_BOOTTIME, &mut ts) } != 0 {
                panic!("clock_gettime doesn't work!");
            }
            Self(Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32))
        }
        /// Get the amount of time that has passed between an Instant and now.
        pub fn elapsed(&self) -> Duration {
            let now = Self::now();
            now.0 - self.0
        }
    }
}

#[cfg(target_os = "macos")]
mod platform {
    use std::time::Duration;
    #[derive(Debug, Clone)]
    pub struct HailInstant(Duration);

    extern "C" fn clock_gettime_nsec_np(t: libc::clockid_t) -> u64;

    impl HailInstant {
        /// Create an instant corresponding to "now".
        pub fn now() -> Self {
            let t = unsafe { clock_gettime_nsec_np(libc::CLOCK_MONOTONIC_RAW) };
            Self(Duration::from_nanos(t))
        }
        /// Get the amount of time that has passed between an Instant and now.
        pub fn elapsed(&self) -> Duration {
            let now = Self::now();
            now.0 - self.0
        }
    }
}