1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
//! This crate provides a set of synchronized initialization primitives, which //! are primarily useful for lazy and one-time initialization of static //! variables. //! //! # Synchronization Primitives //! //! With the `std` feature enabled (which is the default setting), this crate //! provides the [`Once`], [`OnceCell`] and [`Lazy`] types and the equivalents //! of these types using spin-locks in the `spin` sub-module. //! //! ## Lazy //! //! The [`Lazy`] type has the same functionality as the `lazy_static!` macro, //! but works without any macros. //! //! ## Once //! //! This type is very similar to the `std::sync::Once` type in the standard //! library, but features a richer API. //! //! ## OnceCell //! //! A cell type with interior mutability that can be only written to once and //! only allows read access to the contained data after initialization. //! //! # Credits //! //! Inspiration for this crate is heavily drawn from [`once_cell`](https://crates.io/crates/once_cell), //! but features clear distinctions between blocking and non-blocking operations //! and support for `#[no_std]` environments out of the box, by offering //! additional synchronization primitives using spin-locks instead of OS reliant //! blocking mechanisms. //! Unlike many other crates, support for the `#[no_std]` compatible types is //! not mutually exclusive with using the types relying on the presence of the //! standard library. //! //! The idea for the implementation of the [`Once`]/[`OnceCell`] types is also //! directly inspired by the implementation in the standard library. //! The reasoning behind re-implementing [`Once`] is the fairly restricted and //! partly unstable API of the version in the standard library. #![cfg_attr(all(not(test), not(feature = "std")), no_std)] #![deny(missing_docs)] #[cfg(test)] #[macro_use] mod tests; pub mod spin; pub mod raw { //! Generic 'raw' types exposed through various type aliases. pub use crate::cell::OnceCell; pub use crate::lazy::Lazy; } mod cell; mod lazy; mod state; #[cfg(feature = "std")] mod with_std; mod internal { pub trait Internal {} } pub use crate::cell::{TryGetError, TryInitError}; use crate::internal::Internal; #[cfg(feature = "std")] use crate::with_std::ParkThread; /// Whenever a poisoned [`OnceCell`] is encountered, the panic is propagated /// with this message. const POISON_PANIC_MSG: &str = "OnceCell instance has been poisoned."; #[cfg(feature = "std")] /// A type for lazy initialization of e.g. global static variables, which /// provides the same functionality as the `lazy_static!` macro. /// /// For the API of this type alias, see the API of the generic /// [`Lazy`](crate::raw::Lazy) type. /// /// # Examples /// /// ``` /// use std::sync::Mutex; /// /// use conquer_once::Lazy; /// /// static MUTEX: Lazy<Mutex<Vec<i32>>> = Lazy::new(Mutex::default); /// /// let mut lock = MUTEX.lock().unwrap(); /// /// lock.push(1); /// lock.push(2); /// lock.push(3); /// /// assert_eq!(lock.as_slice(), &[1, 2, 3]); /// ``` /// /// The associated [`new`](crate::raw::Lazy::new) function can be used with any function or /// closure that implements `Fn() -> T`. /// /// ``` /// use std::collections::HashMap; /// /// use conquer_once::Lazy; /// /// static CAPITALS: Lazy<HashMap<&str, &str>> = Lazy::new(|| { /// let mut map = HashMap::new(); /// map.insert("Norway", "Oslo"); /// map.insert("Belgium", "Brussels"); /// map.insert("Latvia", "Riga"); /// map /// }); /// /// assert_eq!(CAPITALS.get(&"Norway"), Some(&"Oslo")); /// assert_eq!(CAPITALS.get(&"Belgium"), Some(&"Brussels")); /// assert_eq!(CAPITALS.get(&"Latvia"), Some(&"Riga")); /// ``` pub type Lazy<T, F = fn() -> T> = crate::lazy::Lazy<T, ParkThread, F>; #[cfg(feature = "std")] /// An interior mutability cell type which allows synchronized one-time /// initialization and read-only access exclusively after initialization. /// /// For the API of this type alias, see the generic /// [`OnceCell`](crate::raw::OnceCell) type. /// /// # Examples /// /// ``` /// use conquer_once::OnceCell; /// /// #[derive(Copy, Clone)] /// struct Configuration { /// mode: i32, /// threshold: u64, /// msg: &'static str, /// } /// /// static CONFIG: OnceCell<Configuration> = OnceCell::uninit(); /// /// // producer thread /// CONFIG.init_once(|| Configuration { /// mode: 2, /// threshold: 128, /// msg: "..." /// }); /// /// // consumer thread /// let res = CONFIG.get().copied(); /// if let Some(config) = res { /// assert_eq!(config.mode, 2); /// assert_eq!(config.threshold, 128); /// } /// ``` pub type OnceCell<T> = crate::cell::OnceCell<T, ParkThread>; #[cfg(feature = "std")] /// A synchronization primitive which can be used to run a one-time global /// initialization. /// /// For the API of this type alias, see the generic /// [`OnceCell`](crate::raw::OnceCell) type. /// This is a specialization with `T = ()`. /// /// # Examples /// /// ``` /// use conquer_once::Once; /// /// static mut GLOBAL: usize = 0; /// static INIT: Once = Once::uninit(); /// /// fn get_global() -> usize { /// // this is safe because the `Once` ensures the `static mut` is assigned /// // by only one thread and without data races. /// unsafe { /// INIT.init_once(|| { /// GLOBAL = expensive_computation(); /// }); /// # assert_eq!(GLOBAL, 1); /// GLOBAL /// } /// } /// /// fn expensive_computation() -> usize { /// // ... /// # 1 /// } /// ``` pub type Once = OnceCell<()>;