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