Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
This commit is contained in:
1
vendor/once_cell/.cargo-checksum.json
vendored
Normal file
1
vendor/once_cell/.cargo-checksum.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"files":{"CHANGELOG.md":"cc4e490ceb3a92be753f3ffee297921a341faf67b304e1e0e63833aba4c3d529","Cargo.lock":"57fb641115940cc1870a3460ebb53ca921461c38894a68e62bf0fc4438825fa8","Cargo.toml":"b0c4dcab027bb78093c9cd0e643b778303bb113fed7f3ab251252141d2b6735d","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"2331182c8b5a6971fd0d04a0ca711d5839e93b3de6b2003108940a8c93850aaf","bors.toml":"ebd69f714a49dceb8fd10ebadfea6e2767be4732fdef49eddf6239151b4bc78c","examples/bench.rs":"1597a52529f75d6c5ad0b86759a775b1d723dfa810e2016317283b13594219da","examples/bench_acquire.rs":"9f4912ca262194cb55e893c33739c85c2f4868d07905b9dd3238552b6ce8a6e4","examples/lazy_static.rs":"8bca1b264da21eceb1ccaf30477fc941bc71bedd030f1c6982ed3a7804abfb4f","examples/reentrant_init_deadlocks.rs":"ff84929de27a848e5b155549caa96db5db5f030afca975f8ba3f3da640083001","examples/regex.rs":"4a2e0fb093c7f5bbe0fff8689fc0c670c5334344a1bfda376f5faa98a05d459f","examples/test_synchronization.rs":"88abd5c16275bb2f2d77eaecf369d97681404a77b8edd0021f24bfd377c46be3","src/imp_cs.rs":"32ee2c252d176726e62cf1f81a270d3738cb06784c47d4064e62350d9f7672cd","src/imp_pl.rs":"6a97f60a91ab44192dcaf028e987f6be0328b5d4d69216dcdaec93bc39401f68","src/imp_std.rs":"1c130f83be5c1360dfd379911f97797c1e4c730b845f465c8c2630467ca317d2","src/lib.rs":"60fe685113e11203ec32876b5dad9c8e1eb705da5854eff8f044d3f4651a7d0f","src/race.rs":"e8400987cc44b3e4b1a321d1e0506df07be7034a7d1c16be641dc75b44fee05c","tests/it/main.rs":"e6e9987e053af84b9d76052602995b1e777efb5bc06cd5f49009e6f03b18626c","tests/it/race.rs":"8dfe38563b6d0be890ab076be1fc1122d41a7c7792354cd7f60bc4454666b968","tests/it/race_once_box.rs":"1c2fe9e2988ec38d60c93c797fceb4c7a65d1b2e48a6a1e78db78ab91388e844","tests/it/sync_lazy.rs":"a36c5d66340b3d6d20aad331a499858a2125dfdfd624c5bf3b4b06a0b157c75c","tests/it/sync_once_cell.rs":"0d04beeb394eb53dd3fc0309fcfc382d56350e72b89d22356e0047d6c7bfef58","tests/it/unsync_lazy.rs":"51a1ffd411770d1e32399ec23feb5f61be362bbed34e100eb7509f8496224e1a","tests/it/unsync_once_cell.rs":"82b72936d7bd4090db25cfc543c01ef3206d6917ac56f09d17d4110a65deb30a"},"package":"3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"}
|
229
vendor/once_cell/CHANGELOG.md
vendored
Normal file
229
vendor/once_cell/CHANGELOG.md
vendored
Normal file
@ -0,0 +1,229 @@
|
||||
# Changelog
|
||||
|
||||
## Unreleased
|
||||
|
||||
-
|
||||
|
||||
## 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<T>` 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<T>`.
|
||||
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<T>` 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<T, F>`.
|
||||
|
||||
## 1.3.0
|
||||
|
||||
- `Lazy<T>` 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<T>` 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<T>` 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<T> 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<T>` is `Clone` if `T` is `Clone`.
|
||||
|
||||
## 0.1.5
|
||||
|
||||
- No changelog until this point :(
|
169
vendor/once_cell/Cargo.lock
generated
vendored
Normal file
169
vendor/once_cell/Cargo.lock
generated
vendored
Normal file
@ -0,0 +1,169 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[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.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.144"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.19.0"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
"parking_lot_core",
|
||||
"portable-atomic",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
97
vendor/once_cell/Cargo.toml
vendored
Normal file
97
vendor/once_cell/Cargo.toml
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
# 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.19.0"
|
||||
authors = ["Aleksey Kladov <aleksey.kladov@gmail.com>"]
|
||||
exclude = [
|
||||
"*.png",
|
||||
"*.svg",
|
||||
"/Cargo.lock.msrv",
|
||||
"rustfmt.toml",
|
||||
]
|
||||
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"]
|
||||
|
||||
[[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"]
|
||||
|
||||
[dependencies.critical-section]
|
||||
version = "1"
|
||||
optional = true
|
||||
|
||||
[dependencies.parking_lot_core]
|
||||
version = "0.9.3"
|
||||
optional = true
|
||||
default_features = false
|
||||
|
||||
[dependencies.portable-atomic]
|
||||
version = "1"
|
||||
optional = true
|
||||
|
||||
[dev-dependencies.critical-section]
|
||||
version = "1.1.1"
|
||||
features = ["std"]
|
||||
|
||||
[dev-dependencies.regex]
|
||||
version = "1.2.0"
|
||||
|
||||
[features]
|
||||
alloc = ["race"]
|
||||
atomic-polyfill = ["critical-section"]
|
||||
critical-section = [
|
||||
"dep:critical-section",
|
||||
"portable-atomic",
|
||||
]
|
||||
default = ["std"]
|
||||
parking_lot = ["dep:parking_lot_core"]
|
||||
race = []
|
||||
std = ["alloc"]
|
||||
unstable = []
|
201
vendor/once_cell/LICENSE-APACHE
vendored
Normal file
201
vendor/once_cell/LICENSE-APACHE
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
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.
|
23
vendor/once_cell/LICENSE-MIT
vendored
Normal file
23
vendor/once_cell/LICENSE-MIT
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
Permission 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.
|
57
vendor/once_cell/README.md
vendored
Normal file
57
vendor/once_cell/README.md
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
<p align="center"><img src="design/logo.png" alt="once_cell"></p>
|
||||
|
||||
|
||||
[](https://github.com/matklad/once_cell/actions)
|
||||
[](https://crates.io/crates/once_cell)
|
||||
[](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<T> {
|
||||
fn new() -> OnceCell<T> { ... }
|
||||
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<T>`
|
||||
or `MutexGuard<T>`.
|
||||
|
||||
`once_cell` also has a `Lazy<T>` 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<Mutex<HashMap<i32, String>>> = 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).
|
2
vendor/once_cell/bors.toml
vendored
Normal file
2
vendor/once_cell/bors.toml
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
status = [ "Rust" ]
|
||||
delete_merged_branches = true
|
28
vendor/once_cell/examples/bench.rs
vendored
Normal file
28
vendor/once_cell/examples/bench.rs
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
use std::mem::size_of;
|
||||
|
||||
use once_cell::sync::OnceCell;
|
||||
|
||||
const N_THREADS: usize = 32;
|
||||
const N_ROUNDS: usize = 100_000_000;
|
||||
|
||||
static CELL: OnceCell<usize> = 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::<Vec<_>>();
|
||||
for thread in threads {
|
||||
thread.join().unwrap();
|
||||
}
|
||||
println!("{:?}", start.elapsed());
|
||||
println!("size_of::<OnceCell<()>>() = {:?}", size_of::<OnceCell<()>>());
|
||||
println!("size_of::<OnceCell<bool>>() = {:?}", size_of::<OnceCell<bool>>());
|
||||
println!("size_of::<OnceCell<u32>>() = {:?}", size_of::<OnceCell<u32>>());
|
||||
}
|
||||
|
||||
fn thread_main(i: usize) {
|
||||
for _ in 0..N_ROUNDS {
|
||||
let &value = CELL.get_or_init(|| i);
|
||||
assert!(value < N_THREADS)
|
||||
}
|
||||
}
|
39
vendor/once_cell/examples/bench_acquire.rs
vendored
Normal file
39
vendor/once_cell/examples/bench_acquire.rs
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
//! 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<usize> = 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::<Vec<_>>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
36
vendor/once_cell/examples/lazy_static.rs
vendored
Normal file
36
vendor/once_cell/examples/lazy_static.rs
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
extern crate once_cell;
|
||||
|
||||
use once_cell::sync::{Lazy, OnceCell};
|
||||
use std::collections::HashMap;
|
||||
|
||||
static HASHMAP: Lazy<HashMap<u32, &'static str>> = 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<u32, &'static str> {
|
||||
static INSTANCE: OnceCell<HashMap<u32, &'static str>> = 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"));
|
||||
}
|
14
vendor/once_cell/examples/reentrant_init_deadlocks.rs
vendored
Normal file
14
vendor/once_cell/examples/reentrant_init_deadlocks.rs
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
fn main() {
|
||||
let cell = once_cell::sync::OnceCell::<u32>::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));
|
||||
}
|
49
vendor/once_cell/examples/regex.rs
vendored
Normal file
49
vendor/once_cell/examples/regex.rs
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
use std::{str::FromStr, time::Instant};
|
||||
|
||||
use regex::Regex;
|
||||
|
||||
macro_rules! regex {
|
||||
($re:literal $(,)?) => {{
|
||||
static RE: once_cell::sync::OnceCell<regex::Regex> = 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());
|
||||
}
|
38
vendor/once_cell/examples/test_synchronization.rs
vendored
Normal file
38
vendor/once_cell/examples/test_synchronization.rs
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
//! 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<Vec<OnceCell<usize>>> = OnceCell::new();
|
||||
static RESULT: OnceCell<usize> = 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::<Vec<_>>();
|
||||
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);
|
||||
}
|
78
vendor/once_cell/src/imp_cs.rs
vendored
Normal file
78
vendor/once_cell/src/imp_cs.rs
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
use core::panic::{RefUnwindSafe, UnwindSafe};
|
||||
|
||||
use portable_atomic::{AtomicBool, Ordering};
|
||||
use critical_section::{CriticalSection, Mutex};
|
||||
|
||||
use crate::unsync;
|
||||
|
||||
pub(crate) struct OnceCell<T> {
|
||||
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<unsync::OnceCell<T>>,
|
||||
}
|
||||
|
||||
// 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<T: Sync + Send> Sync for OnceCell<T> {}
|
||||
unsafe impl<T: Send> Send for OnceCell<T> {}
|
||||
|
||||
impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceCell<T> {}
|
||||
impl<T: UnwindSafe> UnwindSafe for OnceCell<T> {}
|
||||
|
||||
impl<T> OnceCell<T> {
|
||||
pub(crate) const fn new() -> OnceCell<T> {
|
||||
OnceCell { initialized: AtomicBool::new(false), value: Mutex::new(unsync::OnceCell::new()) }
|
||||
}
|
||||
|
||||
pub(crate) const fn with_value(value: T) -> OnceCell<T> {
|
||||
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<F, E>(&self, f: F) -> Result<(), E>
|
||||
where
|
||||
F: FnOnce() -> Result<T, E>,
|
||||
{
|
||||
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<T> {
|
||||
self.value.into_inner().into_inner()
|
||||
}
|
||||
}
|
174
vendor/once_cell/src/imp_pl.rs
vendored
Normal file
174
vendor/once_cell/src/imp_pl.rs
vendored
Normal file
@ -0,0 +1,174 @@
|
||||
use std::{
|
||||
cell::UnsafeCell,
|
||||
panic::{RefUnwindSafe, UnwindSafe},
|
||||
sync::atomic::{AtomicU8, Ordering},
|
||||
};
|
||||
|
||||
pub(crate) struct OnceCell<T> {
|
||||
state: AtomicU8,
|
||||
value: UnsafeCell<Option<T>>,
|
||||
}
|
||||
|
||||
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<T: Sync + Send> Sync for OnceCell<T> {}
|
||||
unsafe impl<T: Send> Send for OnceCell<T> {}
|
||||
|
||||
impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceCell<T> {}
|
||||
impl<T: UnwindSafe> UnwindSafe for OnceCell<T> {}
|
||||
|
||||
impl<T> OnceCell<T> {
|
||||
pub(crate) const fn new() -> OnceCell<T> {
|
||||
OnceCell { state: AtomicU8::new(INCOMPLETE), value: UnsafeCell::new(None) }
|
||||
}
|
||||
|
||||
pub(crate) const fn with_value(value: T) -> OnceCell<T> {
|
||||
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<F, E>(&self, f: F) -> Result<(), E>
|
||||
where
|
||||
F: FnOnce() -> Result<T, E>,
|
||||
{
|
||||
let mut f = Some(f);
|
||||
let mut res: Result<(), E> = Ok(());
|
||||
let slot: *mut Option<T> = 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<T> = 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<T> {
|
||||
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::<OnceCell<bool>>(), 1 * size_of::<bool>() + size_of::<u8>());
|
||||
}
|
415
vendor/once_cell/src/imp_std.rs
vendored
Normal file
415
vendor/once_cell/src/imp_std.rs
vendored
Normal file
@ -0,0 +1,415 @@
|
||||
// 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<T> {
|
||||
// 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<Waiter>,
|
||||
value: UnsafeCell<Option<T>>,
|
||||
}
|
||||
|
||||
// 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<T: Sync + Send> Sync for OnceCell<T> {}
|
||||
unsafe impl<T: Send> Send for OnceCell<T> {}
|
||||
|
||||
impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceCell<T> {}
|
||||
impl<T: UnwindSafe> UnwindSafe for OnceCell<T> {}
|
||||
|
||||
impl<T> OnceCell<T> {
|
||||
pub(crate) const fn new() -> OnceCell<T> {
|
||||
OnceCell { queue: AtomicPtr::new(INCOMPLETE_PTR), value: UnsafeCell::new(None) }
|
||||
}
|
||||
|
||||
pub(crate) const fn with_value(value: T) -> OnceCell<T> {
|
||||
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<F, E>(&self, f: F) -> Result<(), E>
|
||||
where
|
||||
F: FnOnce() -> Result<T, E>,
|
||||
{
|
||||
let mut f = Some(f);
|
||||
let mut res: Result<(), E> = Ok(());
|
||||
let slot: *mut Option<T> = 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<T> {
|
||||
// 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<T>`.
|
||||
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<Option<Thread>>,
|
||||
signaled: AtomicBool,
|
||||
next: *mut Waiter,
|
||||
}
|
||||
|
||||
/// Drains and notifies the queue of waiters on drop.
|
||||
struct Guard<'a> {
|
||||
queue: &'a AtomicPtr<Waiter>,
|
||||
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<Waiter>, 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<Waiter>, 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<T>(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<T>(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::<u8>().wrapping_offset(offset).cast::<T>()
|
||||
(ptr as *mut u8).wrapping_offset(offset) as *mut T
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub(crate) fn map_addr<T>(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<T> OnceCell<T> {
|
||||
fn init(&self, f: impl FnOnce() -> T) {
|
||||
enum Void {}
|
||||
let _ = self.initialize(|| Ok::<T, Void>(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::<OnceCell<u32>>(), 4 * size_of::<u32>());
|
||||
}
|
||||
}
|
1412
vendor/once_cell/src/lib.rs
vendored
Normal file
1412
vendor/once_cell/src/lib.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
419
vendor/once_cell/src/race.rs
vendored
Normal file
419
vendor/once_cell/src/race.rs
vendored
Normal file
@ -0,0 +1,419 @@
|
||||
//! 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(feature = "critical-section")]
|
||||
use portable_atomic as atomic;
|
||||
#[cfg(not(feature = "critical-section"))]
|
||||
use core::sync::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<NonZeroUsize> {
|
||||
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<F>(&self, f: F) -> NonZeroUsize
|
||||
where
|
||||
F: FnOnce() -> NonZeroUsize,
|
||||
{
|
||||
enum Void {}
|
||||
match self.get_or_try_init(|| Ok::<NonZeroUsize, 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<F, E>(&self, f: F) -> Result<NonZeroUsize, E>
|
||||
where
|
||||
F: FnOnce() -> Result<NonZeroUsize, E>,
|
||||
{
|
||||
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<bool> {
|
||||
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<F>(&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<F, E>(&self, f: F) -> Result<bool, E>
|
||||
where
|
||||
F: FnOnce() -> Result<bool, E>,
|
||||
{
|
||||
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<T>,
|
||||
ghost: PhantomData<UnsafeCell<&'a T>>,
|
||||
}
|
||||
|
||||
// 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<F>(&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<F, E>(&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<T> {
|
||||
inner: AtomicPtr<T>,
|
||||
ghost: PhantomData<Option<Box<T>>>,
|
||||
}
|
||||
|
||||
impl<T> core::fmt::Debug for OnceBox<T> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "OnceBox({:?})", self.inner.load(Ordering::Relaxed))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for OnceBox<T> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for OnceBox<T> {
|
||||
fn drop(&mut self) {
|
||||
let ptr = *self.inner.get_mut();
|
||||
if !ptr.is_null() {
|
||||
drop(unsafe { Box::from_raw(ptr) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> OnceBox<T> {
|
||||
/// Creates a new empty cell.
|
||||
pub const fn new() -> OnceBox<T> {
|
||||
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<T>) -> Result<(), Box<T>> {
|
||||
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<F>(&self, f: F) -> &T
|
||||
where
|
||||
F: FnOnce() -> Box<T>,
|
||||
{
|
||||
enum Void {}
|
||||
match self.get_or_try_init(|| Ok::<Box<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<F, E>(&self, f: F) -> Result<&T, E>
|
||||
where
|
||||
F: FnOnce() -> Result<Box<T>, 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<T: Sync + Send> Sync for OnceBox<T> {}
|
||||
|
||||
/// ```compile_fail
|
||||
/// struct S(*mut ());
|
||||
/// unsafe impl Sync for S {}
|
||||
///
|
||||
/// fn share<T: Sync>(_: &T) {}
|
||||
/// share(&once_cell::race::OnceBox::<S>::new());
|
||||
/// ```
|
||||
fn _dummy() {}
|
||||
}
|
12
vendor/once_cell/tests/it/main.rs
vendored
Normal file
12
vendor/once_cell/tests/it/main.rs
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
mod 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;
|
128
vendor/once_cell/tests/it/race.rs
vendored
Normal file
128
vendor/once_cell/tests/it/race.rs
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
#[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));
|
||||
}
|
145
vendor/once_cell/tests/it/race_once_box.rs
vendored
Normal file
145
vendor/once_cell/tests/it/race_once_box.rs
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
#[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<AtomicUsize>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Pebble<T> {
|
||||
val: T,
|
||||
total: Arc<AtomicUsize>,
|
||||
}
|
||||
|
||||
impl<T> Drop for Pebble<T> {
|
||||
fn drop(&mut self) {
|
||||
self.total.fetch_sub(1, SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
impl Heap {
|
||||
fn total(&self) -> usize {
|
||||
self.total.load(SeqCst)
|
||||
}
|
||||
fn new_pebble<T>(&self, val: T) -> Pebble<T> {
|
||||
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<Foo> = Default::default();
|
||||
assert!(cell.get().is_none());
|
||||
}
|
176
vendor/once_cell/tests/it/sync_lazy.rs
vendored
Normal file
176
vendor/once_cell/tests/it/sync_lazy.rs
vendored
Normal file
@ -0,0 +1,176 @@
|
||||
use 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<u32, _> = 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<std::sync::Mutex<Foo>> = <_>::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<Vec<i32>> = 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<i32> {
|
||||
static XS: OnceCell<Vec<i32>> = 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<i32, _> = 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<String> = 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<T: Send + Sync>() {}
|
||||
assert_traits::<Lazy<String>>();
|
||||
}
|
309
vendor/once_cell/tests/it/sync_once_cell.rs
vendored
Normal file
309
vendor/once_cell/tests/it/sync_once_cell.rs
vendored
Normal file
@ -0,0 +1,309 @@
|
||||
use 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<i32> = 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::<String>::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<String> = 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<String> = 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::<String>::new() == OnceCell::new());
|
||||
assert!(OnceCell::<String>::new() != OnceCell::from("value".to_owned()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn into_inner() {
|
||||
let cell: OnceCell<String> = 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<Box<i32>> = OnceCell::new();
|
||||
let dangling_ref: Cell<Option<&i32>> = 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<i32> = eval_once! {
|
||||
|| -> Vec<i32> {
|
||||
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<String> = 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<T: Send + Sync>() {}
|
||||
assert_traits::<OnceCell<String>>();
|
||||
assert_traits::<Lazy<String>>();
|
||||
}
|
134
vendor/once_cell/tests/it/unsync_lazy.rs
vendored
Normal file
134
vendor/once_cell/tests/it/unsync_lazy.rs
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
use 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<u32, _> = 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<std::sync::Mutex<Foo>> = <_>::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<i32, _> = 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<String> = 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;
|
||||
}
|
||||
}
|
154
vendor/once_cell/tests/it/unsync_once_cell.rs
vendored
Normal file
154
vendor/once_cell/tests/it/unsync_once_cell.rs
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
use 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<i32> = 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::<String>::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<String> = 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::<String>::new() == OnceCell::new());
|
||||
assert!(OnceCell::<String>::new() != OnceCell::from("value".to_owned()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn into_inner() {
|
||||
let cell: OnceCell<String> = 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<Box<i32>> = OnceCell::new();
|
||||
let dangling_ref: Cell<Option<&i32>> = 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<T>` --+
|
||||
let _ = x.set(27); // <-- temporary (unique) borrow of inner `Option<T>` |
|
||||
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();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user