├── .github └── workflows │ └── ci.yaml ├── .gitignore ├── CHANGELOG.md ├── Cargo.lock.msrv ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── bors.toml ├── design ├── icon.png └── logo.png ├── examples ├── bench.rs ├── bench_acquire.rs ├── lazy_static.rs ├── reentrant_init_deadlocks.rs ├── regex.rs └── test_synchronization.rs ├── logo.svg ├── rustfmt.toml ├── src ├── imp_cs.rs ├── imp_pl.rs ├── imp_std.rs ├── lib.rs └── race.rs ├── tests └── it │ ├── main.rs │ ├── race.rs │ ├── race_once_box.rs │ ├── sync_lazy.rs │ ├── sync_once_cell.rs │ ├── unsync_lazy.rs │ └── unsync_once_cell.rs └── xtask ├── Cargo.toml └── src ├── main.rs └── tidy.rs /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | pull_request: 4 | push: 5 | branches: ["master", "staging", "trying"] 6 | 7 | env: 8 | CARGO_INCREMENTAL: 0 9 | CARGO_NET_RETRY: 10 10 | CI: 1 11 | RUST_BACKTRACE: short 12 | RUSTFLAGS: -D warnings 13 | RUSTUP_MAX_RETRIES: 10 14 | 15 | jobs: 16 | test: 17 | name: Rust 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@v2 22 | with: 23 | fetch-depth: 0 # fetch tags for publish 24 | - uses: Swatinem/rust-cache@359a70e43a0bb8a13953b04a90f76428b4959bb6 25 | - run: cargo run -p xtask -- ci 26 | env: 27 | CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }} 28 | MIRIFLAGS: -Zmiri-strict-provenance 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /.vscode 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.21.3 4 | 5 | - Outline more initialization in `race`: [#284](https://github.com/matklad/once_cell/pull/284), 6 | [#285](https://github.com/matklad/once_cell/pull/285). 7 | 8 | ## 1.21.2 9 | - Relax success ordering from AcqRel to Release in `race`: [#278](https://github.com/matklad/once_cell/pull/278). 10 | 11 | ## 1.21.1 12 | - Reduce MSRV to 1.65: [#277](https://github.com/matklad/once_cell/pull/277). 13 | 14 | ## 1.21.0 15 | 16 | - Outline initialization in `race`: [#273](https://github.com/matklad/once_cell/pull/273). 17 | - Add `OnceNonZereUsize::get_unchecked`: [#274](https://github.com/matklad/once_cell/pull/274). 18 | - Add `OnceBox::clone` and `OnceBox::with_value`: [#275](https://github.com/matklad/once_cell/pull/275). 19 | - Increase MSRV to 1.70 20 | 21 | ## 1.20.2 22 | 23 | - Remove `portable_atomic` from Cargo.lock if it is not, in fact, used: [#267](https://github.com/matklad/once_cell/pull/267) 24 | This is a work-around for this cargo bug: https://github.com/rust-lang/cargo/issues/10801. 25 | 26 | ## 1.20.1 27 | 28 | - Allow using `race` module using just `portable_atomic`, without `critical_section` and provide 29 | better error messages on targets without atomic CAS instruction, 30 | [#265](https://github.com/matklad/once_cell/pull/265). 31 | 32 | ## 1.19.0 33 | 34 | - Use `portable-atomic` instead of `atomic-polyfill`, [#251](https://github.com/matklad/once_cell/pull/251). 35 | 36 | ## 1.18.0 37 | 38 | - `MSRV` is updated to 1.60.0 to take advantage of `dep:` syntax for cargo features, 39 | removing "implementation details" from publicly visible surface. 40 | 41 | ## 1.17.2 42 | 43 | - Avoid unnecessary synchronization in `Lazy::{force,deref}_mut()`, [#231](https://github.com/matklad/once_cell/pull/231). 44 | 45 | ## 1.17.1 46 | 47 | - Make `OnceRef` implementation compliant with [strict provenance](https://github.com/rust-lang/rust/issues/95228). 48 | 49 | ## 1.17.0 50 | 51 | - Add `race::OnceRef` for storing a `&'a T`. 52 | 53 | ## 1.16.0 54 | 55 | - Add `no_std` implementation based on `critical-section`, 56 | [#195](https://github.com/matklad/once_cell/pull/195). 57 | - Deprecate `atomic-polyfill` feature (use the new `critical-section` instead) 58 | 59 | ## 1.15.0 60 | 61 | - Increase minimal supported Rust version to 1.56.0. 62 | - Implement `UnwindSafe` even if the `std` feature is disabled. 63 | 64 | ## 1.14.0 65 | 66 | - Add extension to `unsync` and `sync` `Lazy` mut API: 67 | - `force_mut` 68 | - `get_mut` 69 | 70 | 71 | ## 1.13.1 72 | 73 | - Make implementation compliant with [strict provenance](https://github.com/rust-lang/rust/issues/95228). 74 | - Upgrade `atomic-polyfill` to `1.0` 75 | 76 | ## 1.13.0 77 | 78 | - Add `Lazy::get`, similar to `OnceCell::get`. 79 | 80 | ## 1.12.1 81 | 82 | - Remove incorrect `debug_assert`. 83 | 84 | ## 1.12.0 85 | 86 | - Add `OnceCell::wait`, a blocking variant of `get`. 87 | 88 | ## 1.11.0 89 | 90 | - Add `OnceCell::with_value` to create initialized `OnceCell` in `const` context. 91 | - Improve `Clone` implementation for `OnceCell`. 92 | - Rewrite `parking_lot` version on top of `parking_lot_core`, for even smaller cells! 93 | 94 | ## 1.10.0 95 | 96 | - upgrade `parking_lot` to `0.12.0` (note that this bumps MSRV with `parking_lot` feature enabled to `1.49.0`). 97 | 98 | ## 1.9.0 99 | 100 | - Added an `atomic-polyfill` optional dependency to compile `race` on platforms without atomics 101 | 102 | ## 1.8.0 103 | 104 | - Add `try_insert` API -- a version of `set` that returns a reference. 105 | 106 | ## 1.7.2 107 | 108 | - Improve code size when using parking_lot feature. 109 | 110 | ## 1.7.1 111 | 112 | - Fix `race::OnceBox` to also impl `Default` even if `T` doesn't impl `Default`. 113 | 114 | ## 1.7.0 115 | 116 | - Hide the `race` module behind (default) `race` feature. 117 | Turns out that adding `race` by default was a breaking change on some platforms without atomics. 118 | In this release, we make the module opt-out. 119 | Technically, this is a breaking change for those who use `race` with `no_default_features`. 120 | Given that the `race` module itself only several days old, the breakage is deemed acceptable. 121 | 122 | ## 1.6.0 123 | 124 | - Add `Lazy::into_value` 125 | - Stabilize `once_cell::race` module for "first one wins" no_std-compatible initialization flavor. 126 | - Migrate from deprecated `compare_and_swap` to `compare_exchange`. 127 | 128 | ## 1.5.2 129 | 130 | - `OnceBox` API uses `Box`. 131 | This a breaking change to unstable API. 132 | 133 | ## 1.5.1 134 | 135 | - MSRV is increased to `1.36.0`. 136 | - document `once_cell::race` module. 137 | - introduce `alloc` feature for `OnceBox`. 138 | - fix `OnceBox::set`. 139 | 140 | ## 1.5.0 141 | 142 | - add new `once_cell::race` module for "first one wins" no_std-compatible initialization flavor. 143 | The API is provisional, subject to change and is gated by the `unstable` cargo feature. 144 | 145 | ## 1.4.1 146 | 147 | - upgrade `parking_lot` to `0.11.0` 148 | - make `sync::OnceCell` pass https://doc.rust-lang.org/nomicon/dropck.html#an-escape-hatch[dropck] with `parking_lot` feature enabled. 149 | This fixes a (minor) semver-incompatible changed introduced in `1.4.0` 150 | 151 | ## 1.4.0 152 | 153 | - upgrade `parking_lot` to `0.10` (note that this bumps MSRV with `parking_lot` feature enabled to `1.36.0`). 154 | - add `OnceCell::take`. 155 | - upgrade crossbeam utils (private dependency) to `0.7`. 156 | 157 | ## 1.3.1 158 | 159 | - remove unnecessary `F: fmt::Debug` bound from `impl fmt::Debug for Lazy`. 160 | 161 | ## 1.3.0 162 | 163 | - `Lazy` now implements `DerefMut`. 164 | - update implementation according to the latest changes in `std`. 165 | 166 | ## 1.2.0 167 | 168 | - add `sync::OnceCell::get_unchecked`. 169 | 170 | ## 1.1.0 171 | 172 | - implement `Default` for `Lazy`: it creates an empty `Lazy` which is initialized with `T::default` on first access. 173 | - add `OnceCell::get_mut`. 174 | 175 | ## 1.0.2 176 | 177 | - actually add `#![no_std]` attribute if std feature is not enabled. 178 | 179 | ## 1.0.1 180 | 181 | - fix unsoundness in `Lazy` if the initializing function panics. Thanks [@xfix](https://github.com/xfix)! 182 | - implement `RefUnwindSafe` for `Lazy`. 183 | - share more code between `std` and `parking_lot` implementations. 184 | - add F.A.Q section to the docs. 185 | 186 | ## 1.0.0 187 | 188 | - remove `parking_lot` from the list of default features. 189 | - add `std` default feature. Without `std`, only `unsync` module is supported. 190 | - implement `Eq` for `OnceCell`. 191 | - fix wrong `Sync` bound on `sync::Lazy`. 192 | - run the whole test suite with miri. 193 | 194 | ## 0.2.7 195 | 196 | - New implementation of `sync::OnceCell` if `parking_lot` feature is disabled. 197 | It now employs a hand-rolled variant of `std::sync::Once`. 198 | - `sync::OnceCell::get_or_try_init` works without `parking_lot` as well! 199 | - document the effects of `parking_lot` feature: same performance but smaller types. 200 | 201 | ## 0.2.6 202 | 203 | - Updated `Lazy`'s `Deref` impl to requires only `FnOnce` instead of `Fn` 204 | 205 | ## 0.2.5 206 | 207 | - `Lazy` requires only `FnOnce` instead of `Fn` 208 | 209 | ## 0.2.4 210 | 211 | - nicer `fmt::Debug` implementation 212 | 213 | ## 0.2.3 214 | 215 | - update `parking_lot` to `0.9.0` 216 | - fix stacked borrows violation in `unsync::OnceCell::get` 217 | - implement `Clone` for `sync::OnceCell where T: Clone` 218 | 219 | ## 0.2.2 220 | 221 | - add `OnceCell::into_inner` which consumes a cell and returns an option 222 | 223 | ## 0.2.1 224 | 225 | - implement `sync::OnceCell::get_or_try_init` if `parking_lot` feature is enabled 226 | - switch internal `unsafe` implementation of `sync::OnceCell` from `Once` to `Mutex` 227 | - `sync::OnceCell::get_or_init` is twice as fast if cell is already initialized 228 | - implement `std::panic::RefUnwindSafe` and `std::panic::UnwindSafe` for `OnceCell` 229 | - better document behavior around panics 230 | 231 | ## 0.2.0 232 | 233 | - MSRV is now 1.31.1 234 | - `Lazy::new` and `OnceCell::new` are now const-fns 235 | - `unsync_lazy` and `sync_lazy` macros are removed 236 | 237 | ## 0.1.8 238 | 239 | - update crossbeam-utils to 0.6 240 | - enable bors-ng 241 | 242 | ## 0.1.7 243 | 244 | - cells implement `PartialEq` and `From` 245 | - MSRV is down to 1.24.1 246 | - update `parking_lot` to `0.7.1` 247 | 248 | ## 0.1.6 249 | 250 | - `unsync::OnceCell` is `Clone` if `T` is `Clone`. 251 | 252 | ## 0.1.5 253 | 254 | - No changelog until this point :( 255 | -------------------------------------------------------------------------------- /Cargo.lock.msrv: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "1.1.3" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "bitflags" 16 | version = "2.6.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 19 | 20 | [[package]] 21 | name = "cfg-if" 22 | version = "1.0.0" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 25 | 26 | [[package]] 27 | name = "critical-section" 28 | version = "1.1.3" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "f64009896348fc5af4222e9cf7d7d82a95a256c634ebcf61c53e4ea461422242" 31 | 32 | [[package]] 33 | name = "libc" 34 | version = "0.2.158" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" 37 | 38 | [[package]] 39 | name = "memchr" 40 | version = "2.7.4" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 43 | 44 | [[package]] 45 | name = "once_cell" 46 | version = "1.21.3" 47 | dependencies = [ 48 | "critical-section", 49 | "parking_lot_core", 50 | "portable-atomic", 51 | "regex", 52 | ] 53 | 54 | [[package]] 55 | name = "parking_lot_core" 56 | version = "0.9.10" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 59 | dependencies = [ 60 | "cfg-if", 61 | "libc", 62 | "redox_syscall", 63 | "smallvec", 64 | "windows-targets", 65 | ] 66 | 67 | [[package]] 68 | name = "portable-atomic" 69 | version = "1.9.0" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" 72 | 73 | [[package]] 74 | name = "redox_syscall" 75 | version = "0.5.4" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" 78 | dependencies = [ 79 | "bitflags", 80 | ] 81 | 82 | [[package]] 83 | name = "regex" 84 | version = "1.10.6" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" 87 | dependencies = [ 88 | "aho-corasick", 89 | "memchr", 90 | "regex-automata", 91 | "regex-syntax", 92 | ] 93 | 94 | [[package]] 95 | name = "regex-automata" 96 | version = "0.4.7" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" 99 | dependencies = [ 100 | "aho-corasick", 101 | "memchr", 102 | "regex-syntax", 103 | ] 104 | 105 | [[package]] 106 | name = "regex-syntax" 107 | version = "0.8.4" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" 110 | 111 | [[package]] 112 | name = "smallvec" 113 | version = "1.13.2" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 116 | 117 | [[package]] 118 | name = "windows-targets" 119 | version = "0.52.6" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 122 | dependencies = [ 123 | "windows_aarch64_gnullvm", 124 | "windows_aarch64_msvc", 125 | "windows_i686_gnu", 126 | "windows_i686_gnullvm", 127 | "windows_i686_msvc", 128 | "windows_x86_64_gnu", 129 | "windows_x86_64_gnullvm", 130 | "windows_x86_64_msvc", 131 | ] 132 | 133 | [[package]] 134 | name = "windows_aarch64_gnullvm" 135 | version = "0.52.6" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 138 | 139 | [[package]] 140 | name = "windows_aarch64_msvc" 141 | version = "0.52.6" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 144 | 145 | [[package]] 146 | name = "windows_i686_gnu" 147 | version = "0.52.6" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 150 | 151 | [[package]] 152 | name = "windows_i686_gnullvm" 153 | version = "0.52.6" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 156 | 157 | [[package]] 158 | name = "windows_i686_msvc" 159 | version = "0.52.6" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 162 | 163 | [[package]] 164 | name = "windows_x86_64_gnu" 165 | version = "0.52.6" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 168 | 169 | [[package]] 170 | name = "windows_x86_64_gnullvm" 171 | version = "0.52.6" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 174 | 175 | [[package]] 176 | name = "windows_x86_64_msvc" 177 | version = "0.52.6" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 180 | 181 | [[package]] 182 | name = "xshell" 183 | version = "0.2.6" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "6db0ab86eae739efd1b054a8d3d16041914030ac4e01cd1dca0cf252fd8b6437" 186 | dependencies = [ 187 | "xshell-macros", 188 | ] 189 | 190 | [[package]] 191 | name = "xshell-macros" 192 | version = "0.2.6" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "9d422e8e38ec76e2f06ee439ccc765e9c6a9638b9e7c9f2e8255e4d41e8bd852" 195 | 196 | [[package]] 197 | name = "xtask" 198 | version = "0.0.0" 199 | dependencies = [ 200 | "xshell", 201 | ] 202 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "once_cell" 3 | version = "1.21.3" 4 | authors = ["Aleksey Kladov "] 5 | license = "MIT OR Apache-2.0" 6 | edition = "2021" 7 | rust-version = "1.65" 8 | 9 | description = "Single assignment cells and lazy values." 10 | readme = "README.md" 11 | documentation = "https://docs.rs/once_cell" 12 | 13 | repository = "https://github.com/matklad/once_cell" 14 | keywords = ["lazy", "static"] 15 | categories = ["rust-patterns", "memory-management"] 16 | 17 | exclude = ["*.png", "*.svg", "/Cargo.lock.msrv", "rustfmt.toml"] 18 | 19 | [workspace] 20 | members = ["xtask"] 21 | 22 | [dependencies] 23 | parking_lot_core = { version = "0.9.10", optional = true, default-features = false } 24 | portable-atomic = { version = "1.8", optional = true, default-features = false } 25 | critical-section = { version = "1.1.3", optional = true } 26 | 27 | [dev-dependencies] 28 | regex = "1.10.6" 29 | critical-section = { version = "1.1.3", features = ["std"] } 30 | 31 | [features] 32 | default = ["std"] 33 | 34 | # Enables `once_cell::sync` module. 35 | std = ["alloc"] 36 | 37 | # Enables `once_cell::race::OnceBox` type. 38 | alloc = ["race"] 39 | 40 | # Enables `once_cell::race` module. 41 | race = [] 42 | 43 | # Uses parking_lot to implement once_cell::sync::OnceCell. 44 | # This makes no speed difference, but makes each OnceCell 45 | # up to 16 bytes smaller, depending on the size of the T. 46 | parking_lot = ["dep:parking_lot_core"] 47 | 48 | # Uses `portable-atomic` to implement `race` module. in 49 | # `#![no_std]` mode. Please read `portable-atomic` docs carefully 50 | # before enabling this feature. 51 | portable-atomic = ["dep:portable-atomic"] 52 | 53 | # Uses `critical-section` to implement `sync` module. in 54 | # `#![no_std]` mode. Please read `critical-section` docs carefully 55 | # before enabling this feature. 56 | # `portable-atomic` feature is enabled for backwards compatibility. 57 | critical-section = ["dep:critical-section", "portable-atomic"] 58 | 59 | # Enables semver-exempt APIs of this crate. 60 | # At the moment, this feature is unused. 61 | unstable = [] 62 | 63 | # Only for backwards compatibility. 64 | atomic-polyfill = ["critical-section"] 65 | 66 | [[example]] 67 | name = "bench" 68 | required-features = ["std"] 69 | 70 | [[example]] 71 | name = "bench_acquire" 72 | required-features = ["std"] 73 | 74 | [[example]] 75 | name = "lazy_static" 76 | required-features = ["std"] 77 | 78 | [[example]] 79 | name = "reentrant_init_deadlocks" 80 | required-features = ["std"] 81 | 82 | [[example]] 83 | name = "regex" 84 | required-features = ["std"] 85 | 86 | [[example]] 87 | name = "test_synchronization" 88 | required-features = ["std"] 89 | 90 | [package.metadata.docs.rs] 91 | all-features = true 92 | rustdoc-args = ["--generate-link-to-definition"] 93 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

once_cell

2 | 3 | 4 | [![Build Status](https://github.com/matklad/once_cell/actions/workflows/ci.yaml/badge.svg)](https://github.com/matklad/once_cell/actions) 5 | [![Crates.io](https://img.shields.io/crates/v/once_cell.svg)](https://crates.io/crates/once_cell) 6 | [![API reference](https://docs.rs/once_cell/badge.svg)](https://docs.rs/once_cell/) 7 | 8 | # Overview 9 | 10 | `once_cell` provides two new cell-like types, `unsync::OnceCell` and `sync::OnceCell`. `OnceCell` 11 | might store arbitrary non-`Copy` types, can be assigned to at most once and provide direct access 12 | to the stored contents. In a nutshell, API looks *roughly* like this: 13 | 14 | ```rust 15 | impl OnceCell { 16 | fn new() -> OnceCell { ... } 17 | fn set(&self, value: T) -> Result<(), T> { ... } 18 | fn get(&self) -> Option<&T> { ... } 19 | } 20 | ``` 21 | 22 | Note that, like with `RefCell` and `Mutex`, the `set` method requires only a shared reference. 23 | Because of the single assignment restriction `get` can return an `&T` instead of `Ref` 24 | or `MutexGuard`. 25 | 26 | `once_cell` also has a `Lazy` type, build on top of `OnceCell` which provides the same API as 27 | the `lazy_static!` macro, but without using any macros: 28 | 29 | ```rust 30 | use std::{sync::Mutex, collections::HashMap}; 31 | use once_cell::sync::Lazy; 32 | 33 | static GLOBAL_DATA: Lazy>> = Lazy::new(|| { 34 | let mut m = HashMap::new(); 35 | m.insert(13, "Spica".to_string()); 36 | m.insert(74, "Hoyten".to_string()); 37 | Mutex::new(m) 38 | }); 39 | 40 | fn main() { 41 | println!("{:?}", GLOBAL_DATA.lock().unwrap()); 42 | } 43 | ``` 44 | 45 | More patterns and use-cases are in the [docs](https://docs.rs/once_cell/)! 46 | 47 | # Related crates 48 | 49 | * [double-checked-cell](https://github.com/niklasf/double-checked-cell) 50 | * [lazy-init](https://crates.io/crates/lazy-init) 51 | * [lazycell](https://crates.io/crates/lazycell) 52 | * [mitochondria](https://crates.io/crates/mitochondria) 53 | * [lazy_static](https://crates.io/crates/lazy_static) 54 | * [async_once_cell](https://crates.io/crates/async_once_cell) 55 | * [generic_once_cell](https://crates.io/crates/generic_once_cell) (bring your own mutex) 56 | 57 | Parts of `once_cell` API are included into `std` [as of Rust 1.70.0](https://github.com/rust-lang/rust/pull/105587). 58 | -------------------------------------------------------------------------------- /bors.toml: -------------------------------------------------------------------------------- 1 | status = [ "Rust" ] 2 | delete_merged_branches = true 3 | -------------------------------------------------------------------------------- /design/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matklad/once_cell/fda60a6c70eb2e25a0c73bf515ec4779df3d2e6c/design/icon.png -------------------------------------------------------------------------------- /design/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matklad/once_cell/fda60a6c70eb2e25a0c73bf515ec4779df3d2e6c/design/logo.png -------------------------------------------------------------------------------- /examples/bench.rs: -------------------------------------------------------------------------------- 1 | use std::mem::size_of; 2 | 3 | use once_cell::sync::OnceCell; 4 | 5 | const N_THREADS: usize = 32; 6 | const N_ROUNDS: usize = 100_000_000; 7 | 8 | static CELL: OnceCell = OnceCell::new(); 9 | 10 | fn main() { 11 | let start = std::time::Instant::now(); 12 | let threads = 13 | (0..N_THREADS).map(|i| std::thread::spawn(move || thread_main(i))).collect::>(); 14 | for thread in threads { 15 | thread.join().unwrap(); 16 | } 17 | println!("{:?}", start.elapsed()); 18 | println!("size_of::>() = {:?}", size_of::>()); 19 | println!("size_of::>() = {:?}", size_of::>()); 20 | println!("size_of::>() = {:?}", size_of::>()); 21 | } 22 | 23 | fn thread_main(i: usize) { 24 | for _ in 0..N_ROUNDS { 25 | let &value = CELL.get_or_init(|| i); 26 | assert!(value < N_THREADS) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/bench_acquire.rs: -------------------------------------------------------------------------------- 1 | //! Benchmark the overhead that the synchronization of `OnceCell::get` causes. 2 | //! We do some other operations that write to memory to get an imprecise but somewhat realistic 3 | //! measurement. 4 | 5 | use once_cell::sync::OnceCell; 6 | use std::sync::atomic::{AtomicUsize, Ordering}; 7 | 8 | const N_THREADS: usize = 16; 9 | const N_ROUNDS: usize = 1_000_000; 10 | 11 | static CELL: OnceCell = OnceCell::new(); 12 | static OTHER: AtomicUsize = AtomicUsize::new(0); 13 | 14 | fn main() { 15 | let start = std::time::Instant::now(); 16 | let threads = 17 | (0..N_THREADS).map(|i| std::thread::spawn(move || thread_main(i))).collect::>(); 18 | for thread in threads { 19 | thread.join().unwrap(); 20 | } 21 | println!("{:?}", start.elapsed()); 22 | println!("{:?}", OTHER.load(Ordering::Relaxed)); 23 | } 24 | 25 | #[inline(never)] 26 | fn thread_main(i: usize) { 27 | // The operations we do here don't really matter, as long as we do multiple writes, and 28 | // everything is messy enough to prevent the compiler from optimizing the loop away. 29 | let mut data = [i; 128]; 30 | let mut accum = 0usize; 31 | for _ in 0..N_ROUNDS { 32 | let _value = CELL.get_or_init(|| i + 1); 33 | let k = OTHER.fetch_add(data[accum & 0x7F] as usize, Ordering::Relaxed); 34 | for j in data.iter_mut() { 35 | *j = (*j).wrapping_add(accum); 36 | accum = accum.wrapping_add(k); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/lazy_static.rs: -------------------------------------------------------------------------------- 1 | extern crate once_cell; 2 | 3 | use once_cell::sync::{Lazy, OnceCell}; 4 | use std::collections::HashMap; 5 | 6 | static HASHMAP: Lazy> = Lazy::new(|| { 7 | let mut m = HashMap::new(); 8 | m.insert(0, "foo"); 9 | m.insert(1, "bar"); 10 | m.insert(2, "baz"); 11 | m 12 | }); 13 | 14 | // Same, but completely without macros 15 | fn hashmap() -> &'static HashMap { 16 | static INSTANCE: OnceCell> = OnceCell::new(); 17 | INSTANCE.get_or_init(|| { 18 | let mut m = HashMap::new(); 19 | m.insert(0, "foo"); 20 | m.insert(1, "bar"); 21 | m.insert(2, "baz"); 22 | m 23 | }) 24 | } 25 | 26 | fn main() { 27 | // First access to `HASHMAP` initializes it 28 | println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap()); 29 | 30 | // Any further access to `HASHMAP` just returns the computed value 31 | println!("The entry for `1` is \"{}\".", HASHMAP.get(&1).unwrap()); 32 | 33 | // The same works for function-style: 34 | assert_eq!(hashmap().get(&0), Some(&"foo")); 35 | assert_eq!(hashmap().get(&1), Some(&"bar")); 36 | } 37 | -------------------------------------------------------------------------------- /examples/reentrant_init_deadlocks.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let cell = once_cell::sync::OnceCell::::new(); 3 | cell.get_or_init(|| { 4 | cell.get_or_init(|| 1); 5 | 2 6 | }); 7 | } 8 | 9 | /// Dummy test to make it seem hang when compiled as `--test` 10 | /// See https://github.com/matklad/once_cell/issues/79 11 | #[test] 12 | fn dummy_test() { 13 | std::thread::sleep(std::time::Duration::from_secs(4)); 14 | } 15 | -------------------------------------------------------------------------------- /examples/regex.rs: -------------------------------------------------------------------------------- 1 | use std::{str::FromStr, time::Instant}; 2 | 3 | use regex::Regex; 4 | 5 | macro_rules! regex { 6 | ($re:literal $(,)?) => {{ 7 | static RE: once_cell::sync::OnceCell = once_cell::sync::OnceCell::new(); 8 | RE.get_or_init(|| regex::Regex::new($re).unwrap()) 9 | }}; 10 | } 11 | 12 | fn slow() { 13 | let s = r##"13.28.24.13 - - [10/Mar/2016:19:29:25 +0100] "GET /etc/lib/pChart2/examples/index.php?Action=View&Script=../../../../cnf/db.php HTTP/1.1" 404 151 "-" "HTTP_Request2/2.2.1 (http://pear.php.net/package/http_request2) PHP/5.3.16""##; 14 | 15 | let mut total = 0; 16 | for _ in 0..1000 { 17 | let re = Regex::new( 18 | r##"^(\S+) (\S+) (\S+) \[([^]]+)\] "([^"]*)" (\d+) (\d+) "([^"]*)" "([^"]*)"$"##, 19 | ) 20 | .unwrap(); 21 | let size = usize::from_str(re.captures(s).unwrap().get(7).unwrap().as_str()).unwrap(); 22 | total += size; 23 | } 24 | println!("{}", total); 25 | } 26 | 27 | fn fast() { 28 | let s = r##"13.28.24.13 - - [10/Mar/2016:19:29:25 +0100] "GET /etc/lib/pChart2/examples/index.php?Action=View&Script=../../../../cnf/db.php HTTP/1.1" 404 151 "-" "HTTP_Request2/2.2.1 (http://pear.php.net/package/http_request2) PHP/5.3.16""##; 29 | 30 | let mut total = 0; 31 | for _ in 0..1000 { 32 | let re: &Regex = regex!( 33 | r##"^(\S+) (\S+) (\S+) \[([^]]+)\] "([^"]*)" (\d+) (\d+) "([^"]*)" "([^"]*)"$"##, 34 | ); 35 | let size = usize::from_str(re.captures(s).unwrap().get(7).unwrap().as_str()).unwrap(); 36 | total += size; 37 | } 38 | println!("{}", total); 39 | } 40 | 41 | fn main() { 42 | let t = Instant::now(); 43 | slow(); 44 | println!("slow: {:?}", t.elapsed()); 45 | 46 | let t = Instant::now(); 47 | fast(); 48 | println!("fast: {:?}", t.elapsed()); 49 | } 50 | -------------------------------------------------------------------------------- /examples/test_synchronization.rs: -------------------------------------------------------------------------------- 1 | //! Test if the OnceCell properly synchronizes. 2 | //! Needs to be run in release mode. 3 | //! 4 | //! We create a `Vec` with `N_ROUNDS` of `OnceCell`s. All threads will walk the `Vec`, and race to 5 | //! be the first one to initialize a cell. 6 | //! Every thread adds the results of the cells it sees to an accumulator, which is compared at the 7 | //! end. 8 | //! All threads should end up with the same result. 9 | 10 | use once_cell::sync::OnceCell; 11 | 12 | const N_THREADS: usize = 32; 13 | const N_ROUNDS: usize = 1_000_000; 14 | 15 | static CELLS: OnceCell>> = OnceCell::new(); 16 | static RESULT: OnceCell = OnceCell::new(); 17 | 18 | fn main() { 19 | let start = std::time::Instant::now(); 20 | CELLS.get_or_init(|| vec![OnceCell::new(); N_ROUNDS]); 21 | let threads = 22 | (0..N_THREADS).map(|i| std::thread::spawn(move || thread_main(i))).collect::>(); 23 | for thread in threads { 24 | thread.join().unwrap(); 25 | } 26 | println!("{:?}", start.elapsed()); 27 | println!("No races detected"); 28 | } 29 | 30 | fn thread_main(i: usize) { 31 | let cells = CELLS.get().unwrap(); 32 | let mut accum = 0; 33 | for cell in cells.iter() { 34 | let &value = cell.get_or_init(|| i); 35 | accum += value; 36 | } 37 | assert_eq!(RESULT.get_or_init(|| accum), &accum); 38 | } 39 | -------------------------------------------------------------------------------- /logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 13 | 16 | 17 | 27 | 28 | 29 | 41 | 48 | 57 | 68 | 77 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | reorder_modules = false 2 | use_small_heuristics = "Max" 3 | -------------------------------------------------------------------------------- /src/imp_cs.rs: -------------------------------------------------------------------------------- 1 | use core::panic::{RefUnwindSafe, UnwindSafe}; 2 | 3 | use critical_section::{CriticalSection, Mutex}; 4 | use portable_atomic::{AtomicBool, Ordering}; 5 | 6 | use crate::unsync; 7 | 8 | pub(crate) struct OnceCell { 9 | initialized: AtomicBool, 10 | // Use `unsync::OnceCell` internally since `Mutex` does not provide 11 | // interior mutability and to be able to re-use `get_or_try_init`. 12 | value: Mutex>, 13 | } 14 | 15 | // Why do we need `T: Send`? 16 | // Thread A creates a `OnceCell` and shares it with 17 | // scoped thread B, which fills the cell, which is 18 | // then destroyed by A. That is, destructor observes 19 | // a sent value. 20 | unsafe impl Sync for OnceCell {} 21 | unsafe impl Send for OnceCell {} 22 | 23 | impl RefUnwindSafe for OnceCell {} 24 | impl UnwindSafe for OnceCell {} 25 | 26 | impl OnceCell { 27 | pub(crate) const fn new() -> OnceCell { 28 | OnceCell { initialized: AtomicBool::new(false), value: Mutex::new(unsync::OnceCell::new()) } 29 | } 30 | 31 | pub(crate) const fn with_value(value: T) -> OnceCell { 32 | OnceCell { 33 | initialized: AtomicBool::new(true), 34 | value: Mutex::new(unsync::OnceCell::with_value(value)), 35 | } 36 | } 37 | 38 | #[inline] 39 | pub(crate) fn is_initialized(&self) -> bool { 40 | self.initialized.load(Ordering::Acquire) 41 | } 42 | 43 | #[cold] 44 | pub(crate) fn initialize(&self, f: F) -> Result<(), E> 45 | where 46 | F: FnOnce() -> Result, 47 | { 48 | critical_section::with(|cs| { 49 | let cell = self.value.borrow(cs); 50 | cell.get_or_try_init(f).map(|_| { 51 | self.initialized.store(true, Ordering::Release); 52 | }) 53 | }) 54 | } 55 | 56 | /// Get the reference to the underlying value, without checking if the cell 57 | /// is initialized. 58 | /// 59 | /// # Safety 60 | /// 61 | /// Caller must ensure that the cell is in initialized state, and that 62 | /// the contents are acquired by (synchronized to) this thread. 63 | pub(crate) unsafe fn get_unchecked(&self) -> &T { 64 | debug_assert!(self.is_initialized()); 65 | // SAFETY: The caller ensures that the value is initialized and access synchronized. 66 | self.value.borrow(CriticalSection::new()).get().unwrap_unchecked() 67 | } 68 | 69 | #[inline] 70 | pub(crate) fn get_mut(&mut self) -> Option<&mut T> { 71 | self.value.get_mut().get_mut() 72 | } 73 | 74 | #[inline] 75 | pub(crate) fn into_inner(self) -> Option { 76 | self.value.into_inner().into_inner() 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/imp_pl.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | cell::UnsafeCell, 3 | panic::{RefUnwindSafe, UnwindSafe}, 4 | sync::atomic::{AtomicU8, Ordering}, 5 | }; 6 | 7 | pub(crate) struct OnceCell { 8 | state: AtomicU8, 9 | value: UnsafeCell>, 10 | } 11 | 12 | const INCOMPLETE: u8 = 0x0; 13 | const RUNNING: u8 = 0x1; 14 | const COMPLETE: u8 = 0x2; 15 | 16 | // Why do we need `T: Send`? 17 | // Thread A creates a `OnceCell` and shares it with 18 | // scoped thread B, which fills the cell, which is 19 | // then destroyed by A. That is, destructor observes 20 | // a sent value. 21 | unsafe impl Sync for OnceCell {} 22 | unsafe impl Send for OnceCell {} 23 | 24 | impl RefUnwindSafe for OnceCell {} 25 | impl UnwindSafe for OnceCell {} 26 | 27 | impl OnceCell { 28 | pub(crate) const fn new() -> OnceCell { 29 | OnceCell { state: AtomicU8::new(INCOMPLETE), value: UnsafeCell::new(None) } 30 | } 31 | 32 | pub(crate) const fn with_value(value: T) -> OnceCell { 33 | OnceCell { state: AtomicU8::new(COMPLETE), value: UnsafeCell::new(Some(value)) } 34 | } 35 | 36 | /// Safety: synchronizes with store to value via Release/Acquire. 37 | #[inline] 38 | pub(crate) fn is_initialized(&self) -> bool { 39 | self.state.load(Ordering::Acquire) == COMPLETE 40 | } 41 | 42 | /// Safety: synchronizes with store to value via `is_initialized` or mutex 43 | /// lock/unlock, writes value only once because of the mutex. 44 | #[cold] 45 | pub(crate) fn initialize(&self, f: F) -> Result<(), E> 46 | where 47 | F: FnOnce() -> Result, 48 | { 49 | let mut f = Some(f); 50 | let mut res: Result<(), E> = Ok(()); 51 | let slot: *mut Option = self.value.get(); 52 | initialize_inner(&self.state, &mut || { 53 | // We are calling user-supplied function and need to be careful. 54 | // - if it returns Err, we unlock mutex and return without touching anything 55 | // - if it panics, we unlock mutex and propagate panic without touching anything 56 | // - if it calls `set` or `get_or_try_init` re-entrantly, we get a deadlock on 57 | // mutex, which is important for safety. We *could* detect this and panic, 58 | // but that is more complicated 59 | // - finally, if it returns Ok, we store the value and store the flag with 60 | // `Release`, which synchronizes with `Acquire`s. 61 | let f = unsafe { f.take().unwrap_unchecked() }; 62 | match f() { 63 | Ok(value) => unsafe { 64 | // Safe b/c we have a unique access and no panic may happen 65 | // until the cell is marked as initialized. 66 | debug_assert!((*slot).is_none()); 67 | *slot = Some(value); 68 | true 69 | }, 70 | Err(err) => { 71 | res = Err(err); 72 | false 73 | } 74 | } 75 | }); 76 | res 77 | } 78 | 79 | #[cold] 80 | pub(crate) fn wait(&self) { 81 | let key = &self.state as *const _ as usize; 82 | unsafe { 83 | parking_lot_core::park( 84 | key, 85 | || self.state.load(Ordering::Acquire) != COMPLETE, 86 | || (), 87 | |_, _| (), 88 | parking_lot_core::DEFAULT_PARK_TOKEN, 89 | None, 90 | ); 91 | } 92 | } 93 | 94 | /// Get the reference to the underlying value, without checking if the cell 95 | /// is initialized. 96 | /// 97 | /// # Safety 98 | /// 99 | /// Caller must ensure that the cell is in initialized state, and that 100 | /// the contents are acquired by (synchronized to) this thread. 101 | pub(crate) unsafe fn get_unchecked(&self) -> &T { 102 | debug_assert!(self.is_initialized()); 103 | let slot = &*self.value.get(); 104 | slot.as_ref().unwrap_unchecked() 105 | } 106 | 107 | /// Gets the mutable reference to the underlying value. 108 | /// Returns `None` if the cell is empty. 109 | pub(crate) fn get_mut(&mut self) -> Option<&mut T> { 110 | // Safe b/c we have an exclusive access 111 | let slot: &mut Option = unsafe { &mut *self.value.get() }; 112 | slot.as_mut() 113 | } 114 | 115 | /// Consumes this `OnceCell`, returning the wrapped value. 116 | /// Returns `None` if the cell was empty. 117 | pub(crate) fn into_inner(self) -> Option { 118 | self.value.into_inner() 119 | } 120 | } 121 | 122 | struct Guard<'a> { 123 | state: &'a AtomicU8, 124 | new_state: u8, 125 | } 126 | 127 | impl<'a> Drop for Guard<'a> { 128 | fn drop(&mut self) { 129 | self.state.store(self.new_state, Ordering::Release); 130 | unsafe { 131 | let key = self.state as *const AtomicU8 as usize; 132 | parking_lot_core::unpark_all(key, parking_lot_core::DEFAULT_UNPARK_TOKEN); 133 | } 134 | } 135 | } 136 | 137 | // Note: this is intentionally monomorphic 138 | #[inline(never)] 139 | fn initialize_inner(state: &AtomicU8, init: &mut dyn FnMut() -> bool) { 140 | loop { 141 | let exchange = 142 | state.compare_exchange_weak(INCOMPLETE, RUNNING, Ordering::Acquire, Ordering::Acquire); 143 | match exchange { 144 | Ok(_) => { 145 | let mut guard = Guard { state, new_state: INCOMPLETE }; 146 | if init() { 147 | guard.new_state = COMPLETE; 148 | } 149 | return; 150 | } 151 | Err(COMPLETE) => return, 152 | Err(RUNNING) => unsafe { 153 | let key = state as *const AtomicU8 as usize; 154 | parking_lot_core::park( 155 | key, 156 | || state.load(Ordering::Relaxed) == RUNNING, 157 | || (), 158 | |_, _| (), 159 | parking_lot_core::DEFAULT_PARK_TOKEN, 160 | None, 161 | ); 162 | }, 163 | Err(INCOMPLETE) => (), 164 | Err(_) => debug_assert!(false), 165 | } 166 | } 167 | } 168 | 169 | #[test] 170 | fn test_size() { 171 | use std::mem::size_of; 172 | 173 | assert_eq!(size_of::>(), 1 * size_of::() + size_of::()); 174 | } 175 | -------------------------------------------------------------------------------- /src/imp_std.rs: -------------------------------------------------------------------------------- 1 | // There's a lot of scary concurrent code in this module, but it is copied from 2 | // `std::sync::Once` with two changes: 3 | // * no poisoning 4 | // * init function can fail 5 | 6 | use std::{ 7 | cell::{Cell, UnsafeCell}, 8 | panic::{RefUnwindSafe, UnwindSafe}, 9 | sync::atomic::{AtomicBool, AtomicPtr, Ordering}, 10 | thread::{self, Thread}, 11 | }; 12 | 13 | #[derive(Debug)] 14 | pub(crate) struct OnceCell { 15 | // This `queue` field is the core of the implementation. It encodes two 16 | // pieces of information: 17 | // 18 | // * The current state of the cell (`INCOMPLETE`, `RUNNING`, `COMPLETE`) 19 | // * Linked list of threads waiting for the current cell. 20 | // 21 | // State is encoded in two low bits. Only `INCOMPLETE` and `RUNNING` states 22 | // allow waiters. 23 | queue: AtomicPtr, 24 | value: UnsafeCell>, 25 | } 26 | 27 | // Why do we need `T: Send`? 28 | // Thread A creates a `OnceCell` and shares it with 29 | // scoped thread B, which fills the cell, which is 30 | // then destroyed by A. That is, destructor observes 31 | // a sent value. 32 | unsafe impl Sync for OnceCell {} 33 | unsafe impl Send for OnceCell {} 34 | 35 | impl RefUnwindSafe for OnceCell {} 36 | impl UnwindSafe for OnceCell {} 37 | 38 | impl OnceCell { 39 | pub(crate) const fn new() -> OnceCell { 40 | OnceCell { queue: AtomicPtr::new(INCOMPLETE_PTR), value: UnsafeCell::new(None) } 41 | } 42 | 43 | pub(crate) const fn with_value(value: T) -> OnceCell { 44 | OnceCell { queue: AtomicPtr::new(COMPLETE_PTR), value: UnsafeCell::new(Some(value)) } 45 | } 46 | 47 | /// Safety: synchronizes with store to value via Release/(Acquire|SeqCst). 48 | #[inline] 49 | pub(crate) fn is_initialized(&self) -> bool { 50 | // An `Acquire` load is enough because that makes all the initialization 51 | // operations visible to us, and, this being a fast path, weaker 52 | // ordering helps with performance. This `Acquire` synchronizes with 53 | // `SeqCst` operations on the slow path. 54 | self.queue.load(Ordering::Acquire) == COMPLETE_PTR 55 | } 56 | 57 | /// Safety: synchronizes with store to value via SeqCst read from state, 58 | /// writes value only once because we never get to INCOMPLETE state after a 59 | /// successful write. 60 | #[cold] 61 | pub(crate) fn initialize(&self, f: F) -> Result<(), E> 62 | where 63 | F: FnOnce() -> Result, 64 | { 65 | let mut f = Some(f); 66 | let mut res: Result<(), E> = Ok(()); 67 | let slot: *mut Option = self.value.get(); 68 | initialize_or_wait( 69 | &self.queue, 70 | Some(&mut || { 71 | let f = unsafe { f.take().unwrap_unchecked() }; 72 | match f() { 73 | Ok(value) => { 74 | unsafe { *slot = Some(value) }; 75 | true 76 | } 77 | Err(err) => { 78 | res = Err(err); 79 | false 80 | } 81 | } 82 | }), 83 | ); 84 | res 85 | } 86 | 87 | #[cold] 88 | pub(crate) fn wait(&self) { 89 | initialize_or_wait(&self.queue, None); 90 | } 91 | 92 | /// Get the reference to the underlying value, without checking if the cell 93 | /// is initialized. 94 | /// 95 | /// # Safety 96 | /// 97 | /// Caller must ensure that the cell is in initialized state, and that 98 | /// the contents are acquired by (synchronized to) this thread. 99 | pub(crate) unsafe fn get_unchecked(&self) -> &T { 100 | debug_assert!(self.is_initialized()); 101 | let slot = &*self.value.get(); 102 | slot.as_ref().unwrap_unchecked() 103 | } 104 | 105 | /// Gets the mutable reference to the underlying value. 106 | /// Returns `None` if the cell is empty. 107 | pub(crate) fn get_mut(&mut self) -> Option<&mut T> { 108 | // Safe b/c we have a unique access. 109 | unsafe { &mut *self.value.get() }.as_mut() 110 | } 111 | 112 | /// Consumes this `OnceCell`, returning the wrapped value. 113 | /// Returns `None` if the cell was empty. 114 | #[inline] 115 | pub(crate) fn into_inner(self) -> Option { 116 | // Because `into_inner` takes `self` by value, the compiler statically 117 | // verifies that it is not currently borrowed. 118 | // So, it is safe to move out `Option`. 119 | self.value.into_inner() 120 | } 121 | } 122 | 123 | // Three states that a OnceCell can be in, encoded into the lower bits of `queue` in 124 | // the OnceCell structure. 125 | const INCOMPLETE: usize = 0x0; 126 | const RUNNING: usize = 0x1; 127 | const COMPLETE: usize = 0x2; 128 | const INCOMPLETE_PTR: *mut Waiter = INCOMPLETE as *mut Waiter; 129 | const COMPLETE_PTR: *mut Waiter = COMPLETE as *mut Waiter; 130 | 131 | // Mask to learn about the state. All other bits are the queue of waiters if 132 | // this is in the RUNNING state. 133 | const STATE_MASK: usize = 0x3; 134 | 135 | /// Representation of a node in the linked list of waiters in the RUNNING state. 136 | /// A waiters is stored on the stack of the waiting threads. 137 | #[repr(align(4))] // Ensure the two lower bits are free to use as state bits. 138 | struct Waiter { 139 | thread: Cell>, 140 | signaled: AtomicBool, 141 | next: *mut Waiter, 142 | } 143 | 144 | /// Drains and notifies the queue of waiters on drop. 145 | struct Guard<'a> { 146 | queue: &'a AtomicPtr, 147 | new_queue: *mut Waiter, 148 | } 149 | 150 | impl Drop for Guard<'_> { 151 | fn drop(&mut self) { 152 | let queue = self.queue.swap(self.new_queue, Ordering::AcqRel); 153 | 154 | let state = strict::addr(queue) & STATE_MASK; 155 | assert_eq!(state, RUNNING); 156 | 157 | unsafe { 158 | let mut waiter = strict::map_addr(queue, |q| q & !STATE_MASK); 159 | while !waiter.is_null() { 160 | let next = (*waiter).next; 161 | let thread = (*waiter).thread.take().unwrap(); 162 | (*waiter).signaled.store(true, Ordering::Release); 163 | waiter = next; 164 | thread.unpark(); 165 | } 166 | } 167 | } 168 | } 169 | 170 | // Corresponds to `std::sync::Once::call_inner`. 171 | // 172 | // Originally copied from std, but since modified to remove poisoning and to 173 | // support wait. 174 | // 175 | // Note: this is intentionally monomorphic 176 | #[inline(never)] 177 | fn initialize_or_wait(queue: &AtomicPtr, mut init: Option<&mut dyn FnMut() -> bool>) { 178 | let mut curr_queue = queue.load(Ordering::Acquire); 179 | 180 | loop { 181 | let curr_state = strict::addr(curr_queue) & STATE_MASK; 182 | match (curr_state, &mut init) { 183 | (COMPLETE, _) => return, 184 | (INCOMPLETE, Some(init)) => { 185 | let exchange = queue.compare_exchange( 186 | curr_queue, 187 | strict::map_addr(curr_queue, |q| (q & !STATE_MASK) | RUNNING), 188 | Ordering::Acquire, 189 | Ordering::Acquire, 190 | ); 191 | if let Err(new_queue) = exchange { 192 | curr_queue = new_queue; 193 | continue; 194 | } 195 | let mut guard = Guard { queue, new_queue: INCOMPLETE_PTR }; 196 | if init() { 197 | guard.new_queue = COMPLETE_PTR; 198 | } 199 | return; 200 | } 201 | (INCOMPLETE, None) | (RUNNING, _) => { 202 | wait(queue, curr_queue); 203 | curr_queue = queue.load(Ordering::Acquire); 204 | } 205 | _ => debug_assert!(false), 206 | } 207 | } 208 | } 209 | 210 | fn wait(queue: &AtomicPtr, mut curr_queue: *mut Waiter) { 211 | let curr_state = strict::addr(curr_queue) & STATE_MASK; 212 | loop { 213 | let node = Waiter { 214 | thread: Cell::new(Some(thread::current())), 215 | signaled: AtomicBool::new(false), 216 | next: strict::map_addr(curr_queue, |q| q & !STATE_MASK), 217 | }; 218 | let me = &node as *const Waiter as *mut Waiter; 219 | 220 | let exchange = queue.compare_exchange( 221 | curr_queue, 222 | strict::map_addr(me, |q| q | curr_state), 223 | Ordering::Release, 224 | Ordering::Relaxed, 225 | ); 226 | if let Err(new_queue) = exchange { 227 | if strict::addr(new_queue) & STATE_MASK != curr_state { 228 | return; 229 | } 230 | curr_queue = new_queue; 231 | continue; 232 | } 233 | 234 | while !node.signaled.load(Ordering::Acquire) { 235 | thread::park(); 236 | } 237 | break; 238 | } 239 | } 240 | 241 | // Polyfill of strict provenance from https://crates.io/crates/sptr. 242 | // 243 | // Use free-standing function rather than a trait to keep things simple and 244 | // avoid any potential conflicts with future stabile std API. 245 | mod strict { 246 | #[must_use] 247 | #[inline] 248 | pub(crate) fn addr(ptr: *mut T) -> usize 249 | where 250 | T: Sized, 251 | { 252 | // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. 253 | // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the 254 | // provenance). 255 | unsafe { core::mem::transmute(ptr) } 256 | } 257 | 258 | #[must_use] 259 | #[inline] 260 | pub(crate) fn with_addr(ptr: *mut T, addr: usize) -> *mut T 261 | where 262 | T: Sized, 263 | { 264 | // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. 265 | // 266 | // In the mean-time, this operation is defined to be "as if" it was 267 | // a wrapping_offset, so we can emulate it as such. This should properly 268 | // restore pointer provenance even under today's compiler. 269 | let self_addr = self::addr(ptr) as isize; 270 | let dest_addr = addr as isize; 271 | let offset = dest_addr.wrapping_sub(self_addr); 272 | 273 | // This is the canonical desugarring of this operation, 274 | // but `pointer::cast` was only stabilized in 1.38. 275 | // self.cast::().wrapping_offset(offset).cast::() 276 | (ptr as *mut u8).wrapping_offset(offset) as *mut T 277 | } 278 | 279 | #[must_use] 280 | #[inline] 281 | pub(crate) fn map_addr(ptr: *mut T, f: impl FnOnce(usize) -> usize) -> *mut T 282 | where 283 | T: Sized, 284 | { 285 | self::with_addr(ptr, f(addr(ptr))) 286 | } 287 | } 288 | 289 | // These test are snatched from std as well. 290 | #[cfg(test)] 291 | mod tests { 292 | use std::panic; 293 | use std::{sync::mpsc::channel, thread}; 294 | 295 | use super::OnceCell; 296 | 297 | impl OnceCell { 298 | fn init(&self, f: impl FnOnce() -> T) { 299 | enum Void {} 300 | let _ = self.initialize(|| Ok::(f())); 301 | } 302 | } 303 | 304 | #[test] 305 | fn smoke_once() { 306 | static O: OnceCell<()> = OnceCell::new(); 307 | let mut a = 0; 308 | O.init(|| a += 1); 309 | assert_eq!(a, 1); 310 | O.init(|| a += 1); 311 | assert_eq!(a, 1); 312 | } 313 | 314 | #[test] 315 | fn stampede_once() { 316 | static O: OnceCell<()> = OnceCell::new(); 317 | static mut RUN: bool = false; 318 | 319 | let (tx, rx) = channel(); 320 | for _ in 0..10 { 321 | let tx = tx.clone(); 322 | thread::spawn(move || { 323 | for _ in 0..4 { 324 | thread::yield_now() 325 | } 326 | unsafe { 327 | O.init(|| { 328 | assert!(!RUN); 329 | RUN = true; 330 | }); 331 | assert!(RUN); 332 | } 333 | tx.send(()).unwrap(); 334 | }); 335 | } 336 | 337 | unsafe { 338 | O.init(|| { 339 | assert!(!RUN); 340 | RUN = true; 341 | }); 342 | assert!(RUN); 343 | } 344 | 345 | for _ in 0..10 { 346 | rx.recv().unwrap(); 347 | } 348 | } 349 | 350 | #[test] 351 | fn poison_bad() { 352 | static O: OnceCell<()> = OnceCell::new(); 353 | 354 | // poison the once 355 | let t = panic::catch_unwind(|| { 356 | O.init(|| panic!()); 357 | }); 358 | assert!(t.is_err()); 359 | 360 | // we can subvert poisoning, however 361 | let mut called = false; 362 | O.init(|| { 363 | called = true; 364 | }); 365 | assert!(called); 366 | 367 | // once any success happens, we stop propagating the poison 368 | O.init(|| {}); 369 | } 370 | 371 | #[test] 372 | fn wait_for_force_to_finish() { 373 | static O: OnceCell<()> = OnceCell::new(); 374 | 375 | // poison the once 376 | let t = panic::catch_unwind(|| { 377 | O.init(|| panic!()); 378 | }); 379 | assert!(t.is_err()); 380 | 381 | // make sure someone's waiting inside the once via a force 382 | let (tx1, rx1) = channel(); 383 | let (tx2, rx2) = channel(); 384 | let t1 = thread::spawn(move || { 385 | O.init(|| { 386 | tx1.send(()).unwrap(); 387 | rx2.recv().unwrap(); 388 | }); 389 | }); 390 | 391 | rx1.recv().unwrap(); 392 | 393 | // put another waiter on the once 394 | let t2 = thread::spawn(|| { 395 | let mut called = false; 396 | O.init(|| { 397 | called = true; 398 | }); 399 | assert!(!called); 400 | }); 401 | 402 | tx2.send(()).unwrap(); 403 | 404 | assert!(t1.join().is_ok()); 405 | assert!(t2.join().is_ok()); 406 | } 407 | 408 | #[test] 409 | #[cfg(target_pointer_width = "64")] 410 | fn test_size() { 411 | use std::mem::size_of; 412 | 413 | assert_eq!(size_of::>(), 4 * size_of::()); 414 | } 415 | } 416 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! # Overview 2 | //! 3 | //! `once_cell` provides two new cell-like types, [`unsync::OnceCell`] and 4 | //! [`sync::OnceCell`]. A `OnceCell` might store arbitrary non-`Copy` types, can 5 | //! be assigned to at most once and provides direct access to the stored 6 | //! contents. The core API looks *roughly* like this (and there's much more 7 | //! inside, read on!): 8 | //! 9 | //! ```rust,ignore 10 | //! impl OnceCell { 11 | //! const fn new() -> OnceCell { ... } 12 | //! fn set(&self, value: T) -> Result<(), T> { ... } 13 | //! fn get(&self) -> Option<&T> { ... } 14 | //! } 15 | //! ``` 16 | //! 17 | //! Note that, like with [`RefCell`] and [`Mutex`], the `set` method requires 18 | //! only a shared reference. Because of the single assignment restriction `get` 19 | //! can return a `&T` instead of `Ref` or `MutexGuard`. 20 | //! 21 | //! The `sync` flavor is thread-safe (that is, implements the [`Sync`] trait), 22 | //! while the `unsync` one is not. 23 | //! 24 | //! [`unsync::OnceCell`]: unsync/struct.OnceCell.html 25 | //! [`sync::OnceCell`]: sync/struct.OnceCell.html 26 | //! [`RefCell`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html 27 | //! [`Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html 28 | //! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html 29 | //! 30 | //! # Recipes 31 | //! 32 | //! `OnceCell` might be useful for a variety of patterns. 33 | //! 34 | //! ## Safe Initialization of Global Data 35 | //! 36 | //! ```rust 37 | //! use std::{env, io}; 38 | //! 39 | //! use once_cell::sync::OnceCell; 40 | //! 41 | //! #[derive(Debug)] 42 | //! pub struct Logger { 43 | //! // ... 44 | //! } 45 | //! static INSTANCE: OnceCell = OnceCell::new(); 46 | //! 47 | //! impl Logger { 48 | //! pub fn global() -> &'static Logger { 49 | //! INSTANCE.get().expect("logger is not initialized") 50 | //! } 51 | //! 52 | //! fn from_cli(args: env::Args) -> Result { 53 | //! // ... 54 | //! # Ok(Logger {}) 55 | //! } 56 | //! } 57 | //! 58 | //! fn main() { 59 | //! let logger = Logger::from_cli(env::args()).unwrap(); 60 | //! INSTANCE.set(logger).unwrap(); 61 | //! // use `Logger::global()` from now on 62 | //! } 63 | //! ``` 64 | //! 65 | //! ## Lazy Initialized Global Data 66 | //! 67 | //! This is essentially the `lazy_static!` macro, but without a macro. 68 | //! 69 | //! ```rust 70 | //! use std::{sync::Mutex, collections::HashMap}; 71 | //! 72 | //! use once_cell::sync::OnceCell; 73 | //! 74 | //! fn global_data() -> &'static Mutex> { 75 | //! static INSTANCE: OnceCell>> = OnceCell::new(); 76 | //! INSTANCE.get_or_init(|| { 77 | //! let mut m = HashMap::new(); 78 | //! m.insert(13, "Spica".to_string()); 79 | //! m.insert(74, "Hoyten".to_string()); 80 | //! Mutex::new(m) 81 | //! }) 82 | //! } 83 | //! ``` 84 | //! 85 | //! There are also the [`sync::Lazy`] and [`unsync::Lazy`] convenience types to 86 | //! streamline this pattern: 87 | //! 88 | //! ```rust 89 | //! use std::{sync::Mutex, collections::HashMap}; 90 | //! use once_cell::sync::Lazy; 91 | //! 92 | //! static GLOBAL_DATA: Lazy>> = Lazy::new(|| { 93 | //! let mut m = HashMap::new(); 94 | //! m.insert(13, "Spica".to_string()); 95 | //! m.insert(74, "Hoyten".to_string()); 96 | //! Mutex::new(m) 97 | //! }); 98 | //! 99 | //! fn main() { 100 | //! println!("{:?}", GLOBAL_DATA.lock().unwrap()); 101 | //! } 102 | //! ``` 103 | //! 104 | //! Note that the variable that holds `Lazy` is declared as `static`, *not* 105 | //! `const`. This is important: using `const` instead compiles, but works wrong. 106 | //! 107 | //! [`sync::Lazy`]: sync/struct.Lazy.html 108 | //! [`unsync::Lazy`]: unsync/struct.Lazy.html 109 | //! 110 | //! ## General purpose lazy evaluation 111 | //! 112 | //! Unlike `lazy_static!`, `Lazy` works with local variables. 113 | //! 114 | //! ```rust 115 | //! use once_cell::unsync::Lazy; 116 | //! 117 | //! fn main() { 118 | //! let ctx = vec![1, 2, 3]; 119 | //! let thunk = Lazy::new(|| { 120 | //! ctx.iter().sum::() 121 | //! }); 122 | //! assert_eq!(*thunk, 6); 123 | //! } 124 | //! ``` 125 | //! 126 | //! If you need a lazy field in a struct, you probably should use `OnceCell` 127 | //! directly, because that will allow you to access `self` during 128 | //! initialization. 129 | //! 130 | //! ```rust 131 | //! use std::{fs, path::PathBuf}; 132 | //! 133 | //! use once_cell::unsync::OnceCell; 134 | //! 135 | //! struct Ctx { 136 | //! config_path: PathBuf, 137 | //! config: OnceCell, 138 | //! } 139 | //! 140 | //! impl Ctx { 141 | //! pub fn get_config(&self) -> Result<&str, std::io::Error> { 142 | //! let cfg = self.config.get_or_try_init(|| { 143 | //! fs::read_to_string(&self.config_path) 144 | //! })?; 145 | //! Ok(cfg.as_str()) 146 | //! } 147 | //! } 148 | //! ``` 149 | //! 150 | //! ## Lazily Compiled Regex 151 | //! 152 | //! This is a `regex!` macro which takes a string literal and returns an 153 | //! *expression* that evaluates to a `&'static Regex`: 154 | //! 155 | //! ``` 156 | //! macro_rules! regex { 157 | //! ($re:literal $(,)?) => {{ 158 | //! static RE: once_cell::sync::OnceCell = once_cell::sync::OnceCell::new(); 159 | //! RE.get_or_init(|| regex::Regex::new($re).unwrap()) 160 | //! }}; 161 | //! } 162 | //! ``` 163 | //! 164 | //! This macro can be useful to avoid the "compile regex on every loop 165 | //! iteration" problem. 166 | //! 167 | //! ## Runtime `include_bytes!` 168 | //! 169 | //! The `include_bytes` macro is useful to include test resources, but it slows 170 | //! down test compilation a lot. An alternative is to load the resources at 171 | //! runtime: 172 | //! 173 | //! ``` 174 | //! use std::path::Path; 175 | //! 176 | //! use once_cell::sync::OnceCell; 177 | //! 178 | //! pub struct TestResource { 179 | //! path: &'static str, 180 | //! cell: OnceCell>, 181 | //! } 182 | //! 183 | //! impl TestResource { 184 | //! pub const fn new(path: &'static str) -> TestResource { 185 | //! TestResource { path, cell: OnceCell::new() } 186 | //! } 187 | //! pub fn bytes(&self) -> &[u8] { 188 | //! self.cell.get_or_init(|| { 189 | //! let dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); 190 | //! let path = Path::new(dir.as_str()).join(self.path); 191 | //! std::fs::read(&path).unwrap_or_else(|_err| { 192 | //! panic!("failed to load test resource: {}", path.display()) 193 | //! }) 194 | //! }).as_slice() 195 | //! } 196 | //! } 197 | //! 198 | //! static TEST_IMAGE: TestResource = TestResource::new("test_data/lena.png"); 199 | //! 200 | //! #[test] 201 | //! fn test_sobel_filter() { 202 | //! let rgb: &[u8] = TEST_IMAGE.bytes(); 203 | //! // ... 204 | //! # drop(rgb); 205 | //! } 206 | //! ``` 207 | //! 208 | //! ## `lateinit` 209 | //! 210 | //! `LateInit` type for delayed initialization. It is reminiscent of Kotlin's 211 | //! `lateinit` keyword and allows construction of cyclic data structures: 212 | //! 213 | //! 214 | //! ``` 215 | //! use once_cell::sync::OnceCell; 216 | //! 217 | //! pub struct LateInit { cell: OnceCell } 218 | //! 219 | //! impl LateInit { 220 | //! pub fn init(&self, value: T) { 221 | //! assert!(self.cell.set(value).is_ok()) 222 | //! } 223 | //! } 224 | //! 225 | //! impl Default for LateInit { 226 | //! fn default() -> Self { LateInit { cell: OnceCell::default() } } 227 | //! } 228 | //! 229 | //! impl std::ops::Deref for LateInit { 230 | //! type Target = T; 231 | //! fn deref(&self) -> &T { 232 | //! self.cell.get().unwrap() 233 | //! } 234 | //! } 235 | //! 236 | //! #[derive(Default)] 237 | //! struct A<'a> { 238 | //! b: LateInit<&'a B<'a>>, 239 | //! } 240 | //! 241 | //! #[derive(Default)] 242 | //! struct B<'a> { 243 | //! a: LateInit<&'a A<'a>> 244 | //! } 245 | //! 246 | //! 247 | //! fn build_cycle() { 248 | //! let a = A::default(); 249 | //! let b = B::default(); 250 | //! a.b.init(&b); 251 | //! b.a.init(&a); 252 | //! 253 | //! let _a = &a.b.a.b.a; 254 | //! } 255 | //! ``` 256 | //! 257 | //! # Comparison with std 258 | //! 259 | //! |`!Sync` types | Access Mode | Drawbacks | 260 | //! |----------------------|------------------------|-----------------------------------------------| 261 | //! |`Cell` | `T` | requires `T: Copy` for `get` | 262 | //! |`RefCell` | `RefMut` / `Ref` | may panic at runtime | 263 | //! |`unsync::OnceCell` | `&T` | assignable only once | 264 | //! 265 | //! |`Sync` types | Access Mode | Drawbacks | 266 | //! |----------------------|------------------------|-----------------------------------------------| 267 | //! |`AtomicT` | `T` | works only with certain `Copy` types | 268 | //! |`Mutex` | `MutexGuard` | may deadlock at runtime, may block the thread | 269 | //! |`sync::OnceCell` | `&T` | assignable only once, may block the thread | 270 | //! 271 | //! Technically, calling `get_or_init` will also cause a panic or a deadlock if 272 | //! it recursively calls itself. However, because the assignment can happen only 273 | //! once, such cases should be more rare than equivalents with `RefCell` and 274 | //! `Mutex`. 275 | //! 276 | //! # Minimum Supported `rustc` Version 277 | //! 278 | //! If only the `std`, `alloc`, or `race` features are enabled, MSRV will be 279 | //! updated conservatively, supporting at least latest 8 versions of the compiler. 280 | //! When using other features, like `parking_lot`, MSRV might be updated more 281 | //! frequently, up to the latest stable. In both cases, increasing MSRV is *not* 282 | //! considered a semver-breaking change and requires only a minor version bump. 283 | //! 284 | //! # Implementation details 285 | //! 286 | //! The implementation is based on the 287 | //! [`lazy_static`](https://github.com/rust-lang-nursery/lazy-static.rs/) and 288 | //! [`lazy_cell`](https://github.com/indiv0/lazycell/) crates and 289 | //! [`std::sync::Once`]. In some sense, `once_cell` just streamlines and unifies 290 | //! those APIs. 291 | //! 292 | //! To implement a sync flavor of `OnceCell`, this crates uses either a custom 293 | //! re-implementation of `std::sync::Once` or `parking_lot::Mutex`. This is 294 | //! controlled by the `parking_lot` feature (disabled by default). Performance 295 | //! is the same for both cases, but the `parking_lot` based `OnceCell` is 296 | //! smaller by up to 16 bytes. 297 | //! 298 | //! This crate uses `unsafe`. 299 | //! 300 | //! [`std::sync::Once`]: https://doc.rust-lang.org/std/sync/struct.Once.html 301 | //! 302 | //! # F.A.Q. 303 | //! 304 | //! **Should I use the sync or unsync flavor?** 305 | //! 306 | //! Because Rust compiler checks thread safety for you, it's impossible to 307 | //! accidentally use `unsync` where `sync` is required. So, use `unsync` in 308 | //! single-threaded code and `sync` in multi-threaded. It's easy to switch 309 | //! between the two if code becomes multi-threaded later. 310 | //! 311 | //! At the moment, `unsync` has an additional benefit that reentrant 312 | //! initialization causes a panic, which might be easier to debug than a 313 | //! deadlock. 314 | //! 315 | //! **Does this crate support async?** 316 | //! 317 | //! No, but you can use 318 | //! [`async_once_cell`](https://crates.io/crates/async_once_cell) instead. 319 | //! 320 | //! **Does this crate support `no_std`?** 321 | //! 322 | //! Yes, but with caveats. `OnceCell` is a synchronization primitive which 323 | //! _semantically_ relies on blocking. `OnceCell` guarantees that at most one 324 | //! `f` will be called to compute the value. If two threads of execution call 325 | //! `get_or_init` concurrently, one of them has to wait. 326 | //! 327 | //! Waiting fundamentally requires OS support. Execution environment needs to 328 | //! understand who waits on whom to prevent deadlocks due to priority inversion. 329 | //! You _could_ make code to compile by blindly using pure spinlocks, but the 330 | //! runtime behavior would be subtly wrong. 331 | //! 332 | //! Given these constraints, `once_cell` provides the following options: 333 | //! 334 | //! - The `race` module provides similar, but distinct synchronization primitive 335 | //! which is compatible with `no_std`. With `race`, the `f` function can be 336 | //! called multiple times by different threads, but only one thread will win 337 | //! to install the value. 338 | //! - `critical-section` feature (with a `-`, not `_`) uses `critical_section` 339 | //! to implement blocking. 340 | //! 341 | //! **Can I bring my own mutex?** 342 | //! 343 | //! There is [generic_once_cell](https://crates.io/crates/generic_once_cell) to 344 | //! allow just that. 345 | //! 346 | //! **Should I use `std::cell::OnceCell`, `once_cell`, or `lazy_static`?** 347 | //! 348 | //! If you can use `std` version (your MSRV is at least 1.70, and you don't need 349 | //! extra features `once_cell` provides), use `std`. Otherwise, use `once_cell`. 350 | //! Don't use `lazy_static`. 351 | //! 352 | //! # Related crates 353 | //! 354 | //! * Most of this crate's functionality is available in `std` starting with 355 | //! Rust 1.70. See `std::cell::OnceCell` and `std::sync::OnceLock`. 356 | //! * [double-checked-cell](https://github.com/niklasf/double-checked-cell) 357 | //! * [lazy-init](https://crates.io/crates/lazy-init) 358 | //! * [lazycell](https://crates.io/crates/lazycell) 359 | //! * [mitochondria](https://crates.io/crates/mitochondria) 360 | //! * [lazy_static](https://crates.io/crates/lazy_static) 361 | //! * [async_once_cell](https://crates.io/crates/async_once_cell) 362 | //! * [generic_once_cell](https://crates.io/crates/generic_once_cell) (bring 363 | //! your own mutex) 364 | 365 | #![cfg_attr(not(feature = "std"), no_std)] 366 | 367 | #[cfg(feature = "alloc")] 368 | extern crate alloc; 369 | 370 | #[cfg(all(feature = "critical-section", not(feature = "std")))] 371 | #[path = "imp_cs.rs"] 372 | mod imp; 373 | 374 | #[cfg(all(feature = "std", feature = "parking_lot"))] 375 | #[path = "imp_pl.rs"] 376 | mod imp; 377 | 378 | #[cfg(all(feature = "std", not(feature = "parking_lot")))] 379 | #[path = "imp_std.rs"] 380 | mod imp; 381 | 382 | /// Single-threaded version of `OnceCell`. 383 | pub mod unsync { 384 | use core::{ 385 | cell::{Cell, UnsafeCell}, 386 | fmt, mem, 387 | ops::{Deref, DerefMut}, 388 | panic::{RefUnwindSafe, UnwindSafe}, 389 | }; 390 | 391 | /// A cell which can be written to only once. It is not thread safe. 392 | /// 393 | /// Unlike [`std::cell::RefCell`], a `OnceCell` provides simple `&` 394 | /// references to the contents. 395 | /// 396 | /// [`std::cell::RefCell`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html 397 | /// 398 | /// # Example 399 | /// ``` 400 | /// use once_cell::unsync::OnceCell; 401 | /// 402 | /// let cell = OnceCell::new(); 403 | /// assert!(cell.get().is_none()); 404 | /// 405 | /// let value: &String = cell.get_or_init(|| { 406 | /// "Hello, World!".to_string() 407 | /// }); 408 | /// assert_eq!(value, "Hello, World!"); 409 | /// assert!(cell.get().is_some()); 410 | /// ``` 411 | pub struct OnceCell { 412 | // Invariant: written to at most once. 413 | inner: UnsafeCell>, 414 | } 415 | 416 | // Similarly to a `Sync` bound on `sync::OnceCell`, we can use 417 | // `&unsync::OnceCell` to sneak a `T` through `catch_unwind`, 418 | // by initializing the cell in closure and extracting the value in the 419 | // `Drop`. 420 | impl RefUnwindSafe for OnceCell {} 421 | impl UnwindSafe for OnceCell {} 422 | 423 | impl Default for OnceCell { 424 | fn default() -> Self { 425 | Self::new() 426 | } 427 | } 428 | 429 | impl fmt::Debug for OnceCell { 430 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 431 | match self.get() { 432 | Some(v) => f.debug_tuple("OnceCell").field(v).finish(), 433 | None => f.write_str("OnceCell(Uninit)"), 434 | } 435 | } 436 | } 437 | 438 | impl Clone for OnceCell { 439 | fn clone(&self) -> OnceCell { 440 | match self.get() { 441 | Some(value) => OnceCell::with_value(value.clone()), 442 | None => OnceCell::new(), 443 | } 444 | } 445 | 446 | fn clone_from(&mut self, source: &Self) { 447 | match (self.get_mut(), source.get()) { 448 | (Some(this), Some(source)) => this.clone_from(source), 449 | _ => *self = source.clone(), 450 | } 451 | } 452 | } 453 | 454 | impl PartialEq for OnceCell { 455 | fn eq(&self, other: &Self) -> bool { 456 | self.get() == other.get() 457 | } 458 | } 459 | 460 | impl Eq for OnceCell {} 461 | 462 | impl From for OnceCell { 463 | fn from(value: T) -> Self { 464 | OnceCell::with_value(value) 465 | } 466 | } 467 | 468 | impl OnceCell { 469 | /// Creates a new empty cell. 470 | pub const fn new() -> OnceCell { 471 | OnceCell { inner: UnsafeCell::new(None) } 472 | } 473 | 474 | /// Creates a new initialized cell. 475 | pub const fn with_value(value: T) -> OnceCell { 476 | OnceCell { inner: UnsafeCell::new(Some(value)) } 477 | } 478 | 479 | /// Gets a reference to the underlying value. 480 | /// 481 | /// Returns `None` if the cell is empty. 482 | #[inline] 483 | pub fn get(&self) -> Option<&T> { 484 | // Safe due to `inner`'s invariant of being written to at most once. 485 | // Had multiple writes to `inner` been allowed, a reference to the 486 | // value we return now would become dangling by a write of a 487 | // different value later. 488 | unsafe { &*self.inner.get() }.as_ref() 489 | } 490 | 491 | /// Gets a mutable reference to the underlying value. 492 | /// 493 | /// Returns `None` if the cell is empty. 494 | /// 495 | /// This method is allowed to violate the invariant of writing to a `OnceCell` 496 | /// at most once because it requires `&mut` access to `self`. As with all 497 | /// interior mutability, `&mut` access permits arbitrary modification: 498 | /// 499 | /// ``` 500 | /// use once_cell::unsync::OnceCell; 501 | /// 502 | /// let mut cell: OnceCell = OnceCell::new(); 503 | /// cell.set(92).unwrap(); 504 | /// *cell.get_mut().unwrap() = 93; 505 | /// assert_eq!(cell.get(), Some(&93)); 506 | /// ``` 507 | #[inline] 508 | pub fn get_mut(&mut self) -> Option<&mut T> { 509 | // Safe because we have unique access 510 | unsafe { &mut *self.inner.get() }.as_mut() 511 | } 512 | 513 | /// Sets the contents of this cell to `value`. 514 | /// 515 | /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was 516 | /// full. 517 | /// 518 | /// # Example 519 | /// ``` 520 | /// use once_cell::unsync::OnceCell; 521 | /// 522 | /// let cell = OnceCell::new(); 523 | /// assert!(cell.get().is_none()); 524 | /// 525 | /// assert_eq!(cell.set(92), Ok(())); 526 | /// assert_eq!(cell.set(62), Err(62)); 527 | /// 528 | /// assert!(cell.get().is_some()); 529 | /// ``` 530 | pub fn set(&self, value: T) -> Result<(), T> { 531 | match self.try_insert(value) { 532 | Ok(_) => Ok(()), 533 | Err((_, value)) => Err(value), 534 | } 535 | } 536 | 537 | /// Like [`set`](Self::set), but also returns a reference to the final cell value. 538 | /// 539 | /// # Example 540 | /// ``` 541 | /// use once_cell::unsync::OnceCell; 542 | /// 543 | /// let cell = OnceCell::new(); 544 | /// assert!(cell.get().is_none()); 545 | /// 546 | /// assert_eq!(cell.try_insert(92), Ok(&92)); 547 | /// assert_eq!(cell.try_insert(62), Err((&92, 62))); 548 | /// 549 | /// assert!(cell.get().is_some()); 550 | /// ``` 551 | pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> { 552 | if let Some(old) = self.get() { 553 | return Err((old, value)); 554 | } 555 | 556 | let slot = unsafe { &mut *self.inner.get() }; 557 | // This is the only place where we set the slot, no races 558 | // due to reentrancy/concurrency are possible, and we've 559 | // checked that slot is currently `None`, so this write 560 | // maintains the `inner`'s invariant. 561 | *slot = Some(value); 562 | Ok(unsafe { slot.as_ref().unwrap_unchecked() }) 563 | } 564 | 565 | /// Gets the contents of the cell, initializing it with `f` 566 | /// if the cell was empty. 567 | /// 568 | /// # Panics 569 | /// 570 | /// If `f` panics, the panic is propagated to the caller, and the cell 571 | /// remains uninitialized. 572 | /// 573 | /// It is an error to reentrantly initialize the cell from `f`. Doing 574 | /// so results in a panic. 575 | /// 576 | /// # Example 577 | /// ``` 578 | /// use once_cell::unsync::OnceCell; 579 | /// 580 | /// let cell = OnceCell::new(); 581 | /// let value = cell.get_or_init(|| 92); 582 | /// assert_eq!(value, &92); 583 | /// let value = cell.get_or_init(|| unreachable!()); 584 | /// assert_eq!(value, &92); 585 | /// ``` 586 | pub fn get_or_init(&self, f: F) -> &T 587 | where 588 | F: FnOnce() -> T, 589 | { 590 | enum Void {} 591 | match self.get_or_try_init(|| Ok::(f())) { 592 | Ok(val) => val, 593 | Err(void) => match void {}, 594 | } 595 | } 596 | 597 | /// Gets the contents of the cell, initializing it with `f` if 598 | /// the cell was empty. If the cell was empty and `f` failed, an 599 | /// error is returned. 600 | /// 601 | /// # Panics 602 | /// 603 | /// If `f` panics, the panic is propagated to the caller, and the cell 604 | /// remains uninitialized. 605 | /// 606 | /// It is an error to reentrantly initialize the cell from `f`. Doing 607 | /// so results in a panic. 608 | /// 609 | /// # Example 610 | /// ``` 611 | /// use once_cell::unsync::OnceCell; 612 | /// 613 | /// let cell = OnceCell::new(); 614 | /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); 615 | /// assert!(cell.get().is_none()); 616 | /// let value = cell.get_or_try_init(|| -> Result { 617 | /// Ok(92) 618 | /// }); 619 | /// assert_eq!(value, Ok(&92)); 620 | /// assert_eq!(cell.get(), Some(&92)) 621 | /// ``` 622 | pub fn get_or_try_init(&self, f: F) -> Result<&T, E> 623 | where 624 | F: FnOnce() -> Result, 625 | { 626 | if let Some(val) = self.get() { 627 | return Ok(val); 628 | } 629 | let val = f()?; 630 | // Note that *some* forms of reentrant initialization might lead to 631 | // UB (see `reentrant_init` test). I believe that just removing this 632 | // `assert`, while keeping `set/get` would be sound, but it seems 633 | // better to panic, rather than to silently use an old value. 634 | assert!(self.set(val).is_ok(), "reentrant init"); 635 | Ok(unsafe { self.get().unwrap_unchecked() }) 636 | } 637 | 638 | /// Takes the value out of this `OnceCell`, moving it back to an uninitialized state. 639 | /// 640 | /// Has no effect and returns `None` if the `OnceCell` hasn't been initialized. 641 | /// 642 | /// # Examples 643 | /// 644 | /// ``` 645 | /// use once_cell::unsync::OnceCell; 646 | /// 647 | /// let mut cell: OnceCell = OnceCell::new(); 648 | /// assert_eq!(cell.take(), None); 649 | /// 650 | /// let mut cell = OnceCell::new(); 651 | /// cell.set("hello".to_string()).unwrap(); 652 | /// assert_eq!(cell.take(), Some("hello".to_string())); 653 | /// assert_eq!(cell.get(), None); 654 | /// ``` 655 | /// 656 | /// This method is allowed to violate the invariant of writing to a `OnceCell` 657 | /// at most once because it requires `&mut` access to `self`. As with all 658 | /// interior mutability, `&mut` access permits arbitrary modification: 659 | /// 660 | /// ``` 661 | /// use once_cell::unsync::OnceCell; 662 | /// 663 | /// let mut cell: OnceCell = OnceCell::new(); 664 | /// cell.set(92).unwrap(); 665 | /// cell = OnceCell::new(); 666 | /// ``` 667 | pub fn take(&mut self) -> Option { 668 | mem::take(self).into_inner() 669 | } 670 | 671 | /// Consumes the `OnceCell`, returning the wrapped value. 672 | /// 673 | /// Returns `None` if the cell was empty. 674 | /// 675 | /// # Examples 676 | /// 677 | /// ``` 678 | /// use once_cell::unsync::OnceCell; 679 | /// 680 | /// let cell: OnceCell = OnceCell::new(); 681 | /// assert_eq!(cell.into_inner(), None); 682 | /// 683 | /// let cell = OnceCell::new(); 684 | /// cell.set("hello".to_string()).unwrap(); 685 | /// assert_eq!(cell.into_inner(), Some("hello".to_string())); 686 | /// ``` 687 | pub fn into_inner(self) -> Option { 688 | // Because `into_inner` takes `self` by value, the compiler statically verifies 689 | // that it is not currently borrowed. So it is safe to move out `Option`. 690 | self.inner.into_inner() 691 | } 692 | } 693 | 694 | /// A value which is initialized on the first access. 695 | /// 696 | /// # Example 697 | /// ``` 698 | /// use once_cell::unsync::Lazy; 699 | /// 700 | /// let lazy: Lazy = Lazy::new(|| { 701 | /// println!("initializing"); 702 | /// 92 703 | /// }); 704 | /// println!("ready"); 705 | /// println!("{}", *lazy); 706 | /// println!("{}", *lazy); 707 | /// 708 | /// // Prints: 709 | /// // ready 710 | /// // initializing 711 | /// // 92 712 | /// // 92 713 | /// ``` 714 | pub struct Lazy T> { 715 | cell: OnceCell, 716 | init: Cell>, 717 | } 718 | 719 | impl RefUnwindSafe for Lazy where OnceCell: RefUnwindSafe {} 720 | 721 | impl fmt::Debug for Lazy { 722 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 723 | f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() 724 | } 725 | } 726 | 727 | impl Lazy { 728 | /// Creates a new lazy value with the given initializing function. 729 | /// 730 | /// # Example 731 | /// ``` 732 | /// # fn main() { 733 | /// use once_cell::unsync::Lazy; 734 | /// 735 | /// let hello = "Hello, World!".to_string(); 736 | /// 737 | /// let lazy = Lazy::new(|| hello.to_uppercase()); 738 | /// 739 | /// assert_eq!(&*lazy, "HELLO, WORLD!"); 740 | /// # } 741 | /// ``` 742 | pub const fn new(init: F) -> Lazy { 743 | Lazy { cell: OnceCell::new(), init: Cell::new(Some(init)) } 744 | } 745 | 746 | /// Consumes this `Lazy` returning the stored value. 747 | /// 748 | /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise. 749 | pub fn into_value(this: Lazy) -> Result { 750 | let cell = this.cell; 751 | let init = this.init; 752 | cell.into_inner().ok_or_else(|| { 753 | init.take().unwrap_or_else(|| panic!("Lazy instance has previously been poisoned")) 754 | }) 755 | } 756 | } 757 | 758 | impl T> Lazy { 759 | /// Forces the evaluation of this lazy value and returns a reference to 760 | /// the result. 761 | /// 762 | /// This is equivalent to the `Deref` impl, but is explicit. 763 | /// 764 | /// # Example 765 | /// ``` 766 | /// use once_cell::unsync::Lazy; 767 | /// 768 | /// let lazy = Lazy::new(|| 92); 769 | /// 770 | /// assert_eq!(Lazy::force(&lazy), &92); 771 | /// assert_eq!(&*lazy, &92); 772 | /// ``` 773 | pub fn force(this: &Lazy) -> &T { 774 | this.cell.get_or_init(|| match this.init.take() { 775 | Some(f) => f(), 776 | None => panic!("Lazy instance has previously been poisoned"), 777 | }) 778 | } 779 | 780 | /// Forces the evaluation of this lazy value and returns a mutable reference to 781 | /// the result. 782 | /// 783 | /// This is equivalent to the `DerefMut` impl, but is explicit. 784 | /// 785 | /// # Example 786 | /// ``` 787 | /// use once_cell::unsync::Lazy; 788 | /// 789 | /// let mut lazy = Lazy::new(|| 92); 790 | /// 791 | /// assert_eq!(Lazy::force_mut(&mut lazy), &92); 792 | /// assert_eq!(*lazy, 92); 793 | /// ``` 794 | pub fn force_mut(this: &mut Lazy) -> &mut T { 795 | if this.cell.get_mut().is_none() { 796 | let value = match this.init.get_mut().take() { 797 | Some(f) => f(), 798 | None => panic!("Lazy instance has previously been poisoned"), 799 | }; 800 | this.cell = OnceCell::with_value(value); 801 | } 802 | this.cell.get_mut().unwrap_or_else(|| unreachable!()) 803 | } 804 | 805 | /// Gets the reference to the result of this lazy value if 806 | /// it was initialized, otherwise returns `None`. 807 | /// 808 | /// # Example 809 | /// ``` 810 | /// use once_cell::unsync::Lazy; 811 | /// 812 | /// let lazy = Lazy::new(|| 92); 813 | /// 814 | /// assert_eq!(Lazy::get(&lazy), None); 815 | /// assert_eq!(&*lazy, &92); 816 | /// assert_eq!(Lazy::get(&lazy), Some(&92)); 817 | /// ``` 818 | pub fn get(this: &Lazy) -> Option<&T> { 819 | this.cell.get() 820 | } 821 | 822 | /// Gets the mutable reference to the result of this lazy value if 823 | /// it was initialized, otherwise returns `None`. 824 | /// 825 | /// # Example 826 | /// ``` 827 | /// use once_cell::unsync::Lazy; 828 | /// 829 | /// let mut lazy = Lazy::new(|| 92); 830 | /// 831 | /// assert_eq!(Lazy::get_mut(&mut lazy), None); 832 | /// assert_eq!(*lazy, 92); 833 | /// assert_eq!(Lazy::get_mut(&mut lazy), Some(&mut 92)); 834 | /// ``` 835 | pub fn get_mut(this: &mut Lazy) -> Option<&mut T> { 836 | this.cell.get_mut() 837 | } 838 | } 839 | 840 | impl T> Deref for Lazy { 841 | type Target = T; 842 | fn deref(&self) -> &T { 843 | Lazy::force(self) 844 | } 845 | } 846 | 847 | impl T> DerefMut for Lazy { 848 | fn deref_mut(&mut self) -> &mut T { 849 | Lazy::force_mut(self) 850 | } 851 | } 852 | 853 | impl Default for Lazy { 854 | /// Creates a new lazy value using `Default` as the initializing function. 855 | fn default() -> Lazy { 856 | Lazy::new(T::default) 857 | } 858 | } 859 | } 860 | 861 | /// Thread-safe, blocking version of `OnceCell`. 862 | #[cfg(any(feature = "std", feature = "critical-section"))] 863 | pub mod sync { 864 | use core::{ 865 | cell::Cell, 866 | fmt, mem, 867 | ops::{Deref, DerefMut}, 868 | panic::RefUnwindSafe, 869 | }; 870 | 871 | use super::imp::OnceCell as Imp; 872 | 873 | /// A thread-safe cell which can be written to only once. 874 | /// 875 | /// `OnceCell` provides `&` references to the contents without RAII guards. 876 | /// 877 | /// Reading a non-`None` value out of `OnceCell` establishes a 878 | /// happens-before relationship with a corresponding write. For example, if 879 | /// thread A initializes the cell with `get_or_init(f)`, and thread B 880 | /// subsequently reads the result of this call, B also observes all the side 881 | /// effects of `f`. 882 | /// 883 | /// # Example 884 | /// ``` 885 | /// use once_cell::sync::OnceCell; 886 | /// 887 | /// static CELL: OnceCell = OnceCell::new(); 888 | /// assert!(CELL.get().is_none()); 889 | /// 890 | /// std::thread::spawn(|| { 891 | /// let value: &String = CELL.get_or_init(|| { 892 | /// "Hello, World!".to_string() 893 | /// }); 894 | /// assert_eq!(value, "Hello, World!"); 895 | /// }).join().unwrap(); 896 | /// 897 | /// let value: Option<&String> = CELL.get(); 898 | /// assert!(value.is_some()); 899 | /// assert_eq!(value.unwrap().as_str(), "Hello, World!"); 900 | /// ``` 901 | pub struct OnceCell(Imp); 902 | 903 | impl Default for OnceCell { 904 | fn default() -> OnceCell { 905 | OnceCell::new() 906 | } 907 | } 908 | 909 | impl fmt::Debug for OnceCell { 910 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 911 | match self.get() { 912 | Some(v) => f.debug_tuple("OnceCell").field(v).finish(), 913 | None => f.write_str("OnceCell(Uninit)"), 914 | } 915 | } 916 | } 917 | 918 | impl Clone for OnceCell { 919 | fn clone(&self) -> OnceCell { 920 | match self.get() { 921 | Some(value) => Self::with_value(value.clone()), 922 | None => Self::new(), 923 | } 924 | } 925 | 926 | fn clone_from(&mut self, source: &Self) { 927 | match (self.get_mut(), source.get()) { 928 | (Some(this), Some(source)) => this.clone_from(source), 929 | _ => *self = source.clone(), 930 | } 931 | } 932 | } 933 | 934 | impl From for OnceCell { 935 | fn from(value: T) -> Self { 936 | Self::with_value(value) 937 | } 938 | } 939 | 940 | impl PartialEq for OnceCell { 941 | fn eq(&self, other: &OnceCell) -> bool { 942 | self.get() == other.get() 943 | } 944 | } 945 | 946 | impl Eq for OnceCell {} 947 | 948 | impl OnceCell { 949 | /// Creates a new empty cell. 950 | pub const fn new() -> OnceCell { 951 | OnceCell(Imp::new()) 952 | } 953 | 954 | /// Creates a new initialized cell. 955 | pub const fn with_value(value: T) -> OnceCell { 956 | OnceCell(Imp::with_value(value)) 957 | } 958 | 959 | /// Gets the reference to the underlying value. 960 | /// 961 | /// Returns `None` if the cell is empty, or being initialized. This 962 | /// method never blocks. 963 | pub fn get(&self) -> Option<&T> { 964 | if self.0.is_initialized() { 965 | // Safe b/c value is initialized. 966 | Some(unsafe { self.get_unchecked() }) 967 | } else { 968 | None 969 | } 970 | } 971 | 972 | /// Gets the reference to the underlying value, blocking the current 973 | /// thread until it is set. 974 | /// 975 | /// ``` 976 | /// use once_cell::sync::OnceCell; 977 | /// 978 | /// let mut cell = std::sync::Arc::new(OnceCell::new()); 979 | /// let t = std::thread::spawn({ 980 | /// let cell = std::sync::Arc::clone(&cell); 981 | /// move || cell.set(92).unwrap() 982 | /// }); 983 | /// 984 | /// // Returns immediately, but might return None. 985 | /// let _value_or_none = cell.get(); 986 | /// 987 | /// // Will return 92, but might block until the other thread does `.set`. 988 | /// let value: &u32 = cell.wait(); 989 | /// assert_eq!(*value, 92); 990 | /// t.join().unwrap(); 991 | /// ``` 992 | #[cfg(feature = "std")] 993 | pub fn wait(&self) -> &T { 994 | if !self.0.is_initialized() { 995 | self.0.wait() 996 | } 997 | debug_assert!(self.0.is_initialized()); 998 | // Safe b/c of the wait call above and the fact that we didn't 999 | // relinquish our borrow. 1000 | unsafe { self.get_unchecked() } 1001 | } 1002 | 1003 | /// Gets the mutable reference to the underlying value. 1004 | /// 1005 | /// Returns `None` if the cell is empty. 1006 | /// 1007 | /// This method is allowed to violate the invariant of writing to a `OnceCell` 1008 | /// at most once because it requires `&mut` access to `self`. As with all 1009 | /// interior mutability, `&mut` access permits arbitrary modification: 1010 | /// 1011 | /// ``` 1012 | /// use once_cell::sync::OnceCell; 1013 | /// 1014 | /// let mut cell: OnceCell = OnceCell::new(); 1015 | /// cell.set(92).unwrap(); 1016 | /// cell = OnceCell::new(); 1017 | /// ``` 1018 | #[inline] 1019 | pub fn get_mut(&mut self) -> Option<&mut T> { 1020 | self.0.get_mut() 1021 | } 1022 | 1023 | /// Get the reference to the underlying value, without checking if the 1024 | /// cell is initialized. 1025 | /// 1026 | /// # Safety 1027 | /// 1028 | /// Caller must ensure that the cell is in initialized state, and that 1029 | /// the contents are acquired by (synchronized to) this thread. 1030 | #[inline] 1031 | pub unsafe fn get_unchecked(&self) -> &T { 1032 | self.0.get_unchecked() 1033 | } 1034 | 1035 | /// Sets the contents of this cell to `value`. 1036 | /// 1037 | /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was 1038 | /// full. 1039 | /// 1040 | /// # Example 1041 | /// 1042 | /// ``` 1043 | /// use once_cell::sync::OnceCell; 1044 | /// 1045 | /// static CELL: OnceCell = OnceCell::new(); 1046 | /// 1047 | /// fn main() { 1048 | /// assert!(CELL.get().is_none()); 1049 | /// 1050 | /// std::thread::spawn(|| { 1051 | /// assert_eq!(CELL.set(92), Ok(())); 1052 | /// }).join().unwrap(); 1053 | /// 1054 | /// assert_eq!(CELL.set(62), Err(62)); 1055 | /// assert_eq!(CELL.get(), Some(&92)); 1056 | /// } 1057 | /// ``` 1058 | pub fn set(&self, value: T) -> Result<(), T> { 1059 | match self.try_insert(value) { 1060 | Ok(_) => Ok(()), 1061 | Err((_, value)) => Err(value), 1062 | } 1063 | } 1064 | 1065 | /// Like [`set`](Self::set), but also returns a reference to the final cell value. 1066 | /// 1067 | /// # Example 1068 | /// 1069 | /// ``` 1070 | /// use once_cell::unsync::OnceCell; 1071 | /// 1072 | /// let cell = OnceCell::new(); 1073 | /// assert!(cell.get().is_none()); 1074 | /// 1075 | /// assert_eq!(cell.try_insert(92), Ok(&92)); 1076 | /// assert_eq!(cell.try_insert(62), Err((&92, 62))); 1077 | /// 1078 | /// assert!(cell.get().is_some()); 1079 | /// ``` 1080 | pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> { 1081 | let mut value = Some(value); 1082 | let res = self.get_or_init(|| unsafe { value.take().unwrap_unchecked() }); 1083 | match value { 1084 | None => Ok(res), 1085 | Some(value) => Err((res, value)), 1086 | } 1087 | } 1088 | 1089 | /// Gets the contents of the cell, initializing it with `f` if the cell 1090 | /// was empty. 1091 | /// 1092 | /// Many threads may call `get_or_init` concurrently with different 1093 | /// initializing functions, but it is guaranteed that only one function 1094 | /// will be executed. 1095 | /// 1096 | /// # Panics 1097 | /// 1098 | /// If `f` panics, the panic is propagated to the caller, and the cell 1099 | /// remains uninitialized. 1100 | /// 1101 | /// It is an error to reentrantly initialize the cell from `f`. The 1102 | /// exact outcome is unspecified. Current implementation deadlocks, but 1103 | /// this may be changed to a panic in the future. 1104 | /// 1105 | /// # Example 1106 | /// ``` 1107 | /// use once_cell::sync::OnceCell; 1108 | /// 1109 | /// let cell = OnceCell::new(); 1110 | /// let value = cell.get_or_init(|| 92); 1111 | /// assert_eq!(value, &92); 1112 | /// let value = cell.get_or_init(|| unreachable!()); 1113 | /// assert_eq!(value, &92); 1114 | /// ``` 1115 | pub fn get_or_init(&self, f: F) -> &T 1116 | where 1117 | F: FnOnce() -> T, 1118 | { 1119 | enum Void {} 1120 | match self.get_or_try_init(|| Ok::(f())) { 1121 | Ok(val) => val, 1122 | Err(void) => match void {}, 1123 | } 1124 | } 1125 | 1126 | /// Gets the contents of the cell, initializing it with `f` if 1127 | /// the cell was empty. If the cell was empty and `f` failed, an 1128 | /// error is returned. 1129 | /// 1130 | /// # Panics 1131 | /// 1132 | /// If `f` panics, the panic is propagated to the caller, and 1133 | /// the cell remains uninitialized. 1134 | /// 1135 | /// It is an error to reentrantly initialize the cell from `f`. 1136 | /// The exact outcome is unspecified. Current implementation 1137 | /// deadlocks, but this may be changed to a panic in the future. 1138 | /// 1139 | /// # Example 1140 | /// ``` 1141 | /// use once_cell::sync::OnceCell; 1142 | /// 1143 | /// let cell = OnceCell::new(); 1144 | /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); 1145 | /// assert!(cell.get().is_none()); 1146 | /// let value = cell.get_or_try_init(|| -> Result { 1147 | /// Ok(92) 1148 | /// }); 1149 | /// assert_eq!(value, Ok(&92)); 1150 | /// assert_eq!(cell.get(), Some(&92)) 1151 | /// ``` 1152 | pub fn get_or_try_init(&self, f: F) -> Result<&T, E> 1153 | where 1154 | F: FnOnce() -> Result, 1155 | { 1156 | // Fast path check 1157 | if let Some(value) = self.get() { 1158 | return Ok(value); 1159 | } 1160 | 1161 | self.0.initialize(f)?; 1162 | 1163 | // Safe b/c value is initialized. 1164 | debug_assert!(self.0.is_initialized()); 1165 | Ok(unsafe { self.get_unchecked() }) 1166 | } 1167 | 1168 | /// Takes the value out of this `OnceCell`, moving it back to an uninitialized state. 1169 | /// 1170 | /// Has no effect and returns `None` if the `OnceCell` hasn't been initialized. 1171 | /// 1172 | /// # Examples 1173 | /// 1174 | /// ``` 1175 | /// use once_cell::sync::OnceCell; 1176 | /// 1177 | /// let mut cell: OnceCell = OnceCell::new(); 1178 | /// assert_eq!(cell.take(), None); 1179 | /// 1180 | /// let mut cell = OnceCell::new(); 1181 | /// cell.set("hello".to_string()).unwrap(); 1182 | /// assert_eq!(cell.take(), Some("hello".to_string())); 1183 | /// assert_eq!(cell.get(), None); 1184 | /// ``` 1185 | /// 1186 | /// This method is allowed to violate the invariant of writing to a `OnceCell` 1187 | /// at most once because it requires `&mut` access to `self`. As with all 1188 | /// interior mutability, `&mut` access permits arbitrary modification: 1189 | /// 1190 | /// ``` 1191 | /// use once_cell::sync::OnceCell; 1192 | /// 1193 | /// let mut cell: OnceCell = OnceCell::new(); 1194 | /// cell.set(92).unwrap(); 1195 | /// cell = OnceCell::new(); 1196 | /// ``` 1197 | pub fn take(&mut self) -> Option { 1198 | mem::take(self).into_inner() 1199 | } 1200 | 1201 | /// Consumes the `OnceCell`, returning the wrapped value. Returns 1202 | /// `None` if the cell was empty. 1203 | /// 1204 | /// # Examples 1205 | /// 1206 | /// ``` 1207 | /// use once_cell::sync::OnceCell; 1208 | /// 1209 | /// let cell: OnceCell = OnceCell::new(); 1210 | /// assert_eq!(cell.into_inner(), None); 1211 | /// 1212 | /// let cell = OnceCell::new(); 1213 | /// cell.set("hello".to_string()).unwrap(); 1214 | /// assert_eq!(cell.into_inner(), Some("hello".to_string())); 1215 | /// ``` 1216 | #[inline] 1217 | pub fn into_inner(self) -> Option { 1218 | self.0.into_inner() 1219 | } 1220 | } 1221 | 1222 | /// A value which is initialized on the first access. 1223 | /// 1224 | /// This type is thread-safe and can be used in statics. 1225 | /// 1226 | /// # Example 1227 | /// 1228 | /// ``` 1229 | /// use std::collections::HashMap; 1230 | /// 1231 | /// use once_cell::sync::Lazy; 1232 | /// 1233 | /// static HASHMAP: Lazy> = Lazy::new(|| { 1234 | /// println!("initializing"); 1235 | /// let mut m = HashMap::new(); 1236 | /// m.insert(13, "Spica".to_string()); 1237 | /// m.insert(74, "Hoyten".to_string()); 1238 | /// m 1239 | /// }); 1240 | /// 1241 | /// fn main() { 1242 | /// println!("ready"); 1243 | /// std::thread::spawn(|| { 1244 | /// println!("{:?}", HASHMAP.get(&13)); 1245 | /// }).join().unwrap(); 1246 | /// println!("{:?}", HASHMAP.get(&74)); 1247 | /// 1248 | /// // Prints: 1249 | /// // ready 1250 | /// // initializing 1251 | /// // Some("Spica") 1252 | /// // Some("Hoyten") 1253 | /// } 1254 | /// ``` 1255 | pub struct Lazy T> { 1256 | cell: OnceCell, 1257 | init: Cell>, 1258 | } 1259 | 1260 | impl fmt::Debug for Lazy { 1261 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1262 | f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() 1263 | } 1264 | } 1265 | 1266 | // We never create a `&F` from a `&Lazy` so it is fine to not impl 1267 | // `Sync` for `F`. We do create a `&mut Option` in `force`, but this is 1268 | // properly synchronized, so it only happens once so it also does not 1269 | // contribute to this impl. 1270 | unsafe impl Sync for Lazy where OnceCell: Sync {} 1271 | // auto-derived `Send` impl is OK. 1272 | 1273 | impl RefUnwindSafe for Lazy where OnceCell: RefUnwindSafe {} 1274 | 1275 | impl Lazy { 1276 | /// Creates a new lazy value with the given initializing 1277 | /// function. 1278 | pub const fn new(f: F) -> Lazy { 1279 | Lazy { cell: OnceCell::new(), init: Cell::new(Some(f)) } 1280 | } 1281 | 1282 | /// Consumes this `Lazy` returning the stored value. 1283 | /// 1284 | /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise. 1285 | pub fn into_value(this: Lazy) -> Result { 1286 | let cell = this.cell; 1287 | let init = this.init; 1288 | cell.into_inner().ok_or_else(|| { 1289 | init.take().unwrap_or_else(|| panic!("Lazy instance has previously been poisoned")) 1290 | }) 1291 | } 1292 | } 1293 | 1294 | impl T> Lazy { 1295 | /// Forces the evaluation of this lazy value and 1296 | /// returns a reference to the result. This is equivalent 1297 | /// to the `Deref` impl, but is explicit. 1298 | /// 1299 | /// # Example 1300 | /// ``` 1301 | /// use once_cell::sync::Lazy; 1302 | /// 1303 | /// let lazy = Lazy::new(|| 92); 1304 | /// 1305 | /// assert_eq!(Lazy::force(&lazy), &92); 1306 | /// assert_eq!(&*lazy, &92); 1307 | /// ``` 1308 | pub fn force(this: &Lazy) -> &T { 1309 | this.cell.get_or_init(|| match this.init.take() { 1310 | Some(f) => f(), 1311 | None => panic!("Lazy instance has previously been poisoned"), 1312 | }) 1313 | } 1314 | 1315 | /// Forces the evaluation of this lazy value and 1316 | /// returns a mutable reference to the result. This is equivalent 1317 | /// to the `Deref` impl, but is explicit. 1318 | /// 1319 | /// # Example 1320 | /// ``` 1321 | /// use once_cell::sync::Lazy; 1322 | /// 1323 | /// let mut lazy = Lazy::new(|| 92); 1324 | /// 1325 | /// assert_eq!(Lazy::force_mut(&mut lazy), &mut 92); 1326 | /// ``` 1327 | pub fn force_mut(this: &mut Lazy) -> &mut T { 1328 | if this.cell.get_mut().is_none() { 1329 | let value = match this.init.get_mut().take() { 1330 | Some(f) => f(), 1331 | None => panic!("Lazy instance has previously been poisoned"), 1332 | }; 1333 | this.cell = OnceCell::with_value(value); 1334 | } 1335 | this.cell.get_mut().unwrap_or_else(|| unreachable!()) 1336 | } 1337 | 1338 | /// Gets the reference to the result of this lazy value if 1339 | /// it was initialized, otherwise returns `None`. 1340 | /// 1341 | /// # Example 1342 | /// ``` 1343 | /// use once_cell::sync::Lazy; 1344 | /// 1345 | /// let lazy = Lazy::new(|| 92); 1346 | /// 1347 | /// assert_eq!(Lazy::get(&lazy), None); 1348 | /// assert_eq!(&*lazy, &92); 1349 | /// assert_eq!(Lazy::get(&lazy), Some(&92)); 1350 | /// ``` 1351 | pub fn get(this: &Lazy) -> Option<&T> { 1352 | this.cell.get() 1353 | } 1354 | 1355 | /// Gets the reference to the result of this lazy value if 1356 | /// it was initialized, otherwise returns `None`. 1357 | /// 1358 | /// # Example 1359 | /// ``` 1360 | /// use once_cell::sync::Lazy; 1361 | /// 1362 | /// let mut lazy = Lazy::new(|| 92); 1363 | /// 1364 | /// assert_eq!(Lazy::get_mut(&mut lazy), None); 1365 | /// assert_eq!(&*lazy, &92); 1366 | /// assert_eq!(Lazy::get_mut(&mut lazy), Some(&mut 92)); 1367 | /// ``` 1368 | pub fn get_mut(this: &mut Lazy) -> Option<&mut T> { 1369 | this.cell.get_mut() 1370 | } 1371 | } 1372 | 1373 | impl T> Deref for Lazy { 1374 | type Target = T; 1375 | fn deref(&self) -> &T { 1376 | Lazy::force(self) 1377 | } 1378 | } 1379 | 1380 | impl T> DerefMut for Lazy { 1381 | fn deref_mut(&mut self) -> &mut T { 1382 | Lazy::force_mut(self) 1383 | } 1384 | } 1385 | 1386 | impl Default for Lazy { 1387 | /// Creates a new lazy value using `Default` as the initializing function. 1388 | fn default() -> Lazy { 1389 | Lazy::new(T::default) 1390 | } 1391 | } 1392 | 1393 | /// ```compile_fail 1394 | /// struct S(*mut ()); 1395 | /// unsafe impl Sync for S {} 1396 | /// 1397 | /// fn share(_: &T) {} 1398 | /// share(&once_cell::sync::OnceCell::::new()); 1399 | /// ``` 1400 | /// 1401 | /// ```compile_fail 1402 | /// struct S(*mut ()); 1403 | /// unsafe impl Sync for S {} 1404 | /// 1405 | /// fn share(_: &T) {} 1406 | /// share(&once_cell::sync::Lazy::::new(|| unimplemented!())); 1407 | /// ``` 1408 | fn _dummy() {} 1409 | } 1410 | 1411 | #[cfg(feature = "race")] 1412 | pub mod race; 1413 | -------------------------------------------------------------------------------- /src/race.rs: -------------------------------------------------------------------------------- 1 | //! Thread-safe, non-blocking, "first one wins" flavor of `OnceCell`. 2 | //! 3 | //! If two threads race to initialize a type from the `race` module, they 4 | //! don't block, execute initialization function together, but only one of 5 | //! them stores the result. 6 | //! 7 | //! This module does not require `std` feature. 8 | //! 9 | //! # Atomic orderings 10 | //! 11 | //! All types in this module use `Acquire` and `Release` 12 | //! [atomic orderings](Ordering) for all their operations. While this is not 13 | //! strictly necessary for types other than `OnceBox`, it is useful for users as 14 | //! it allows them to be certain that after `get` or `get_or_init` returns on 15 | //! one thread, any side-effects caused by the setter thread prior to them 16 | //! calling `set` or `get_or_init` will be made visible to that thread; without 17 | //! it, it's possible for it to appear as if they haven't happened yet from the 18 | //! getter thread's perspective. This is an acceptable tradeoff to make since 19 | //! `Acquire` and `Release` have very little performance overhead on most 20 | //! architectures versus `Relaxed`. 21 | 22 | // The "atomic orderings" section of the documentation above promises 23 | // "happens-before" semantics. This drives the choice of orderings in the uses 24 | // of `compare_exchange` below. On success, the value was zero/null, so there 25 | // was nothing to acquire (there is never any `Ordering::Release` store of 0). 26 | // On failure, the value was nonzero, so it was initialized previously (perhaps 27 | // on another thread) using `Ordering::Release`, so we must use 28 | // `Ordering::Acquire` to ensure that store "happens-before" this load. 29 | 30 | #[cfg(not(feature = "portable-atomic"))] 31 | use core::sync::atomic; 32 | #[cfg(feature = "portable-atomic")] 33 | use portable_atomic as atomic; 34 | 35 | use atomic::{AtomicPtr, AtomicUsize, Ordering}; 36 | use core::cell::UnsafeCell; 37 | use core::marker::PhantomData; 38 | use core::num::NonZeroUsize; 39 | use core::ptr; 40 | 41 | /// A thread-safe cell which can be written to only once. 42 | #[derive(Default, Debug)] 43 | pub struct OnceNonZeroUsize { 44 | inner: AtomicUsize, 45 | } 46 | 47 | impl OnceNonZeroUsize { 48 | /// Creates a new empty cell. 49 | #[inline] 50 | pub const fn new() -> Self { 51 | Self { inner: AtomicUsize::new(0) } 52 | } 53 | 54 | /// Gets the underlying value. 55 | #[inline] 56 | pub fn get(&self) -> Option { 57 | let val = self.inner.load(Ordering::Acquire); 58 | NonZeroUsize::new(val) 59 | } 60 | 61 | /// Get the reference to the underlying value, without checking if the cell 62 | /// is initialized. 63 | /// 64 | /// # Safety 65 | /// 66 | /// Caller must ensure that the cell is in initialized state, and that 67 | /// the contents are acquired by (synchronized to) this thread. 68 | pub unsafe fn get_unchecked(&self) -> NonZeroUsize { 69 | #[inline(always)] 70 | fn as_const_ptr(r: &AtomicUsize) -> *const usize { 71 | use core::mem::align_of; 72 | 73 | let p: *const AtomicUsize = r; 74 | // SAFETY: "This type has the same size and bit validity as 75 | // the underlying integer type, usize. However, the alignment of 76 | // this type is always equal to its size, even on targets where 77 | // usize has a lesser alignment." 78 | const _ALIGNMENT_COMPATIBLE: () = 79 | assert!(align_of::() % align_of::() == 0); 80 | p.cast::() 81 | } 82 | 83 | // TODO(MSRV-1.70): Use `AtomicUsize::as_ptr().cast_const()` 84 | // See https://github.com/rust-lang/rust/issues/138246. 85 | let p = as_const_ptr(&self.inner); 86 | 87 | // SAFETY: The caller is responsible for ensuring that the value 88 | // was initialized and that the contents have been acquired by 89 | // this thread. Assuming that, we can assume there will be no 90 | // conflicting writes to the value since the value will never 91 | // change once initialized. This relies on the statement in 92 | // https://doc.rust-lang.org/1.83.0/core/sync/atomic/ that "(A 93 | // `compare_exchange` or `compare_exchange_weak` that does not 94 | // succeed is not considered a write." 95 | let val = unsafe { p.read() }; 96 | 97 | // SAFETY: The caller is responsible for ensuring the value is 98 | // initialized and thus not zero. 99 | unsafe { NonZeroUsize::new_unchecked(val) } 100 | } 101 | 102 | /// Sets the contents of this cell to `value`. 103 | /// 104 | /// Returns `Ok(())` if the cell was empty and `Err(())` if it was 105 | /// full. 106 | #[inline] 107 | pub fn set(&self, value: NonZeroUsize) -> Result<(), ()> { 108 | match self.compare_exchange(value) { 109 | Ok(_) => Ok(()), 110 | Err(_) => Err(()), 111 | } 112 | } 113 | 114 | /// Gets the contents of the cell, initializing it with `f` if the cell was 115 | /// empty. 116 | /// 117 | /// If several threads concurrently run `get_or_init`, more than one `f` can 118 | /// be called. However, all threads will return the same value, produced by 119 | /// some `f`. 120 | pub fn get_or_init(&self, f: F) -> NonZeroUsize 121 | where 122 | F: FnOnce() -> NonZeroUsize, 123 | { 124 | enum Void {} 125 | match self.get_or_try_init(|| Ok::(f())) { 126 | Ok(val) => val, 127 | Err(void) => match void {}, 128 | } 129 | } 130 | 131 | /// Gets the contents of the cell, initializing it with `f` if 132 | /// the cell was empty. If the cell was empty and `f` failed, an 133 | /// error is returned. 134 | /// 135 | /// If several threads concurrently run `get_or_init`, more than one `f` can 136 | /// be called. However, all threads will return the same value, produced by 137 | /// some `f`. 138 | pub fn get_or_try_init(&self, f: F) -> Result 139 | where 140 | F: FnOnce() -> Result, 141 | { 142 | match self.get() { 143 | Some(it) => Ok(it), 144 | None => self.init(f), 145 | } 146 | } 147 | 148 | #[cold] 149 | #[inline(never)] 150 | fn init(&self, f: impl FnOnce() -> Result) -> Result { 151 | let nz = f()?; 152 | let mut val = nz.get(); 153 | if let Err(old) = self.compare_exchange(nz) { 154 | val = old; 155 | } 156 | Ok(unsafe { NonZeroUsize::new_unchecked(val) }) 157 | } 158 | 159 | #[inline(always)] 160 | fn compare_exchange(&self, val: NonZeroUsize) -> Result { 161 | self.inner.compare_exchange(0, val.get(), Ordering::Release, Ordering::Acquire) 162 | } 163 | } 164 | 165 | /// A thread-safe cell which can be written to only once. 166 | #[derive(Default, Debug)] 167 | pub struct OnceBool { 168 | inner: OnceNonZeroUsize, 169 | } 170 | 171 | impl OnceBool { 172 | /// Creates a new empty cell. 173 | #[inline] 174 | pub const fn new() -> Self { 175 | Self { inner: OnceNonZeroUsize::new() } 176 | } 177 | 178 | /// Gets the underlying value. 179 | #[inline] 180 | pub fn get(&self) -> Option { 181 | self.inner.get().map(Self::from_usize) 182 | } 183 | 184 | /// Sets the contents of this cell to `value`. 185 | /// 186 | /// Returns `Ok(())` if the cell was empty and `Err(())` if it was 187 | /// full. 188 | #[inline] 189 | pub fn set(&self, value: bool) -> Result<(), ()> { 190 | self.inner.set(Self::to_usize(value)) 191 | } 192 | 193 | /// Gets the contents of the cell, initializing it with `f` if the cell was 194 | /// empty. 195 | /// 196 | /// If several threads concurrently run `get_or_init`, more than one `f` can 197 | /// be called. However, all threads will return the same value, produced by 198 | /// some `f`. 199 | pub fn get_or_init(&self, f: F) -> bool 200 | where 201 | F: FnOnce() -> bool, 202 | { 203 | Self::from_usize(self.inner.get_or_init(|| Self::to_usize(f()))) 204 | } 205 | 206 | /// Gets the contents of the cell, initializing it with `f` if 207 | /// the cell was empty. If the cell was empty and `f` failed, an 208 | /// error is returned. 209 | /// 210 | /// If several threads concurrently run `get_or_init`, more than one `f` can 211 | /// be called. However, all threads will return the same value, produced by 212 | /// some `f`. 213 | pub fn get_or_try_init(&self, f: F) -> Result 214 | where 215 | F: FnOnce() -> Result, 216 | { 217 | self.inner.get_or_try_init(|| f().map(Self::to_usize)).map(Self::from_usize) 218 | } 219 | 220 | #[inline] 221 | fn from_usize(value: NonZeroUsize) -> bool { 222 | value.get() == 1 223 | } 224 | 225 | #[inline] 226 | fn to_usize(value: bool) -> NonZeroUsize { 227 | unsafe { NonZeroUsize::new_unchecked(if value { 1 } else { 2 }) } 228 | } 229 | } 230 | 231 | /// A thread-safe cell which can be written to only once. 232 | pub struct OnceRef<'a, T> { 233 | inner: AtomicPtr, 234 | ghost: PhantomData>, 235 | } 236 | 237 | // TODO: Replace UnsafeCell with SyncUnsafeCell once stabilized 238 | unsafe impl<'a, T: Sync> Sync for OnceRef<'a, T> {} 239 | 240 | impl<'a, T> core::fmt::Debug for OnceRef<'a, T> { 241 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 242 | write!(f, "OnceRef({:?})", self.inner) 243 | } 244 | } 245 | 246 | impl<'a, T> Default for OnceRef<'a, T> { 247 | fn default() -> Self { 248 | Self::new() 249 | } 250 | } 251 | 252 | impl<'a, T> OnceRef<'a, T> { 253 | /// Creates a new empty cell. 254 | pub const fn new() -> Self { 255 | Self { inner: AtomicPtr::new(ptr::null_mut()), ghost: PhantomData } 256 | } 257 | 258 | /// Gets a reference to the underlying value. 259 | pub fn get(&self) -> Option<&'a T> { 260 | let ptr = self.inner.load(Ordering::Acquire); 261 | unsafe { ptr.as_ref() } 262 | } 263 | 264 | /// Sets the contents of this cell to `value`. 265 | /// 266 | /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was 267 | /// full. 268 | pub fn set(&self, value: &'a T) -> Result<(), ()> { 269 | match self.compare_exchange(value) { 270 | Ok(_) => Ok(()), 271 | Err(_) => Err(()), 272 | } 273 | } 274 | 275 | /// Gets the contents of the cell, initializing it with `f` if the cell was 276 | /// empty. 277 | /// 278 | /// If several threads concurrently run `get_or_init`, more than one `f` can 279 | /// be called. However, all threads will return the same value, produced by 280 | /// some `f`. 281 | pub fn get_or_init(&self, f: F) -> &'a T 282 | where 283 | F: FnOnce() -> &'a T, 284 | { 285 | enum Void {} 286 | match self.get_or_try_init(|| Ok::<&'a T, Void>(f())) { 287 | Ok(val) => val, 288 | Err(void) => match void {}, 289 | } 290 | } 291 | 292 | /// Gets the contents of the cell, initializing it with `f` if 293 | /// the cell was empty. If the cell was empty and `f` failed, an 294 | /// error is returned. 295 | /// 296 | /// If several threads concurrently run `get_or_init`, more than one `f` can 297 | /// be called. However, all threads will return the same value, produced by 298 | /// some `f`. 299 | pub fn get_or_try_init(&self, f: F) -> Result<&'a T, E> 300 | where 301 | F: FnOnce() -> Result<&'a T, E>, 302 | { 303 | match self.get() { 304 | Some(val) => Ok(val), 305 | None => self.init(f), 306 | } 307 | } 308 | 309 | #[cold] 310 | #[inline(never)] 311 | fn init(&self, f: impl FnOnce() -> Result<&'a T, E>) -> Result<&'a T, E> { 312 | let mut value: &'a T = f()?; 313 | if let Err(old) = self.compare_exchange(value) { 314 | value = unsafe { &*old }; 315 | } 316 | Ok(value) 317 | } 318 | 319 | #[inline(always)] 320 | fn compare_exchange(&self, value: &'a T) -> Result<(), *const T> { 321 | self.inner 322 | .compare_exchange( 323 | ptr::null_mut(), 324 | <*const T>::cast_mut(value), 325 | Ordering::Release, 326 | Ordering::Acquire, 327 | ) 328 | .map(|_: *mut T| ()) 329 | .map_err(<*mut T>::cast_const) 330 | } 331 | 332 | /// ```compile_fail 333 | /// use once_cell::race::OnceRef; 334 | /// 335 | /// let mut l = OnceRef::new(); 336 | /// 337 | /// { 338 | /// let y = 2; 339 | /// let mut r = OnceRef::new(); 340 | /// r.set(&y).unwrap(); 341 | /// core::mem::swap(&mut l, &mut r); 342 | /// } 343 | /// 344 | /// // l now contains a dangling reference to y 345 | /// eprintln!("uaf: {}", l.get().unwrap()); 346 | /// ``` 347 | fn _dummy() {} 348 | } 349 | 350 | #[cfg(feature = "alloc")] 351 | pub use self::once_box::OnceBox; 352 | 353 | #[cfg(feature = "alloc")] 354 | mod once_box { 355 | use super::atomic::{AtomicPtr, Ordering}; 356 | use core::{marker::PhantomData, ptr}; 357 | 358 | use alloc::boxed::Box; 359 | 360 | /// A thread-safe cell which can be written to only once. 361 | pub struct OnceBox { 362 | inner: AtomicPtr, 363 | ghost: PhantomData>>, 364 | } 365 | 366 | impl core::fmt::Debug for OnceBox { 367 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 368 | write!(f, "OnceBox({:?})", self.inner.load(Ordering::Relaxed)) 369 | } 370 | } 371 | 372 | impl Default for OnceBox { 373 | fn default() -> Self { 374 | Self::new() 375 | } 376 | } 377 | 378 | impl Drop for OnceBox { 379 | fn drop(&mut self) { 380 | let ptr = *self.inner.get_mut(); 381 | if !ptr.is_null() { 382 | drop(unsafe { Box::from_raw(ptr) }) 383 | } 384 | } 385 | } 386 | 387 | impl OnceBox { 388 | /// Creates a new empty cell. 389 | pub const fn new() -> Self { 390 | Self { inner: AtomicPtr::new(ptr::null_mut()), ghost: PhantomData } 391 | } 392 | 393 | /// Creates a new cell with the given value. 394 | pub fn with_value(value: Box) -> Self { 395 | Self { inner: AtomicPtr::new(Box::into_raw(value)), ghost: PhantomData } 396 | } 397 | 398 | /// Gets a reference to the underlying value. 399 | pub fn get(&self) -> Option<&T> { 400 | let ptr = self.inner.load(Ordering::Acquire); 401 | if ptr.is_null() { 402 | return None; 403 | } 404 | Some(unsafe { &*ptr }) 405 | } 406 | 407 | /// Sets the contents of this cell to `value`. 408 | /// 409 | /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was 410 | /// full. 411 | pub fn set(&self, value: Box) -> Result<(), Box> { 412 | let ptr = Box::into_raw(value); 413 | let exchange = self.inner.compare_exchange( 414 | ptr::null_mut(), 415 | ptr, 416 | Ordering::Release, 417 | Ordering::Acquire, 418 | ); 419 | if exchange.is_err() { 420 | let value = unsafe { Box::from_raw(ptr) }; 421 | return Err(value); 422 | } 423 | Ok(()) 424 | } 425 | 426 | /// Gets the contents of the cell, initializing it with `f` if the cell was 427 | /// empty. 428 | /// 429 | /// If several threads concurrently run `get_or_init`, more than one `f` can 430 | /// be called. However, all threads will return the same value, produced by 431 | /// some `f`. 432 | pub fn get_or_init(&self, f: F) -> &T 433 | where 434 | F: FnOnce() -> Box, 435 | { 436 | enum Void {} 437 | match self.get_or_try_init(|| Ok::, Void>(f())) { 438 | Ok(val) => val, 439 | Err(void) => match void {}, 440 | } 441 | } 442 | 443 | /// Gets the contents of the cell, initializing it with `f` if 444 | /// the cell was empty. If the cell was empty and `f` failed, an 445 | /// error is returned. 446 | /// 447 | /// If several threads concurrently run `get_or_init`, more than one `f` can 448 | /// be called. However, all threads will return the same value, produced by 449 | /// some `f`. 450 | pub fn get_or_try_init(&self, f: F) -> Result<&T, E> 451 | where 452 | F: FnOnce() -> Result, E>, 453 | { 454 | match self.get() { 455 | Some(val) => Ok(val), 456 | None => self.init(f) 457 | } 458 | } 459 | 460 | #[cold] 461 | #[inline(never)] 462 | fn init(&self, f: impl FnOnce() -> Result, E>) -> Result<&T, E> { 463 | let val = f()?; 464 | let mut ptr = Box::into_raw(val); 465 | let exchange = self.inner.compare_exchange( 466 | ptr::null_mut(), 467 | ptr, 468 | Ordering::Release, 469 | Ordering::Acquire, 470 | ); 471 | if let Err(old) = exchange { 472 | drop(unsafe { Box::from_raw(ptr) }); 473 | ptr = old; 474 | } 475 | Ok(unsafe { &*ptr }) 476 | } 477 | } 478 | 479 | unsafe impl Sync for OnceBox {} 480 | 481 | impl Clone for OnceBox { 482 | fn clone(&self) -> Self { 483 | match self.get() { 484 | Some(value) => OnceBox::with_value(Box::new(value.clone())), 485 | None => OnceBox::new(), 486 | } 487 | } 488 | } 489 | 490 | /// ```compile_fail 491 | /// struct S(*mut ()); 492 | /// unsafe impl Sync for S {} 493 | /// 494 | /// fn share(_: &T) {} 495 | /// share(&once_cell::race::OnceBox::::new()); 496 | /// ``` 497 | fn _dummy() {} 498 | } 499 | -------------------------------------------------------------------------------- /tests/it/main.rs: -------------------------------------------------------------------------------- 1 | mod unsync_once_cell; 2 | #[cfg(any(feature = "std", feature = "critical-section"))] 3 | mod sync_once_cell; 4 | 5 | mod unsync_lazy; 6 | #[cfg(any(feature = "std", feature = "critical-section"))] 7 | mod sync_lazy; 8 | 9 | #[cfg(feature = "race")] 10 | mod race; 11 | #[cfg(all(feature = "race", feature = "alloc"))] 12 | mod race_once_box; 13 | -------------------------------------------------------------------------------- /tests/it/race.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "std")] 2 | use std::sync::Barrier; 3 | use std::{ 4 | num::NonZeroUsize, 5 | sync::atomic::{AtomicUsize, Ordering::SeqCst}, 6 | thread::scope, 7 | }; 8 | 9 | use once_cell::race::{OnceBool, OnceNonZeroUsize, OnceRef}; 10 | 11 | #[test] 12 | fn once_non_zero_usize_smoke_test() { 13 | let cnt = AtomicUsize::new(0); 14 | let cell = OnceNonZeroUsize::new(); 15 | let val = NonZeroUsize::new(92).unwrap(); 16 | scope(|s| { 17 | s.spawn(|| { 18 | assert_eq!( 19 | cell.get_or_init(|| { 20 | cnt.fetch_add(1, SeqCst); 21 | val 22 | }), 23 | val 24 | ); 25 | assert_eq!(cnt.load(SeqCst), 1); 26 | 27 | assert_eq!( 28 | cell.get_or_init(|| { 29 | cnt.fetch_add(1, SeqCst); 30 | val 31 | }), 32 | val 33 | ); 34 | assert_eq!(cnt.load(SeqCst), 1); 35 | }); 36 | }); 37 | assert_eq!(cell.get(), Some(val)); 38 | assert_eq!(cnt.load(SeqCst), 1); 39 | } 40 | 41 | #[test] 42 | fn once_non_zero_usize_set() { 43 | let val1 = NonZeroUsize::new(92).unwrap(); 44 | let val2 = NonZeroUsize::new(62).unwrap(); 45 | 46 | let cell = OnceNonZeroUsize::new(); 47 | 48 | assert!(cell.set(val1).is_ok()); 49 | assert_eq!(cell.get(), Some(val1)); 50 | 51 | assert!(cell.set(val2).is_err()); 52 | assert_eq!(cell.get(), Some(val1)); 53 | } 54 | 55 | #[cfg(feature = "std")] 56 | #[test] 57 | fn once_non_zero_usize_first_wins() { 58 | let val1 = NonZeroUsize::new(92).unwrap(); 59 | let val2 = NonZeroUsize::new(62).unwrap(); 60 | 61 | let cell = OnceNonZeroUsize::new(); 62 | 63 | let b1 = Barrier::new(2); 64 | let b2 = Barrier::new(2); 65 | let b3 = Barrier::new(2); 66 | scope(|s| { 67 | s.spawn(|| { 68 | let r1 = cell.get_or_init(|| { 69 | b1.wait(); 70 | b2.wait(); 71 | val1 72 | }); 73 | assert_eq!(r1, val1); 74 | b3.wait(); 75 | }); 76 | b1.wait(); 77 | s.spawn(|| { 78 | let r2 = cell.get_or_init(|| { 79 | b2.wait(); 80 | b3.wait(); 81 | val2 82 | }); 83 | assert_eq!(r2, val1); 84 | }); 85 | }); 86 | 87 | assert_eq!(cell.get(), Some(val1)); 88 | } 89 | 90 | #[test] 91 | fn once_bool_smoke_test() { 92 | let cnt = AtomicUsize::new(0); 93 | let cell = OnceBool::new(); 94 | scope(|s| { 95 | s.spawn(|| { 96 | assert_eq!( 97 | cell.get_or_init(|| { 98 | cnt.fetch_add(1, SeqCst); 99 | false 100 | }), 101 | false 102 | ); 103 | assert_eq!(cnt.load(SeqCst), 1); 104 | 105 | assert_eq!( 106 | cell.get_or_init(|| { 107 | cnt.fetch_add(1, SeqCst); 108 | false 109 | }), 110 | false 111 | ); 112 | assert_eq!(cnt.load(SeqCst), 1); 113 | }); 114 | }); 115 | assert_eq!(cell.get(), Some(false)); 116 | assert_eq!(cnt.load(SeqCst), 1); 117 | } 118 | 119 | #[test] 120 | fn once_bool_set() { 121 | let cell = OnceBool::new(); 122 | 123 | assert!(cell.set(false).is_ok()); 124 | assert_eq!(cell.get(), Some(false)); 125 | 126 | assert!(cell.set(true).is_err()); 127 | assert_eq!(cell.get(), Some(false)); 128 | } 129 | 130 | #[test] 131 | fn once_bool_get_or_try_init() { 132 | let cell = OnceBool::new(); 133 | 134 | let result1: Result = cell.get_or_try_init(|| Ok(true)); 135 | let result2: Result = cell.get_or_try_init(|| Ok(false)); 136 | assert_eq!(result1, Ok(true)); 137 | assert_eq!(result2, Ok(true)); 138 | 139 | let cell = OnceBool::new(); 140 | 141 | let result3: Result = cell.get_or_try_init(|| Err(())); 142 | assert_eq!(result3, Err(())); 143 | } 144 | 145 | #[test] 146 | fn once_ref_smoke_test() { 147 | let cnt: AtomicUsize = AtomicUsize::new(0); 148 | let cell: OnceRef<'_, &str> = OnceRef::new(); 149 | scope(|s| { 150 | s.spawn(|| { 151 | assert_eq!( 152 | cell.get_or_init(|| { 153 | cnt.fetch_add(1, SeqCst); 154 | &"false" 155 | }), 156 | &"false" 157 | ); 158 | assert_eq!(cnt.load(SeqCst), 1); 159 | 160 | assert_eq!( 161 | cell.get_or_init(|| { 162 | cnt.fetch_add(1, SeqCst); 163 | &"false" 164 | }), 165 | &"false" 166 | ); 167 | assert_eq!(cnt.load(SeqCst), 1); 168 | }); 169 | }); 170 | assert_eq!(cell.get(), Some(&"false")); 171 | assert_eq!(cnt.load(SeqCst), 1); 172 | } 173 | 174 | #[test] 175 | fn once_ref_set() { 176 | let cell: OnceRef<'_, &str> = OnceRef::new(); 177 | 178 | assert!(cell.set(&"false").is_ok()); 179 | assert_eq!(cell.get(), Some(&"false")); 180 | 181 | assert!(cell.set(&"true").is_err()); 182 | assert_eq!(cell.get(), Some(&"false")); 183 | } 184 | 185 | #[test] 186 | fn get_unchecked() { 187 | let cell = OnceNonZeroUsize::new(); 188 | cell.set(NonZeroUsize::new(92).unwrap()).unwrap(); 189 | let value = unsafe { cell.get_unchecked() }; 190 | assert_eq!(value, NonZeroUsize::new(92).unwrap()); 191 | } 192 | -------------------------------------------------------------------------------- /tests/it/race_once_box.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "std")] 2 | use std::sync::Barrier; 3 | use std::sync::{ 4 | atomic::{AtomicUsize, Ordering::SeqCst}, 5 | Arc, 6 | }; 7 | 8 | use once_cell::race::OnceBox; 9 | 10 | #[derive(Default)] 11 | struct Heap { 12 | total: Arc, 13 | } 14 | 15 | #[derive(Debug)] 16 | struct Pebble { 17 | val: T, 18 | total: Arc, 19 | } 20 | 21 | impl Drop for Pebble { 22 | fn drop(&mut self) { 23 | self.total.fetch_sub(1, SeqCst); 24 | } 25 | } 26 | 27 | impl Heap { 28 | fn total(&self) -> usize { 29 | self.total.load(SeqCst) 30 | } 31 | fn new_pebble(&self, val: T) -> Pebble { 32 | self.total.fetch_add(1, SeqCst); 33 | Pebble { val, total: Arc::clone(&self.total) } 34 | } 35 | } 36 | 37 | #[cfg(feature = "std")] 38 | #[test] 39 | fn once_box_smoke_test() { 40 | use std::thread::scope; 41 | 42 | let heap = Heap::default(); 43 | let global_cnt = AtomicUsize::new(0); 44 | let cell = OnceBox::new(); 45 | let b = Barrier::new(128); 46 | scope(|s| { 47 | for _ in 0..128 { 48 | s.spawn(|| { 49 | let local_cnt = AtomicUsize::new(0); 50 | cell.get_or_init(|| { 51 | global_cnt.fetch_add(1, SeqCst); 52 | local_cnt.fetch_add(1, SeqCst); 53 | b.wait(); 54 | Box::new(heap.new_pebble(())) 55 | }); 56 | assert_eq!(local_cnt.load(SeqCst), 1); 57 | 58 | cell.get_or_init(|| { 59 | global_cnt.fetch_add(1, SeqCst); 60 | local_cnt.fetch_add(1, SeqCst); 61 | Box::new(heap.new_pebble(())) 62 | }); 63 | assert_eq!(local_cnt.load(SeqCst), 1); 64 | }); 65 | } 66 | }); 67 | assert!(cell.get().is_some()); 68 | assert!(global_cnt.load(SeqCst) > 10); 69 | 70 | assert_eq!(heap.total(), 1); 71 | drop(cell); 72 | assert_eq!(heap.total(), 0); 73 | } 74 | 75 | #[test] 76 | fn once_box_set() { 77 | let heap = Heap::default(); 78 | let cell = OnceBox::new(); 79 | assert!(cell.get().is_none()); 80 | 81 | assert!(cell.set(Box::new(heap.new_pebble("hello"))).is_ok()); 82 | assert_eq!(cell.get().unwrap().val, "hello"); 83 | assert_eq!(heap.total(), 1); 84 | 85 | assert!(cell.set(Box::new(heap.new_pebble("world"))).is_err()); 86 | assert_eq!(cell.get().unwrap().val, "hello"); 87 | assert_eq!(heap.total(), 1); 88 | 89 | drop(cell); 90 | assert_eq!(heap.total(), 0); 91 | } 92 | 93 | #[cfg(feature = "std")] 94 | #[test] 95 | fn once_box_first_wins() { 96 | use std::thread::scope; 97 | 98 | let cell = OnceBox::new(); 99 | let val1 = 92; 100 | let val2 = 62; 101 | 102 | let b1 = Barrier::new(2); 103 | let b2 = Barrier::new(2); 104 | let b3 = Barrier::new(2); 105 | scope(|s| { 106 | s.spawn(|| { 107 | let r1 = cell.get_or_init(|| { 108 | b1.wait(); 109 | b2.wait(); 110 | Box::new(val1) 111 | }); 112 | assert_eq!(*r1, val1); 113 | b3.wait(); 114 | }); 115 | b1.wait(); 116 | s.spawn(|| { 117 | let r2 = cell.get_or_init(|| { 118 | b2.wait(); 119 | b3.wait(); 120 | Box::new(val2) 121 | }); 122 | assert_eq!(*r2, val1); 123 | }); 124 | }); 125 | 126 | assert_eq!(cell.get(), Some(&val1)); 127 | } 128 | 129 | #[test] 130 | fn once_box_reentrant() { 131 | let cell = OnceBox::new(); 132 | let res = cell.get_or_init(|| { 133 | cell.get_or_init(|| Box::new("hello".to_string())); 134 | Box::new("world".to_string()) 135 | }); 136 | assert_eq!(res, "hello"); 137 | } 138 | 139 | #[test] 140 | fn once_box_default() { 141 | struct Foo; 142 | 143 | let cell: OnceBox = Default::default(); 144 | assert!(cell.get().is_none()); 145 | } 146 | 147 | #[test] 148 | fn onece_box_with_value() { 149 | let cell = OnceBox::with_value(Box::new(92)); 150 | assert_eq!(cell.get(), Some(&92)); 151 | } 152 | 153 | #[test] 154 | fn onece_box_clone() { 155 | let cell1 = OnceBox::new(); 156 | let cell2 = cell1.clone(); 157 | cell1.set(Box::new(92)).unwrap(); 158 | let cell3 = cell1.clone(); 159 | assert_eq!(cell1.get(), Some(&92)); 160 | assert_eq!(cell2.get(), None); 161 | assert_eq!(cell3.get(), Some(&92)); 162 | } 163 | -------------------------------------------------------------------------------- /tests/it/sync_lazy.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | cell::Cell, 3 | sync::atomic::{AtomicUsize, Ordering::SeqCst}, 4 | thread::scope, 5 | }; 6 | 7 | use once_cell::sync::{Lazy, OnceCell}; 8 | 9 | #[test] 10 | fn lazy_new() { 11 | let called = AtomicUsize::new(0); 12 | let x = Lazy::new(|| { 13 | called.fetch_add(1, SeqCst); 14 | 92 15 | }); 16 | 17 | assert_eq!(called.load(SeqCst), 0); 18 | 19 | scope(|s| { 20 | s.spawn(|| { 21 | let y = *x - 30; 22 | assert_eq!(y, 62); 23 | assert_eq!(called.load(SeqCst), 1); 24 | }); 25 | }); 26 | 27 | let y = *x - 30; 28 | assert_eq!(y, 62); 29 | assert_eq!(called.load(SeqCst), 1); 30 | } 31 | 32 | #[test] 33 | fn lazy_deref_mut() { 34 | let called = AtomicUsize::new(0); 35 | let mut x = Lazy::new(|| { 36 | called.fetch_add(1, SeqCst); 37 | 92 38 | }); 39 | 40 | assert_eq!(called.load(SeqCst), 0); 41 | 42 | let y = *x - 30; 43 | assert_eq!(y, 62); 44 | assert_eq!(called.load(SeqCst), 1); 45 | 46 | *x /= 2; 47 | assert_eq!(*x, 46); 48 | assert_eq!(called.load(SeqCst), 1); 49 | } 50 | 51 | #[test] 52 | fn lazy_force_mut() { 53 | let called = Cell::new(0); 54 | let mut x = Lazy::new(|| { 55 | called.set(called.get() + 1); 56 | 92 57 | }); 58 | assert_eq!(called.get(), 0); 59 | let v = Lazy::force_mut(&mut x); 60 | assert_eq!(called.get(), 1); 61 | 62 | *v /= 2; 63 | assert_eq!(*x, 46); 64 | assert_eq!(called.get(), 1); 65 | } 66 | 67 | #[test] 68 | fn lazy_get_mut() { 69 | let called = Cell::new(0); 70 | let mut x: Lazy = Lazy::new(|| { 71 | called.set(called.get() + 1); 72 | 92 73 | }); 74 | 75 | assert_eq!(called.get(), 0); 76 | assert_eq!(*x, 92); 77 | 78 | let mut_ref: &mut u32 = Lazy::get_mut(&mut x).unwrap(); 79 | assert_eq!(called.get(), 1); 80 | 81 | *mut_ref /= 2; 82 | assert_eq!(*x, 46); 83 | assert_eq!(called.get(), 1); 84 | } 85 | 86 | #[test] 87 | fn lazy_default() { 88 | static CALLED: AtomicUsize = AtomicUsize::new(0); 89 | 90 | struct Foo(u8); 91 | impl Default for Foo { 92 | fn default() -> Self { 93 | CALLED.fetch_add(1, SeqCst); 94 | Foo(42) 95 | } 96 | } 97 | 98 | let lazy: Lazy> = <_>::default(); 99 | 100 | assert_eq!(CALLED.load(SeqCst), 0); 101 | 102 | assert_eq!(lazy.lock().unwrap().0, 42); 103 | assert_eq!(CALLED.load(SeqCst), 1); 104 | 105 | lazy.lock().unwrap().0 = 21; 106 | 107 | assert_eq!(lazy.lock().unwrap().0, 21); 108 | assert_eq!(CALLED.load(SeqCst), 1); 109 | } 110 | 111 | #[test] 112 | fn static_lazy() { 113 | static XS: Lazy> = Lazy::new(|| { 114 | let mut xs = Vec::new(); 115 | xs.push(1); 116 | xs.push(2); 117 | xs.push(3); 118 | xs 119 | }); 120 | scope(|s| { 121 | s.spawn(|| { 122 | assert_eq!(&*XS, &vec![1, 2, 3]); 123 | }); 124 | }); 125 | assert_eq!(&*XS, &vec![1, 2, 3]); 126 | } 127 | 128 | #[test] 129 | fn static_lazy_via_fn() { 130 | fn xs() -> &'static Vec { 131 | static XS: OnceCell> = OnceCell::new(); 132 | XS.get_or_init(|| { 133 | let mut xs = Vec::new(); 134 | xs.push(1); 135 | xs.push(2); 136 | xs.push(3); 137 | xs 138 | }) 139 | } 140 | assert_eq!(xs(), &vec![1, 2, 3]); 141 | } 142 | 143 | #[test] 144 | fn lazy_into_value() { 145 | let l: Lazy = Lazy::new(|| panic!()); 146 | assert!(matches!(Lazy::into_value(l), Err(_))); 147 | let l = Lazy::new(|| -> i32 { 92 }); 148 | Lazy::force(&l); 149 | assert!(matches!(Lazy::into_value(l), Ok(92))); 150 | } 151 | 152 | #[test] 153 | fn lazy_poisoning() { 154 | let x: Lazy = Lazy::new(|| panic!("kaboom")); 155 | for _ in 0..2 { 156 | let res = std::panic::catch_unwind(|| x.len()); 157 | assert!(res.is_err()); 158 | } 159 | } 160 | 161 | #[test] 162 | // https://github.com/rust-lang/rust/issues/34761#issuecomment-256320669 163 | fn arrrrrrrrrrrrrrrrrrrrrr() { 164 | let lazy: Lazy<&String, _>; 165 | { 166 | let s = String::new(); 167 | lazy = Lazy::new(|| &s); 168 | _ = *lazy; 169 | } 170 | } 171 | 172 | #[test] 173 | fn lazy_is_sync_send() { 174 | fn assert_traits() {} 175 | assert_traits::>(); 176 | } 177 | -------------------------------------------------------------------------------- /tests/it/sync_once_cell.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | sync::atomic::{AtomicUsize, Ordering::SeqCst}, 3 | thread::scope, 4 | }; 5 | 6 | #[cfg(feature = "std")] 7 | use std::sync::Barrier; 8 | 9 | #[cfg(not(feature = "std"))] 10 | use core::cell::Cell; 11 | 12 | use once_cell::sync::{Lazy, OnceCell}; 13 | 14 | #[test] 15 | fn once_cell() { 16 | let c = OnceCell::new(); 17 | assert!(c.get().is_none()); 18 | scope(|s| { 19 | s.spawn(|| { 20 | c.get_or_init(|| 92); 21 | assert_eq!(c.get(), Some(&92)); 22 | }); 23 | }); 24 | c.get_or_init(|| panic!("Kabom!")); 25 | assert_eq!(c.get(), Some(&92)); 26 | } 27 | 28 | #[test] 29 | fn once_cell_with_value() { 30 | static CELL: OnceCell = OnceCell::with_value(12); 31 | assert_eq!(CELL.get(), Some(&12)); 32 | } 33 | 34 | #[test] 35 | fn once_cell_get_mut() { 36 | let mut c = OnceCell::new(); 37 | assert!(c.get_mut().is_none()); 38 | c.set(90).unwrap(); 39 | *c.get_mut().unwrap() += 2; 40 | assert_eq!(c.get_mut(), Some(&mut 92)); 41 | } 42 | 43 | #[test] 44 | fn once_cell_get_unchecked() { 45 | let c = OnceCell::new(); 46 | c.set(92).unwrap(); 47 | unsafe { 48 | assert_eq!(c.get_unchecked(), &92); 49 | } 50 | } 51 | 52 | #[test] 53 | fn once_cell_drop() { 54 | static DROP_CNT: AtomicUsize = AtomicUsize::new(0); 55 | struct Dropper; 56 | impl Drop for Dropper { 57 | fn drop(&mut self) { 58 | DROP_CNT.fetch_add(1, SeqCst); 59 | } 60 | } 61 | 62 | let x = OnceCell::new(); 63 | scope(|s| { 64 | s.spawn(|| { 65 | x.get_or_init(|| Dropper); 66 | assert_eq!(DROP_CNT.load(SeqCst), 0); 67 | drop(x); 68 | }); 69 | }); 70 | assert_eq!(DROP_CNT.load(SeqCst), 1); 71 | } 72 | 73 | #[test] 74 | fn once_cell_drop_empty() { 75 | let x = OnceCell::::new(); 76 | drop(x); 77 | } 78 | 79 | #[test] 80 | fn clone() { 81 | let s = OnceCell::new(); 82 | let c = s.clone(); 83 | assert!(c.get().is_none()); 84 | 85 | s.set("hello".to_string()).unwrap(); 86 | let c = s.clone(); 87 | assert_eq!(c.get().map(String::as_str), Some("hello")); 88 | } 89 | 90 | #[test] 91 | fn get_or_try_init() { 92 | let cell: OnceCell = OnceCell::new(); 93 | assert!(cell.get().is_none()); 94 | 95 | let res = std::panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() })); 96 | assert!(res.is_err()); 97 | assert!(cell.get().is_none()); 98 | 99 | assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); 100 | 101 | assert_eq!(cell.get_or_try_init(|| Ok::<_, ()>("hello".to_string())), Ok(&"hello".to_string())); 102 | assert_eq!(cell.get(), Some(&"hello".to_string())); 103 | } 104 | 105 | #[cfg(feature = "std")] 106 | #[test] 107 | fn wait() { 108 | let cell: OnceCell = OnceCell::new(); 109 | scope(|s| { 110 | s.spawn(|| cell.set("hello".to_string())); 111 | let greeting = cell.wait(); 112 | assert_eq!(greeting, "hello") 113 | }); 114 | } 115 | 116 | #[cfg(feature = "std")] 117 | #[test] 118 | fn get_or_init_stress() { 119 | let n_threads = if cfg!(miri) { 30 } else { 1_000 }; 120 | let n_cells = if cfg!(miri) { 30 } else { 1_000 }; 121 | let cells: Vec<_> = std::iter::repeat_with(|| (Barrier::new(n_threads), OnceCell::new())) 122 | .take(n_cells) 123 | .collect(); 124 | scope(|s| { 125 | for t in 0..n_threads { 126 | let cells = &cells; 127 | s.spawn(move || { 128 | for (i, (b, s)) in cells.iter().enumerate() { 129 | b.wait(); 130 | let j = if t % 2 == 0 { s.wait() } else { s.get_or_init(|| i) }; 131 | assert_eq!(*j, i); 132 | } 133 | }); 134 | } 135 | }); 136 | } 137 | 138 | #[test] 139 | fn from_impl() { 140 | assert_eq!(OnceCell::from("value").get(), Some(&"value")); 141 | assert_ne!(OnceCell::from("foo").get(), Some(&"bar")); 142 | } 143 | 144 | #[test] 145 | fn partialeq_impl() { 146 | assert!(OnceCell::from("value") == OnceCell::from("value")); 147 | assert!(OnceCell::from("foo") != OnceCell::from("bar")); 148 | 149 | assert!(OnceCell::::new() == OnceCell::new()); 150 | assert!(OnceCell::::new() != OnceCell::from("value".to_owned())); 151 | } 152 | 153 | #[test] 154 | fn into_inner() { 155 | let cell: OnceCell = OnceCell::new(); 156 | assert_eq!(cell.into_inner(), None); 157 | let cell = OnceCell::new(); 158 | cell.set("hello".to_string()).unwrap(); 159 | assert_eq!(cell.into_inner(), Some("hello".to_string())); 160 | } 161 | 162 | #[test] 163 | fn debug_impl() { 164 | let cell = OnceCell::new(); 165 | assert_eq!(format!("{:#?}", cell), "OnceCell(Uninit)"); 166 | cell.set(vec!["hello", "world"]).unwrap(); 167 | assert_eq!( 168 | format!("{:#?}", cell), 169 | r#"OnceCell( 170 | [ 171 | "hello", 172 | "world", 173 | ], 174 | )"# 175 | ); 176 | } 177 | 178 | #[test] 179 | #[cfg_attr(miri, ignore)] // miri doesn't support processes 180 | #[cfg(feature = "std")] 181 | fn reentrant_init() { 182 | let examples_dir = { 183 | let mut exe = std::env::current_exe().unwrap(); 184 | exe.pop(); 185 | exe.pop(); 186 | exe.push("examples"); 187 | exe 188 | }; 189 | let bin = examples_dir 190 | .join("reentrant_init_deadlocks") 191 | .with_extension(std::env::consts::EXE_EXTENSION); 192 | let mut guard = Guard { child: std::process::Command::new(bin).spawn().unwrap() }; 193 | std::thread::sleep(std::time::Duration::from_secs(2)); 194 | let status = guard.child.try_wait().unwrap(); 195 | assert!(status.is_none()); 196 | 197 | struct Guard { 198 | child: std::process::Child, 199 | } 200 | 201 | impl Drop for Guard { 202 | fn drop(&mut self) { 203 | let _ = self.child.kill(); 204 | } 205 | } 206 | } 207 | 208 | #[cfg(not(feature = "std"))] 209 | #[test] 210 | #[should_panic(expected = "reentrant init")] 211 | fn reentrant_init() { 212 | let x: OnceCell> = OnceCell::new(); 213 | let dangling_ref: Cell> = Cell::new(None); 214 | x.get_or_init(|| { 215 | let r = x.get_or_init(|| Box::new(92)); 216 | dangling_ref.set(Some(r)); 217 | Box::new(62) 218 | }); 219 | eprintln!("use after free: {:?}", dangling_ref.get().unwrap()); 220 | } 221 | 222 | #[test] 223 | fn eval_once_macro() { 224 | macro_rules! eval_once { 225 | (|| -> $ty:ty { 226 | $($body:tt)* 227 | }) => {{ 228 | static ONCE_CELL: OnceCell<$ty> = OnceCell::new(); 229 | fn init() -> $ty { 230 | $($body)* 231 | } 232 | ONCE_CELL.get_or_init(init) 233 | }}; 234 | } 235 | 236 | let fib: &'static Vec = eval_once! { 237 | || -> Vec { 238 | let mut res = vec![1, 1]; 239 | for i in 0..10 { 240 | let next = res[i] + res[i + 1]; 241 | res.push(next); 242 | } 243 | res 244 | } 245 | }; 246 | assert_eq!(fib[5], 8) 247 | } 248 | 249 | #[test] 250 | fn once_cell_does_not_leak_partially_constructed_boxes() { 251 | let n_tries = if cfg!(miri) { 10 } else { 100 }; 252 | let n_readers = 10; 253 | let n_writers = 3; 254 | const MSG: &str = "Hello, World"; 255 | 256 | for _ in 0..n_tries { 257 | let cell: OnceCell = OnceCell::new(); 258 | scope(|scope| { 259 | for _ in 0..n_readers { 260 | scope.spawn(|| loop { 261 | if let Some(msg) = cell.get() { 262 | assert_eq!(msg, MSG); 263 | break; 264 | } 265 | }); 266 | } 267 | for _ in 0..n_writers { 268 | let _ = scope.spawn(|| cell.set(MSG.to_owned())); 269 | } 270 | }); 271 | } 272 | } 273 | 274 | #[cfg(feature = "std")] 275 | #[test] 276 | fn get_does_not_block() { 277 | let cell = OnceCell::new(); 278 | let barrier = Barrier::new(2); 279 | scope(|scope| { 280 | scope.spawn(|| { 281 | cell.get_or_init(|| { 282 | barrier.wait(); 283 | barrier.wait(); 284 | "hello".to_string() 285 | }); 286 | }); 287 | barrier.wait(); 288 | assert_eq!(cell.get(), None); 289 | barrier.wait(); 290 | }); 291 | assert_eq!(cell.get(), Some(&"hello".to_string())); 292 | } 293 | 294 | #[test] 295 | // https://github.com/rust-lang/rust/issues/34761#issuecomment-256320669 296 | fn arrrrrrrrrrrrrrrrrrrrrr() { 297 | let cell = OnceCell::new(); 298 | { 299 | let s = String::new(); 300 | cell.set(&s).unwrap(); 301 | } 302 | } 303 | 304 | #[test] 305 | fn once_cell_is_sync_send() { 306 | fn assert_traits() {} 307 | assert_traits::>(); 308 | assert_traits::>(); 309 | } 310 | -------------------------------------------------------------------------------- /tests/it/unsync_lazy.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | cell::Cell, 3 | sync::atomic::{AtomicUsize, Ordering::SeqCst}, 4 | }; 5 | 6 | use once_cell::unsync::Lazy; 7 | 8 | #[test] 9 | fn lazy_new() { 10 | let called = Cell::new(0); 11 | let x = Lazy::new(|| { 12 | called.set(called.get() + 1); 13 | 92 14 | }); 15 | 16 | assert_eq!(called.get(), 0); 17 | 18 | let y = *x - 30; 19 | assert_eq!(y, 62); 20 | assert_eq!(called.get(), 1); 21 | 22 | let y = *x - 30; 23 | assert_eq!(y, 62); 24 | assert_eq!(called.get(), 1); 25 | } 26 | 27 | #[test] 28 | fn lazy_deref_mut() { 29 | let called = Cell::new(0); 30 | let mut x = Lazy::new(|| { 31 | called.set(called.get() + 1); 32 | 92 33 | }); 34 | 35 | assert_eq!(called.get(), 0); 36 | 37 | let y = *x - 30; 38 | assert_eq!(y, 62); 39 | assert_eq!(called.get(), 1); 40 | 41 | *x /= 2; 42 | assert_eq!(*x, 46); 43 | assert_eq!(called.get(), 1); 44 | } 45 | 46 | #[test] 47 | fn lazy_force_mut() { 48 | let called = Cell::new(0); 49 | let mut x = Lazy::new(|| { 50 | called.set(called.get() + 1); 51 | 92 52 | }); 53 | assert_eq!(called.get(), 0); 54 | let v = Lazy::force_mut(&mut x); 55 | assert_eq!(called.get(), 1); 56 | 57 | *v /= 2; 58 | assert_eq!(*x, 46); 59 | assert_eq!(called.get(), 1); 60 | } 61 | 62 | #[test] 63 | fn lazy_get_mut() { 64 | let called = Cell::new(0); 65 | let mut x: Lazy = Lazy::new(|| { 66 | called.set(called.get() + 1); 67 | 92 68 | }); 69 | 70 | assert_eq!(called.get(), 0); 71 | assert_eq!(*x, 92); 72 | 73 | let mut_ref: &mut u32 = Lazy::get_mut(&mut x).unwrap(); 74 | assert_eq!(called.get(), 1); 75 | 76 | *mut_ref /= 2; 77 | assert_eq!(*x, 46); 78 | assert_eq!(called.get(), 1); 79 | } 80 | 81 | #[test] 82 | fn lazy_default() { 83 | static CALLED: AtomicUsize = AtomicUsize::new(0); 84 | 85 | struct Foo(u8); 86 | impl Default for Foo { 87 | fn default() -> Self { 88 | CALLED.fetch_add(1, SeqCst); 89 | Foo(42) 90 | } 91 | } 92 | 93 | let lazy: Lazy> = <_>::default(); 94 | 95 | assert_eq!(CALLED.load(SeqCst), 0); 96 | 97 | assert_eq!(lazy.lock().unwrap().0, 42); 98 | assert_eq!(CALLED.load(SeqCst), 1); 99 | 100 | lazy.lock().unwrap().0 = 21; 101 | 102 | assert_eq!(lazy.lock().unwrap().0, 21); 103 | assert_eq!(CALLED.load(SeqCst), 1); 104 | } 105 | 106 | #[test] 107 | fn lazy_into_value() { 108 | let l: Lazy = Lazy::new(|| panic!()); 109 | assert!(matches!(Lazy::into_value(l), Err(_))); 110 | let l = Lazy::new(|| -> i32 { 92 }); 111 | Lazy::force(&l); 112 | assert!(matches!(Lazy::into_value(l), Ok(92))); 113 | } 114 | 115 | #[test] 116 | #[cfg(feature = "std")] 117 | fn lazy_poisoning() { 118 | let x: Lazy = Lazy::new(|| panic!("kaboom")); 119 | for _ in 0..2 { 120 | let res = std::panic::catch_unwind(|| x.len()); 121 | assert!(res.is_err()); 122 | } 123 | } 124 | 125 | #[test] 126 | // https://github.com/rust-lang/rust/issues/34761#issuecomment-256320669 127 | fn arrrrrrrrrrrrrrrrrrrrrr() { 128 | let lazy: Lazy<&String, _>; 129 | { 130 | let s = String::new(); 131 | lazy = Lazy::new(|| &s); 132 | _ = *lazy; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /tests/it/unsync_once_cell.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | cell::Cell, 3 | sync::atomic::{AtomicUsize, Ordering::SeqCst}, 4 | }; 5 | 6 | use once_cell::unsync::OnceCell; 7 | 8 | #[test] 9 | fn once_cell() { 10 | let c = OnceCell::new(); 11 | assert!(c.get().is_none()); 12 | c.get_or_init(|| 92); 13 | assert_eq!(c.get(), Some(&92)); 14 | 15 | c.get_or_init(|| panic!("Kabom!")); 16 | assert_eq!(c.get(), Some(&92)); 17 | } 18 | 19 | #[test] 20 | fn once_cell_with_value() { 21 | const CELL: OnceCell = OnceCell::with_value(12); 22 | let cell = CELL; 23 | assert_eq!(cell.get(), Some(&12)); 24 | } 25 | 26 | #[test] 27 | fn once_cell_get_mut() { 28 | let mut c = OnceCell::new(); 29 | assert!(c.get_mut().is_none()); 30 | c.set(90).unwrap(); 31 | *c.get_mut().unwrap() += 2; 32 | assert_eq!(c.get_mut(), Some(&mut 92)); 33 | } 34 | 35 | #[test] 36 | fn once_cell_drop() { 37 | static DROP_CNT: AtomicUsize = AtomicUsize::new(0); 38 | struct Dropper; 39 | impl Drop for Dropper { 40 | fn drop(&mut self) { 41 | DROP_CNT.fetch_add(1, SeqCst); 42 | } 43 | } 44 | 45 | let x = OnceCell::new(); 46 | x.get_or_init(|| Dropper); 47 | assert_eq!(DROP_CNT.load(SeqCst), 0); 48 | drop(x); 49 | assert_eq!(DROP_CNT.load(SeqCst), 1); 50 | } 51 | 52 | #[test] 53 | fn once_cell_drop_empty() { 54 | let x = OnceCell::::new(); 55 | drop(x); 56 | } 57 | 58 | #[test] 59 | fn clone() { 60 | let s = OnceCell::new(); 61 | let c = s.clone(); 62 | assert!(c.get().is_none()); 63 | 64 | s.set("hello".to_string()).unwrap(); 65 | let c = s.clone(); 66 | assert_eq!(c.get().map(String::as_str), Some("hello")); 67 | } 68 | 69 | #[test] 70 | fn get_or_try_init() { 71 | let cell: OnceCell = OnceCell::new(); 72 | assert!(cell.get().is_none()); 73 | 74 | let res = std::panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() })); 75 | assert!(res.is_err()); 76 | assert!(cell.get().is_none()); 77 | 78 | assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); 79 | 80 | assert_eq!(cell.get_or_try_init(|| Ok::<_, ()>("hello".to_string())), Ok(&"hello".to_string())); 81 | assert_eq!(cell.get(), Some(&"hello".to_string())); 82 | } 83 | 84 | #[test] 85 | fn from_impl() { 86 | assert_eq!(OnceCell::from("value").get(), Some(&"value")); 87 | assert_ne!(OnceCell::from("foo").get(), Some(&"bar")); 88 | } 89 | 90 | #[test] 91 | fn partialeq_impl() { 92 | assert!(OnceCell::from("value") == OnceCell::from("value")); 93 | assert!(OnceCell::from("foo") != OnceCell::from("bar")); 94 | 95 | assert!(OnceCell::::new() == OnceCell::new()); 96 | assert!(OnceCell::::new() != OnceCell::from("value".to_owned())); 97 | } 98 | 99 | #[test] 100 | fn into_inner() { 101 | let cell: OnceCell = OnceCell::new(); 102 | assert_eq!(cell.into_inner(), None); 103 | let cell = OnceCell::new(); 104 | cell.set("hello".to_string()).unwrap(); 105 | assert_eq!(cell.into_inner(), Some("hello".to_string())); 106 | } 107 | 108 | #[test] 109 | fn debug_impl() { 110 | let cell = OnceCell::new(); 111 | assert_eq!(format!("{:#?}", cell), "OnceCell(Uninit)"); 112 | cell.set(vec!["hello", "world"]).unwrap(); 113 | assert_eq!( 114 | format!("{:#?}", cell), 115 | r#"OnceCell( 116 | [ 117 | "hello", 118 | "world", 119 | ], 120 | )"# 121 | ); 122 | } 123 | 124 | #[test] 125 | #[should_panic(expected = "reentrant init")] 126 | fn reentrant_init() { 127 | let x: OnceCell> = OnceCell::new(); 128 | let dangling_ref: Cell> = Cell::new(None); 129 | x.get_or_init(|| { 130 | let r = x.get_or_init(|| Box::new(92)); 131 | dangling_ref.set(Some(r)); 132 | Box::new(62) 133 | }); 134 | eprintln!("use after free: {:?}", dangling_ref.get().unwrap()); 135 | } 136 | 137 | #[test] 138 | fn aliasing_in_get() { 139 | let x = OnceCell::new(); 140 | x.set(42).unwrap(); 141 | let at_x = x.get().unwrap(); // --- (shared) borrow of inner `Option` --+ 142 | let _ = x.set(27); // <-- temporary (unique) borrow of inner `Option` | 143 | println!("{}", at_x); // <------- up until here ---------------------------+ 144 | } 145 | 146 | #[test] 147 | // https://github.com/rust-lang/rust/issues/34761#issuecomment-256320669 148 | fn arrrrrrrrrrrrrrrrrrrrrr() { 149 | let cell = OnceCell::new(); 150 | { 151 | let s = String::new(); 152 | cell.set(&s).unwrap(); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /xtask/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "xtask" 3 | version = "0.0.0" 4 | publish = false 5 | authors = ["Aleksey Kladov "] 6 | edition = "2018" 7 | 8 | [dependencies] 9 | xshell = "0.2.2" 10 | -------------------------------------------------------------------------------- /xtask/src/main.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tidy; 3 | 4 | use std::time::Instant; 5 | 6 | use xshell::{cmd, Shell}; 7 | 8 | fn main() -> xshell::Result<()> { 9 | let sh = Shell::new()?; 10 | 11 | let _e = push_toolchain(&sh, "stable")?; 12 | let _e = sh.push_env("CARGO", ""); 13 | 14 | { 15 | let _s = section("BUILD"); 16 | cmd!(sh, "cargo test --workspace --no-run").run()?; 17 | } 18 | 19 | { 20 | let _s = section("TEST"); 21 | 22 | cmd!(sh, "cargo test --workspace").run()?; 23 | 24 | for &release in &[None, Some("--release")] { 25 | cmd!(sh, "cargo test --features unstable {release...}").run()?; 26 | cmd!( 27 | sh, 28 | "cargo test --no-default-features --features unstable,std,parking_lot {release...}" 29 | ) 30 | .run()?; 31 | } 32 | 33 | // Skip doctests for no_std tests as those don't work 34 | cmd!(sh, "cargo test --no-default-features --features unstable --test it").run()?; 35 | cmd!(sh, "cargo test --no-default-features --features unstable,alloc --test it").run()?; 36 | 37 | cmd!(sh, "cargo test --no-default-features --features critical-section").run()?; 38 | cmd!(sh, "cargo test --features critical-section").run()?; 39 | } 40 | 41 | { 42 | let _s = section("TEST_BETA"); 43 | let _e = push_toolchain(&sh, "beta")?; 44 | // TEMPORARY WORKAROUND for Rust compiler issue ref: 45 | // - https://github.com/rust-lang/rust/issues/129352 46 | // - https://github.com/matklad/once_cell/issues/261 47 | let _e = sh.push_env("RUSTFLAGS", "-A unreachable_patterns"); 48 | 49 | cmd!(sh, "cargo test --features unstable").run()?; 50 | } 51 | 52 | { 53 | let _s = section("TEST_MSRV"); 54 | let msrv = { 55 | let manifest = sh.read_file("Cargo.toml")?; 56 | let (_, suffix) = manifest.split_once("rust-version = \"").unwrap(); 57 | let (version, _) = suffix.split_once("\"").unwrap(); 58 | version.to_string() 59 | }; 60 | 61 | let _e = push_toolchain(&sh, &msrv)?; 62 | sh.copy_file("Cargo.lock.msrv", "Cargo.lock")?; 63 | if let err @ Err(_) = cmd!(sh, "cargo update -w -v --locked").run() { 64 | // `Cargo.lock.msrv` is out of date! Probably from having bumped our own version number. 65 | println! {"\ 66 | Error: `Cargo.lock.msrv` is out of date. \ 67 | Please run:\n \ 68 | (cp Cargo.lock{{.msrv,}} && cargo +{msrv} update -w -v && cp Cargo.lock{{.msrv,}})\n\ 69 | \n\ 70 | Alternatively, `git apply` the `.patch` below:\ 71 | "} 72 | cmd!(sh, "cargo update -q -w").quiet().run()?; 73 | sh.copy_file("Cargo.lock", "Cargo.lock.msrv")?; 74 | cmd!(sh, "git --no-pager diff --color=always -- Cargo.lock.msrv").quiet().run()?; 75 | return err; 76 | } 77 | cmd!(sh, "cargo build --locked").run()?; 78 | } 79 | 80 | { 81 | let _s = section("TEST_MIRI"); 82 | let miri_nightly= cmd!(sh, "curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri").read()?; 83 | let _e = push_toolchain(&sh, &format!("nightly-{}", miri_nightly))?; 84 | 85 | sh.remove_path("./target")?; 86 | 87 | cmd!(sh, "rustup component add miri").run()?; 88 | cmd!(sh, "cargo miri setup").run()?; 89 | cmd!(sh, "cargo miri test --features unstable").run()?; 90 | } 91 | 92 | { 93 | let _s = section("PUBLISH"); 94 | 95 | let version = cmd!(sh, "cargo pkgid").read()?.rsplit_once('#').unwrap().1.to_string(); 96 | let tag = format!("v{version}"); 97 | 98 | let current_branch = cmd!(sh, "git branch --show-current").read()?; 99 | let has_tag = cmd!(sh, "git tag --list").read()?.lines().any(|it| it.trim() == tag); 100 | let dry_run = sh.var("CI").is_err() || has_tag || current_branch != "master"; 101 | eprintln!("Publishing{}!", if dry_run { " (dry run)" } else { "" }); 102 | 103 | let dry_run_arg = if dry_run { Some("--dry-run") } else { None }; 104 | cmd!(sh, "cargo publish {dry_run_arg...}").run()?; 105 | if dry_run { 106 | eprintln!("{}", cmd!(sh, "git tag {tag}")); 107 | eprintln!("{}", cmd!(sh, "git push --tags")); 108 | } else { 109 | cmd!(sh, "git tag {tag}").run()?; 110 | cmd!(sh, "git push --tags").run()?; 111 | } 112 | } 113 | Ok(()) 114 | } 115 | 116 | fn push_toolchain<'a>( 117 | sh: &'a xshell::Shell, 118 | toolchain: &str, 119 | ) -> xshell::Result> { 120 | cmd!(sh, "rustup toolchain install {toolchain} --no-self-update").run()?; 121 | let res = sh.push_env("RUSTUP_TOOLCHAIN", toolchain); 122 | cmd!(sh, "rustc --version").run()?; 123 | Ok(res) 124 | } 125 | 126 | fn section(name: &'static str) -> impl Drop { 127 | println!("::group::{name}"); 128 | let start = Instant::now(); 129 | defer(move || { 130 | let elapsed = start.elapsed(); 131 | eprintln!("{name}: {elapsed:.2?}"); 132 | println!("::endgroup::"); 133 | }) 134 | } 135 | 136 | fn defer(f: F) -> impl Drop { 137 | struct D(Option); 138 | impl Drop for D { 139 | fn drop(&mut self) { 140 | if let Some(f) = self.0.take() { 141 | f() 142 | } 143 | } 144 | } 145 | D(Some(f)) 146 | } 147 | -------------------------------------------------------------------------------- /xtask/src/tidy.rs: -------------------------------------------------------------------------------- 1 | use xshell::{cmd, Shell}; 2 | 3 | #[test] 4 | fn test_formatting() { 5 | let sh = Shell::new().unwrap(); 6 | cmd!(sh, "cargo fmt -- --check").run().unwrap() 7 | } 8 | --------------------------------------------------------------------------------