#static #token #init

init-token

A crate for one-time safe initialization of static, without overhead

2 releases

0.1.1 Jul 21, 2022
0.1.0 Jul 20, 2022

#2575 in Rust patterns

MIT license

20KB
204 lines

A crate for one-time safe initialization of static, without overhead.

There are multiple ways to initialize statics in Rust. The most common is lazy_static or once_cell that is even being integrated into the standard library. Those crates lazily-initialize the value. The problem is that this incurs an overhead for each access, very small overhead but this is a problem for some applications.

This crate proposes another approach: initialization that produces a zero sized access token that you can then use to access the value via Deref.

There are two options on how to do that: init! and init_big!. init! should be the default choice. Its syntax is like the following:

init_token::init! {
    /// The magic token to get `MY_STATIC` working.
    pub token MyInitToken;
    /// My cool static.
    pub static MY_STATIC: i32 = std::env::var("MY_STATIC").unwrap().parse().unwrap();
}

init_big! is intended for cases where the static value is very big, too big to pass on stack, and thus returning it from the initializer is problematic. Instead, you provide a const initializer, and then init(name) { init_code }, where name will be a mutable reference to the contents of the static. An example will explain better:

init_token::init_big! {
    /// The magic token to get `MY_STATIC` working.
    pub token MyInitToken;
    /// My cool static.
    // The initializer here must be `const` and will be put directly on the `static`'s
    // initializer expression.
    pub static MY_STATIC: i32 = 0;

    // Now, we write code to calculate the static and assign to it as we wish.
    // `my_static` here is a pointer to `MY_STATIC` and has the type `&mut i32`.
    init(my_static) {
        *my_static = std::env::var("MY_STATIC").unwrap().parse().unwrap();
    }
}

With init!, the static will be an instance of init::Static. With init_big, it'll be an instance of init_big::Static. In both cases you should call the init() method on the static to get an access token. The token will be some auto-generated struct, which implements Deref to the static's type. If you need a 'static reference, you can instead use the static_ref() associated function (it is not a method - call it as TokenType::static_ref(token) and not as token.static_ref()!).

The visibilities of the static and the token don't have to match. This can be useful if you want to control who can get a token but let everybody use the static once they have a token, without carrying a reference to the static that is not zero-sized and thus has some overhead.

No runtime deps