Josh Weinstein
Josh Weinstein

Reputation: 2968

How to implement a safe global Instance?

In Rust, I am trying to find a way to safely set a global Instant. Instant is perhaps a unique form of a singleton because it has no way to initialize itself through constant function calls. Attempting to initialize a static Instant via Instant::now() results in the following error:

error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
  --> src/main.rs:45:24
   |
45 | static EPOCH:Instant = Instant::now();
   | 

               ^^^^^^^^^^^^^^

Therefore I am looking for an ideally safe way to do the above. For context, I already have a way to do this using unsafe rust:

use std::time::{Instant};
use std::mem::{self, MaybeUninit};

static mut MONOTONIC_EPOCH:MaybeUninit<Instant> = MaybeUninit::<Instant>::uninit();

fn set_epoch() {
    unsafe {
        MONOTONIC_EPOCH.as_mut_ptr().write(Instant::now());
    }
}

In my use case, I need global monotonic point in time that can be used to track the time since some point in the program execution. Thus, the global Instant does not need to be mutable after it's first set. It can be assumed that this initialization would be guaranteed in the use case to occur with only one thread active.

Note: I do need a way to control when the initialization of the Instant occurs.

Upvotes: 4

Views: 1158

Answers (1)

Netwave
Netwave

Reputation: 42718

You can use once_cell::Lazy any of sync or unsync versions depending your needs:

use std::time::{Instant};
use once_cell::sync::Lazy;

static EPOCH: Lazy<Instant> = Lazy::new(Instant::now);

Playground

If you want to handle when and where initialization is done use OnceCell instead:

use std::time::{Instant};
use once_cell::sync::OnceCell;

static EPOCH: OnceCell<Instant> = OnceCell::new();

fn main() {
    let instant = EPOCH.get_or_init(Instant::now);
    println!("{:?}", *instant);
}

Playground

Upvotes: 2

Related Questions