Skip to main content

AtomicTime

Struct AtomicTime 

Source
#[repr(C)]
pub struct AtomicTime { pub realtime: AtomicBool, pub timestamp_ns: AtomicU64, }
Expand description

Represents an atomic timekeeping structure.

AtomicTime can act as a real-time clock or static clock based on its mode. It uses an AtomicU64 to atomically update the value using only immutable references.

The realtime flag indicates which mode the clock is currently in. For concurrency, this struct uses atomic operations with appropriate memory orderings:

  • Acquire/Release for reading/writing in static mode.
  • Compare-and-exchange (AcqRel) in real-time mode to guarantee monotonic increments.

Fields§

§realtime: AtomicBool

Indicates whether the clock is operating in real-time mode (true) or static mode (false)

§timestamp_ns: AtomicU64

The last recorded time (in UNIX nanoseconds). Updated atomically with compare-and-exchange in real-time mode, or simple store/fetch in static mode.

Implementations§

Source§

impl AtomicTime

Source

pub fn new(realtime: bool, time: UnixNanos) -> Self

Creates a new AtomicTime instance.

  • If realtime is true, the provided time is used only as an initial placeholder and will quickly be overridden by calls to AtomicTime::time_since_epoch.
  • If realtime is false, this clock starts in static mode, with the given time as its current value.
Source

pub fn get_time_ns(&self) -> UnixNanos

Returns the current time in nanoseconds, based on the clock’s mode.

§Thread Safety

The mode check is not atomic with the subsequent read/update. If another thread switches modes between the check and the operation, one stale-mode result may be returned. This is intentional: mode switching is a setup-time operation and should not occur concurrently with time operations.

Source

pub fn get_time_us(&self) -> u64

Returns the current time as microseconds.

Source

pub fn get_time_ms(&self) -> u64

Returns the current time as milliseconds.

Source

pub fn get_time(&self) -> f64

Returns the current time as seconds.

Source

pub fn set_time(&self, time: UnixNanos)

Manually sets a new time for the clock (only possible in static mode).

This uses an atomic store with Ordering::Release, so any thread reading with Ordering::Acquire will see the updated time. This does not enforce a total ordering among all threads, but is enough to ensure that once a thread sees this update, it also sees all writes made before this call in the writing thread.

Typically used in single-threaded scenarios or coordinated concurrency in static mode, since there’s no global ordering across threads.

§Panics

Panics if invoked when in real-time mode.

§Thread Safety

The mode check is not atomic with the subsequent store. If another thread calls make_realtime() between the check and store, the invariant can be violated. This is intentional: mode switching is a setup-time operation and should not occur concurrently with time operations. Callers must ensure mode switches are complete before resuming time operations.

Source

pub fn increment_time(&self, delta: u64) -> Result<UnixNanos>

Increments the current (static-mode) time by delta nanoseconds and returns the updated value.

Internally this uses AtomicU64::fetch_update with Ordering::AcqRel to ensure the increment is atomic and visible to readers using Acquire loads.

§Errors

Returns an error if the increment would overflow u64::MAX or if called while the clock is in real-time mode.

§Thread Safety

The mode check is not atomic with the subsequent update. If another thread calls make_realtime() between the check and update, the invariant can be violated. This is intentional: mode switching is a setup-time operation and should not occur concurrently with time operations. Callers must ensure mode switches are complete before resuming time operations.

Source

pub fn time_since_epoch(&self) -> UnixNanos

Retrieves and updates the current “real-time” clock, returning a strictly increasing timestamp based on system time.

Internally:

  • We fetch now from SystemTime::now().
  • We do an atomic compare-and-exchange (using Ordering::AcqRel) to ensure the stored timestamp is never less than the last timestamp.

This ensures:

  1. Monotonic increments: The returned timestamp is strictly greater than the previous one (by at least 1 nanosecond).
  2. No backward jumps: If the OS time moves backward, we ignore that shift to preserve monotonicity.
  3. Visibility: In a multi-threaded environment, other threads see the updated value once this compare-and-exchange completes.
§Panics

Panics if the internal counter has reached u64::MAX, which would indicate the process has been running for longer than the representable range (~584 years) or the clock was manually corrupted.

Source

pub fn make_realtime(&self)

Switches the clock to real-time mode (realtime = true).

If transitioning from static mode, the internal counter is reset to the current wall-clock time so that AtomicTime::time_since_epoch does not carry forward a timestamp set during static mode (e.g. a backtest far in the future).

Uses Ordering::SeqCst for the mode flag to ensure global ordering.

Source

pub fn make_static(&self)

Switches the clock to static mode (realtime = false).

If transitioning from real-time mode, the internal counter is snapshotted to the current wall-clock time so that subsequent static reads return a reasonable value rather than a stale or zero placeholder.

Uses Ordering::SeqCst for the mode flag to ensure global ordering.

Trait Implementations§

Source§

impl Debug for AtomicTime

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for AtomicTime

Source§

fn default() -> Self

Creates a new default AtomicTime instance in real-time mode, starting at the current system time.

Source§

impl Deref for AtomicTime

Source§

type Target = Atomic<u64>

The resulting type after dereferencing.
Source§

fn deref(&self) -> &Self::Target

Dereferences the value.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> Ungil for T
where T: Send,