once_cell-1.20.2/.cargo_vcs_info.json0000644000000001360000000000100130410ustar { "git": { "sha1": "4fbd4a53509ca59c8e09efc2ab0a22f21de70f7e" }, "path_in_vcs": "" }once_cell-1.20.2/.github/workflows/ci.yaml000064400000000000000000000011321046102023000165020ustar 00000000000000name: CI on: pull_request: push: branches: ["master", "staging", "trying"] env: CARGO_INCREMENTAL: 0 CARGO_NET_RETRY: 10 CI: 1 RUST_BACKTRACE: short RUSTFLAGS: -D warnings RUSTUP_MAX_RETRIES: 10 jobs: test: name: Rust runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 with: fetch-depth: 0 # fetch tags for publish - uses: Swatinem/rust-cache@359a70e43a0bb8a13953b04a90f76428b4959bb6 - run: cargo run -p xtask -- ci env: CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }} MIRIFLAGS: -Zmiri-strict-provenance once_cell-1.20.2/.gitignore000064400000000000000000000000341046102023000136160ustar 00000000000000/target /.vscode Cargo.lock once_cell-1.20.2/CHANGELOG.md000064400000000000000000000147311046102023000134500ustar 00000000000000# Changelog ## Unreleased ## 1.20.2 - Remove `portable_atomic` from Cargo.lock if it is not, in fact, used: [#267](https://github.com/matklad/once_cell/pull/267) This is a work-around for this cargo bug: https://github.com/rust-lang/cargo/issues/10801. ## 1.20.1 - Allow using `race` module using just `portable_atomic`, without `critical_section` and provide better error messages on targets without atomic CAS instruction, [#265](https://github.com/matklad/once_cell/pull/265). ## 1.19.0 - Use `portable-atomic` instead of `atomic-polyfill`, [#251](https://github.com/matklad/once_cell/pull/251). ## 1.18.0 - `MSRV` is updated to 1.60.0 to take advantage of `dep:` syntax for cargo features, removing "implementation details" from publicly visible surface. ## 1.17.2 - Avoid unnecessary synchronization in `Lazy::{force,deref}_mut()`, [#231](https://github.com/matklad/once_cell/pull/231). ## 1.17.1 - Make `OnceRef` implementation compliant with [strict provenance](https://github.com/rust-lang/rust/issues/95228). ## 1.17.0 - Add `race::OnceRef` for storing a `&'a T`. ## 1.16.0 - Add `no_std` implementation based on `critical-section`, [#195](https://github.com/matklad/once_cell/pull/195). - Deprecate `atomic-polyfill` feature (use the new `critical-section` instead) ## 1.15.0 - Increase minimal supported Rust version to 1.56.0. - Implement `UnwindSafe` even if the `std` feature is disabled. ## 1.14.0 - Add extension to `unsync` and `sync` `Lazy` mut API: - `force_mut` - `get_mut` ## 1.13.1 - Make implementation compliant with [strict provenance](https://github.com/rust-lang/rust/issues/95228). - Upgrade `atomic-polyfill` to `1.0` ## 1.13.0 - Add `Lazy::get`, similar to `OnceCell::get`. ## 1.12.1 - Remove incorrect `debug_assert`. ## 1.12.0 - Add `OnceCell::wait`, a blocking variant of `get`. ## 1.11.0 - Add `OnceCell::with_value` to create initialized `OnceCell` in `const` context. - Improve `Clone` implementation for `OnceCell`. - Rewrite `parking_lot` version on top of `parking_lot_core`, for even smaller cells! ## 1.10.0 - upgrade `parking_lot` to `0.12.0` (note that this bumps MSRV with `parking_lot` feature enabled to `1.49.0`). ## 1.9.0 - Added an `atomic-polyfill` optional dependency to compile `race` on platforms without atomics ## 1.8.0 - Add `try_insert` API -- a version of `set` that returns a reference. ## 1.7.2 - Improve code size when using parking_lot feature. ## 1.7.1 - Fix `race::OnceBox` to also impl `Default` even if `T` doesn't impl `Default`. ## 1.7.0 - Hide the `race` module behind (default) `race` feature. Turns out that adding `race` by default was a breaking change on some platforms without atomics. In this release, we make the module opt-out. Technically, this is a breaking change for those who use `race` with `no_default_features`. Given that the `race` module itself only several days old, the breakage is deemed acceptable. ## 1.6.0 - Add `Lazy::into_value` - Stabilize `once_cell::race` module for "first one wins" no_std-compatible initialization flavor. - Migrate from deprecated `compare_and_swap` to `compare_exchange`. ## 1.5.2 - `OnceBox` API uses `Box`. This a breaking change to unstable API. ## 1.5.1 - MSRV is increased to `1.36.0`. - document `once_cell::race` module. - introduce `alloc` feature for `OnceBox`. - fix `OnceBox::set`. ## 1.5.0 - add new `once_cell::race` module for "first one wins" no_std-compatible initialization flavor. The API is provisional, subject to change and is gated by the `unstable` cargo feature. ## 1.4.1 - upgrade `parking_lot` to `0.11.0` - make `sync::OnceCell` pass https://doc.rust-lang.org/nomicon/dropck.html#an-escape-hatch[dropck] with `parking_lot` feature enabled. This fixes a (minor) semver-incompatible changed introduced in `1.4.0` ## 1.4.0 - upgrade `parking_lot` to `0.10` (note that this bumps MSRV with `parking_lot` feature enabled to `1.36.0`). - add `OnceCell::take`. - upgrade crossbeam utils (private dependency) to `0.7`. ## 1.3.1 - remove unnecessary `F: fmt::Debug` bound from `impl fmt::Debug for Lazy`. ## 1.3.0 - `Lazy` now implements `DerefMut`. - update implementation according to the latest changes in `std`. ## 1.2.0 - add `sync::OnceCell::get_unchecked`. ## 1.1.0 - implement `Default` for `Lazy`: it creates an empty `Lazy` which is initialized with `T::default` on first access. - add `OnceCell::get_mut`. ## 1.0.2 - actually add `#![no_std]` attribute if std feature is not enabled. ## 1.0.1 - fix unsoundness in `Lazy` if the initializing function panics. Thanks [@xfix](https://github.com/xfix)! - implement `RefUnwindSafe` for `Lazy`. - share more code between `std` and `parking_lot` implementations. - add F.A.Q section to the docs. ## 1.0.0 - remove `parking_lot` from the list of default features. - add `std` default feature. Without `std`, only `unsync` module is supported. - implement `Eq` for `OnceCell`. - fix wrong `Sync` bound on `sync::Lazy`. - run the whole test suite with miri. ## 0.2.7 - New implementation of `sync::OnceCell` if `parking_lot` feature is disabled. It now employs a hand-rolled variant of `std::sync::Once`. - `sync::OnceCell::get_or_try_init` works without `parking_lot` as well! - document the effects of `parking_lot` feature: same performance but smaller types. ## 0.2.6 - Updated `Lazy`'s `Deref` impl to requires only `FnOnce` instead of `Fn` ## 0.2.5 - `Lazy` requires only `FnOnce` instead of `Fn` ## 0.2.4 - nicer `fmt::Debug` implementation ## 0.2.3 - update `parking_lot` to `0.9.0` - fix stacked borrows violation in `unsync::OnceCell::get` - implement `Clone` for `sync::OnceCell where T: Clone` ## 0.2.2 - add `OnceCell::into_inner` which consumes a cell and returns an option ## 0.2.1 - implement `sync::OnceCell::get_or_try_init` if `parking_lot` feature is enabled - switch internal `unsafe` implementation of `sync::OnceCell` from `Once` to `Mutex` - `sync::OnceCell::get_or_init` is twice as fast if cell is already initialized - implement `std::panic::RefUnwindSafe` and `std::panic::UnwindSafe` for `OnceCell` - better document behavior around panics ## 0.2.0 - MSRV is now 1.31.1 - `Lazy::new` and `OnceCell::new` are now const-fns - `unsync_lazy` and `sync_lazy` macros are removed ## 0.1.8 - update crossbeam-utils to 0.6 - enable bors-ng ## 0.1.7 - cells implement `PartialEq` and `From` - MSRV is down to 1.24.1 - update `parking_lot` to `0.7.1` ## 0.1.6 - `unsync::OnceCell` is `Clone` if `T` is `Clone`. ## 0.1.5 - No changelog until this point :( once_cell-1.20.2/Cargo.lock0000644000000120050000000000100110120ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "critical-section" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f64009896348fc5af4222e9cf7d7d82a95a256c634ebcf61c53e4ea461422242" [[package]] name = "libc" version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "once_cell" version = "1.20.2" dependencies = [ "critical-section", "parking_lot_core", "portable-atomic", "regex", ] [[package]] name = "parking_lot_core" version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", "windows-targets", ] [[package]] name = "portable-atomic" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" [[package]] name = "redox_syscall" version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" dependencies = [ "bitflags", ] [[package]] name = "regex" version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" once_cell-1.20.2/Cargo.toml0000644000000047360000000000100110510ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.60" name = "once_cell" version = "1.20.2" authors = ["Aleksey Kladov "] build = false exclude = [ "*.png", "*.svg", "/Cargo.lock.msrv", "rustfmt.toml", ] autobins = false autoexamples = false autotests = false autobenches = false description = "Single assignment cells and lazy values." documentation = "https://docs.rs/once_cell" readme = "README.md" keywords = [ "lazy", "static", ] categories = [ "rust-patterns", "memory-management", ] license = "MIT OR Apache-2.0" repository = "https://github.com/matklad/once_cell" [package.metadata.docs.rs] all-features = true rustdoc-args = ["--generate-link-to-definition"] [lib] name = "once_cell" path = "src/lib.rs" [[example]] name = "bench" path = "examples/bench.rs" required-features = ["std"] [[example]] name = "bench_acquire" path = "examples/bench_acquire.rs" required-features = ["std"] [[example]] name = "lazy_static" path = "examples/lazy_static.rs" required-features = ["std"] [[example]] name = "reentrant_init_deadlocks" path = "examples/reentrant_init_deadlocks.rs" required-features = ["std"] [[example]] name = "regex" path = "examples/regex.rs" required-features = ["std"] [[example]] name = "test_synchronization" path = "examples/test_synchronization.rs" required-features = ["std"] [[test]] name = "it" path = "tests/it/main.rs" [dependencies.critical-section] version = "1.1.3" optional = true [dependencies.parking_lot_core] version = "0.9.10" optional = true default-features = false [dependencies.portable-atomic] version = "1.8" optional = true default-features = false [dev-dependencies.critical-section] version = "1.1.3" features = ["std"] [dev-dependencies.regex] version = "1.10.6" [features] alloc = ["race"] atomic-polyfill = ["critical-section"] critical-section = [ "dep:critical-section", "portable-atomic", ] default = ["std"] parking_lot = ["dep:parking_lot_core"] portable-atomic = ["dep:portable-atomic"] race = [] std = ["alloc"] unstable = [] once_cell-1.20.2/Cargo.toml.orig000064400000000000000000000045641046102023000145310ustar 00000000000000[package] name = "once_cell" version = "1.20.2" authors = ["Aleksey Kladov "] license = "MIT OR Apache-2.0" edition = "2021" rust-version = "1.60" description = "Single assignment cells and lazy values." readme = "README.md" documentation = "https://docs.rs/once_cell" repository = "https://github.com/matklad/once_cell" keywords = ["lazy", "static"] categories = ["rust-patterns", "memory-management"] exclude = ["*.png", "*.svg", "/Cargo.lock.msrv", "rustfmt.toml"] [workspace] members = ["xtask"] [dependencies] parking_lot_core = { version = "0.9.10", optional = true, default-features = false } portable-atomic = { version = "1.8", optional = true, default-features = false } critical-section = { version = "1.1.3", optional = true } [dev-dependencies] regex = "1.10.6" critical-section = { version = "1.1.3", features = ["std"] } [features] default = ["std"] # Enables `once_cell::sync` module. std = ["alloc"] # Enables `once_cell::race::OnceBox` type. alloc = ["race"] # Enables `once_cell::race` module. race = [] # Uses parking_lot to implement once_cell::sync::OnceCell. # This makes no speed difference, but makes each OnceCell # up to 16 bytes smaller, depending on the size of the T. parking_lot = ["dep:parking_lot_core"] # Uses `portable-atomic` to implement `race` module. in # `#![no_std]` mode. Please read `portable-atomic` docs carefully # before enabling this feature. portable-atomic = ["dep:portable-atomic"] # Uses `critical-section` to implement `sync` module. in # `#![no_std]` mode. Please read `critical-section` docs carefully # before enabling this feature. # `portable-atomic` feature is enabled for backwards compatibility. critical-section = ["dep:critical-section", "portable-atomic"] # Enables semver-exempt APIs of this crate. # At the moment, this feature is unused. unstable = [] # Only for backwards compatibility. atomic-polyfill = ["critical-section"] [[example]] name = "bench" required-features = ["std"] [[example]] name = "bench_acquire" required-features = ["std"] [[example]] name = "lazy_static" required-features = ["std"] [[example]] name = "reentrant_init_deadlocks" required-features = ["std"] [[example]] name = "regex" required-features = ["std"] [[example]] name = "test_synchronization" required-features = ["std"] [package.metadata.docs.rs] all-features = true rustdoc-args = ["--generate-link-to-definition"] once_cell-1.20.2/LICENSE-APACHE000064400000000000000000000251371046102023000135650ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. once_cell-1.20.2/LICENSE-MIT000064400000000000000000000017771046102023000133010ustar 00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. once_cell-1.20.2/README.md000064400000000000000000000042171046102023000131140ustar 00000000000000

once_cell

[![Build Status](https://github.com/matklad/once_cell/actions/workflows/ci.yaml/badge.svg)](https://github.com/matklad/once_cell/actions) [![Crates.io](https://img.shields.io/crates/v/once_cell.svg)](https://crates.io/crates/once_cell) [![API reference](https://docs.rs/once_cell/badge.svg)](https://docs.rs/once_cell/) # Overview `once_cell` provides two new cell-like types, `unsync::OnceCell` and `sync::OnceCell`. `OnceCell` might store arbitrary non-`Copy` types, can be assigned to at most once and provide direct access to the stored contents. In a nutshell, API looks *roughly* like this: ```rust impl OnceCell { fn new() -> OnceCell { ... } fn set(&self, value: T) -> Result<(), T> { ... } fn get(&self) -> Option<&T> { ... } } ``` Note that, like with `RefCell` and `Mutex`, the `set` method requires only a shared reference. Because of the single assignment restriction `get` can return an `&T` instead of `Ref` or `MutexGuard`. `once_cell` also has a `Lazy` type, build on top of `OnceCell` which provides the same API as the `lazy_static!` macro, but without using any macros: ```rust use std::{sync::Mutex, collections::HashMap}; use once_cell::sync::Lazy; static GLOBAL_DATA: Lazy>> = Lazy::new(|| { let mut m = HashMap::new(); m.insert(13, "Spica".to_string()); m.insert(74, "Hoyten".to_string()); Mutex::new(m) }); fn main() { println!("{:?}", GLOBAL_DATA.lock().unwrap()); } ``` More patterns and use-cases are in the [docs](https://docs.rs/once_cell/)! # Related crates * [double-checked-cell](https://github.com/niklasf/double-checked-cell) * [lazy-init](https://crates.io/crates/lazy-init) * [lazycell](https://crates.io/crates/lazycell) * [mitochondria](https://crates.io/crates/mitochondria) * [lazy_static](https://crates.io/crates/lazy_static) * [async_once_cell](https://crates.io/crates/async_once_cell) * [generic_once_cell](https://crates.io/crates/generic_once_cell) (bring your own mutex) Parts of `once_cell` API are included into `std` [as of Rust 1.70.0](https://github.com/rust-lang/rust/pull/105587). once_cell-1.20.2/bors.toml000064400000000000000000000000621046102023000134710ustar 00000000000000status = [ "Rust" ] delete_merged_branches = true once_cell-1.20.2/examples/bench.rs000064400000000000000000000014771046102023000151050ustar 00000000000000use std::mem::size_of; use once_cell::sync::OnceCell; const N_THREADS: usize = 32; const N_ROUNDS: usize = 100_000_000; static CELL: OnceCell = OnceCell::new(); fn main() { let start = std::time::Instant::now(); let threads = (0..N_THREADS).map(|i| std::thread::spawn(move || thread_main(i))).collect::>(); for thread in threads { thread.join().unwrap(); } println!("{:?}", start.elapsed()); println!("size_of::>() = {:?}", size_of::>()); println!("size_of::>() = {:?}", size_of::>()); println!("size_of::>() = {:?}", size_of::>()); } fn thread_main(i: usize) { for _ in 0..N_ROUNDS { let &value = CELL.get_or_init(|| i); assert!(value < N_THREADS) } } once_cell-1.20.2/examples/bench_acquire.rs000064400000000000000000000025001046102023000166020ustar 00000000000000//! Benchmark the overhead that the synchronization of `OnceCell::get` causes. //! We do some other operations that write to memory to get an imprecise but somewhat realistic //! measurement. use once_cell::sync::OnceCell; use std::sync::atomic::{AtomicUsize, Ordering}; const N_THREADS: usize = 16; const N_ROUNDS: usize = 1_000_000; static CELL: OnceCell = OnceCell::new(); static OTHER: AtomicUsize = AtomicUsize::new(0); fn main() { let start = std::time::Instant::now(); let threads = (0..N_THREADS).map(|i| std::thread::spawn(move || thread_main(i))).collect::>(); for thread in threads { thread.join().unwrap(); } println!("{:?}", start.elapsed()); println!("{:?}", OTHER.load(Ordering::Relaxed)); } #[inline(never)] fn thread_main(i: usize) { // The operations we do here don't really matter, as long as we do multiple writes, and // everything is messy enough to prevent the compiler from optimizing the loop away. let mut data = [i; 128]; let mut accum = 0usize; for _ in 0..N_ROUNDS { let _value = CELL.get_or_init(|| i + 1); let k = OTHER.fetch_add(data[accum & 0x7F] as usize, Ordering::Relaxed); for j in data.iter_mut() { *j = (*j).wrapping_add(accum); accum = accum.wrapping_add(k); } } } once_cell-1.20.2/examples/lazy_static.rs000064400000000000000000000020141046102023000163400ustar 00000000000000extern crate once_cell; use once_cell::sync::{Lazy, OnceCell}; use std::collections::HashMap; static HASHMAP: Lazy> = Lazy::new(|| { let mut m = HashMap::new(); m.insert(0, "foo"); m.insert(1, "bar"); m.insert(2, "baz"); m }); // Same, but completely without macros fn hashmap() -> &'static HashMap { static INSTANCE: OnceCell> = OnceCell::new(); INSTANCE.get_or_init(|| { let mut m = HashMap::new(); m.insert(0, "foo"); m.insert(1, "bar"); m.insert(2, "baz"); m }) } fn main() { // First access to `HASHMAP` initializes it println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap()); // Any further access to `HASHMAP` just returns the computed value println!("The entry for `1` is \"{}\".", HASHMAP.get(&1).unwrap()); // The same works for function-style: assert_eq!(hashmap().get(&0), Some(&"foo")); assert_eq!(hashmap().get(&1), Some(&"bar")); } once_cell-1.20.2/examples/reentrant_init_deadlocks.rs000064400000000000000000000005371046102023000210600ustar 00000000000000fn main() { let cell = once_cell::sync::OnceCell::::new(); cell.get_or_init(|| { cell.get_or_init(|| 1); 2 }); } /// Dummy test to make it seem hang when compiled as `--test` /// See https://github.com/matklad/once_cell/issues/79 #[test] fn dummy_test() { std::thread::sleep(std::time::Duration::from_secs(4)); } once_cell-1.20.2/examples/regex.rs000064400000000000000000000031771046102023000151370ustar 00000000000000use std::{str::FromStr, time::Instant}; use regex::Regex; macro_rules! regex { ($re:literal $(,)?) => {{ static RE: once_cell::sync::OnceCell = once_cell::sync::OnceCell::new(); RE.get_or_init(|| regex::Regex::new($re).unwrap()) }}; } fn slow() { 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""##; let mut total = 0; for _ in 0..1000 { let re = Regex::new( r##"^(\S+) (\S+) (\S+) \[([^]]+)\] "([^"]*)" (\d+) (\d+) "([^"]*)" "([^"]*)"$"##, ) .unwrap(); let size = usize::from_str(re.captures(s).unwrap().get(7).unwrap().as_str()).unwrap(); total += size; } println!("{}", total); } fn fast() { 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""##; let mut total = 0; for _ in 0..1000 { let re: &Regex = regex!( r##"^(\S+) (\S+) (\S+) \[([^]]+)\] "([^"]*)" (\d+) (\d+) "([^"]*)" "([^"]*)"$"##, ); let size = usize::from_str(re.captures(s).unwrap().get(7).unwrap().as_str()).unwrap(); total += size; } println!("{}", total); } fn main() { let t = Instant::now(); slow(); println!("slow: {:?}", t.elapsed()); let t = Instant::now(); fast(); println!("fast: {:?}", t.elapsed()); } once_cell-1.20.2/examples/test_synchronization.rs000064400000000000000000000023111046102023000203120ustar 00000000000000//! Test if the OnceCell properly synchronizes. //! Needs to be run in release mode. //! //! We create a `Vec` with `N_ROUNDS` of `OnceCell`s. All threads will walk the `Vec`, and race to //! be the first one to initialize a cell. //! Every thread adds the results of the cells it sees to an accumulator, which is compared at the //! end. //! All threads should end up with the same result. use once_cell::sync::OnceCell; const N_THREADS: usize = 32; const N_ROUNDS: usize = 1_000_000; static CELLS: OnceCell>> = OnceCell::new(); static RESULT: OnceCell = OnceCell::new(); fn main() { let start = std::time::Instant::now(); CELLS.get_or_init(|| vec![OnceCell::new(); N_ROUNDS]); let threads = (0..N_THREADS).map(|i| std::thread::spawn(move || thread_main(i))).collect::>(); for thread in threads { thread.join().unwrap(); } println!("{:?}", start.elapsed()); println!("No races detected"); } fn thread_main(i: usize) { let cells = CELLS.get().unwrap(); let mut accum = 0; for cell in cells.iter() { let &value = cell.get_or_init(|| i); accum += value; } assert_eq!(RESULT.get_or_init(|| accum), &accum); } once_cell-1.20.2/src/imp_cs.rs000064400000000000000000000046651046102023000142530ustar 00000000000000use core::panic::{RefUnwindSafe, UnwindSafe}; use critical_section::{CriticalSection, Mutex}; use portable_atomic::{AtomicBool, Ordering}; use crate::unsync; pub(crate) struct OnceCell { initialized: AtomicBool, // Use `unsync::OnceCell` internally since `Mutex` does not provide // interior mutability and to be able to re-use `get_or_try_init`. value: Mutex>, } // Why do we need `T: Send`? // Thread A creates a `OnceCell` and shares it with // scoped thread B, which fills the cell, which is // then destroyed by A. That is, destructor observes // a sent value. unsafe impl Sync for OnceCell {} unsafe impl Send for OnceCell {} impl RefUnwindSafe for OnceCell {} impl UnwindSafe for OnceCell {} impl OnceCell { pub(crate) const fn new() -> OnceCell { OnceCell { initialized: AtomicBool::new(false), value: Mutex::new(unsync::OnceCell::new()) } } pub(crate) const fn with_value(value: T) -> OnceCell { OnceCell { initialized: AtomicBool::new(true), value: Mutex::new(unsync::OnceCell::with_value(value)), } } #[inline] pub(crate) fn is_initialized(&self) -> bool { self.initialized.load(Ordering::Acquire) } #[cold] pub(crate) fn initialize(&self, f: F) -> Result<(), E> where F: FnOnce() -> Result, { critical_section::with(|cs| { let cell = self.value.borrow(cs); cell.get_or_try_init(f).map(|_| { self.initialized.store(true, Ordering::Release); }) }) } /// Get the reference to the underlying value, without checking if the cell /// is initialized. /// /// # Safety /// /// Caller must ensure that the cell is in initialized state, and that /// the contents are acquired by (synchronized to) this thread. pub(crate) unsafe fn get_unchecked(&self) -> &T { debug_assert!(self.is_initialized()); // SAFETY: The caller ensures that the value is initialized and access synchronized. self.value.borrow(CriticalSection::new()).get().unwrap_unchecked() } #[inline] pub(crate) fn get_mut(&mut self) -> Option<&mut T> { self.value.get_mut().get_mut() } #[inline] pub(crate) fn into_inner(self) -> Option { self.value.into_inner().into_inner() } } once_cell-1.20.2/src/imp_pl.rs000064400000000000000000000132531046102023000142520ustar 00000000000000use std::{ cell::UnsafeCell, panic::{RefUnwindSafe, UnwindSafe}, sync::atomic::{AtomicU8, Ordering}, }; pub(crate) struct OnceCell { state: AtomicU8, value: UnsafeCell>, } const INCOMPLETE: u8 = 0x0; const RUNNING: u8 = 0x1; const COMPLETE: u8 = 0x2; // Why do we need `T: Send`? // Thread A creates a `OnceCell` and shares it with // scoped thread B, which fills the cell, which is // then destroyed by A. That is, destructor observes // a sent value. unsafe impl Sync for OnceCell {} unsafe impl Send for OnceCell {} impl RefUnwindSafe for OnceCell {} impl UnwindSafe for OnceCell {} impl OnceCell { pub(crate) const fn new() -> OnceCell { OnceCell { state: AtomicU8::new(INCOMPLETE), value: UnsafeCell::new(None) } } pub(crate) const fn with_value(value: T) -> OnceCell { OnceCell { state: AtomicU8::new(COMPLETE), value: UnsafeCell::new(Some(value)) } } /// Safety: synchronizes with store to value via Release/Acquire. #[inline] pub(crate) fn is_initialized(&self) -> bool { self.state.load(Ordering::Acquire) == COMPLETE } /// Safety: synchronizes with store to value via `is_initialized` or mutex /// lock/unlock, writes value only once because of the mutex. #[cold] pub(crate) fn initialize(&self, f: F) -> Result<(), E> where F: FnOnce() -> Result, { let mut f = Some(f); let mut res: Result<(), E> = Ok(()); let slot: *mut Option = self.value.get(); initialize_inner(&self.state, &mut || { // We are calling user-supplied function and need to be careful. // - if it returns Err, we unlock mutex and return without touching anything // - if it panics, we unlock mutex and propagate panic without touching anything // - if it calls `set` or `get_or_try_init` re-entrantly, we get a deadlock on // mutex, which is important for safety. We *could* detect this and panic, // but that is more complicated // - finally, if it returns Ok, we store the value and store the flag with // `Release`, which synchronizes with `Acquire`s. let f = unsafe { f.take().unwrap_unchecked() }; match f() { Ok(value) => unsafe { // Safe b/c we have a unique access and no panic may happen // until the cell is marked as initialized. debug_assert!((*slot).is_none()); *slot = Some(value); true }, Err(err) => { res = Err(err); false } } }); res } #[cold] pub(crate) fn wait(&self) { let key = &self.state as *const _ as usize; unsafe { parking_lot_core::park( key, || self.state.load(Ordering::Acquire) != COMPLETE, || (), |_, _| (), parking_lot_core::DEFAULT_PARK_TOKEN, None, ); } } /// Get the reference to the underlying value, without checking if the cell /// is initialized. /// /// # Safety /// /// Caller must ensure that the cell is in initialized state, and that /// the contents are acquired by (synchronized to) this thread. pub(crate) unsafe fn get_unchecked(&self) -> &T { debug_assert!(self.is_initialized()); let slot = &*self.value.get(); slot.as_ref().unwrap_unchecked() } /// Gets the mutable reference to the underlying value. /// Returns `None` if the cell is empty. pub(crate) fn get_mut(&mut self) -> Option<&mut T> { // Safe b/c we have an exclusive access let slot: &mut Option = unsafe { &mut *self.value.get() }; slot.as_mut() } /// Consumes this `OnceCell`, returning the wrapped value. /// Returns `None` if the cell was empty. pub(crate) fn into_inner(self) -> Option { self.value.into_inner() } } struct Guard<'a> { state: &'a AtomicU8, new_state: u8, } impl<'a> Drop for Guard<'a> { fn drop(&mut self) { self.state.store(self.new_state, Ordering::Release); unsafe { let key = self.state as *const AtomicU8 as usize; parking_lot_core::unpark_all(key, parking_lot_core::DEFAULT_UNPARK_TOKEN); } } } // Note: this is intentionally monomorphic #[inline(never)] fn initialize_inner(state: &AtomicU8, init: &mut dyn FnMut() -> bool) { loop { let exchange = state.compare_exchange_weak(INCOMPLETE, RUNNING, Ordering::Acquire, Ordering::Acquire); match exchange { Ok(_) => { let mut guard = Guard { state, new_state: INCOMPLETE }; if init() { guard.new_state = COMPLETE; } return; } Err(COMPLETE) => return, Err(RUNNING) => unsafe { let key = state as *const AtomicU8 as usize; parking_lot_core::park( key, || state.load(Ordering::Relaxed) == RUNNING, || (), |_, _| (), parking_lot_core::DEFAULT_PARK_TOKEN, None, ); }, Err(INCOMPLETE) => (), Err(_) => debug_assert!(false), } } } #[test] fn test_size() { use std::mem::size_of; assert_eq!(size_of::>(), 1 * size_of::() + size_of::()); } once_cell-1.20.2/src/imp_std.rs000064400000000000000000000307071046102023000144340ustar 00000000000000// There's a lot of scary concurrent code in this module, but it is copied from // `std::sync::Once` with two changes: // * no poisoning // * init function can fail use std::{ cell::{Cell, UnsafeCell}, panic::{RefUnwindSafe, UnwindSafe}, sync::atomic::{AtomicBool, AtomicPtr, Ordering}, thread::{self, Thread}, }; #[derive(Debug)] pub(crate) struct OnceCell { // This `queue` field is the core of the implementation. It encodes two // pieces of information: // // * The current state of the cell (`INCOMPLETE`, `RUNNING`, `COMPLETE`) // * Linked list of threads waiting for the current cell. // // State is encoded in two low bits. Only `INCOMPLETE` and `RUNNING` states // allow waiters. queue: AtomicPtr, value: UnsafeCell>, } // Why do we need `T: Send`? // Thread A creates a `OnceCell` and shares it with // scoped thread B, which fills the cell, which is // then destroyed by A. That is, destructor observes // a sent value. unsafe impl Sync for OnceCell {} unsafe impl Send for OnceCell {} impl RefUnwindSafe for OnceCell {} impl UnwindSafe for OnceCell {} impl OnceCell { pub(crate) const fn new() -> OnceCell { OnceCell { queue: AtomicPtr::new(INCOMPLETE_PTR), value: UnsafeCell::new(None) } } pub(crate) const fn with_value(value: T) -> OnceCell { OnceCell { queue: AtomicPtr::new(COMPLETE_PTR), value: UnsafeCell::new(Some(value)) } } /// Safety: synchronizes with store to value via Release/(Acquire|SeqCst). #[inline] pub(crate) fn is_initialized(&self) -> bool { // An `Acquire` load is enough because that makes all the initialization // operations visible to us, and, this being a fast path, weaker // ordering helps with performance. This `Acquire` synchronizes with // `SeqCst` operations on the slow path. self.queue.load(Ordering::Acquire) == COMPLETE_PTR } /// Safety: synchronizes with store to value via SeqCst read from state, /// writes value only once because we never get to INCOMPLETE state after a /// successful write. #[cold] pub(crate) fn initialize(&self, f: F) -> Result<(), E> where F: FnOnce() -> Result, { let mut f = Some(f); let mut res: Result<(), E> = Ok(()); let slot: *mut Option = self.value.get(); initialize_or_wait( &self.queue, Some(&mut || { let f = unsafe { f.take().unwrap_unchecked() }; match f() { Ok(value) => { unsafe { *slot = Some(value) }; true } Err(err) => { res = Err(err); false } } }), ); res } #[cold] pub(crate) fn wait(&self) { initialize_or_wait(&self.queue, None); } /// Get the reference to the underlying value, without checking if the cell /// is initialized. /// /// # Safety /// /// Caller must ensure that the cell is in initialized state, and that /// the contents are acquired by (synchronized to) this thread. pub(crate) unsafe fn get_unchecked(&self) -> &T { debug_assert!(self.is_initialized()); let slot = &*self.value.get(); slot.as_ref().unwrap_unchecked() } /// Gets the mutable reference to the underlying value. /// Returns `None` if the cell is empty. pub(crate) fn get_mut(&mut self) -> Option<&mut T> { // Safe b/c we have a unique access. unsafe { &mut *self.value.get() }.as_mut() } /// Consumes this `OnceCell`, returning the wrapped value. /// Returns `None` if the cell was empty. #[inline] pub(crate) fn into_inner(self) -> Option { // Because `into_inner` takes `self` by value, the compiler statically // verifies that it is not currently borrowed. // So, it is safe to move out `Option`. self.value.into_inner() } } // Three states that a OnceCell can be in, encoded into the lower bits of `queue` in // the OnceCell structure. const INCOMPLETE: usize = 0x0; const RUNNING: usize = 0x1; const COMPLETE: usize = 0x2; const INCOMPLETE_PTR: *mut Waiter = INCOMPLETE as *mut Waiter; const COMPLETE_PTR: *mut Waiter = COMPLETE as *mut Waiter; // Mask to learn about the state. All other bits are the queue of waiters if // this is in the RUNNING state. const STATE_MASK: usize = 0x3; /// Representation of a node in the linked list of waiters in the RUNNING state. /// A waiters is stored on the stack of the waiting threads. #[repr(align(4))] // Ensure the two lower bits are free to use as state bits. struct Waiter { thread: Cell>, signaled: AtomicBool, next: *mut Waiter, } /// Drains and notifies the queue of waiters on drop. struct Guard<'a> { queue: &'a AtomicPtr, new_queue: *mut Waiter, } impl Drop for Guard<'_> { fn drop(&mut self) { let queue = self.queue.swap(self.new_queue, Ordering::AcqRel); let state = strict::addr(queue) & STATE_MASK; assert_eq!(state, RUNNING); unsafe { let mut waiter = strict::map_addr(queue, |q| q & !STATE_MASK); while !waiter.is_null() { let next = (*waiter).next; let thread = (*waiter).thread.take().unwrap(); (*waiter).signaled.store(true, Ordering::Release); waiter = next; thread.unpark(); } } } } // Corresponds to `std::sync::Once::call_inner`. // // Originally copied from std, but since modified to remove poisoning and to // support wait. // // Note: this is intentionally monomorphic #[inline(never)] fn initialize_or_wait(queue: &AtomicPtr, mut init: Option<&mut dyn FnMut() -> bool>) { let mut curr_queue = queue.load(Ordering::Acquire); loop { let curr_state = strict::addr(curr_queue) & STATE_MASK; match (curr_state, &mut init) { (COMPLETE, _) => return, (INCOMPLETE, Some(init)) => { let exchange = queue.compare_exchange( curr_queue, strict::map_addr(curr_queue, |q| (q & !STATE_MASK) | RUNNING), Ordering::Acquire, Ordering::Acquire, ); if let Err(new_queue) = exchange { curr_queue = new_queue; continue; } let mut guard = Guard { queue, new_queue: INCOMPLETE_PTR }; if init() { guard.new_queue = COMPLETE_PTR; } return; } (INCOMPLETE, None) | (RUNNING, _) => { wait(queue, curr_queue); curr_queue = queue.load(Ordering::Acquire); } _ => debug_assert!(false), } } } fn wait(queue: &AtomicPtr, mut curr_queue: *mut Waiter) { let curr_state = strict::addr(curr_queue) & STATE_MASK; loop { let node = Waiter { thread: Cell::new(Some(thread::current())), signaled: AtomicBool::new(false), next: strict::map_addr(curr_queue, |q| q & !STATE_MASK), }; let me = &node as *const Waiter as *mut Waiter; let exchange = queue.compare_exchange( curr_queue, strict::map_addr(me, |q| q | curr_state), Ordering::Release, Ordering::Relaxed, ); if let Err(new_queue) = exchange { if strict::addr(new_queue) & STATE_MASK != curr_state { return; } curr_queue = new_queue; continue; } while !node.signaled.load(Ordering::Acquire) { thread::park(); } break; } } // Polyfill of strict provenance from https://crates.io/crates/sptr. // // Use free-standing function rather than a trait to keep things simple and // avoid any potential conflicts with future stabile std API. mod strict { #[must_use] #[inline] pub(crate) fn addr(ptr: *mut T) -> usize where T: Sized, { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the // provenance). unsafe { core::mem::transmute(ptr) } } #[must_use] #[inline] pub(crate) fn with_addr(ptr: *mut T, addr: usize) -> *mut T where T: Sized, { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. // // In the mean-time, this operation is defined to be "as if" it was // a wrapping_offset, so we can emulate it as such. This should properly // restore pointer provenance even under today's compiler. let self_addr = self::addr(ptr) as isize; let dest_addr = addr as isize; let offset = dest_addr.wrapping_sub(self_addr); // This is the canonical desugarring of this operation, // but `pointer::cast` was only stabilized in 1.38. // self.cast::().wrapping_offset(offset).cast::() (ptr as *mut u8).wrapping_offset(offset) as *mut T } #[must_use] #[inline] pub(crate) fn map_addr(ptr: *mut T, f: impl FnOnce(usize) -> usize) -> *mut T where T: Sized, { self::with_addr(ptr, f(addr(ptr))) } } // These test are snatched from std as well. #[cfg(test)] mod tests { use std::panic; use std::{sync::mpsc::channel, thread}; use super::OnceCell; impl OnceCell { fn init(&self, f: impl FnOnce() -> T) { enum Void {} let _ = self.initialize(|| Ok::(f())); } } #[test] fn smoke_once() { static O: OnceCell<()> = OnceCell::new(); let mut a = 0; O.init(|| a += 1); assert_eq!(a, 1); O.init(|| a += 1); assert_eq!(a, 1); } #[test] fn stampede_once() { static O: OnceCell<()> = OnceCell::new(); static mut RUN: bool = false; let (tx, rx) = channel(); for _ in 0..10 { let tx = tx.clone(); thread::spawn(move || { for _ in 0..4 { thread::yield_now() } unsafe { O.init(|| { assert!(!RUN); RUN = true; }); assert!(RUN); } tx.send(()).unwrap(); }); } unsafe { O.init(|| { assert!(!RUN); RUN = true; }); assert!(RUN); } for _ in 0..10 { rx.recv().unwrap(); } } #[test] fn poison_bad() { static O: OnceCell<()> = OnceCell::new(); // poison the once let t = panic::catch_unwind(|| { O.init(|| panic!()); }); assert!(t.is_err()); // we can subvert poisoning, however let mut called = false; O.init(|| { called = true; }); assert!(called); // once any success happens, we stop propagating the poison O.init(|| {}); } #[test] fn wait_for_force_to_finish() { static O: OnceCell<()> = OnceCell::new(); // poison the once let t = panic::catch_unwind(|| { O.init(|| panic!()); }); assert!(t.is_err()); // make sure someone's waiting inside the once via a force let (tx1, rx1) = channel(); let (tx2, rx2) = channel(); let t1 = thread::spawn(move || { O.init(|| { tx1.send(()).unwrap(); rx2.recv().unwrap(); }); }); rx1.recv().unwrap(); // put another waiter on the once let t2 = thread::spawn(|| { let mut called = false; O.init(|| { called = true; }); assert!(!called); }); tx2.send(()).unwrap(); assert!(t1.join().is_ok()); assert!(t2.join().is_ok()); } #[test] #[cfg(target_pointer_width = "64")] fn test_size() { use std::mem::size_of; assert_eq!(size_of::>(), 4 * size_of::()); } } once_cell-1.20.2/src/lib.rs000064400000000000000000001335451046102023000135470ustar 00000000000000//! # Overview //! //! `once_cell` provides two new cell-like types, [`unsync::OnceCell`] and //! [`sync::OnceCell`]. A `OnceCell` might store arbitrary non-`Copy` types, can //! be assigned to at most once and provides direct access to the stored //! contents. The core API looks *roughly* like this (and there's much more //! inside, read on!): //! //! ```rust,ignore //! impl OnceCell { //! const fn new() -> OnceCell { ... } //! fn set(&self, value: T) -> Result<(), T> { ... } //! fn get(&self) -> Option<&T> { ... } //! } //! ``` //! //! Note that, like with [`RefCell`] and [`Mutex`], the `set` method requires //! only a shared reference. Because of the single assignment restriction `get` //! can return a `&T` instead of `Ref` or `MutexGuard`. //! //! The `sync` flavor is thread-safe (that is, implements the [`Sync`] trait), //! while the `unsync` one is not. //! //! [`unsync::OnceCell`]: unsync/struct.OnceCell.html //! [`sync::OnceCell`]: sync/struct.OnceCell.html //! [`RefCell`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html //! [`Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html //! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html //! //! # Recipes //! //! `OnceCell` might be useful for a variety of patterns. //! //! ## Safe Initialization of Global Data //! //! ```rust //! use std::{env, io}; //! //! use once_cell::sync::OnceCell; //! //! #[derive(Debug)] //! pub struct Logger { //! // ... //! } //! static INSTANCE: OnceCell = OnceCell::new(); //! //! impl Logger { //! pub fn global() -> &'static Logger { //! INSTANCE.get().expect("logger is not initialized") //! } //! //! fn from_cli(args: env::Args) -> Result { //! // ... //! # Ok(Logger {}) //! } //! } //! //! fn main() { //! let logger = Logger::from_cli(env::args()).unwrap(); //! INSTANCE.set(logger).unwrap(); //! // use `Logger::global()` from now on //! } //! ``` //! //! ## Lazy Initialized Global Data //! //! This is essentially the `lazy_static!` macro, but without a macro. //! //! ```rust //! use std::{sync::Mutex, collections::HashMap}; //! //! use once_cell::sync::OnceCell; //! //! fn global_data() -> &'static Mutex> { //! static INSTANCE: OnceCell>> = OnceCell::new(); //! INSTANCE.get_or_init(|| { //! let mut m = HashMap::new(); //! m.insert(13, "Spica".to_string()); //! m.insert(74, "Hoyten".to_string()); //! Mutex::new(m) //! }) //! } //! ``` //! //! There are also the [`sync::Lazy`] and [`unsync::Lazy`] convenience types to //! streamline this pattern: //! //! ```rust //! use std::{sync::Mutex, collections::HashMap}; //! use once_cell::sync::Lazy; //! //! static GLOBAL_DATA: Lazy>> = Lazy::new(|| { //! let mut m = HashMap::new(); //! m.insert(13, "Spica".to_string()); //! m.insert(74, "Hoyten".to_string()); //! Mutex::new(m) //! }); //! //! fn main() { //! println!("{:?}", GLOBAL_DATA.lock().unwrap()); //! } //! ``` //! //! Note that the variable that holds `Lazy` is declared as `static`, *not* //! `const`. This is important: using `const` instead compiles, but works wrong. //! //! [`sync::Lazy`]: sync/struct.Lazy.html //! [`unsync::Lazy`]: unsync/struct.Lazy.html //! //! ## General purpose lazy evaluation //! //! Unlike `lazy_static!`, `Lazy` works with local variables. //! //! ```rust //! use once_cell::unsync::Lazy; //! //! fn main() { //! let ctx = vec![1, 2, 3]; //! let thunk = Lazy::new(|| { //! ctx.iter().sum::() //! }); //! assert_eq!(*thunk, 6); //! } //! ``` //! //! If you need a lazy field in a struct, you probably should use `OnceCell` //! directly, because that will allow you to access `self` during //! initialization. //! //! ```rust //! use std::{fs, path::PathBuf}; //! //! use once_cell::unsync::OnceCell; //! //! struct Ctx { //! config_path: PathBuf, //! config: OnceCell, //! } //! //! impl Ctx { //! pub fn get_config(&self) -> Result<&str, std::io::Error> { //! let cfg = self.config.get_or_try_init(|| { //! fs::read_to_string(&self.config_path) //! })?; //! Ok(cfg.as_str()) //! } //! } //! ``` //! //! ## Lazily Compiled Regex //! //! This is a `regex!` macro which takes a string literal and returns an //! *expression* that evaluates to a `&'static Regex`: //! //! ``` //! macro_rules! regex { //! ($re:literal $(,)?) => {{ //! static RE: once_cell::sync::OnceCell = once_cell::sync::OnceCell::new(); //! RE.get_or_init(|| regex::Regex::new($re).unwrap()) //! }}; //! } //! ``` //! //! This macro can be useful to avoid the "compile regex on every loop //! iteration" problem. //! //! ## Runtime `include_bytes!` //! //! The `include_bytes` macro is useful to include test resources, but it slows //! down test compilation a lot. An alternative is to load the resources at //! runtime: //! //! ``` //! use std::path::Path; //! //! use once_cell::sync::OnceCell; //! //! pub struct TestResource { //! path: &'static str, //! cell: OnceCell>, //! } //! //! impl TestResource { //! pub const fn new(path: &'static str) -> TestResource { //! TestResource { path, cell: OnceCell::new() } //! } //! pub fn bytes(&self) -> &[u8] { //! self.cell.get_or_init(|| { //! let dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); //! let path = Path::new(dir.as_str()).join(self.path); //! std::fs::read(&path).unwrap_or_else(|_err| { //! panic!("failed to load test resource: {}", path.display()) //! }) //! }).as_slice() //! } //! } //! //! static TEST_IMAGE: TestResource = TestResource::new("test_data/lena.png"); //! //! #[test] //! fn test_sobel_filter() { //! let rgb: &[u8] = TEST_IMAGE.bytes(); //! // ... //! # drop(rgb); //! } //! ``` //! //! ## `lateinit` //! //! `LateInit` type for delayed initialization. It is reminiscent of Kotlin's //! `lateinit` keyword and allows construction of cyclic data structures: //! //! //! ``` //! use once_cell::sync::OnceCell; //! //! pub struct LateInit { cell: OnceCell } //! //! impl LateInit { //! pub fn init(&self, value: T) { //! assert!(self.cell.set(value).is_ok()) //! } //! } //! //! impl Default for LateInit { //! fn default() -> Self { LateInit { cell: OnceCell::default() } } //! } //! //! impl std::ops::Deref for LateInit { //! type Target = T; //! fn deref(&self) -> &T { //! self.cell.get().unwrap() //! } //! } //! //! #[derive(Default)] //! struct A<'a> { //! b: LateInit<&'a B<'a>>, //! } //! //! #[derive(Default)] //! struct B<'a> { //! a: LateInit<&'a A<'a>> //! } //! //! //! fn build_cycle() { //! let a = A::default(); //! let b = B::default(); //! a.b.init(&b); //! b.a.init(&a); //! //! let _a = &a.b.a.b.a; //! } //! ``` //! //! # Comparison with std //! //! |`!Sync` types | Access Mode | Drawbacks | //! |----------------------|------------------------|-----------------------------------------------| //! |`Cell` | `T` | requires `T: Copy` for `get` | //! |`RefCell` | `RefMut` / `Ref` | may panic at runtime | //! |`unsync::OnceCell` | `&T` | assignable only once | //! //! |`Sync` types | Access Mode | Drawbacks | //! |----------------------|------------------------|-----------------------------------------------| //! |`AtomicT` | `T` | works only with certain `Copy` types | //! |`Mutex` | `MutexGuard` | may deadlock at runtime, may block the thread | //! |`sync::OnceCell` | `&T` | assignable only once, may block the thread | //! //! Technically, calling `get_or_init` will also cause a panic or a deadlock if //! it recursively calls itself. However, because the assignment can happen only //! once, such cases should be more rare than equivalents with `RefCell` and //! `Mutex`. //! //! # Minimum Supported `rustc` Version //! //! If only the `std`, `alloc`, or `race` features are enabled, MSRV will be //! updated conservatively, supporting at least latest 8 versions of the compiler. //! When using other features, like `parking_lot`, MSRV might be updated more //! frequently, up to the latest stable. In both cases, increasing MSRV is *not* //! considered a semver-breaking change and requires only a minor version bump. //! //! # Implementation details //! //! The implementation is based on the //! [`lazy_static`](https://github.com/rust-lang-nursery/lazy-static.rs/) and //! [`lazy_cell`](https://github.com/indiv0/lazycell/) crates and //! [`std::sync::Once`]. In some sense, `once_cell` just streamlines and unifies //! those APIs. //! //! To implement a sync flavor of `OnceCell`, this crates uses either a custom //! re-implementation of `std::sync::Once` or `parking_lot::Mutex`. This is //! controlled by the `parking_lot` feature (disabled by default). Performance //! is the same for both cases, but the `parking_lot` based `OnceCell` is //! smaller by up to 16 bytes. //! //! This crate uses `unsafe`. //! //! [`std::sync::Once`]: https://doc.rust-lang.org/std/sync/struct.Once.html //! //! # F.A.Q. //! //! **Should I use the sync or unsync flavor?** //! //! Because Rust compiler checks thread safety for you, it's impossible to //! accidentally use `unsync` where `sync` is required. So, use `unsync` in //! single-threaded code and `sync` in multi-threaded. It's easy to switch //! between the two if code becomes multi-threaded later. //! //! At the moment, `unsync` has an additional benefit that reentrant //! initialization causes a panic, which might be easier to debug than a //! deadlock. //! //! **Does this crate support async?** //! //! No, but you can use //! [`async_once_cell`](https://crates.io/crates/async_once_cell) instead. //! //! **Does this crate support `no_std`?** //! //! Yes, but with caveats. `OnceCell` is a synchronization primitive which //! _semantically_ relies on blocking. `OnceCell` guarantees that at most one //! `f` will be called to compute the value. If two threads of execution call //! `get_or_init` concurrently, one of them has to wait. //! //! Waiting fundamentally requires OS support. Execution environment needs to //! understand who waits on whom to prevent deadlocks due to priority inversion. //! You _could_ make code to compile by blindly using pure spinlocks, but the //! runtime behavior would be subtly wrong. //! //! Given these constraints, `once_cell` provides the following options: //! //! - The `race` module provides similar, but distinct synchronization primitive //! which is compatible with `no_std`. With `race`, the `f` function can be //! called multiple times by different threads, but only one thread will win //! to install the value. //! - `critical-section` feature (with a `-`, not `_`) uses `critical_section` //! to implement blocking. //! //! **Can I bring my own mutex?** //! //! There is [generic_once_cell](https://crates.io/crates/generic_once_cell) to //! allow just that. //! //! **Should I use `std::cell::OnceCell`, `once_cell`, or `lazy_static`?** //! //! If you can use `std` version (your MSRV is at least 1.70, and you don't need //! extra features `once_cell` provides), use `std`. Otherwise, use `once_cell`. //! Don't use `lazy_static`. //! //! # Related crates //! //! * Most of this crate's functionality is available in `std` starting with //! Rust 1.70. See `std::cell::OnceCell` and `std::sync::OnceLock`. //! * [double-checked-cell](https://github.com/niklasf/double-checked-cell) //! * [lazy-init](https://crates.io/crates/lazy-init) //! * [lazycell](https://crates.io/crates/lazycell) //! * [mitochondria](https://crates.io/crates/mitochondria) //! * [lazy_static](https://crates.io/crates/lazy_static) //! * [async_once_cell](https://crates.io/crates/async_once_cell) //! * [generic_once_cell](https://crates.io/crates/generic_once_cell) (bring //! your own mutex) #![cfg_attr(not(feature = "std"), no_std)] #[cfg(feature = "alloc")] extern crate alloc; #[cfg(all(feature = "critical-section", not(feature = "std")))] #[path = "imp_cs.rs"] mod imp; #[cfg(all(feature = "std", feature = "parking_lot"))] #[path = "imp_pl.rs"] mod imp; #[cfg(all(feature = "std", not(feature = "parking_lot")))] #[path = "imp_std.rs"] mod imp; /// Single-threaded version of `OnceCell`. pub mod unsync { use core::{ cell::{Cell, UnsafeCell}, fmt, mem, ops::{Deref, DerefMut}, panic::{RefUnwindSafe, UnwindSafe}, }; /// A cell which can be written to only once. It is not thread safe. /// /// Unlike [`std::cell::RefCell`], a `OnceCell` provides simple `&` /// references to the contents. /// /// [`std::cell::RefCell`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html /// /// # Example /// ``` /// use once_cell::unsync::OnceCell; /// /// let cell = OnceCell::new(); /// assert!(cell.get().is_none()); /// /// let value: &String = cell.get_or_init(|| { /// "Hello, World!".to_string() /// }); /// assert_eq!(value, "Hello, World!"); /// assert!(cell.get().is_some()); /// ``` pub struct OnceCell { // Invariant: written to at most once. inner: UnsafeCell>, } // Similarly to a `Sync` bound on `sync::OnceCell`, we can use // `&unsync::OnceCell` to sneak a `T` through `catch_unwind`, // by initializing the cell in closure and extracting the value in the // `Drop`. impl RefUnwindSafe for OnceCell {} impl UnwindSafe for OnceCell {} impl Default for OnceCell { fn default() -> Self { Self::new() } } impl fmt::Debug for OnceCell { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.get() { Some(v) => f.debug_tuple("OnceCell").field(v).finish(), None => f.write_str("OnceCell(Uninit)"), } } } impl Clone for OnceCell { fn clone(&self) -> OnceCell { match self.get() { Some(value) => OnceCell::with_value(value.clone()), None => OnceCell::new(), } } fn clone_from(&mut self, source: &Self) { match (self.get_mut(), source.get()) { (Some(this), Some(source)) => this.clone_from(source), _ => *self = source.clone(), } } } impl PartialEq for OnceCell { fn eq(&self, other: &Self) -> bool { self.get() == other.get() } } impl Eq for OnceCell {} impl From for OnceCell { fn from(value: T) -> Self { OnceCell::with_value(value) } } impl OnceCell { /// Creates a new empty cell. pub const fn new() -> OnceCell { OnceCell { inner: UnsafeCell::new(None) } } /// Creates a new initialized cell. pub const fn with_value(value: T) -> OnceCell { OnceCell { inner: UnsafeCell::new(Some(value)) } } /// Gets a reference to the underlying value. /// /// Returns `None` if the cell is empty. #[inline] pub fn get(&self) -> Option<&T> { // Safe due to `inner`'s invariant of being written to at most once. // Had multiple writes to `inner` been allowed, a reference to the // value we return now would become dangling by a write of a // different value later. unsafe { &*self.inner.get() }.as_ref() } /// Gets a mutable reference to the underlying value. /// /// Returns `None` if the cell is empty. /// /// This method is allowed to violate the invariant of writing to a `OnceCell` /// at most once because it requires `&mut` access to `self`. As with all /// interior mutability, `&mut` access permits arbitrary modification: /// /// ``` /// use once_cell::unsync::OnceCell; /// /// let mut cell: OnceCell = OnceCell::new(); /// cell.set(92).unwrap(); /// *cell.get_mut().unwrap() = 93; /// assert_eq!(cell.get(), Some(&93)); /// ``` #[inline] pub fn get_mut(&mut self) -> Option<&mut T> { // Safe because we have unique access unsafe { &mut *self.inner.get() }.as_mut() } /// Sets the contents of this cell to `value`. /// /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was /// full. /// /// # Example /// ``` /// use once_cell::unsync::OnceCell; /// /// let cell = OnceCell::new(); /// assert!(cell.get().is_none()); /// /// assert_eq!(cell.set(92), Ok(())); /// assert_eq!(cell.set(62), Err(62)); /// /// assert!(cell.get().is_some()); /// ``` pub fn set(&self, value: T) -> Result<(), T> { match self.try_insert(value) { Ok(_) => Ok(()), Err((_, value)) => Err(value), } } /// Like [`set`](Self::set), but also returns a reference to the final cell value. /// /// # Example /// ``` /// use once_cell::unsync::OnceCell; /// /// let cell = OnceCell::new(); /// assert!(cell.get().is_none()); /// /// assert_eq!(cell.try_insert(92), Ok(&92)); /// assert_eq!(cell.try_insert(62), Err((&92, 62))); /// /// assert!(cell.get().is_some()); /// ``` pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> { if let Some(old) = self.get() { return Err((old, value)); } let slot = unsafe { &mut *self.inner.get() }; // This is the only place where we set the slot, no races // due to reentrancy/concurrency are possible, and we've // checked that slot is currently `None`, so this write // maintains the `inner`'s invariant. *slot = Some(value); Ok(unsafe { slot.as_ref().unwrap_unchecked() }) } /// Gets the contents of the cell, initializing it with `f` /// if the cell was empty. /// /// # Panics /// /// If `f` panics, the panic is propagated to the caller, and the cell /// remains uninitialized. /// /// It is an error to reentrantly initialize the cell from `f`. Doing /// so results in a panic. /// /// # Example /// ``` /// use once_cell::unsync::OnceCell; /// /// let cell = OnceCell::new(); /// let value = cell.get_or_init(|| 92); /// assert_eq!(value, &92); /// let value = cell.get_or_init(|| unreachable!()); /// assert_eq!(value, &92); /// ``` pub fn get_or_init(&self, f: F) -> &T where F: FnOnce() -> T, { enum Void {} match self.get_or_try_init(|| Ok::(f())) { Ok(val) => val, Err(void) => match void {}, } } /// Gets the contents of the cell, initializing it with `f` if /// the cell was empty. If the cell was empty and `f` failed, an /// error is returned. /// /// # Panics /// /// If `f` panics, the panic is propagated to the caller, and the cell /// remains uninitialized. /// /// It is an error to reentrantly initialize the cell from `f`. Doing /// so results in a panic. /// /// # Example /// ``` /// use once_cell::unsync::OnceCell; /// /// let cell = OnceCell::new(); /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); /// assert!(cell.get().is_none()); /// let value = cell.get_or_try_init(|| -> Result { /// Ok(92) /// }); /// assert_eq!(value, Ok(&92)); /// assert_eq!(cell.get(), Some(&92)) /// ``` pub fn get_or_try_init(&self, f: F) -> Result<&T, E> where F: FnOnce() -> Result, { if let Some(val) = self.get() { return Ok(val); } let val = f()?; // Note that *some* forms of reentrant initialization might lead to // UB (see `reentrant_init` test). I believe that just removing this // `assert`, while keeping `set/get` would be sound, but it seems // better to panic, rather than to silently use an old value. assert!(self.set(val).is_ok(), "reentrant init"); Ok(unsafe { self.get().unwrap_unchecked() }) } /// Takes the value out of this `OnceCell`, moving it back to an uninitialized state. /// /// Has no effect and returns `None` if the `OnceCell` hasn't been initialized. /// /// # Examples /// /// ``` /// use once_cell::unsync::OnceCell; /// /// let mut cell: OnceCell = OnceCell::new(); /// assert_eq!(cell.take(), None); /// /// let mut cell = OnceCell::new(); /// cell.set("hello".to_string()).unwrap(); /// assert_eq!(cell.take(), Some("hello".to_string())); /// assert_eq!(cell.get(), None); /// ``` /// /// This method is allowed to violate the invariant of writing to a `OnceCell` /// at most once because it requires `&mut` access to `self`. As with all /// interior mutability, `&mut` access permits arbitrary modification: /// /// ``` /// use once_cell::unsync::OnceCell; /// /// let mut cell: OnceCell = OnceCell::new(); /// cell.set(92).unwrap(); /// cell = OnceCell::new(); /// ``` pub fn take(&mut self) -> Option { mem::take(self).into_inner() } /// Consumes the `OnceCell`, returning the wrapped value. /// /// Returns `None` if the cell was empty. /// /// # Examples /// /// ``` /// use once_cell::unsync::OnceCell; /// /// let cell: OnceCell = OnceCell::new(); /// assert_eq!(cell.into_inner(), None); /// /// let cell = OnceCell::new(); /// cell.set("hello".to_string()).unwrap(); /// assert_eq!(cell.into_inner(), Some("hello".to_string())); /// ``` pub fn into_inner(self) -> Option { // Because `into_inner` takes `self` by value, the compiler statically verifies // that it is not currently borrowed. So it is safe to move out `Option`. self.inner.into_inner() } } /// A value which is initialized on the first access. /// /// # Example /// ``` /// use once_cell::unsync::Lazy; /// /// let lazy: Lazy = Lazy::new(|| { /// println!("initializing"); /// 92 /// }); /// println!("ready"); /// println!("{}", *lazy); /// println!("{}", *lazy); /// /// // Prints: /// // ready /// // initializing /// // 92 /// // 92 /// ``` pub struct Lazy T> { cell: OnceCell, init: Cell>, } impl RefUnwindSafe for Lazy where OnceCell: RefUnwindSafe {} impl fmt::Debug for Lazy { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() } } impl Lazy { /// Creates a new lazy value with the given initializing function. /// /// # Example /// ``` /// # fn main() { /// use once_cell::unsync::Lazy; /// /// let hello = "Hello, World!".to_string(); /// /// let lazy = Lazy::new(|| hello.to_uppercase()); /// /// assert_eq!(&*lazy, "HELLO, WORLD!"); /// # } /// ``` pub const fn new(init: F) -> Lazy { Lazy { cell: OnceCell::new(), init: Cell::new(Some(init)) } } /// Consumes this `Lazy` returning the stored value. /// /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise. pub fn into_value(this: Lazy) -> Result { let cell = this.cell; let init = this.init; cell.into_inner().ok_or_else(|| { init.take().unwrap_or_else(|| panic!("Lazy instance has previously been poisoned")) }) } } impl T> Lazy { /// Forces the evaluation of this lazy value and returns a reference to /// the result. /// /// This is equivalent to the `Deref` impl, but is explicit. /// /// # Example /// ``` /// use once_cell::unsync::Lazy; /// /// let lazy = Lazy::new(|| 92); /// /// assert_eq!(Lazy::force(&lazy), &92); /// assert_eq!(&*lazy, &92); /// ``` pub fn force(this: &Lazy) -> &T { this.cell.get_or_init(|| match this.init.take() { Some(f) => f(), None => panic!("Lazy instance has previously been poisoned"), }) } /// Forces the evaluation of this lazy value and returns a mutable reference to /// the result. /// /// This is equivalent to the `DerefMut` impl, but is explicit. /// /// # Example /// ``` /// use once_cell::unsync::Lazy; /// /// let mut lazy = Lazy::new(|| 92); /// /// assert_eq!(Lazy::force_mut(&mut lazy), &92); /// assert_eq!(*lazy, 92); /// ``` pub fn force_mut(this: &mut Lazy) -> &mut T { if this.cell.get_mut().is_none() { let value = match this.init.get_mut().take() { Some(f) => f(), None => panic!("Lazy instance has previously been poisoned"), }; this.cell = OnceCell::with_value(value); } this.cell.get_mut().unwrap_or_else(|| unreachable!()) } /// Gets the reference to the result of this lazy value if /// it was initialized, otherwise returns `None`. /// /// # Example /// ``` /// use once_cell::unsync::Lazy; /// /// let lazy = Lazy::new(|| 92); /// /// assert_eq!(Lazy::get(&lazy), None); /// assert_eq!(&*lazy, &92); /// assert_eq!(Lazy::get(&lazy), Some(&92)); /// ``` pub fn get(this: &Lazy) -> Option<&T> { this.cell.get() } /// Gets the mutable reference to the result of this lazy value if /// it was initialized, otherwise returns `None`. /// /// # Example /// ``` /// use once_cell::unsync::Lazy; /// /// let mut lazy = Lazy::new(|| 92); /// /// assert_eq!(Lazy::get_mut(&mut lazy), None); /// assert_eq!(*lazy, 92); /// assert_eq!(Lazy::get_mut(&mut lazy), Some(&mut 92)); /// ``` pub fn get_mut(this: &mut Lazy) -> Option<&mut T> { this.cell.get_mut() } } impl T> Deref for Lazy { type Target = T; fn deref(&self) -> &T { Lazy::force(self) } } impl T> DerefMut for Lazy { fn deref_mut(&mut self) -> &mut T { Lazy::force_mut(self) } } impl Default for Lazy { /// Creates a new lazy value using `Default` as the initializing function. fn default() -> Lazy { Lazy::new(T::default) } } } /// Thread-safe, blocking version of `OnceCell`. #[cfg(any(feature = "std", feature = "critical-section"))] pub mod sync { use core::{ cell::Cell, fmt, mem, ops::{Deref, DerefMut}, panic::RefUnwindSafe, }; use super::imp::OnceCell as Imp; /// A thread-safe cell which can be written to only once. /// /// `OnceCell` provides `&` references to the contents without RAII guards. /// /// Reading a non-`None` value out of `OnceCell` establishes a /// happens-before relationship with a corresponding write. For example, if /// thread A initializes the cell with `get_or_init(f)`, and thread B /// subsequently reads the result of this call, B also observes all the side /// effects of `f`. /// /// # Example /// ``` /// use once_cell::sync::OnceCell; /// /// static CELL: OnceCell = OnceCell::new(); /// assert!(CELL.get().is_none()); /// /// std::thread::spawn(|| { /// let value: &String = CELL.get_or_init(|| { /// "Hello, World!".to_string() /// }); /// assert_eq!(value, "Hello, World!"); /// }).join().unwrap(); /// /// let value: Option<&String> = CELL.get(); /// assert!(value.is_some()); /// assert_eq!(value.unwrap().as_str(), "Hello, World!"); /// ``` pub struct OnceCell(Imp); impl Default for OnceCell { fn default() -> OnceCell { OnceCell::new() } } impl fmt::Debug for OnceCell { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.get() { Some(v) => f.debug_tuple("OnceCell").field(v).finish(), None => f.write_str("OnceCell(Uninit)"), } } } impl Clone for OnceCell { fn clone(&self) -> OnceCell { match self.get() { Some(value) => Self::with_value(value.clone()), None => Self::new(), } } fn clone_from(&mut self, source: &Self) { match (self.get_mut(), source.get()) { (Some(this), Some(source)) => this.clone_from(source), _ => *self = source.clone(), } } } impl From for OnceCell { fn from(value: T) -> Self { Self::with_value(value) } } impl PartialEq for OnceCell { fn eq(&self, other: &OnceCell) -> bool { self.get() == other.get() } } impl Eq for OnceCell {} impl OnceCell { /// Creates a new empty cell. pub const fn new() -> OnceCell { OnceCell(Imp::new()) } /// Creates a new initialized cell. pub const fn with_value(value: T) -> OnceCell { OnceCell(Imp::with_value(value)) } /// Gets the reference to the underlying value. /// /// Returns `None` if the cell is empty, or being initialized. This /// method never blocks. pub fn get(&self) -> Option<&T> { if self.0.is_initialized() { // Safe b/c value is initialized. Some(unsafe { self.get_unchecked() }) } else { None } } /// Gets the reference to the underlying value, blocking the current /// thread until it is set. /// /// ``` /// use once_cell::sync::OnceCell; /// /// let mut cell = std::sync::Arc::new(OnceCell::new()); /// let t = std::thread::spawn({ /// let cell = std::sync::Arc::clone(&cell); /// move || cell.set(92).unwrap() /// }); /// /// // Returns immediately, but might return None. /// let _value_or_none = cell.get(); /// /// // Will return 92, but might block until the other thread does `.set`. /// let value: &u32 = cell.wait(); /// assert_eq!(*value, 92); /// t.join().unwrap(); /// ``` #[cfg(feature = "std")] pub fn wait(&self) -> &T { if !self.0.is_initialized() { self.0.wait() } debug_assert!(self.0.is_initialized()); // Safe b/c of the wait call above and the fact that we didn't // relinquish our borrow. unsafe { self.get_unchecked() } } /// Gets the mutable reference to the underlying value. /// /// Returns `None` if the cell is empty. /// /// This method is allowed to violate the invariant of writing to a `OnceCell` /// at most once because it requires `&mut` access to `self`. As with all /// interior mutability, `&mut` access permits arbitrary modification: /// /// ``` /// use once_cell::sync::OnceCell; /// /// let mut cell: OnceCell = OnceCell::new(); /// cell.set(92).unwrap(); /// cell = OnceCell::new(); /// ``` #[inline] pub fn get_mut(&mut self) -> Option<&mut T> { self.0.get_mut() } /// Get the reference to the underlying value, without checking if the /// cell is initialized. /// /// # Safety /// /// Caller must ensure that the cell is in initialized state, and that /// the contents are acquired by (synchronized to) this thread. #[inline] pub unsafe fn get_unchecked(&self) -> &T { self.0.get_unchecked() } /// Sets the contents of this cell to `value`. /// /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was /// full. /// /// # Example /// /// ``` /// use once_cell::sync::OnceCell; /// /// static CELL: OnceCell = OnceCell::new(); /// /// fn main() { /// assert!(CELL.get().is_none()); /// /// std::thread::spawn(|| { /// assert_eq!(CELL.set(92), Ok(())); /// }).join().unwrap(); /// /// assert_eq!(CELL.set(62), Err(62)); /// assert_eq!(CELL.get(), Some(&92)); /// } /// ``` pub fn set(&self, value: T) -> Result<(), T> { match self.try_insert(value) { Ok(_) => Ok(()), Err((_, value)) => Err(value), } } /// Like [`set`](Self::set), but also returns a reference to the final cell value. /// /// # Example /// /// ``` /// use once_cell::unsync::OnceCell; /// /// let cell = OnceCell::new(); /// assert!(cell.get().is_none()); /// /// assert_eq!(cell.try_insert(92), Ok(&92)); /// assert_eq!(cell.try_insert(62), Err((&92, 62))); /// /// assert!(cell.get().is_some()); /// ``` pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> { let mut value = Some(value); let res = self.get_or_init(|| unsafe { value.take().unwrap_unchecked() }); match value { None => Ok(res), Some(value) => Err((res, value)), } } /// Gets the contents of the cell, initializing it with `f` if the cell /// was empty. /// /// Many threads may call `get_or_init` concurrently with different /// initializing functions, but it is guaranteed that only one function /// will be executed. /// /// # Panics /// /// If `f` panics, the panic is propagated to the caller, and the cell /// remains uninitialized. /// /// It is an error to reentrantly initialize the cell from `f`. The /// exact outcome is unspecified. Current implementation deadlocks, but /// this may be changed to a panic in the future. /// /// # Example /// ``` /// use once_cell::sync::OnceCell; /// /// let cell = OnceCell::new(); /// let value = cell.get_or_init(|| 92); /// assert_eq!(value, &92); /// let value = cell.get_or_init(|| unreachable!()); /// assert_eq!(value, &92); /// ``` pub fn get_or_init(&self, f: F) -> &T where F: FnOnce() -> T, { enum Void {} match self.get_or_try_init(|| Ok::(f())) { Ok(val) => val, Err(void) => match void {}, } } /// Gets the contents of the cell, initializing it with `f` if /// the cell was empty. If the cell was empty and `f` failed, an /// error is returned. /// /// # Panics /// /// If `f` panics, the panic is propagated to the caller, and /// the cell remains uninitialized. /// /// It is an error to reentrantly initialize the cell from `f`. /// The exact outcome is unspecified. Current implementation /// deadlocks, but this may be changed to a panic in the future. /// /// # Example /// ``` /// use once_cell::sync::OnceCell; /// /// let cell = OnceCell::new(); /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); /// assert!(cell.get().is_none()); /// let value = cell.get_or_try_init(|| -> Result { /// Ok(92) /// }); /// assert_eq!(value, Ok(&92)); /// assert_eq!(cell.get(), Some(&92)) /// ``` pub fn get_or_try_init(&self, f: F) -> Result<&T, E> where F: FnOnce() -> Result, { // Fast path check if let Some(value) = self.get() { return Ok(value); } self.0.initialize(f)?; // Safe b/c value is initialized. debug_assert!(self.0.is_initialized()); Ok(unsafe { self.get_unchecked() }) } /// Takes the value out of this `OnceCell`, moving it back to an uninitialized state. /// /// Has no effect and returns `None` if the `OnceCell` hasn't been initialized. /// /// # Examples /// /// ``` /// use once_cell::sync::OnceCell; /// /// let mut cell: OnceCell = OnceCell::new(); /// assert_eq!(cell.take(), None); /// /// let mut cell = OnceCell::new(); /// cell.set("hello".to_string()).unwrap(); /// assert_eq!(cell.take(), Some("hello".to_string())); /// assert_eq!(cell.get(), None); /// ``` /// /// This method is allowed to violate the invariant of writing to a `OnceCell` /// at most once because it requires `&mut` access to `self`. As with all /// interior mutability, `&mut` access permits arbitrary modification: /// /// ``` /// use once_cell::sync::OnceCell; /// /// let mut cell: OnceCell = OnceCell::new(); /// cell.set(92).unwrap(); /// cell = OnceCell::new(); /// ``` pub fn take(&mut self) -> Option { mem::take(self).into_inner() } /// Consumes the `OnceCell`, returning the wrapped value. Returns /// `None` if the cell was empty. /// /// # Examples /// /// ``` /// use once_cell::sync::OnceCell; /// /// let cell: OnceCell = OnceCell::new(); /// assert_eq!(cell.into_inner(), None); /// /// let cell = OnceCell::new(); /// cell.set("hello".to_string()).unwrap(); /// assert_eq!(cell.into_inner(), Some("hello".to_string())); /// ``` #[inline] pub fn into_inner(self) -> Option { self.0.into_inner() } } /// A value which is initialized on the first access. /// /// This type is thread-safe and can be used in statics. /// /// # Example /// /// ``` /// use std::collections::HashMap; /// /// use once_cell::sync::Lazy; /// /// static HASHMAP: Lazy> = Lazy::new(|| { /// println!("initializing"); /// let mut m = HashMap::new(); /// m.insert(13, "Spica".to_string()); /// m.insert(74, "Hoyten".to_string()); /// m /// }); /// /// fn main() { /// println!("ready"); /// std::thread::spawn(|| { /// println!("{:?}", HASHMAP.get(&13)); /// }).join().unwrap(); /// println!("{:?}", HASHMAP.get(&74)); /// /// // Prints: /// // ready /// // initializing /// // Some("Spica") /// // Some("Hoyten") /// } /// ``` pub struct Lazy T> { cell: OnceCell, init: Cell>, } impl fmt::Debug for Lazy { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() } } // We never create a `&F` from a `&Lazy` so it is fine to not impl // `Sync` for `F`. We do create a `&mut Option` in `force`, but this is // properly synchronized, so it only happens once so it also does not // contribute to this impl. unsafe impl Sync for Lazy where OnceCell: Sync {} // auto-derived `Send` impl is OK. impl RefUnwindSafe for Lazy where OnceCell: RefUnwindSafe {} impl Lazy { /// Creates a new lazy value with the given initializing /// function. pub const fn new(f: F) -> Lazy { Lazy { cell: OnceCell::new(), init: Cell::new(Some(f)) } } /// Consumes this `Lazy` returning the stored value. /// /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise. pub fn into_value(this: Lazy) -> Result { let cell = this.cell; let init = this.init; cell.into_inner().ok_or_else(|| { init.take().unwrap_or_else(|| panic!("Lazy instance has previously been poisoned")) }) } } impl T> Lazy { /// Forces the evaluation of this lazy value and /// returns a reference to the result. This is equivalent /// to the `Deref` impl, but is explicit. /// /// # Example /// ``` /// use once_cell::sync::Lazy; /// /// let lazy = Lazy::new(|| 92); /// /// assert_eq!(Lazy::force(&lazy), &92); /// assert_eq!(&*lazy, &92); /// ``` pub fn force(this: &Lazy) -> &T { this.cell.get_or_init(|| match this.init.take() { Some(f) => f(), None => panic!("Lazy instance has previously been poisoned"), }) } /// Forces the evaluation of this lazy value and /// returns a mutable reference to the result. This is equivalent /// to the `Deref` impl, but is explicit. /// /// # Example /// ``` /// use once_cell::sync::Lazy; /// /// let mut lazy = Lazy::new(|| 92); /// /// assert_eq!(Lazy::force_mut(&mut lazy), &mut 92); /// ``` pub fn force_mut(this: &mut Lazy) -> &mut T { if this.cell.get_mut().is_none() { let value = match this.init.get_mut().take() { Some(f) => f(), None => panic!("Lazy instance has previously been poisoned"), }; this.cell = OnceCell::with_value(value); } this.cell.get_mut().unwrap_or_else(|| unreachable!()) } /// Gets the reference to the result of this lazy value if /// it was initialized, otherwise returns `None`. /// /// # Example /// ``` /// use once_cell::sync::Lazy; /// /// let lazy = Lazy::new(|| 92); /// /// assert_eq!(Lazy::get(&lazy), None); /// assert_eq!(&*lazy, &92); /// assert_eq!(Lazy::get(&lazy), Some(&92)); /// ``` pub fn get(this: &Lazy) -> Option<&T> { this.cell.get() } /// Gets the reference to the result of this lazy value if /// it was initialized, otherwise returns `None`. /// /// # Example /// ``` /// use once_cell::sync::Lazy; /// /// let mut lazy = Lazy::new(|| 92); /// /// assert_eq!(Lazy::get_mut(&mut lazy), None); /// assert_eq!(&*lazy, &92); /// assert_eq!(Lazy::get_mut(&mut lazy), Some(&mut 92)); /// ``` pub fn get_mut(this: &mut Lazy) -> Option<&mut T> { this.cell.get_mut() } } impl T> Deref for Lazy { type Target = T; fn deref(&self) -> &T { Lazy::force(self) } } impl T> DerefMut for Lazy { fn deref_mut(&mut self) -> &mut T { Lazy::force_mut(self) } } impl Default for Lazy { /// Creates a new lazy value using `Default` as the initializing function. fn default() -> Lazy { Lazy::new(T::default) } } /// ```compile_fail /// struct S(*mut ()); /// unsafe impl Sync for S {} /// /// fn share(_: &T) {} /// share(&once_cell::sync::OnceCell::::new()); /// ``` /// /// ```compile_fail /// struct S(*mut ()); /// unsafe impl Sync for S {} /// /// fn share(_: &T) {} /// share(&once_cell::sync::Lazy::::new(|| unimplemented!())); /// ``` fn _dummy() {} } #[cfg(feature = "race")] pub mod race; once_cell-1.20.2/src/race.rs000064400000000000000000000317351046102023000137110ustar 00000000000000//! Thread-safe, non-blocking, "first one wins" flavor of `OnceCell`. //! //! If two threads race to initialize a type from the `race` module, they //! don't block, execute initialization function together, but only one of //! them stores the result. //! //! This module does not require `std` feature. //! //! # Atomic orderings //! //! All types in this module use `Acquire` and `Release` //! [atomic orderings](Ordering) for all their operations. While this is not //! strictly necessary for types other than `OnceBox`, it is useful for users as //! it allows them to be certain that after `get` or `get_or_init` returns on //! one thread, any side-effects caused by the setter thread prior to them //! calling `set` or `get_or_init` will be made visible to that thread; without //! it, it's possible for it to appear as if they haven't happened yet from the //! getter thread's perspective. This is an acceptable tradeoff to make since //! `Acquire` and `Release` have very little performance overhead on most //! architectures versus `Relaxed`. #[cfg(not(feature = "portable-atomic"))] use core::sync::atomic; #[cfg(feature = "portable-atomic")] use portable_atomic as atomic; use atomic::{AtomicPtr, AtomicUsize, Ordering}; use core::cell::UnsafeCell; use core::marker::PhantomData; use core::num::NonZeroUsize; use core::ptr; /// A thread-safe cell which can be written to only once. #[derive(Default, Debug)] pub struct OnceNonZeroUsize { inner: AtomicUsize, } impl OnceNonZeroUsize { /// Creates a new empty cell. #[inline] pub const fn new() -> OnceNonZeroUsize { OnceNonZeroUsize { inner: AtomicUsize::new(0) } } /// Gets the underlying value. #[inline] pub fn get(&self) -> Option { let val = self.inner.load(Ordering::Acquire); NonZeroUsize::new(val) } /// Sets the contents of this cell to `value`. /// /// Returns `Ok(())` if the cell was empty and `Err(())` if it was /// full. #[inline] pub fn set(&self, value: NonZeroUsize) -> Result<(), ()> { let exchange = self.inner.compare_exchange(0, value.get(), Ordering::AcqRel, Ordering::Acquire); match exchange { Ok(_) => Ok(()), Err(_) => Err(()), } } /// Gets the contents of the cell, initializing it with `f` if the cell was /// empty. /// /// If several threads concurrently run `get_or_init`, more than one `f` can /// be called. However, all threads will return the same value, produced by /// some `f`. pub fn get_or_init(&self, f: F) -> NonZeroUsize where F: FnOnce() -> NonZeroUsize, { enum Void {} match self.get_or_try_init(|| Ok::(f())) { Ok(val) => val, Err(void) => match void {}, } } /// Gets the contents of the cell, initializing it with `f` if /// the cell was empty. If the cell was empty and `f` failed, an /// error is returned. /// /// If several threads concurrently run `get_or_init`, more than one `f` can /// be called. However, all threads will return the same value, produced by /// some `f`. pub fn get_or_try_init(&self, f: F) -> Result where F: FnOnce() -> Result, { let val = self.inner.load(Ordering::Acquire); let res = match NonZeroUsize::new(val) { Some(it) => it, None => { let mut val = f()?.get(); let exchange = self.inner.compare_exchange(0, val, Ordering::AcqRel, Ordering::Acquire); if let Err(old) = exchange { val = old; } unsafe { NonZeroUsize::new_unchecked(val) } } }; Ok(res) } } /// A thread-safe cell which can be written to only once. #[derive(Default, Debug)] pub struct OnceBool { inner: OnceNonZeroUsize, } impl OnceBool { /// Creates a new empty cell. #[inline] pub const fn new() -> OnceBool { OnceBool { inner: OnceNonZeroUsize::new() } } /// Gets the underlying value. #[inline] pub fn get(&self) -> Option { self.inner.get().map(OnceBool::from_usize) } /// Sets the contents of this cell to `value`. /// /// Returns `Ok(())` if the cell was empty and `Err(())` if it was /// full. #[inline] pub fn set(&self, value: bool) -> Result<(), ()> { self.inner.set(OnceBool::to_usize(value)) } /// Gets the contents of the cell, initializing it with `f` if the cell was /// empty. /// /// If several threads concurrently run `get_or_init`, more than one `f` can /// be called. However, all threads will return the same value, produced by /// some `f`. pub fn get_or_init(&self, f: F) -> bool where F: FnOnce() -> bool, { OnceBool::from_usize(self.inner.get_or_init(|| OnceBool::to_usize(f()))) } /// Gets the contents of the cell, initializing it with `f` if /// the cell was empty. If the cell was empty and `f` failed, an /// error is returned. /// /// If several threads concurrently run `get_or_init`, more than one `f` can /// be called. However, all threads will return the same value, produced by /// some `f`. pub fn get_or_try_init(&self, f: F) -> Result where F: FnOnce() -> Result, { self.inner.get_or_try_init(|| f().map(OnceBool::to_usize)).map(OnceBool::from_usize) } #[inline] fn from_usize(value: NonZeroUsize) -> bool { value.get() == 1 } #[inline] fn to_usize(value: bool) -> NonZeroUsize { unsafe { NonZeroUsize::new_unchecked(if value { 1 } else { 2 }) } } } /// A thread-safe cell which can be written to only once. pub struct OnceRef<'a, T> { inner: AtomicPtr, ghost: PhantomData>, } // TODO: Replace UnsafeCell with SyncUnsafeCell once stabilized unsafe impl<'a, T: Sync> Sync for OnceRef<'a, T> {} impl<'a, T> core::fmt::Debug for OnceRef<'a, T> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "OnceRef({:?})", self.inner) } } impl<'a, T> Default for OnceRef<'a, T> { fn default() -> Self { Self::new() } } impl<'a, T> OnceRef<'a, T> { /// Creates a new empty cell. pub const fn new() -> OnceRef<'a, T> { OnceRef { inner: AtomicPtr::new(ptr::null_mut()), ghost: PhantomData } } /// Gets a reference to the underlying value. pub fn get(&self) -> Option<&'a T> { let ptr = self.inner.load(Ordering::Acquire); unsafe { ptr.as_ref() } } /// Sets the contents of this cell to `value`. /// /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was /// full. pub fn set(&self, value: &'a T) -> Result<(), ()> { let ptr = value as *const T as *mut T; let exchange = self.inner.compare_exchange(ptr::null_mut(), ptr, Ordering::AcqRel, Ordering::Acquire); match exchange { Ok(_) => Ok(()), Err(_) => Err(()), } } /// Gets the contents of the cell, initializing it with `f` if the cell was /// empty. /// /// If several threads concurrently run `get_or_init`, more than one `f` can /// be called. However, all threads will return the same value, produced by /// some `f`. pub fn get_or_init(&self, f: F) -> &'a T where F: FnOnce() -> &'a T, { enum Void {} match self.get_or_try_init(|| Ok::<&'a T, Void>(f())) { Ok(val) => val, Err(void) => match void {}, } } /// Gets the contents of the cell, initializing it with `f` if /// the cell was empty. If the cell was empty and `f` failed, an /// error is returned. /// /// If several threads concurrently run `get_or_init`, more than one `f` can /// be called. However, all threads will return the same value, produced by /// some `f`. pub fn get_or_try_init(&self, f: F) -> Result<&'a T, E> where F: FnOnce() -> Result<&'a T, E>, { let mut ptr = self.inner.load(Ordering::Acquire); if ptr.is_null() { // TODO replace with `cast_mut` when MSRV reaches 1.65.0 (also in `set`) ptr = f()? as *const T as *mut T; let exchange = self.inner.compare_exchange( ptr::null_mut(), ptr, Ordering::AcqRel, Ordering::Acquire, ); if let Err(old) = exchange { ptr = old; } } Ok(unsafe { &*ptr }) } /// ```compile_fail /// use once_cell::race::OnceRef; /// /// let mut l = OnceRef::new(); /// /// { /// let y = 2; /// let mut r = OnceRef::new(); /// r.set(&y).unwrap(); /// core::mem::swap(&mut l, &mut r); /// } /// /// // l now contains a dangling reference to y /// eprintln!("uaf: {}", l.get().unwrap()); /// ``` fn _dummy() {} } #[cfg(feature = "alloc")] pub use self::once_box::OnceBox; #[cfg(feature = "alloc")] mod once_box { use super::atomic::{AtomicPtr, Ordering}; use core::{marker::PhantomData, ptr}; use alloc::boxed::Box; /// A thread-safe cell which can be written to only once. pub struct OnceBox { inner: AtomicPtr, ghost: PhantomData>>, } impl core::fmt::Debug for OnceBox { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "OnceBox({:?})", self.inner.load(Ordering::Relaxed)) } } impl Default for OnceBox { fn default() -> Self { Self::new() } } impl Drop for OnceBox { fn drop(&mut self) { let ptr = *self.inner.get_mut(); if !ptr.is_null() { drop(unsafe { Box::from_raw(ptr) }) } } } impl OnceBox { /// Creates a new empty cell. pub const fn new() -> OnceBox { OnceBox { inner: AtomicPtr::new(ptr::null_mut()), ghost: PhantomData } } /// Gets a reference to the underlying value. pub fn get(&self) -> Option<&T> { let ptr = self.inner.load(Ordering::Acquire); if ptr.is_null() { return None; } Some(unsafe { &*ptr }) } /// Sets the contents of this cell to `value`. /// /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was /// full. pub fn set(&self, value: Box) -> Result<(), Box> { let ptr = Box::into_raw(value); let exchange = self.inner.compare_exchange( ptr::null_mut(), ptr, Ordering::AcqRel, Ordering::Acquire, ); if exchange.is_err() { let value = unsafe { Box::from_raw(ptr) }; return Err(value); } Ok(()) } /// Gets the contents of the cell, initializing it with `f` if the cell was /// empty. /// /// If several threads concurrently run `get_or_init`, more than one `f` can /// be called. However, all threads will return the same value, produced by /// some `f`. pub fn get_or_init(&self, f: F) -> &T where F: FnOnce() -> Box, { enum Void {} match self.get_or_try_init(|| Ok::, Void>(f())) { Ok(val) => val, Err(void) => match void {}, } } /// Gets the contents of the cell, initializing it with `f` if /// the cell was empty. If the cell was empty and `f` failed, an /// error is returned. /// /// If several threads concurrently run `get_or_init`, more than one `f` can /// be called. However, all threads will return the same value, produced by /// some `f`. pub fn get_or_try_init(&self, f: F) -> Result<&T, E> where F: FnOnce() -> Result, E>, { let mut ptr = self.inner.load(Ordering::Acquire); if ptr.is_null() { let val = f()?; ptr = Box::into_raw(val); let exchange = self.inner.compare_exchange( ptr::null_mut(), ptr, Ordering::AcqRel, Ordering::Acquire, ); if let Err(old) = exchange { drop(unsafe { Box::from_raw(ptr) }); ptr = old; } }; Ok(unsafe { &*ptr }) } } unsafe impl Sync for OnceBox {} /// ```compile_fail /// struct S(*mut ()); /// unsafe impl Sync for S {} /// /// fn share(_: &T) {} /// share(&once_cell::race::OnceBox::::new()); /// ``` fn _dummy() {} } once_cell-1.20.2/tests/it/main.rs000064400000000000000000000004511046102023000147010ustar 00000000000000mod unsync_once_cell; #[cfg(any(feature = "std", feature = "critical-section"))] mod sync_once_cell; mod unsync_lazy; #[cfg(any(feature = "std", feature = "critical-section"))] mod sync_lazy; #[cfg(feature = "race")] mod race; #[cfg(all(feature = "race", feature = "alloc"))] mod race_once_box; once_cell-1.20.2/tests/it/race.rs000064400000000000000000000057571046102023000147050ustar 00000000000000#[cfg(feature = "std")] use std::sync::Barrier; use std::{ num::NonZeroUsize, sync::atomic::{AtomicUsize, Ordering::SeqCst}, thread::scope, }; use once_cell::race::{OnceBool, OnceNonZeroUsize}; #[test] fn once_non_zero_usize_smoke_test() { let cnt = AtomicUsize::new(0); let cell = OnceNonZeroUsize::new(); let val = NonZeroUsize::new(92).unwrap(); scope(|s| { s.spawn(|| { assert_eq!( cell.get_or_init(|| { cnt.fetch_add(1, SeqCst); val }), val ); assert_eq!(cnt.load(SeqCst), 1); assert_eq!( cell.get_or_init(|| { cnt.fetch_add(1, SeqCst); val }), val ); assert_eq!(cnt.load(SeqCst), 1); }); }); assert_eq!(cell.get(), Some(val)); assert_eq!(cnt.load(SeqCst), 1); } #[test] fn once_non_zero_usize_set() { let val1 = NonZeroUsize::new(92).unwrap(); let val2 = NonZeroUsize::new(62).unwrap(); let cell = OnceNonZeroUsize::new(); assert!(cell.set(val1).is_ok()); assert_eq!(cell.get(), Some(val1)); assert!(cell.set(val2).is_err()); assert_eq!(cell.get(), Some(val1)); } #[cfg(feature = "std")] #[test] fn once_non_zero_usize_first_wins() { let val1 = NonZeroUsize::new(92).unwrap(); let val2 = NonZeroUsize::new(62).unwrap(); let cell = OnceNonZeroUsize::new(); let b1 = Barrier::new(2); let b2 = Barrier::new(2); let b3 = Barrier::new(2); scope(|s| { s.spawn(|| { let r1 = cell.get_or_init(|| { b1.wait(); b2.wait(); val1 }); assert_eq!(r1, val1); b3.wait(); }); b1.wait(); s.spawn(|| { let r2 = cell.get_or_init(|| { b2.wait(); b3.wait(); val2 }); assert_eq!(r2, val1); }); }); assert_eq!(cell.get(), Some(val1)); } #[test] fn once_bool_smoke_test() { let cnt = AtomicUsize::new(0); let cell = OnceBool::new(); scope(|s| { s.spawn(|| { assert_eq!( cell.get_or_init(|| { cnt.fetch_add(1, SeqCst); false }), false ); assert_eq!(cnt.load(SeqCst), 1); assert_eq!( cell.get_or_init(|| { cnt.fetch_add(1, SeqCst); false }), false ); assert_eq!(cnt.load(SeqCst), 1); }); }); assert_eq!(cell.get(), Some(false)); assert_eq!(cnt.load(SeqCst), 1); } #[test] fn once_bool_set() { let cell = OnceBool::new(); assert!(cell.set(false).is_ok()); assert_eq!(cell.get(), Some(false)); assert!(cell.set(true).is_err()); assert_eq!(cell.get(), Some(false)); } once_cell-1.20.2/tests/it/race_once_box.rs000064400000000000000000000064751046102023000165570ustar 00000000000000#[cfg(feature = "std")] use std::sync::Barrier; use std::sync::{ atomic::{AtomicUsize, Ordering::SeqCst}, Arc, }; use once_cell::race::OnceBox; #[derive(Default)] struct Heap { total: Arc, } #[derive(Debug)] struct Pebble { val: T, total: Arc, } impl Drop for Pebble { fn drop(&mut self) { self.total.fetch_sub(1, SeqCst); } } impl Heap { fn total(&self) -> usize { self.total.load(SeqCst) } fn new_pebble(&self, val: T) -> Pebble { self.total.fetch_add(1, SeqCst); Pebble { val, total: Arc::clone(&self.total) } } } #[cfg(feature = "std")] #[test] fn once_box_smoke_test() { use std::thread::scope; let heap = Heap::default(); let global_cnt = AtomicUsize::new(0); let cell = OnceBox::new(); let b = Barrier::new(128); scope(|s| { for _ in 0..128 { s.spawn(|| { let local_cnt = AtomicUsize::new(0); cell.get_or_init(|| { global_cnt.fetch_add(1, SeqCst); local_cnt.fetch_add(1, SeqCst); b.wait(); Box::new(heap.new_pebble(())) }); assert_eq!(local_cnt.load(SeqCst), 1); cell.get_or_init(|| { global_cnt.fetch_add(1, SeqCst); local_cnt.fetch_add(1, SeqCst); Box::new(heap.new_pebble(())) }); assert_eq!(local_cnt.load(SeqCst), 1); }); } }); assert!(cell.get().is_some()); assert!(global_cnt.load(SeqCst) > 10); assert_eq!(heap.total(), 1); drop(cell); assert_eq!(heap.total(), 0); } #[test] fn once_box_set() { let heap = Heap::default(); let cell = OnceBox::new(); assert!(cell.get().is_none()); assert!(cell.set(Box::new(heap.new_pebble("hello"))).is_ok()); assert_eq!(cell.get().unwrap().val, "hello"); assert_eq!(heap.total(), 1); assert!(cell.set(Box::new(heap.new_pebble("world"))).is_err()); assert_eq!(cell.get().unwrap().val, "hello"); assert_eq!(heap.total(), 1); drop(cell); assert_eq!(heap.total(), 0); } #[cfg(feature = "std")] #[test] fn once_box_first_wins() { use std::thread::scope; let cell = OnceBox::new(); let val1 = 92; let val2 = 62; let b1 = Barrier::new(2); let b2 = Barrier::new(2); let b3 = Barrier::new(2); scope(|s| { s.spawn(|| { let r1 = cell.get_or_init(|| { b1.wait(); b2.wait(); Box::new(val1) }); assert_eq!(*r1, val1); b3.wait(); }); b1.wait(); s.spawn(|| { let r2 = cell.get_or_init(|| { b2.wait(); b3.wait(); Box::new(val2) }); assert_eq!(*r2, val1); }); }); assert_eq!(cell.get(), Some(&val1)); } #[test] fn once_box_reentrant() { let cell = OnceBox::new(); let res = cell.get_or_init(|| { cell.get_or_init(|| Box::new("hello".to_string())); Box::new("world".to_string()) }); assert_eq!(res, "hello"); } #[test] fn once_box_default() { struct Foo; let cell: OnceBox = Default::default(); assert!(cell.get().is_none()); } once_cell-1.20.2/tests/it/sync_lazy.rs000064400000000000000000000071451046102023000157770ustar 00000000000000use std::{ cell::Cell, sync::atomic::{AtomicUsize, Ordering::SeqCst}, thread::scope, }; use once_cell::sync::{Lazy, OnceCell}; #[test] fn lazy_new() { let called = AtomicUsize::new(0); let x = Lazy::new(|| { called.fetch_add(1, SeqCst); 92 }); assert_eq!(called.load(SeqCst), 0); scope(|s| { s.spawn(|| { let y = *x - 30; assert_eq!(y, 62); assert_eq!(called.load(SeqCst), 1); }); }); let y = *x - 30; assert_eq!(y, 62); assert_eq!(called.load(SeqCst), 1); } #[test] fn lazy_deref_mut() { let called = AtomicUsize::new(0); let mut x = Lazy::new(|| { called.fetch_add(1, SeqCst); 92 }); assert_eq!(called.load(SeqCst), 0); let y = *x - 30; assert_eq!(y, 62); assert_eq!(called.load(SeqCst), 1); *x /= 2; assert_eq!(*x, 46); assert_eq!(called.load(SeqCst), 1); } #[test] fn lazy_force_mut() { let called = Cell::new(0); let mut x = Lazy::new(|| { called.set(called.get() + 1); 92 }); assert_eq!(called.get(), 0); let v = Lazy::force_mut(&mut x); assert_eq!(called.get(), 1); *v /= 2; assert_eq!(*x, 46); assert_eq!(called.get(), 1); } #[test] fn lazy_get_mut() { let called = Cell::new(0); let mut x: Lazy = Lazy::new(|| { called.set(called.get() + 1); 92 }); assert_eq!(called.get(), 0); assert_eq!(*x, 92); let mut_ref: &mut u32 = Lazy::get_mut(&mut x).unwrap(); assert_eq!(called.get(), 1); *mut_ref /= 2; assert_eq!(*x, 46); assert_eq!(called.get(), 1); } #[test] fn lazy_default() { static CALLED: AtomicUsize = AtomicUsize::new(0); struct Foo(u8); impl Default for Foo { fn default() -> Self { CALLED.fetch_add(1, SeqCst); Foo(42) } } let lazy: Lazy> = <_>::default(); assert_eq!(CALLED.load(SeqCst), 0); assert_eq!(lazy.lock().unwrap().0, 42); assert_eq!(CALLED.load(SeqCst), 1); lazy.lock().unwrap().0 = 21; assert_eq!(lazy.lock().unwrap().0, 21); assert_eq!(CALLED.load(SeqCst), 1); } #[test] fn static_lazy() { static XS: Lazy> = Lazy::new(|| { let mut xs = Vec::new(); xs.push(1); xs.push(2); xs.push(3); xs }); scope(|s| { s.spawn(|| { assert_eq!(&*XS, &vec![1, 2, 3]); }); }); assert_eq!(&*XS, &vec![1, 2, 3]); } #[test] fn static_lazy_via_fn() { fn xs() -> &'static Vec { static XS: OnceCell> = OnceCell::new(); XS.get_or_init(|| { let mut xs = Vec::new(); xs.push(1); xs.push(2); xs.push(3); xs }) } assert_eq!(xs(), &vec![1, 2, 3]); } #[test] fn lazy_into_value() { let l: Lazy = Lazy::new(|| panic!()); assert!(matches!(Lazy::into_value(l), Err(_))); let l = Lazy::new(|| -> i32 { 92 }); Lazy::force(&l); assert!(matches!(Lazy::into_value(l), Ok(92))); } #[test] fn lazy_poisoning() { let x: Lazy = Lazy::new(|| panic!("kaboom")); for _ in 0..2 { let res = std::panic::catch_unwind(|| x.len()); assert!(res.is_err()); } } #[test] // https://github.com/rust-lang/rust/issues/34761#issuecomment-256320669 fn arrrrrrrrrrrrrrrrrrrrrr() { let lazy: Lazy<&String, _>; { let s = String::new(); lazy = Lazy::new(|| &s); _ = *lazy; } } #[test] fn lazy_is_sync_send() { fn assert_traits() {} assert_traits::>(); } once_cell-1.20.2/tests/it/sync_once_cell.rs000064400000000000000000000167571046102023000167540ustar 00000000000000use std::{ sync::atomic::{AtomicUsize, Ordering::SeqCst}, thread::scope, }; #[cfg(feature = "std")] use std::sync::Barrier; #[cfg(not(feature = "std"))] use core::cell::Cell; use once_cell::sync::{Lazy, OnceCell}; #[test] fn once_cell() { let c = OnceCell::new(); assert!(c.get().is_none()); scope(|s| { s.spawn(|| { c.get_or_init(|| 92); assert_eq!(c.get(), Some(&92)); }); }); c.get_or_init(|| panic!("Kabom!")); assert_eq!(c.get(), Some(&92)); } #[test] fn once_cell_with_value() { static CELL: OnceCell = OnceCell::with_value(12); assert_eq!(CELL.get(), Some(&12)); } #[test] fn once_cell_get_mut() { let mut c = OnceCell::new(); assert!(c.get_mut().is_none()); c.set(90).unwrap(); *c.get_mut().unwrap() += 2; assert_eq!(c.get_mut(), Some(&mut 92)); } #[test] fn once_cell_get_unchecked() { let c = OnceCell::new(); c.set(92).unwrap(); unsafe { assert_eq!(c.get_unchecked(), &92); } } #[test] fn once_cell_drop() { static DROP_CNT: AtomicUsize = AtomicUsize::new(0); struct Dropper; impl Drop for Dropper { fn drop(&mut self) { DROP_CNT.fetch_add(1, SeqCst); } } let x = OnceCell::new(); scope(|s| { s.spawn(|| { x.get_or_init(|| Dropper); assert_eq!(DROP_CNT.load(SeqCst), 0); drop(x); }); }); assert_eq!(DROP_CNT.load(SeqCst), 1); } #[test] fn once_cell_drop_empty() { let x = OnceCell::::new(); drop(x); } #[test] fn clone() { let s = OnceCell::new(); let c = s.clone(); assert!(c.get().is_none()); s.set("hello".to_string()).unwrap(); let c = s.clone(); assert_eq!(c.get().map(String::as_str), Some("hello")); } #[test] fn get_or_try_init() { let cell: OnceCell = OnceCell::new(); assert!(cell.get().is_none()); let res = std::panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() })); assert!(res.is_err()); assert!(cell.get().is_none()); assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); assert_eq!(cell.get_or_try_init(|| Ok::<_, ()>("hello".to_string())), Ok(&"hello".to_string())); assert_eq!(cell.get(), Some(&"hello".to_string())); } #[cfg(feature = "std")] #[test] fn wait() { let cell: OnceCell = OnceCell::new(); scope(|s| { s.spawn(|| cell.set("hello".to_string())); let greeting = cell.wait(); assert_eq!(greeting, "hello") }); } #[cfg(feature = "std")] #[test] fn get_or_init_stress() { let n_threads = if cfg!(miri) { 30 } else { 1_000 }; let n_cells = if cfg!(miri) { 30 } else { 1_000 }; let cells: Vec<_> = std::iter::repeat_with(|| (Barrier::new(n_threads), OnceCell::new())) .take(n_cells) .collect(); scope(|s| { for t in 0..n_threads { let cells = &cells; s.spawn(move || { for (i, (b, s)) in cells.iter().enumerate() { b.wait(); let j = if t % 2 == 0 { s.wait() } else { s.get_or_init(|| i) }; assert_eq!(*j, i); } }); } }); } #[test] fn from_impl() { assert_eq!(OnceCell::from("value").get(), Some(&"value")); assert_ne!(OnceCell::from("foo").get(), Some(&"bar")); } #[test] fn partialeq_impl() { assert!(OnceCell::from("value") == OnceCell::from("value")); assert!(OnceCell::from("foo") != OnceCell::from("bar")); assert!(OnceCell::::new() == OnceCell::new()); assert!(OnceCell::::new() != OnceCell::from("value".to_owned())); } #[test] fn into_inner() { let cell: OnceCell = OnceCell::new(); assert_eq!(cell.into_inner(), None); let cell = OnceCell::new(); cell.set("hello".to_string()).unwrap(); assert_eq!(cell.into_inner(), Some("hello".to_string())); } #[test] fn debug_impl() { let cell = OnceCell::new(); assert_eq!(format!("{:#?}", cell), "OnceCell(Uninit)"); cell.set(vec!["hello", "world"]).unwrap(); assert_eq!( format!("{:#?}", cell), r#"OnceCell( [ "hello", "world", ], )"# ); } #[test] #[cfg_attr(miri, ignore)] // miri doesn't support processes #[cfg(feature = "std")] fn reentrant_init() { let examples_dir = { let mut exe = std::env::current_exe().unwrap(); exe.pop(); exe.pop(); exe.push("examples"); exe }; let bin = examples_dir .join("reentrant_init_deadlocks") .with_extension(std::env::consts::EXE_EXTENSION); let mut guard = Guard { child: std::process::Command::new(bin).spawn().unwrap() }; std::thread::sleep(std::time::Duration::from_secs(2)); let status = guard.child.try_wait().unwrap(); assert!(status.is_none()); struct Guard { child: std::process::Child, } impl Drop for Guard { fn drop(&mut self) { let _ = self.child.kill(); } } } #[cfg(not(feature = "std"))] #[test] #[should_panic(expected = "reentrant init")] fn reentrant_init() { let x: OnceCell> = OnceCell::new(); let dangling_ref: Cell> = Cell::new(None); x.get_or_init(|| { let r = x.get_or_init(|| Box::new(92)); dangling_ref.set(Some(r)); Box::new(62) }); eprintln!("use after free: {:?}", dangling_ref.get().unwrap()); } #[test] fn eval_once_macro() { macro_rules! eval_once { (|| -> $ty:ty { $($body:tt)* }) => {{ static ONCE_CELL: OnceCell<$ty> = OnceCell::new(); fn init() -> $ty { $($body)* } ONCE_CELL.get_or_init(init) }}; } let fib: &'static Vec = eval_once! { || -> Vec { let mut res = vec![1, 1]; for i in 0..10 { let next = res[i] + res[i + 1]; res.push(next); } res } }; assert_eq!(fib[5], 8) } #[test] fn once_cell_does_not_leak_partially_constructed_boxes() { let n_tries = if cfg!(miri) { 10 } else { 100 }; let n_readers = 10; let n_writers = 3; const MSG: &str = "Hello, World"; for _ in 0..n_tries { let cell: OnceCell = OnceCell::new(); scope(|scope| { for _ in 0..n_readers { scope.spawn(|| loop { if let Some(msg) = cell.get() { assert_eq!(msg, MSG); break; } }); } for _ in 0..n_writers { let _ = scope.spawn(|| cell.set(MSG.to_owned())); } }); } } #[cfg(feature = "std")] #[test] fn get_does_not_block() { let cell = OnceCell::new(); let barrier = Barrier::new(2); scope(|scope| { scope.spawn(|| { cell.get_or_init(|| { barrier.wait(); barrier.wait(); "hello".to_string() }); }); barrier.wait(); assert_eq!(cell.get(), None); barrier.wait(); }); assert_eq!(cell.get(), Some(&"hello".to_string())); } #[test] // https://github.com/rust-lang/rust/issues/34761#issuecomment-256320669 fn arrrrrrrrrrrrrrrrrrrrrr() { let cell = OnceCell::new(); { let s = String::new(); cell.set(&s).unwrap(); } } #[test] fn once_cell_is_sync_send() { fn assert_traits() {} assert_traits::>(); assert_traits::>(); } once_cell-1.20.2/tests/it/unsync_lazy.rs000064400000000000000000000053151046102023000163370ustar 00000000000000use core::{ cell::Cell, sync::atomic::{AtomicUsize, Ordering::SeqCst}, }; use once_cell::unsync::Lazy; #[test] fn lazy_new() { let called = Cell::new(0); let x = Lazy::new(|| { called.set(called.get() + 1); 92 }); assert_eq!(called.get(), 0); let y = *x - 30; assert_eq!(y, 62); assert_eq!(called.get(), 1); let y = *x - 30; assert_eq!(y, 62); assert_eq!(called.get(), 1); } #[test] fn lazy_deref_mut() { let called = Cell::new(0); let mut x = Lazy::new(|| { called.set(called.get() + 1); 92 }); assert_eq!(called.get(), 0); let y = *x - 30; assert_eq!(y, 62); assert_eq!(called.get(), 1); *x /= 2; assert_eq!(*x, 46); assert_eq!(called.get(), 1); } #[test] fn lazy_force_mut() { let called = Cell::new(0); let mut x = Lazy::new(|| { called.set(called.get() + 1); 92 }); assert_eq!(called.get(), 0); let v = Lazy::force_mut(&mut x); assert_eq!(called.get(), 1); *v /= 2; assert_eq!(*x, 46); assert_eq!(called.get(), 1); } #[test] fn lazy_get_mut() { let called = Cell::new(0); let mut x: Lazy = Lazy::new(|| { called.set(called.get() + 1); 92 }); assert_eq!(called.get(), 0); assert_eq!(*x, 92); let mut_ref: &mut u32 = Lazy::get_mut(&mut x).unwrap(); assert_eq!(called.get(), 1); *mut_ref /= 2; assert_eq!(*x, 46); assert_eq!(called.get(), 1); } #[test] fn lazy_default() { static CALLED: AtomicUsize = AtomicUsize::new(0); struct Foo(u8); impl Default for Foo { fn default() -> Self { CALLED.fetch_add(1, SeqCst); Foo(42) } } let lazy: Lazy> = <_>::default(); assert_eq!(CALLED.load(SeqCst), 0); assert_eq!(lazy.lock().unwrap().0, 42); assert_eq!(CALLED.load(SeqCst), 1); lazy.lock().unwrap().0 = 21; assert_eq!(lazy.lock().unwrap().0, 21); assert_eq!(CALLED.load(SeqCst), 1); } #[test] fn lazy_into_value() { let l: Lazy = Lazy::new(|| panic!()); assert!(matches!(Lazy::into_value(l), Err(_))); let l = Lazy::new(|| -> i32 { 92 }); Lazy::force(&l); assert!(matches!(Lazy::into_value(l), Ok(92))); } #[test] #[cfg(feature = "std")] fn lazy_poisoning() { let x: Lazy = Lazy::new(|| panic!("kaboom")); for _ in 0..2 { let res = std::panic::catch_unwind(|| x.len()); assert!(res.is_err()); } } #[test] // https://github.com/rust-lang/rust/issues/34761#issuecomment-256320669 fn arrrrrrrrrrrrrrrrrrrrrr() { let lazy: Lazy<&String, _>; { let s = String::new(); lazy = Lazy::new(|| &s); _ = *lazy; } } once_cell-1.20.2/tests/it/unsync_once_cell.rs000064400000000000000000000074151046102023000173060ustar 00000000000000use core::{ cell::Cell, sync::atomic::{AtomicUsize, Ordering::SeqCst}, }; use once_cell::unsync::OnceCell; #[test] fn once_cell() { let c = OnceCell::new(); assert!(c.get().is_none()); c.get_or_init(|| 92); assert_eq!(c.get(), Some(&92)); c.get_or_init(|| panic!("Kabom!")); assert_eq!(c.get(), Some(&92)); } #[test] fn once_cell_with_value() { const CELL: OnceCell = OnceCell::with_value(12); let cell = CELL; assert_eq!(cell.get(), Some(&12)); } #[test] fn once_cell_get_mut() { let mut c = OnceCell::new(); assert!(c.get_mut().is_none()); c.set(90).unwrap(); *c.get_mut().unwrap() += 2; assert_eq!(c.get_mut(), Some(&mut 92)); } #[test] fn once_cell_drop() { static DROP_CNT: AtomicUsize = AtomicUsize::new(0); struct Dropper; impl Drop for Dropper { fn drop(&mut self) { DROP_CNT.fetch_add(1, SeqCst); } } let x = OnceCell::new(); x.get_or_init(|| Dropper); assert_eq!(DROP_CNT.load(SeqCst), 0); drop(x); assert_eq!(DROP_CNT.load(SeqCst), 1); } #[test] fn once_cell_drop_empty() { let x = OnceCell::::new(); drop(x); } #[test] fn clone() { let s = OnceCell::new(); let c = s.clone(); assert!(c.get().is_none()); s.set("hello".to_string()).unwrap(); let c = s.clone(); assert_eq!(c.get().map(String::as_str), Some("hello")); } #[test] fn get_or_try_init() { let cell: OnceCell = OnceCell::new(); assert!(cell.get().is_none()); let res = std::panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() })); assert!(res.is_err()); assert!(cell.get().is_none()); assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); assert_eq!(cell.get_or_try_init(|| Ok::<_, ()>("hello".to_string())), Ok(&"hello".to_string())); assert_eq!(cell.get(), Some(&"hello".to_string())); } #[test] fn from_impl() { assert_eq!(OnceCell::from("value").get(), Some(&"value")); assert_ne!(OnceCell::from("foo").get(), Some(&"bar")); } #[test] fn partialeq_impl() { assert!(OnceCell::from("value") == OnceCell::from("value")); assert!(OnceCell::from("foo") != OnceCell::from("bar")); assert!(OnceCell::::new() == OnceCell::new()); assert!(OnceCell::::new() != OnceCell::from("value".to_owned())); } #[test] fn into_inner() { let cell: OnceCell = OnceCell::new(); assert_eq!(cell.into_inner(), None); let cell = OnceCell::new(); cell.set("hello".to_string()).unwrap(); assert_eq!(cell.into_inner(), Some("hello".to_string())); } #[test] fn debug_impl() { let cell = OnceCell::new(); assert_eq!(format!("{:#?}", cell), "OnceCell(Uninit)"); cell.set(vec!["hello", "world"]).unwrap(); assert_eq!( format!("{:#?}", cell), r#"OnceCell( [ "hello", "world", ], )"# ); } #[test] #[should_panic(expected = "reentrant init")] fn reentrant_init() { let x: OnceCell> = OnceCell::new(); let dangling_ref: Cell> = Cell::new(None); x.get_or_init(|| { let r = x.get_or_init(|| Box::new(92)); dangling_ref.set(Some(r)); Box::new(62) }); eprintln!("use after free: {:?}", dangling_ref.get().unwrap()); } #[test] fn aliasing_in_get() { let x = OnceCell::new(); x.set(42).unwrap(); let at_x = x.get().unwrap(); // --- (shared) borrow of inner `Option` --+ let _ = x.set(27); // <-- temporary (unique) borrow of inner `Option` | println!("{}", at_x); // <------- up until here ---------------------------+ } #[test] // https://github.com/rust-lang/rust/issues/34761#issuecomment-256320669 fn arrrrrrrrrrrrrrrrrrrrrr() { let cell = OnceCell::new(); { let s = String::new(); cell.set(&s).unwrap(); } }