Non const static initialization, and program constructor/destructor code.
This crate provides lazy statics on all plateforms.
On unixes and windows lesser lazy statics are lazy during program startup phase
(before main
is called). Once main is called, those statics are all guaranteed to be
initialized and any access to them is as fast as any access to regular const initialized
statics. Benches sho that usual lazy statics, as those provided by std::lazy::*
or from
lazy_static crate, suffer from a 2ns access penalty.
Lesser lazy statics can optionaly be dropped at program destruction (after main exit but before the program stops).
Lesser lazy statics require the standard library and are enabled by default
crate features lazy
and atexit
.
```rust
use static_init::{dynamic};
static L1: Vec
static L0: Vec
static mut L2: Vec
On plateforms that support it (unixes, mac, windows), this crate provides dynamic statics: statics that are
initialized at program startup. This feature is no_std
.
```rust use static_init::{dynamic};
//equivalent to #[dynamic(init=0)]
static D1: Vec
assert_eq!(unsafe{D1[0]}, 1); ``` As can be seen above, even if D1 is not mutable, access to it must be performed in unsafe blocks. The reason is that during startup phase, accesses to dynamic statics may cause undefined behavior: dynamic statics may be in a zero initialized state.
To prevent such hazardeous accesses, on unixes and window plateforms, a priority can be specified. Dynamic static initializations with higher priority are sequenced before dynamic static initializations with lower priority. Dynamic static initializations with the same priority are underterminately sequenced.
```rust use static_init::{dynamic};
// D2 initialization is sequenced before D1 initialization
static mut D1: Vec
static D2: Vec
Dynamic statics can be dropped at program destruction phase: they are dropped after main exit:
```rust use static_init::{dynamic};
// D2 initialization is sequenced before D1 initialization // D1 drop is sequenced before D2 drop.
static mut D1: Vec
static D2: Vec
Finally, if the feature atexit
is enabled, dynamic statics drop can be registered with
libc::atexit
. lazy dynamic statics and dynamic statics with drop_reverse
attribute
argument are destroyed in the reverse order of their construction. Functions registered with
atexit
are executed before program destructors and drop of dynamic statics that use the
drop
attribute argument. Drop is registered with at atexit
if no priority if given to the
drop
attribute argument.
```rust use static_init::{dynamic};
//D1 is dropped before D2 because //it is initialized before D2
static D1: Vec
static D2: Vec
//D3 is initilized after D1 and D2 initializations //and it is dropped after D1 and D2 drops
static D3: Vec
On plateforms that support it (unixes, mac, windows), this crate provides a way to declare
constructors: a function called before main is called. This feature is no_std
.
```rust use static_init::{constructor};
//called before main
extern "C" fn some_init() {} ```
Constructors also support priorities. Sequencement rules applies also between constructor calls and between dynamic statics initialization and constructor calls.
destructors are called at program destruction. They also support priorities.
```rust use static_init::{constructor, destructor};
//called before some_init
extern "C" fn pre_init() {}
//called before main
extern "C" fn some_init() {}
//called after main
extern "C" fn first_destructor() {}
//called after first_destructor
extern "C" fn last_destructor() {} ```
Variable declared with #[dynamic(lazy)]
can also be declared #[thread_local]
. These
variable will behave as regular lazy statics.
```rust
static mut X: Vec
These variables can also be droped on thread exit.
```rust
static X: Vec
assert!(unsafe{X[1] == 2}); ```
Accessing a thread local lazy statics that should drop during the phase where thread_locals are droped may cause undefined behavior. For this reason any access to a thread local lazy static that is dropped will require an unsafe block, even if the static is const.
If the feature debug_order
is enabled, attempts to access dynamic statics
that are
uninitialized or whose initialization is undeterminately sequenced with the access will cause
a panic with a message specifying which statics was tentatively accessed and how to change this
dynamic static priority to fix this issue.
Run cargo test
in this crate directory to see message examples.
All implementations of lazy statics may suffer from circular initialization dependencies. Those
circular dependencies will cause either a dead lock or an infinite loop. If the feature debug_order
is
enabled, atemp are made to detect those circular dependencies. In most case they will be detected.
std::lazy::Lazy
.