1d0a2ff35Sopenharmony_ci// Copyright 2016 lazy-static.rs Developers 2d0a2ff35Sopenharmony_ci// 3d0a2ff35Sopenharmony_ci// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or 4d0a2ff35Sopenharmony_ci// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or 5d0a2ff35Sopenharmony_ci// http://opensource.org/licenses/MIT>, at your option. This file may not be 6d0a2ff35Sopenharmony_ci// copied, modified, or distributed except according to those terms. 7d0a2ff35Sopenharmony_ci 8d0a2ff35Sopenharmony_ci/*! 9d0a2ff35Sopenharmony_ciA macro for declaring lazily evaluated statics. 10d0a2ff35Sopenharmony_ci 11d0a2ff35Sopenharmony_ciUsing this macro, it is possible to have `static`s that require code to be 12d0a2ff35Sopenharmony_ciexecuted at runtime in order to be initialized. 13d0a2ff35Sopenharmony_ciThis includes anything requiring heap allocations, like vectors or hash maps, 14d0a2ff35Sopenharmony_cias well as anything that requires function calls to be computed. 15d0a2ff35Sopenharmony_ci 16d0a2ff35Sopenharmony_ci# Syntax 17d0a2ff35Sopenharmony_ci 18d0a2ff35Sopenharmony_ci```ignore 19d0a2ff35Sopenharmony_cilazy_static! { 20d0a2ff35Sopenharmony_ci [pub] static ref NAME_1: TYPE_1 = EXPR_1; 21d0a2ff35Sopenharmony_ci [pub] static ref NAME_2: TYPE_2 = EXPR_2; 22d0a2ff35Sopenharmony_ci ... 23d0a2ff35Sopenharmony_ci [pub] static ref NAME_N: TYPE_N = EXPR_N; 24d0a2ff35Sopenharmony_ci} 25d0a2ff35Sopenharmony_ci``` 26d0a2ff35Sopenharmony_ci 27d0a2ff35Sopenharmony_ciAttributes (including doc comments) are supported as well: 28d0a2ff35Sopenharmony_ci 29d0a2ff35Sopenharmony_ci```rust 30d0a2ff35Sopenharmony_ci# #[macro_use] 31d0a2ff35Sopenharmony_ci# extern crate lazy_static; 32d0a2ff35Sopenharmony_ci# fn main() { 33d0a2ff35Sopenharmony_cilazy_static! { 34d0a2ff35Sopenharmony_ci /// This is an example for using doc comment attributes 35d0a2ff35Sopenharmony_ci static ref EXAMPLE: u8 = 42; 36d0a2ff35Sopenharmony_ci} 37d0a2ff35Sopenharmony_ci# } 38d0a2ff35Sopenharmony_ci``` 39d0a2ff35Sopenharmony_ci 40d0a2ff35Sopenharmony_ci# Semantics 41d0a2ff35Sopenharmony_ci 42d0a2ff35Sopenharmony_ciFor a given `static ref NAME: TYPE = EXPR;`, the macro generates a unique type that 43d0a2ff35Sopenharmony_ciimplements `Deref<TYPE>` and stores it in a static with name `NAME`. (Attributes end up 44d0a2ff35Sopenharmony_ciattaching to this type.) 45d0a2ff35Sopenharmony_ci 46d0a2ff35Sopenharmony_ciOn first deref, `EXPR` gets evaluated and stored internally, such that all further derefs 47d0a2ff35Sopenharmony_cican return a reference to the same object. Note that this can lead to deadlocks 48d0a2ff35Sopenharmony_ciif you have multiple lazy statics that depend on each other in their initialization. 49d0a2ff35Sopenharmony_ci 50d0a2ff35Sopenharmony_ciApart from the lazy initialization, the resulting "static ref" variables 51d0a2ff35Sopenharmony_cihave generally the same properties as regular "static" variables: 52d0a2ff35Sopenharmony_ci 53d0a2ff35Sopenharmony_ci- Any type in them needs to fulfill the `Sync` trait. 54d0a2ff35Sopenharmony_ci- If the type has a destructor, then it will not run when the process exits. 55d0a2ff35Sopenharmony_ci 56d0a2ff35Sopenharmony_ci# Example 57d0a2ff35Sopenharmony_ci 58d0a2ff35Sopenharmony_ciUsing the macro: 59d0a2ff35Sopenharmony_ci 60d0a2ff35Sopenharmony_ci```rust 61d0a2ff35Sopenharmony_ci#[macro_use] 62d0a2ff35Sopenharmony_ciextern crate lazy_static; 63d0a2ff35Sopenharmony_ci 64d0a2ff35Sopenharmony_ciuse std::collections::HashMap; 65d0a2ff35Sopenharmony_ci 66d0a2ff35Sopenharmony_cilazy_static! { 67d0a2ff35Sopenharmony_ci static ref HASHMAP: HashMap<u32, &'static str> = { 68d0a2ff35Sopenharmony_ci let mut m = HashMap::new(); 69d0a2ff35Sopenharmony_ci m.insert(0, "foo"); 70d0a2ff35Sopenharmony_ci m.insert(1, "bar"); 71d0a2ff35Sopenharmony_ci m.insert(2, "baz"); 72d0a2ff35Sopenharmony_ci m 73d0a2ff35Sopenharmony_ci }; 74d0a2ff35Sopenharmony_ci static ref COUNT: usize = HASHMAP.len(); 75d0a2ff35Sopenharmony_ci static ref NUMBER: u32 = times_two(21); 76d0a2ff35Sopenharmony_ci} 77d0a2ff35Sopenharmony_ci 78d0a2ff35Sopenharmony_cifn times_two(n: u32) -> u32 { n * 2 } 79d0a2ff35Sopenharmony_ci 80d0a2ff35Sopenharmony_cifn main() { 81d0a2ff35Sopenharmony_ci println!("The map has {} entries.", *COUNT); 82d0a2ff35Sopenharmony_ci println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap()); 83d0a2ff35Sopenharmony_ci println!("A expensive calculation on a static results in: {}.", *NUMBER); 84d0a2ff35Sopenharmony_ci} 85d0a2ff35Sopenharmony_ci``` 86d0a2ff35Sopenharmony_ci 87d0a2ff35Sopenharmony_ci# Implementation details 88d0a2ff35Sopenharmony_ci 89d0a2ff35Sopenharmony_ciThe `Deref` implementation uses a hidden static variable that is guarded by an atomic check on each access. 90d0a2ff35Sopenharmony_ci 91d0a2ff35Sopenharmony_ci# Cargo features 92d0a2ff35Sopenharmony_ci 93d0a2ff35Sopenharmony_ciThis crate provides one cargo feature: 94d0a2ff35Sopenharmony_ci 95d0a2ff35Sopenharmony_ci- `spin_no_std`: This allows using this crate in a no-std environment, by depending on the standalone `spin` crate. 96d0a2ff35Sopenharmony_ci 97d0a2ff35Sopenharmony_ci*/ 98d0a2ff35Sopenharmony_ci 99d0a2ff35Sopenharmony_ci#![doc(html_root_url = "https://docs.rs/lazy_static/1.4.0")] 100d0a2ff35Sopenharmony_ci#![no_std] 101d0a2ff35Sopenharmony_ci 102d0a2ff35Sopenharmony_ci#[cfg(not(feature = "spin_no_std"))] 103d0a2ff35Sopenharmony_ci#[path="inline_lazy.rs"] 104d0a2ff35Sopenharmony_ci#[doc(hidden)] 105d0a2ff35Sopenharmony_cipub mod lazy; 106d0a2ff35Sopenharmony_ci 107d0a2ff35Sopenharmony_ci#[cfg(test)] 108d0a2ff35Sopenharmony_ci#[macro_use] 109d0a2ff35Sopenharmony_ciextern crate doc_comment; 110d0a2ff35Sopenharmony_ci 111d0a2ff35Sopenharmony_ci#[cfg(test)] 112d0a2ff35Sopenharmony_cidoctest!("../README.md"); 113d0a2ff35Sopenharmony_ci 114d0a2ff35Sopenharmony_ci#[cfg(feature = "spin_no_std")] 115d0a2ff35Sopenharmony_ci#[path="core_lazy.rs"] 116d0a2ff35Sopenharmony_ci#[doc(hidden)] 117d0a2ff35Sopenharmony_cipub mod lazy; 118d0a2ff35Sopenharmony_ci 119d0a2ff35Sopenharmony_ci#[doc(hidden)] 120d0a2ff35Sopenharmony_cipub use core::ops::Deref as __Deref; 121d0a2ff35Sopenharmony_ci 122d0a2ff35Sopenharmony_ci#[macro_export(local_inner_macros)] 123d0a2ff35Sopenharmony_ci#[doc(hidden)] 124d0a2ff35Sopenharmony_cimacro_rules! __lazy_static_internal { 125d0a2ff35Sopenharmony_ci // optional visibility restrictions are wrapped in `()` to allow for 126d0a2ff35Sopenharmony_ci // explicitly passing otherwise implicit information about private items 127d0a2ff35Sopenharmony_ci ($(#[$attr:meta])* ($($vis:tt)*) static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => { 128d0a2ff35Sopenharmony_ci __lazy_static_internal!(@MAKE TY, $(#[$attr])*, ($($vis)*), $N); 129d0a2ff35Sopenharmony_ci __lazy_static_internal!(@TAIL, $N : $T = $e); 130d0a2ff35Sopenharmony_ci lazy_static!($($t)*); 131d0a2ff35Sopenharmony_ci }; 132d0a2ff35Sopenharmony_ci (@TAIL, $N:ident : $T:ty = $e:expr) => { 133d0a2ff35Sopenharmony_ci impl $crate::__Deref for $N { 134d0a2ff35Sopenharmony_ci type Target = $T; 135d0a2ff35Sopenharmony_ci fn deref(&self) -> &$T { 136d0a2ff35Sopenharmony_ci #[inline(always)] 137d0a2ff35Sopenharmony_ci fn __static_ref_initialize() -> $T { $e } 138d0a2ff35Sopenharmony_ci 139d0a2ff35Sopenharmony_ci #[inline(always)] 140d0a2ff35Sopenharmony_ci fn __stability() -> &'static $T { 141d0a2ff35Sopenharmony_ci __lazy_static_create!(LAZY, $T); 142d0a2ff35Sopenharmony_ci LAZY.get(__static_ref_initialize) 143d0a2ff35Sopenharmony_ci } 144d0a2ff35Sopenharmony_ci __stability() 145d0a2ff35Sopenharmony_ci } 146d0a2ff35Sopenharmony_ci } 147d0a2ff35Sopenharmony_ci impl $crate::LazyStatic for $N { 148d0a2ff35Sopenharmony_ci fn initialize(lazy: &Self) { 149d0a2ff35Sopenharmony_ci let _ = &**lazy; 150d0a2ff35Sopenharmony_ci } 151d0a2ff35Sopenharmony_ci } 152d0a2ff35Sopenharmony_ci }; 153d0a2ff35Sopenharmony_ci // `vis` is wrapped in `()` to prevent parsing ambiguity 154d0a2ff35Sopenharmony_ci (@MAKE TY, $(#[$attr:meta])*, ($($vis:tt)*), $N:ident) => { 155d0a2ff35Sopenharmony_ci #[allow(missing_copy_implementations)] 156d0a2ff35Sopenharmony_ci #[allow(non_camel_case_types)] 157d0a2ff35Sopenharmony_ci #[allow(dead_code)] 158d0a2ff35Sopenharmony_ci $(#[$attr])* 159d0a2ff35Sopenharmony_ci $($vis)* struct $N {__private_field: ()} 160d0a2ff35Sopenharmony_ci #[doc(hidden)] 161d0a2ff35Sopenharmony_ci $($vis)* static $N: $N = $N {__private_field: ()}; 162d0a2ff35Sopenharmony_ci }; 163d0a2ff35Sopenharmony_ci () => () 164d0a2ff35Sopenharmony_ci} 165d0a2ff35Sopenharmony_ci 166d0a2ff35Sopenharmony_ci#[macro_export(local_inner_macros)] 167d0a2ff35Sopenharmony_cimacro_rules! lazy_static { 168d0a2ff35Sopenharmony_ci ($(#[$attr:meta])* static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => { 169d0a2ff35Sopenharmony_ci // use `()` to explicitly forward the information about private items 170d0a2ff35Sopenharmony_ci __lazy_static_internal!($(#[$attr])* () static ref $N : $T = $e; $($t)*); 171d0a2ff35Sopenharmony_ci }; 172d0a2ff35Sopenharmony_ci ($(#[$attr:meta])* pub static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => { 173d0a2ff35Sopenharmony_ci __lazy_static_internal!($(#[$attr])* (pub) static ref $N : $T = $e; $($t)*); 174d0a2ff35Sopenharmony_ci }; 175d0a2ff35Sopenharmony_ci ($(#[$attr:meta])* pub ($($vis:tt)+) static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => { 176d0a2ff35Sopenharmony_ci __lazy_static_internal!($(#[$attr])* (pub ($($vis)+)) static ref $N : $T = $e; $($t)*); 177d0a2ff35Sopenharmony_ci }; 178d0a2ff35Sopenharmony_ci () => () 179d0a2ff35Sopenharmony_ci} 180d0a2ff35Sopenharmony_ci 181d0a2ff35Sopenharmony_ci/// Support trait for enabling a few common operation on lazy static values. 182d0a2ff35Sopenharmony_ci/// 183d0a2ff35Sopenharmony_ci/// This is implemented by each defined lazy static, and 184d0a2ff35Sopenharmony_ci/// used by the free functions in this crate. 185d0a2ff35Sopenharmony_cipub trait LazyStatic { 186d0a2ff35Sopenharmony_ci #[doc(hidden)] 187d0a2ff35Sopenharmony_ci fn initialize(lazy: &Self); 188d0a2ff35Sopenharmony_ci} 189d0a2ff35Sopenharmony_ci 190d0a2ff35Sopenharmony_ci/// Takes a shared reference to a lazy static and initializes 191d0a2ff35Sopenharmony_ci/// it if it has not been already. 192d0a2ff35Sopenharmony_ci/// 193d0a2ff35Sopenharmony_ci/// This can be used to control the initialization point of a lazy static. 194d0a2ff35Sopenharmony_ci/// 195d0a2ff35Sopenharmony_ci/// Example: 196d0a2ff35Sopenharmony_ci/// 197d0a2ff35Sopenharmony_ci/// ```rust 198d0a2ff35Sopenharmony_ci/// #[macro_use] 199d0a2ff35Sopenharmony_ci/// extern crate lazy_static; 200d0a2ff35Sopenharmony_ci/// 201d0a2ff35Sopenharmony_ci/// lazy_static! { 202d0a2ff35Sopenharmony_ci/// static ref BUFFER: Vec<u8> = (0..255).collect(); 203d0a2ff35Sopenharmony_ci/// } 204d0a2ff35Sopenharmony_ci/// 205d0a2ff35Sopenharmony_ci/// fn main() { 206d0a2ff35Sopenharmony_ci/// lazy_static::initialize(&BUFFER); 207d0a2ff35Sopenharmony_ci/// 208d0a2ff35Sopenharmony_ci/// // ... 209d0a2ff35Sopenharmony_ci/// work_with_initialized_data(&BUFFER); 210d0a2ff35Sopenharmony_ci/// } 211d0a2ff35Sopenharmony_ci/// # fn work_with_initialized_data(_: &[u8]) {} 212d0a2ff35Sopenharmony_ci/// ``` 213d0a2ff35Sopenharmony_cipub fn initialize<T: LazyStatic>(lazy: &T) { 214d0a2ff35Sopenharmony_ci LazyStatic::initialize(lazy); 215d0a2ff35Sopenharmony_ci} 216