Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

View File

@@ -0,0 +1 @@
{"files":{"CHANGELOG.md":"539507c66fda98436c5d855a0647662d1c17485743ee874729848ba278999221","Cargo.lock":"889568d0fd17c9258ac391fbb7766676611910f47904a366153d2e9bf6889733","Cargo.toml":"e80a999988d7e208fb03f907b0332d9959ac14a6b1f1c62e8b7866dacbbe4d77","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"06d1d2a5a9cf3606d8a74051fb155c57b6c9d1019423572c823484988f296fae","src/barrier.rs":"b552b54a45800636120f7827537fa020665a055f4ceb3a79d1ef1b372eeac6b9","src/lib.rs":"278d410fc3d6168591b1d67aa2c6cc3740ac1c899305ddbe334af2190a06fcae","src/mutex.rs":"4f7258fd67a0ec6d5d8f724cea1ae59036b39f1475b0bc4068c64ae9ea6d1658","src/once_cell.rs":"a70c1d3a1c04c2b020c19b01a6092cd82d72a94ca5cc936764f223869fa91eaf","src/rwlock.rs":"21b63c139e4f9e1e29f0e593113fdb995438b87f2ee5b8f03c3626ae6e3c4468","src/rwlock/futures.rs":"b513fa13a7ee3e146d7039bbe8193087f2571d478307c0b0bffe9dd91ad7e0d4","src/rwlock/raw.rs":"c7f0e3a6dad26073ca502f43d229977ed48581349d3a3f9fc12b9c2965d46e24","src/semaphore.rs":"5040c728c84186a6ee4a8101c2bf7a640820cc7dcd127ff0c07f0a16c5de633f","tests/barrier.rs":"46d479150e207179eeecc2e8b49e0219936d522e79ea8faaec85c6a03982eb8f","tests/common/mod.rs":"27c48c3d67d0d647bdcf9ae45e2cd6006fb97b0bbd0114032bf75ac4f4d01d71","tests/loom.rs":"ec53be1b04bc93bafc1aaf65d3d318193dc2ebcc09cc008113ee39fe08151142","tests/mutex.rs":"1d6d3ed23065603f8c6143963aa4c4f933a5926ca24cfc4b168b8e7294afe4ee","tests/rwlock.rs":"d76339a43defe14adc1584f98ad2650fe39a8e46fc770a87de86f98d66b332ce","tests/semaphore.rs":"e6f6bd4b083858f2870af1e96c5e8631d8f977dea34a8e86fa37a2e0623b118c"},"package":"5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc"}

134
vendor/async-lock/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,134 @@
# Version 3.4.1
- Fix typos in docs. (#89)
# Version 3.4.0
- Port to `event-listener` v5.0.0. (#74)
# Version 3.3.0
- Add a `forget()` method for semaphore guards. (#73)
- Increase MSRV to v1.60. (#75)
# Version 3.2.0
- Add missing methods for blocking on locking with types wrapped in `Arc` (#71).
# Version 3.1.2
- Bump `event-listener` to version v4.0.0. (#69)
# Version 3.1.1
- Add a note to the documentation comparing this crate against `libstd`'s locks. (#58)
# Version 3.1.0
- Add a `Default` implementation for `OnceCell` (#63).
# Version 3.0.0
- **Breaking:** Add an enabled-by-default `std` feature that allows using this crate without the standard library. (#43)
- Support blocking and non-blocking operations on the same locks. (#56)
- Switch to a more efficient event notification mechanism. (#43)
# Version 2.8.0
- Fix a bug where the `SemaphoreGuard::acquire_arc` future would busy wait under certain conditions (#42).
- Add a `Semaphore::add_permits()` function to increase the number of available permits on the semaphore (#44).
- Make `RwLockReadGuard` covariant over its lifetime (#45)
- Add `RwLockReadGuardArc`, `RwLockWriteGuardArc`, and other reference counted guards for the `RwLock` type (#47).
- Loosen the `Send`/`Sync` bounds on certain future types (#48).
- Fix UB caused by the `MutexGuardArc::source` function allowing the user to drop an object in a different thread than the one it was acquired in (#50). This is a breaking change, but in the name of soundness. Therefore it doesn't break any valid behavior.
- Fix a bug where this crate would not compile properly on `wasm64` (#51).
# Version 2.7.0
- Replace some `async` blocks with manual futures (#34)
- Remove our dependency on `futures-lite` (#36)
- Mark guard types with `#[clippy::has_significant_drop]` (#37)
# Version 2.6.0
- Add `OnceCell`. (#27)
- Support wasm64.
# Version 2.5.0
- Fix an issue where the future returned by `Mutex::lock_arc`/`Semaphore::acquire_arc` holds a reference to `self`. (#20, #21)
# Version 2.4.0
- Add WASM support. (#14)
# Version 2.3.0
- Merge all subcrates.
# Version 2.2.0
- Add functions to upgrade and downgrade `RwLock` guards.
- Make all constructors `const fn`.
# Version 2.1.3
- Add `#![forbid(unsafe_code)]`.
# Version 2.1.2
- Update dependencies.
# Version 2.1.1
- Update crate description.
# Version 2.1.0
- Add `Barrier` and `Semaphore`.
# Version 2.0.1
- Update crate description.
# Version 2.0.0
- Only re-export `async-mutex` and `async-rwlock`.
# Version 1.1.5
- Replace the implementation with `async-mutex`.
# Version 1.1.4
- Replace `usize::MAX` with `std::usize::MAX`.
# Version 1.1.3
- Update dependencies.
# Version 1.1.2
- Fix a deadlock issue.
# Version 1.1.1
- Fix some typos.
# Version 1.1.0
- Make locking fair.
- Add `LockGuard::source()`.
# Version 1.0.2
- Bump the `event-listener` version.
- Add tests.
# Version 1.0.1
- Update Cargo categories.
# Version 1.0.0
- Initial version

831
vendor/async-lock/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,831 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "async-lock"
version = "3.4.1"
dependencies = [
"event-listener",
"event-listener-strategy",
"fastrand",
"flume",
"futures-lite",
"loom",
"pin-project-lite",
"waker-fn",
"wasm-bindgen-test",
]
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "bumpalo"
version = "3.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
[[package]]
name = "cc"
version = "1.2.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2"
dependencies = [
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
[[package]]
name = "concurrent-queue"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
dependencies = [
"crossbeam-utils",
"loom",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "event-listener"
version = "5.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae"
dependencies = [
"concurrent-queue",
"loom",
"parking",
"pin-project-lite",
]
[[package]]
name = "event-listener-strategy"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
dependencies = [
"event-listener",
"pin-project-lite",
]
[[package]]
name = "fastrand"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
name = "flume"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095"
dependencies = [
"futures-core",
"futures-sink",
"nanorand",
"spin",
]
[[package]]
name = "futures-core"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
name = "futures-io"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
[[package]]
name = "futures-lite"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532"
dependencies = [
"fastrand",
"futures-core",
"futures-io",
"parking",
"pin-project-lite",
]
[[package]]
name = "futures-sink"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
[[package]]
name = "generator"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d18470a76cb7f8ff746cf1f7470914f900252ec36bbc40b569d74b1258446827"
dependencies = [
"cc",
"cfg-if",
"libc",
"log",
"rustversion",
"windows",
]
[[package]]
name = "getrandom"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
dependencies = [
"cfg-if",
"js-sys",
"libc",
"wasi",
"wasm-bindgen",
]
[[package]]
name = "js-sys"
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
dependencies = [
"once_cell",
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.174"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]]
name = "lock_api"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "loom"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca"
dependencies = [
"cfg-if",
"generator",
"scoped-tls",
"tracing",
"tracing-subscriber",
]
[[package]]
name = "matchers"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
dependencies = [
"regex-automata 0.1.10",
]
[[package]]
name = "memchr"
version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "minicov"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b"
dependencies = [
"cc",
"walkdir",
]
[[package]]
name = "nanorand"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
dependencies = [
"getrandom",
]
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
dependencies = [
"overload",
"winapi",
]
[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "overload"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "parking"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
dependencies = [
"loom",
]
[[package]]
name = "pin-project-lite"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
[[package]]
name = "proc-macro2"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata 0.4.9",
"regex-syntax 0.8.5",
]
[[package]]
name = "regex-automata"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
dependencies = [
"regex-syntax 0.6.29",
]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax 0.8.5",
]
[[package]]
name = "regex-syntax"
version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rustversion"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "scoped-tls"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "sharded-slab"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
dependencies = [
"lazy_static",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
dependencies = [
"lock_api",
]
[[package]]
name = "syn"
version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thread_local"
version = "1.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
dependencies = [
"cfg-if",
]
[[package]]
name = "tracing"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
dependencies = [
"pin-project-lite",
"tracing-core",
]
[[package]]
name = "tracing-core"
version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
dependencies = [
"once_cell",
"valuable",
]
[[package]]
name = "tracing-log"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
dependencies = [
"log",
"once_cell",
"tracing-core",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
dependencies = [
"matchers",
"nu-ansi-term",
"once_cell",
"regex",
"sharded-slab",
"smallvec",
"thread_local",
"tracing",
"tracing-core",
"tracing-log",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "valuable"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
[[package]]
name = "waker-fn"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasm-bindgen"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
dependencies = [
"cfg-if",
"once_cell",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
dependencies = [
"bumpalo",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
dependencies = [
"cfg-if",
"js-sys",
"once_cell",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
dependencies = [
"unicode-ident",
]
[[package]]
name = "wasm-bindgen-test"
version = "0.3.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66c8d5e33ca3b6d9fa3b4676d774c5778031d27a578c2b007f905acf816152c3"
dependencies = [
"js-sys",
"minicov",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-bindgen-test-macro",
]
[[package]]
name = "wasm-bindgen-test-macro"
version = "0.3.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "web-sys"
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.61.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
dependencies = [
"windows-collections",
"windows-core",
"windows-future",
"windows-link",
"windows-numerics",
]
[[package]]
name = "windows-collections"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
dependencies = [
"windows-core",
]
[[package]]
name = "windows-core"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link",
"windows-result",
"windows-strings",
]
[[package]]
name = "windows-future"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
dependencies = [
"windows-core",
"windows-link",
"windows-threading",
]
[[package]]
name = "windows-implement"
version = "0.60.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-interface"
version = "0.59.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-link"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
[[package]]
name = "windows-numerics"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
dependencies = [
"windows-core",
"windows-link",
]
[[package]]
name = "windows-result"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows-threading"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6"
dependencies = [
"windows-link",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

109
vendor/async-lock/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,109 @@
# 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 = "async-lock"
version = "3.4.1"
authors = ["Stjepan Glavina <stjepang@gmail.com>"]
build = false
exclude = ["/.*"]
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "Async synchronization primitives"
readme = "README.md"
keywords = [
"lock",
"mutex",
"rwlock",
"semaphore",
"barrier",
]
categories = [
"asynchronous",
"concurrency",
]
license = "Apache-2.0 OR MIT"
repository = "https://github.com/smol-rs/async-lock"
[features]
default = ["std"]
loom = [
"event-listener/loom",
"dep:loom",
]
std = [
"event-listener/std",
"event-listener-strategy/std",
]
[lib]
name = "async_lock"
path = "src/lib.rs"
[[test]]
name = "barrier"
path = "tests/barrier.rs"
[[test]]
name = "loom"
path = "tests/loom.rs"
[[test]]
name = "mutex"
path = "tests/mutex.rs"
[[test]]
name = "rwlock"
path = "tests/rwlock.rs"
[[test]]
name = "semaphore"
path = "tests/semaphore.rs"
[dependencies.event-listener]
version = "5.0.0"
default-features = false
[dependencies.event-listener-strategy]
version = "0.5.0"
default-features = false
[dependencies.pin-project-lite]
version = "0.2.11"
[dev-dependencies.fastrand]
version = "2.0.0"
[dev-dependencies.flume]
version = "0.11.0"
[dev-dependencies.futures-lite]
version = "2.0.0"
[dev-dependencies.waker-fn]
version = "1.1.0"
[target."cfg(loom)".dependencies.loom]
version = "0.7"
optional = true
[target.'cfg(target_family = "wasm")'.dev-dependencies.wasm-bindgen-test]
version = "0.3"
[lints.rust.unexpected_cfgs]
level = "warn"
priority = 0
check-cfg = ["cfg(loom)"]

201
vendor/async-lock/LICENSE-APACHE vendored Normal file
View 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/async-lock/LICENSE-MIT vendored Normal file
View 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.

34
vendor/async-lock/README.md vendored Normal file
View File

@@ -0,0 +1,34 @@
# async-lock
[![Build](https://github.com/smol-rs/async-lock/workflows/Build%20and%20test/badge.svg)](
https://github.com/smol-rs/async-lock/actions)
[![License](https://img.shields.io/badge/license-Apache--2.0_OR_MIT-blue.svg)](
https://github.com/smol-rs/async-lock)
[![Cargo](https://img.shields.io/crates/v/async-lock.svg)](
https://crates.io/crates/async-lock)
[![Documentation](https://docs.rs/async-lock/badge.svg)](
https://docs.rs/async-lock)
Async synchronization primitives.
This crate provides the following primitives:
* `Barrier` - enables tasks to synchronize all together at the same time.
* `Mutex` - a mutual exclusion lock.
* `RwLock` - a reader-writer lock, allowing any number of readers or a single writer.
* `Semaphore` - limits the number of concurrent operations.
## License
Licensed under either of
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
#### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.

290
vendor/async-lock/src/barrier.rs vendored Normal file
View File

@@ -0,0 +1,290 @@
use event_listener::{Event, EventListener};
use event_listener_strategy::{easy_wrapper, EventListenerFuture, Strategy};
use core::fmt;
use core::pin::Pin;
use core::task::Poll;
use crate::futures::Lock;
use crate::Mutex;
/// A counter to synchronize multiple tasks at the same time.
#[derive(Debug)]
pub struct Barrier {
n: usize,
state: Mutex<State>,
event: Event,
}
#[derive(Debug)]
struct State {
count: usize,
generation_id: u64,
}
impl Barrier {
const_fn! {
const_if: #[cfg(not(loom))];
/// Creates a barrier that can block the given number of tasks.
///
/// A barrier will block `n`-1 tasks which call [`wait()`] and then wake up all tasks
/// at once when the `n`th task calls [`wait()`].
///
/// [`wait()`]: `Barrier::wait()`
///
/// # Examples
///
/// ```
/// use async_lock::Barrier;
///
/// let barrier = Barrier::new(5);
/// ```
pub const fn new(n: usize) -> Barrier {
Barrier {
n,
state: Mutex::new(State {
count: 0,
generation_id: 0,
}),
event: Event::new(),
}
}
}
/// Blocks the current task until all tasks reach this point.
///
/// Barriers are reusable after all tasks have synchronized, and can be used continuously.
///
/// Returns a [`BarrierWaitResult`] indicating whether this task is the "leader", meaning the
/// last task to call this method.
///
/// # Examples
///
/// ```
/// use async_lock::Barrier;
/// use futures_lite::future;
/// use std::sync::Arc;
/// use std::thread;
///
/// let barrier = Arc::new(Barrier::new(5));
///
/// for _ in 0..5 {
/// let b = barrier.clone();
/// thread::spawn(move || {
/// future::block_on(async {
/// // The same messages will be printed together.
/// // There will NOT be interleaving of "before" and "after".
/// println!("before wait");
/// b.wait().await;
/// println!("after wait");
/// });
/// });
/// }
/// ```
pub fn wait(&self) -> BarrierWait<'_> {
BarrierWait::_new(BarrierWaitInner {
barrier: self,
lock: Some(self.state.lock()),
evl: None,
state: WaitState::Initial,
})
}
/// Blocks the current thread until all tasks reach this point.
///
/// Barriers are reusable after all tasks have synchronized, and can be used continuously.
///
/// Returns a [`BarrierWaitResult`] indicating whether this task is the "leader", meaning the
/// last task to call this method.
///
/// # Blocking
///
/// Rather than using asynchronous waiting, like the [`wait`][`Barrier::wait`] method,
/// this method will block the current thread until the wait is complete.
///
/// This method should not be used in an asynchronous context. It is intended to be
/// used in a way that a barrier can be used in both asynchronous and synchronous contexts.
/// Calling this method in an asynchronous context may result in a deadlock.
///
/// # Examples
///
/// ```
/// use async_lock::Barrier;
/// use futures_lite::future;
/// use std::sync::Arc;
/// use std::thread;
///
/// let barrier = Arc::new(Barrier::new(5));
///
/// for _ in 0..5 {
/// let b = barrier.clone();
/// thread::spawn(move || {
/// // The same messages will be printed together.
/// // There will NOT be interleaving of "before" and "after".
/// println!("before wait");
/// b.wait_blocking();
/// println!("after wait");
/// });
/// }
/// # // Wait for threads to stop.
/// # std::thread::sleep(std::time::Duration::from_secs(1));
/// ```
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub fn wait_blocking(&self) -> BarrierWaitResult {
self.wait().wait()
}
}
easy_wrapper! {
/// The future returned by [`Barrier::wait()`].
pub struct BarrierWait<'a>(BarrierWaitInner<'a> => BarrierWaitResult);
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub(crate) wait();
}
pin_project_lite::pin_project! {
/// The future returned by [`Barrier::wait()`].
struct BarrierWaitInner<'a> {
// The barrier to wait on.
barrier: &'a Barrier,
// The ongoing mutex lock operation we are blocking on.
#[pin]
lock: Option<Lock<'a, State>>,
// An event listener for the `barrier.event` event.
evl: Option<EventListener>,
// The current state of the future.
state: WaitState,
}
}
impl fmt::Debug for BarrierWait<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("BarrierWait { .. }")
}
}
enum WaitState {
/// We are getting the original values of the state.
Initial,
/// We are waiting for the listener to complete.
Waiting { local_gen: u64 },
/// Waiting to re-acquire the lock to check the state again.
Reacquiring { local_gen: u64 },
}
impl EventListenerFuture for BarrierWaitInner<'_> {
type Output = BarrierWaitResult;
fn poll_with_strategy<'a, S: Strategy<'a>>(
self: Pin<&mut Self>,
strategy: &mut S,
cx: &mut S::Context,
) -> Poll<Self::Output> {
let mut this = self.project();
loop {
match this.state {
WaitState::Initial => {
// See if the lock is ready yet.
let mut state = ready!(this
.lock
.as_mut()
.as_pin_mut()
.unwrap()
.poll_with_strategy(strategy, cx));
this.lock.as_mut().set(None);
let local_gen = state.generation_id;
state.count += 1;
if state.count < this.barrier.n {
// We need to wait for the event.
*this.evl = Some(this.barrier.event.listen());
*this.state = WaitState::Waiting { local_gen };
} else {
// We are the last one.
state.count = 0;
state.generation_id = state.generation_id.wrapping_add(1);
this.barrier.event.notify(usize::MAX);
return Poll::Ready(BarrierWaitResult { is_leader: true });
}
}
WaitState::Waiting { local_gen } => {
ready!(strategy.poll(this.evl, cx));
// We are now re-acquiring the mutex.
this.lock.as_mut().set(Some(this.barrier.state.lock()));
*this.state = WaitState::Reacquiring {
local_gen: *local_gen,
};
}
WaitState::Reacquiring { local_gen } => {
// Acquire the local state again.
let state = ready!(this
.lock
.as_mut()
.as_pin_mut()
.unwrap()
.poll_with_strategy(strategy, cx));
this.lock.set(None);
if *local_gen == state.generation_id && state.count < this.barrier.n {
// We need to wait for the event again.
*this.evl = Some(this.barrier.event.listen());
*this.state = WaitState::Waiting {
local_gen: *local_gen,
};
} else {
// We are ready, but not the leader.
return Poll::Ready(BarrierWaitResult { is_leader: false });
}
}
}
}
}
}
/// Returned by [`Barrier::wait()`] when all tasks have called it.
///
/// # Examples
///
/// ```
/// # futures_lite::future::block_on(async {
/// use async_lock::Barrier;
///
/// let barrier = Barrier::new(1);
/// let barrier_wait_result = barrier.wait().await;
/// # });
/// ```
#[derive(Debug, Clone)]
pub struct BarrierWaitResult {
is_leader: bool,
}
impl BarrierWaitResult {
/// Returns `true` if this task was the last to call to [`Barrier::wait()`].
///
/// # Examples
///
/// ```
/// # futures_lite::future::block_on(async {
/// use async_lock::Barrier;
/// use futures_lite::future;
///
/// let barrier = Barrier::new(2);
/// let (a, b) = future::zip(barrier.wait(), barrier.wait()).await;
/// assert_eq!(a.is_leader(), false);
/// assert_eq!(b.is_leader(), true);
/// # });
/// ```
pub fn is_leader(&self) -> bool {
self.is_leader
}
}

168
vendor/async-lock/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,168 @@
//! Async synchronization primitives.
//!
//! This crate provides the following primitives:
//!
//! * [`Barrier`] - enables tasks to synchronize all together at the same time.
//! * [`Mutex`] - a mutual exclusion lock.
//! * [`RwLock`] - a reader-writer lock, allowing any number of readers or a single writer.
//! * [`Semaphore`] - limits the number of concurrent operations.
//!
//! ## Relationship with `std::sync`
//!
//! In general, you should consider using [`std::sync`] types over types from this crate.
//!
//! There are two primary use cases for types from this crate:
//!
//! - You need to use a synchronization primitive in a `no_std` environment.
//! - You need to hold a lock across an `.await` point.
//! (Holding an [`std::sync`] lock guard across an `.await` will make your future non-`Send`,
//! and is also highly likely to cause deadlocks.)
//!
//! If you already use `libstd` and you aren't holding locks across await points (there is a
//! Clippy lint called [`await_holding_lock`] that emits warnings for this scenario), you should
//! consider [`std::sync`] instead of this crate. Those types are optimized for the currently
//! running operating system, are less complex and are generally much faster.
//!
//! In contrast, `async-lock`'s notification system uses `std::sync::Mutex` under the hood if
//! the `std` feature is enabled, and will fall back to a significantly slower strategy if it is
//! not. So, there are few cases where `async-lock` is a win for performance over [`std::sync`].
//!
//! [`std::sync`]: https://doc.rust-lang.org/std/sync/index.html
//! [`await_holding_lock`]: https://rust-lang.github.io/rust-clippy/stable/index.html#/await_holding_lock
#![cfg_attr(not(feature = "std"), no_std)]
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
#![doc(
html_favicon_url = "https://raw.githubusercontent.com/smol-rs/smol/master/assets/images/logo_fullsize_transparent.png"
)]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/smol-rs/smol/master/assets/images/logo_fullsize_transparent.png"
)]
extern crate alloc;
/// Simple macro to extract the value of `Poll` or return `Pending`.
///
/// TODO: Drop in favor of `core::task::ready`, once MSRV is bumped to 1.64.
macro_rules! ready {
($e:expr) => {{
use ::core::task::Poll;
match $e {
Poll::Ready(v) => v,
Poll::Pending => return Poll::Pending,
}
}};
}
/// Pins a variable on the stack.
///
/// TODO: Drop in favor of `core::pin::pin`, once MSRV is bumped to 1.68.
#[cfg(all(feature = "std", not(target_family = "wasm")))]
macro_rules! pin {
($($x:ident),* $(,)?) => {
$(
let mut $x = $x;
#[allow(unused_mut)]
let mut $x = unsafe {
core::pin::Pin::new_unchecked(&mut $x)
};
)*
}
}
/// Make the given function const if the given condition is true.
macro_rules! const_fn {
(
const_if: #[cfg($($cfg:tt)+)];
$(#[$($attr:tt)*])*
$vis:vis const fn $($rest:tt)*
) => {
#[cfg($($cfg)+)]
$(#[$($attr)*])*
$vis const fn $($rest)*
#[cfg(not($($cfg)+))]
$(#[$($attr)*])*
$vis fn $($rest)*
};
}
mod barrier;
mod mutex;
mod once_cell;
mod rwlock;
mod semaphore;
pub use barrier::{Barrier, BarrierWaitResult};
pub use mutex::{Mutex, MutexGuard, MutexGuardArc};
pub use once_cell::OnceCell;
pub use rwlock::{
RwLock, RwLockReadGuard, RwLockReadGuardArc, RwLockUpgradableReadGuard,
RwLockUpgradableReadGuardArc, RwLockWriteGuard, RwLockWriteGuardArc,
};
pub use semaphore::{Semaphore, SemaphoreGuard, SemaphoreGuardArc};
pub mod futures {
//! Named futures for use with `async_lock` primitives.
pub use crate::barrier::BarrierWait;
pub use crate::mutex::{Lock, LockArc};
pub use crate::rwlock::futures::{
Read, ReadArc, UpgradableRead, UpgradableReadArc, Upgrade, UpgradeArc, Write, WriteArc,
};
pub use crate::semaphore::{Acquire, AcquireArc};
}
#[cfg(not(loom))]
/// Synchronization primitive implementation.
mod sync {
pub(super) use core::sync::atomic;
pub(super) trait WithMut {
type Output;
fn with_mut<F, R>(&mut self, f: F) -> R
where
F: FnOnce(&mut Self::Output) -> R;
}
impl WithMut for atomic::AtomicUsize {
type Output = usize;
#[inline]
fn with_mut<F, R>(&mut self, f: F) -> R
where
F: FnOnce(&mut Self::Output) -> R,
{
f(self.get_mut())
}
}
}
#[cfg(loom)]
/// Synchronization primitive implementation.
mod sync {
pub(super) use loom::sync::atomic;
}
#[cold]
fn abort() -> ! {
// For no_std targets, panicking while panicking is defined as an abort
#[cfg(not(feature = "std"))]
{
struct Bomb;
impl Drop for Bomb {
fn drop(&mut self) {
panic!("Panicking while panicking to abort")
}
}
let _bomb = Bomb;
panic!("Panicking while panicking to abort")
}
// For libstd targets, abort using std::process::abort
#[cfg(feature = "std")]
std::process::abort()
}

762
vendor/async-lock/src/mutex.rs vendored Normal file
View File

@@ -0,0 +1,762 @@
use core::borrow::Borrow;
use core::cell::UnsafeCell;
use core::fmt;
use core::marker::{PhantomData, PhantomPinned};
use core::ops::{Deref, DerefMut};
use core::pin::Pin;
use core::task::Poll;
use alloc::sync::Arc;
// We don't use loom::UnsafeCell as that doesn't work with the Mutex API.
use crate::sync::atomic::{AtomicUsize, Ordering};
#[cfg(all(feature = "std", not(target_family = "wasm")))]
use std::time::{Duration, Instant};
use event_listener::{Event, EventListener};
use event_listener_strategy::{easy_wrapper, EventListenerFuture};
/// An async mutex.
///
/// The locking mechanism uses eventual fairness to ensure locking will be fair on average without
/// sacrificing performance. This is done by forcing a fair lock whenever a lock operation is
/// starved for longer than 0.5 milliseconds.
///
/// # Examples
///
/// ```
/// # futures_lite::future::block_on(async {
/// use async_lock::Mutex;
///
/// let m = Mutex::new(1);
///
/// let mut guard = m.lock().await;
/// *guard = 2;
///
/// assert!(m.try_lock().is_none());
/// drop(guard);
/// assert_eq!(*m.try_lock().unwrap(), 2);
/// # })
/// ```
pub struct Mutex<T: ?Sized> {
/// Current state of the mutex.
///
/// The least significant bit is set to 1 if the mutex is locked.
/// The other bits hold the number of starved lock operations.
state: AtomicUsize,
/// Lock operations waiting for the mutex to be released.
lock_ops: Event,
/// The value inside the mutex.
data: UnsafeCell<T>,
}
unsafe impl<T: Send + ?Sized> Send for Mutex<T> {}
unsafe impl<T: Send + ?Sized> Sync for Mutex<T> {}
impl<T> Mutex<T> {
const_fn! {
const_if: #[cfg(not(loom))];
/// Creates a new async mutex.
///
/// # Examples
///
/// ```
/// use async_lock::Mutex;
///
/// let mutex = Mutex::new(0);
/// ```
pub const fn new(data: T) -> Mutex<T> {
Mutex {
state: AtomicUsize::new(0),
lock_ops: Event::new(),
data: UnsafeCell::new(data),
}
}
}
/// Consumes the mutex, returning the underlying data.
///
/// # Examples
///
/// ```
/// use async_lock::Mutex;
///
/// let mutex = Mutex::new(10);
/// assert_eq!(mutex.into_inner(), 10);
/// ```
pub fn into_inner(self) -> T {
self.data.into_inner()
}
}
impl<T: ?Sized> Mutex<T> {
/// Acquires the mutex.
///
/// Returns a guard that releases the mutex when dropped.
///
/// # Examples
///
/// ```
/// # futures_lite::future::block_on(async {
/// use async_lock::Mutex;
///
/// let mutex = Mutex::new(10);
/// let guard = mutex.lock().await;
/// assert_eq!(*guard, 10);
/// # })
/// ```
#[inline]
pub fn lock(&self) -> Lock<'_, T> {
Lock::_new(LockInner {
mutex: self,
acquire_slow: None,
})
}
/// Acquires the mutex using the blocking strategy.
///
/// Returns a guard that releases the mutex when dropped.
///
/// # Blocking
///
/// Rather than using asynchronous waiting, like the [`lock`][Mutex::lock] method,
/// this method will block the current thread until the lock is acquired.
///
/// This method should not be used in an asynchronous context. It is intended to be
/// used in a way that a mutex can be used in both asynchronous and synchronous contexts.
/// Calling this method in an asynchronous context may result in a deadlock.
///
/// # Examples
///
/// ```
/// use async_lock::Mutex;
///
/// let mutex = Mutex::new(10);
/// let guard = mutex.lock_blocking();
/// assert_eq!(*guard, 10);
/// ```
#[cfg(all(feature = "std", not(target_family = "wasm")))]
#[inline]
pub fn lock_blocking(&self) -> MutexGuard<'_, T> {
self.lock().wait()
}
/// Attempts to acquire the mutex.
///
/// If the mutex could not be acquired at this time, then [`None`] is returned. Otherwise, a
/// guard is returned that releases the mutex when dropped.
///
/// # Examples
///
/// ```
/// use async_lock::Mutex;
///
/// let mutex = Mutex::new(10);
/// if let Some(guard) = mutex.try_lock() {
/// assert_eq!(*guard, 10);
/// }
/// # ;
/// ```
#[inline]
pub fn try_lock(&self) -> Option<MutexGuard<'_, T>> {
if self
.state
.compare_exchange(0, 1, Ordering::Acquire, Ordering::Acquire)
.is_ok()
{
Some(MutexGuard(self))
} else {
None
}
}
/// Returns a mutable reference to the underlying data.
///
/// Since this call borrows the mutex mutably, no actual locking takes place -- the mutable
/// borrow statically guarantees the mutex is not already acquired.
///
/// # Examples
///
/// ```
/// # futures_lite::future::block_on(async {
/// use async_lock::Mutex;
///
/// let mut mutex = Mutex::new(0);
/// *mutex.get_mut() = 10;
/// assert_eq!(*mutex.lock().await, 10);
/// # })
/// ```
pub fn get_mut(&mut self) -> &mut T {
self.data.get_mut()
}
/// Unlocks the mutex directly.
///
/// # Safety
///
/// This function is intended to be used only in the case where the mutex is locked,
/// and the guard is subsequently forgotten. Calling this while you don't hold a lock
/// on the mutex will likely lead to UB.
pub(crate) unsafe fn unlock_unchecked(&self) {
// Remove the last bit and notify a waiting lock operation.
self.state.fetch_sub(1, Ordering::Release);
self.lock_ops.notify(1);
}
}
impl<T: ?Sized> Mutex<T> {
/// Acquires the mutex and clones a reference to it.
///
/// Returns an owned guard that releases the mutex when dropped.
///
/// # Examples
///
/// ```
/// # futures_lite::future::block_on(async {
/// use async_lock::Mutex;
/// use std::sync::Arc;
///
/// let mutex = Arc::new(Mutex::new(10));
/// let guard = mutex.lock_arc().await;
/// assert_eq!(*guard, 10);
/// # })
/// ```
#[inline]
pub fn lock_arc(self: &Arc<Self>) -> LockArc<T> {
LockArc::_new(LockArcInnards::Unpolled {
mutex: Some(self.clone()),
})
}
/// Acquires the mutex and clones a reference to it using the blocking strategy.
///
/// Returns an owned guard that releases the mutex when dropped.
///
/// # Blocking
///
/// Rather than using asynchronous waiting, like the [`lock_arc`][Mutex::lock_arc] method,
/// this method will block the current thread until the lock is acquired.
///
/// This method should not be used in an asynchronous context. It is intended to be
/// used in a way that a mutex can be used in both asynchronous and synchronous contexts.
/// Calling this method in an asynchronous context may result in a deadlock.
///
/// # Examples
///
/// ```
/// use async_lock::Mutex;
/// use std::sync::Arc;
///
/// let mutex = Arc::new(Mutex::new(10));
/// let guard = mutex.lock_arc_blocking();
/// assert_eq!(*guard, 10);
/// ```
#[cfg(all(feature = "std", not(target_family = "wasm")))]
#[inline]
pub fn lock_arc_blocking(self: &Arc<Self>) -> MutexGuardArc<T> {
self.lock_arc().wait()
}
/// Attempts to acquire the mutex and clone a reference to it.
///
/// If the mutex could not be acquired at this time, then [`None`] is returned. Otherwise, an
/// owned guard is returned that releases the mutex when dropped.
///
/// # Examples
///
/// ```
/// use async_lock::Mutex;
/// use std::sync::Arc;
///
/// let mutex = Arc::new(Mutex::new(10));
/// if let Some(guard) = mutex.try_lock() {
/// assert_eq!(*guard, 10);
/// }
/// # ;
/// ```
#[inline]
pub fn try_lock_arc(self: &Arc<Self>) -> Option<MutexGuardArc<T>> {
if self
.state
.compare_exchange(0, 1, Ordering::Acquire, Ordering::Acquire)
.is_ok()
{
Some(MutexGuardArc(self.clone()))
} else {
None
}
}
}
impl<T: fmt::Debug + ?Sized> fmt::Debug for Mutex<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
struct Locked;
impl fmt::Debug for Locked {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("<locked>")
}
}
match self.try_lock() {
None => f.debug_struct("Mutex").field("data", &Locked).finish(),
Some(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(),
}
}
}
impl<T> From<T> for Mutex<T> {
fn from(val: T) -> Mutex<T> {
Mutex::new(val)
}
}
impl<T: Default> Default for Mutex<T> {
fn default() -> Mutex<T> {
Mutex::new(Default::default())
}
}
easy_wrapper! {
/// The future returned by [`Mutex::lock`].
pub struct Lock<'a, T: ?Sized>(LockInner<'a, T> => MutexGuard<'a, T>);
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub(crate) wait();
}
pin_project_lite::pin_project! {
/// Inner future for acquiring the mutex.
struct LockInner<'a, T: ?Sized> {
// Reference to the mutex.
mutex: &'a Mutex<T>,
// The future that waits for the mutex to become available.
#[pin]
acquire_slow: Option<AcquireSlow<&'a Mutex<T>, T>>,
}
}
unsafe impl<T: Send + ?Sized> Send for Lock<'_, T> {}
unsafe impl<T: Sync + ?Sized> Sync for Lock<'_, T> {}
impl<T: ?Sized> fmt::Debug for Lock<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Lock { .. }")
}
}
impl<'a, T: ?Sized> EventListenerFuture for LockInner<'a, T> {
type Output = MutexGuard<'a, T>;
#[inline]
fn poll_with_strategy<'x, S: event_listener_strategy::Strategy<'x>>(
self: Pin<&mut Self>,
strategy: &mut S,
context: &mut S::Context,
) -> Poll<Self::Output> {
let mut this = self.project();
// This may seem weird, but the borrow checker complains otherwise.
if this.acquire_slow.is_none() {
match this.mutex.try_lock() {
Some(guard) => return Poll::Ready(guard),
None => {
this.acquire_slow.set(Some(AcquireSlow::new(this.mutex)));
}
}
}
ready!(this
.acquire_slow
.as_pin_mut()
.unwrap()
.poll_with_strategy(strategy, context));
Poll::Ready(MutexGuard(this.mutex))
}
}
easy_wrapper! {
/// The future returned by [`Mutex::lock_arc`].
pub struct LockArc<T: ?Sized>(LockArcInnards<T> => MutexGuardArc<T>);
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub(crate) wait();
}
pin_project_lite::pin_project! {
#[project = LockArcInnardsProj]
enum LockArcInnards<T: ?Sized> {
/// We have not tried to poll the fast path yet.
Unpolled { mutex: Option<Arc<Mutex<T>>> },
/// We are acquiring the mutex through the slow path.
AcquireSlow {
#[pin]
inner: AcquireSlow<Arc<Mutex<T>>, T>
},
}
}
unsafe impl<T: Send + ?Sized> Send for LockArc<T> {}
unsafe impl<T: Sync + ?Sized> Sync for LockArc<T> {}
impl<T: ?Sized> fmt::Debug for LockArcInnards<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("LockArc { .. }")
}
}
impl<T: ?Sized> EventListenerFuture for LockArcInnards<T> {
type Output = MutexGuardArc<T>;
fn poll_with_strategy<'a, S: event_listener_strategy::Strategy<'a>>(
mut self: Pin<&mut Self>,
strategy: &mut S,
context: &mut S::Context,
) -> Poll<Self::Output> {
// Set the inner future if needed.
if let LockArcInnardsProj::Unpolled { mutex } = self.as_mut().project() {
let mutex = mutex.take().expect("mutex taken more than once");
// Try the fast path before trying to register slowly.
if let Some(guard) = mutex.try_lock_arc() {
return Poll::Ready(guard);
}
// Set the inner future to the slow acquire path.
self.as_mut().set(LockArcInnards::AcquireSlow {
inner: AcquireSlow::new(mutex),
});
}
// Poll the inner future.
let value = match self.project() {
LockArcInnardsProj::AcquireSlow { inner } => {
ready!(inner.poll_with_strategy(strategy, context))
}
_ => unreachable!(),
};
Poll::Ready(MutexGuardArc(value))
}
}
pin_project_lite::pin_project! {
/// Future for acquiring the mutex slowly.
struct AcquireSlow<B: Borrow<Mutex<T>>, T: ?Sized> {
// Reference to the mutex.
mutex: Option<B>,
// The event listener waiting on the mutex.
listener: Option<EventListener>,
// The point at which the mutex lock was started.
start: Start,
// This lock operation is starving.
starved: bool,
// Capture the `T` lifetime.
#[pin]
_marker: PhantomData<T>,
// Keeping this type `!Unpin` enables future optimizations.
#[pin]
_pin: PhantomPinned
}
impl<T: ?Sized, B: Borrow<Mutex<T>>> PinnedDrop for AcquireSlow<B, T> {
fn drop(this: Pin<&mut Self>) {
// Make sure the starvation counter is decremented.
this.take_mutex();
}
}
}
/// `pin_project_lite` doesn't support `#[cfg]` yet, so we have to do this manually.
struct Start {
#[cfg(all(feature = "std", not(target_family = "wasm")))]
start: Option<Instant>,
}
impl<T: ?Sized, B: Borrow<Mutex<T>>> AcquireSlow<B, T> {
/// Create a new `AcquireSlow` future.
#[cold]
fn new(mutex: B) -> Self {
AcquireSlow {
mutex: Some(mutex),
listener: None,
start: Start {
#[cfg(all(feature = "std", not(target_family = "wasm")))]
start: None,
},
starved: false,
_marker: PhantomData,
_pin: PhantomPinned,
}
}
/// Take the mutex reference out, decrementing the counter if necessary.
fn take_mutex(self: Pin<&mut Self>) -> Option<B> {
let this = self.project();
let mutex = this.mutex.take();
if *this.starved {
if let Some(mutex) = mutex.as_ref() {
// Decrement this counter before we exit.
mutex.borrow().state.fetch_sub(2, Ordering::Release);
}
}
mutex
}
}
impl<T: ?Sized, B: Unpin + Borrow<Mutex<T>>> EventListenerFuture for AcquireSlow<B, T> {
type Output = B;
#[cold]
fn poll_with_strategy<'a, S: event_listener_strategy::Strategy<'a>>(
mut self: Pin<&mut Self>,
strategy: &mut S,
context: &mut S::Context,
) -> Poll<Self::Output> {
let this = self.as_mut().project();
#[cfg(all(feature = "std", not(target_family = "wasm")))]
let start = *this.start.start.get_or_insert_with(Instant::now);
let mutex = Borrow::<Mutex<T>>::borrow(
this.mutex.as_ref().expect("future polled after completion"),
);
// Only use this hot loop if we aren't currently starved.
if !*this.starved {
loop {
// Start listening for events.
if this.listener.is_none() {
*this.listener = Some(mutex.lock_ops.listen());
// Try locking if nobody is being starved.
match mutex
.state
.compare_exchange(0, 1, Ordering::Acquire, Ordering::Acquire)
.unwrap_or_else(|x| x)
{
// Lock acquired!
0 => return Poll::Ready(self.take_mutex().unwrap()),
// Lock is held and nobody is starved.
1 => {}
// Somebody is starved.
_ => break,
}
} else {
ready!(strategy.poll(this.listener, context));
// Try locking if nobody is being starved.
match mutex
.state
.compare_exchange(0, 1, Ordering::Acquire, Ordering::Acquire)
.unwrap_or_else(|x| x)
{
// Lock acquired!
0 => return Poll::Ready(self.take_mutex().unwrap()),
// Lock is held and nobody is starved.
1 => {}
// Somebody is starved.
_ => {
// Notify the first listener in line because we probably received a
// notification that was meant for a starved task.
mutex.lock_ops.notify(1);
break;
}
}
// If waiting for too long, fall back to a fairer locking strategy that will prevent
// newer lock operations from starving us forever.
#[cfg(all(feature = "std", not(target_family = "wasm")))]
if start.elapsed() > Duration::from_micros(500) {
break;
}
}
}
// Increment the number of starved lock operations.
if mutex.state.fetch_add(2, Ordering::Release) > usize::MAX / 2 {
// In case of potential overflow, abort.
crate::abort();
}
// Indicate that we are now starving and will use a fairer locking strategy.
*this.starved = true;
}
// Fairer locking loop.
loop {
if this.listener.is_none() {
// Start listening for events.
*this.listener = Some(mutex.lock_ops.listen());
// Try locking if nobody else is being starved.
match mutex
.state
.compare_exchange(2, 2 | 1, Ordering::Acquire, Ordering::Acquire)
.unwrap_or_else(|x| x)
{
// Lock acquired!
2 => return Poll::Ready(self.take_mutex().unwrap()),
// Lock is held by someone.
s if s % 2 == 1 => {}
// Lock is available.
_ => {
// Be fair: notify the first listener and then go wait in line.
mutex.lock_ops.notify(1);
}
}
} else {
// Wait for a notification.
ready!(strategy.poll(this.listener, context));
// Try acquiring the lock without waiting for others.
if mutex.state.fetch_or(1, Ordering::Acquire) % 2 == 0 {
return Poll::Ready(self.take_mutex().unwrap());
}
}
}
}
}
/// A guard that releases the mutex when dropped.
#[clippy::has_significant_drop]
pub struct MutexGuard<'a, T: ?Sized>(&'a Mutex<T>);
unsafe impl<T: Send + ?Sized> Send for MutexGuard<'_, T> {}
unsafe impl<T: Sync + ?Sized> Sync for MutexGuard<'_, T> {}
impl<'a, T: ?Sized> MutexGuard<'a, T> {
/// Returns a reference to the mutex a guard came from.
///
/// # Examples
///
/// ```
/// # futures_lite::future::block_on(async {
/// use async_lock::{Mutex, MutexGuard};
///
/// let mutex = Mutex::new(10i32);
/// let guard = mutex.lock().await;
/// dbg!(MutexGuard::source(&guard));
/// # })
/// ```
pub fn source(guard: &MutexGuard<'a, T>) -> &'a Mutex<T> {
guard.0
}
}
impl<T: ?Sized> Drop for MutexGuard<'_, T> {
#[inline]
fn drop(&mut self) {
// SAFETY: we are dropping the mutex guard, therefore unlocking the mutex.
unsafe {
self.0.unlock_unchecked();
}
}
}
impl<T: fmt::Debug + ?Sized> fmt::Debug for MutexGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<T: fmt::Display + ?Sized> fmt::Display for MutexGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
impl<T: ?Sized> Deref for MutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.0.data.get() }
}
}
impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.0.data.get() }
}
}
/// An owned guard that releases the mutex when dropped.
#[clippy::has_significant_drop]
pub struct MutexGuardArc<T: ?Sized>(Arc<Mutex<T>>);
unsafe impl<T: Send + ?Sized> Send for MutexGuardArc<T> {}
unsafe impl<T: Sync + ?Sized> Sync for MutexGuardArc<T> {}
impl<T: ?Sized> MutexGuardArc<T> {
/// Returns a reference to the mutex a guard came from.
///
/// # Examples
///
/// ```
/// # futures_lite::future::block_on(async {
/// use async_lock::{Mutex, MutexGuardArc};
/// use std::sync::Arc;
///
/// let mutex = Arc::new(Mutex::new(10i32));
/// let guard = mutex.lock_arc().await;
/// dbg!(MutexGuardArc::source(&guard));
/// # })
/// ```
pub fn source(guard: &Self) -> &Arc<Mutex<T>>
where
// Required because `MutexGuardArc` implements `Sync` regardless of whether `T` is `Send`,
// but this method allows dropping `T` from a different thead than it was created in.
T: Send,
{
&guard.0
}
}
impl<T: ?Sized> Drop for MutexGuardArc<T> {
#[inline]
fn drop(&mut self) {
// SAFETY: we are dropping the mutex guard, therefore unlocking the mutex.
unsafe {
self.0.unlock_unchecked();
}
}
}
impl<T: fmt::Debug + ?Sized> fmt::Debug for MutexGuardArc<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<T: fmt::Display + ?Sized> fmt::Display for MutexGuardArc<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
impl<T: ?Sized> Deref for MutexGuardArc<T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.0.data.get() }
}
}
impl<T: ?Sized> DerefMut for MutexGuardArc<T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.0.data.get() }
}
}

814
vendor/async-lock/src/once_cell.rs vendored Normal file
View File

@@ -0,0 +1,814 @@
use core::cell::UnsafeCell;
use core::convert::Infallible;
use core::fmt;
use core::future::Future;
use core::mem::{forget, MaybeUninit};
use core::ptr;
use crate::sync::atomic::{AtomicUsize, Ordering};
#[cfg(not(loom))]
use crate::sync::WithMut;
#[cfg(all(feature = "std", not(target_family = "wasm")))]
use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
use event_listener::Event;
use event_listener_strategy::{NonBlocking, Strategy};
#[cfg(all(feature = "std", not(target_family = "wasm")))]
use event_listener::Listener;
/// The current state of the `OnceCell`.
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(usize)]
enum State {
/// The `OnceCell` is uninitialized.
Uninitialized = 0,
/// The `OnceCell` is being initialized.
Initializing = 1,
/// The `OnceCell` is initialized.
Initialized = 2,
}
impl From<usize> for State {
fn from(val: usize) -> Self {
match val {
0 => State::Uninitialized,
1 => State::Initializing,
2 => State::Initialized,
_ => unreachable!("Invalid state"),
}
}
}
impl From<State> for usize {
fn from(val: State) -> Self {
val as usize
}
}
/// A memory location that can be written to at most once.
///
/// A `OnceCell` can be used to store a single value, and only once. However,
/// once the value is stored, it can be accessed directly through a reference
/// instead of needing an RAII guard like `Mutex` or `RwLock`.
///
/// # Examples
///
/// This structure is useful for a variety of patterns, most notably for one-time
/// initialization.
///
/// ```rust
/// use async_lock::OnceCell;
///
/// # struct Foobar;
///
/// async fn very_expensive_initialization() -> Foobar {
/// // Imagine this is very expensive to initialize,
/// // for instance, it requires a network request or
/// // a database call.
/// # Foobar
/// }
///
/// struct LazyFoobar {
/// inner: OnceCell<Foobar>,
/// }
///
/// impl LazyFoobar {
/// fn new() -> Self {
/// Self {
/// inner: OnceCell::new(),
/// }
/// }
///
/// async fn load(&self) -> &Foobar {
/// self.inner.get_or_init(|| async {
/// very_expensive_initialization().await
/// }).await
/// }
/// }
/// ```
pub struct OnceCell<T> {
/// Listeners waiting for a chance to initialize the cell.
///
/// These are the users of get_or_init() and similar functions.
active_initializers: Event,
/// Listeners waiting for the cell to be initialized.
///
/// These are the users of wait().
passive_waiters: Event,
/// State associated with the cell.
state: AtomicUsize,
/// The value of the cell.
value: UnsafeCell<MaybeUninit<T>>,
}
unsafe impl<T: Send> Send for OnceCell<T> {}
unsafe impl<T: Send + Sync> Sync for OnceCell<T> {}
impl<T> OnceCell<T> {
const_fn! {
const_if: #[cfg(not(loom))];
/// Create a new, uninitialized `OnceCell`.
///
/// # Example
///
/// ```rust
/// use async_lock::OnceCell;
///
/// let cell = OnceCell::new();
/// # cell.set_blocking(1);
/// ```
pub const fn new() -> Self {
Self {
active_initializers: Event::new(),
passive_waiters: Event::new(),
state: AtomicUsize::new(State::Uninitialized as _),
value: UnsafeCell::new(MaybeUninit::uninit()),
}
}
}
/// Tell whether or not the cell is initialized.
///
/// This may not always be accurate. For instance, it is possible for
/// another thread to initialize the cell between the time when this
/// function is called and the time when the result is actually used.
///
/// # Example
///
/// ```rust
/// use async_lock::OnceCell;
///
/// # futures_lite::future::block_on(async {
/// let cell = OnceCell::new();
/// assert!(!cell.is_initialized());
/// cell.set(1).await;
/// assert!(cell.is_initialized());
/// # });
/// ```
pub fn is_initialized(&self) -> bool {
State::from(self.state.load(Ordering::Acquire)) == State::Initialized
}
/// Get a reference to the inner value, or `None` if the value
/// is not yet initialized.
///
/// # Example
///
/// ```rust
/// use async_lock::OnceCell;
///
/// # futures_lite::future::block_on(async {
/// let cell = OnceCell::new();
/// assert!(cell.get().is_none());
/// cell.set(1).await;
/// assert_eq!(cell.get(), Some(&1));
/// # });
/// ```
pub fn get(&self) -> Option<&T> {
if self.is_initialized() {
// SAFETY: We know that the value is initialized, so it is safe to
// read it.
Some(unsafe { self.get_unchecked() })
} else {
None
}
}
/// Get a mutable reference to the inner value, or `None` if the value
/// is not yet initialized.
///
/// This function is useful for initializing the value inside the cell
/// when we still have a mutable reference to the cell.
///
/// # Example
///
/// ```rust
/// use async_lock::OnceCell;
///
/// # futures_lite::future::block_on(async {
/// let mut cell = OnceCell::new();
/// assert!(cell.get_mut().is_none());
/// cell.set(1).await;
/// assert_eq!(cell.get_mut(), Some(&mut 1));
/// *cell.get_mut().unwrap() = 2;
/// assert_eq!(cell.get(), Some(&2));
/// # });
/// ```
pub fn get_mut(&mut self) -> Option<&mut T> {
self.state.with_mut(|state| {
if State::from(*state) == State::Initialized {
// SAFETY: We know that the value is initialized, so it is safe to
// read it.
Some(unsafe { &mut *self.value.get().cast() })
} else {
None
}
})
}
/// Take the value out of this `OnceCell`, moving it back to the uninitialized
/// state.
///
/// # Example
///
/// ```rust
/// use async_lock::OnceCell;
///
/// # futures_lite::future::block_on(async {
/// let mut cell = OnceCell::new();
/// cell.set(1).await;
/// assert_eq!(cell.take(), Some(1));
/// assert!(!cell.is_initialized());
/// # });
/// ```
pub fn take(&mut self) -> Option<T> {
self.state.with_mut(|state| {
if State::from(*state) == State::Initialized {
// SAFETY: We know that the value is initialized, so it is safe to
// read it.
let value = unsafe { ptr::read(self.value.get().cast()) };
*state = State::Uninitialized.into();
Some(value)
} else {
None
}
})
}
/// Convert this `OnceCell` into the inner value, if it is initialized.
///
/// # Example
///
/// ```rust
/// use async_lock::OnceCell;
///
/// # futures_lite::future::block_on(async {
/// let cell = OnceCell::new();
/// cell.set(1).await;
/// assert_eq!(cell.into_inner(), Some(1));
/// # });
/// ```
pub fn into_inner(mut self) -> Option<T> {
self.take()
}
/// Wait for the cell to be initialized, and then return a reference to the
/// inner value.
///
/// # Example
///
/// ```rust
/// use async_lock::OnceCell;
/// use std::sync::Arc;
/// use std::time::Duration;
/// use std::thread::{sleep, spawn};
///
/// let cell = Arc::new(OnceCell::new());
/// let cell2 = cell.clone();
///
/// spawn(move || {
/// sleep(Duration::from_millis(5));
/// cell2.set_blocking(1);
/// });
///
/// # futures_lite::future::block_on(async {
/// assert_eq!(cell.wait().await, &1);
/// # });
/// ```
pub async fn wait(&self) -> &T {
// Fast path: see if the value is already initialized.
if let Some(value) = self.get() {
return value;
}
// Slow path: wait for the value to be initialized.
event_listener::listener!(self.passive_waiters => listener);
// Try again.
if let Some(value) = self.get() {
return value;
}
listener.await;
debug_assert!(self.is_initialized());
// SAFETY: We know that the value is initialized, so it is safe to
// read it.
unsafe { self.get_unchecked() }
}
/// Wait for the cell to be initialized, and then return a reference to the
/// inner value.
///
/// # Blocking
///
/// In contrast to the `wait` method, this method blocks the current thread of
/// execution instead of awaiting.
///
/// This method should not be used in an asynchronous context. It is intended
/// to be used such that a `OnceCell` can be used in both asynchronous and synchronous contexts.
/// Calling this method in an asynchronous context may result in deadlocks.
///
/// # Example
///
/// ```rust
/// use async_lock::OnceCell;
/// use std::sync::Arc;
/// use std::time::Duration;
/// use std::thread::{sleep, spawn};
///
/// let cell = Arc::new(OnceCell::new());
/// let cell2 = cell.clone();
///
/// spawn(move || {
/// sleep(Duration::from_millis(5));
/// cell2.set_blocking(1);
/// });
///
/// assert_eq!(cell.wait_blocking(), &1);
/// ```
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub fn wait_blocking(&self) -> &T {
// Fast path: see if the value is already initialized.
if let Some(value) = self.get() {
return value;
}
// Slow path: wait for the value to be initialized.
event_listener::listener!(self.passive_waiters => listener);
// Try again.
if let Some(value) = self.get() {
return value;
}
listener.wait();
debug_assert!(self.is_initialized());
// SAFETY: We know that the value is initialized, so it is safe to
// read it.
unsafe { self.get_unchecked() }
}
/// Either get the value or initialize it with the given closure.
///
/// The cell will not be initialized if the closure returns an error.
///
/// # Example
///
/// ```rust
/// use async_lock::OnceCell;
/// #
/// # // Prevent explicit value errors.
/// # fn _explicit(_: &Result<&i32, ()>) {}
///
/// # futures_lite::future::block_on(async {
/// let cell = OnceCell::new();
///
/// let result = cell.get_or_try_init(|| async { Err(()) }).await;
/// assert!(result.is_err());
///
/// let result = cell.get_or_try_init(|| async { Ok(1) }).await;
/// # _explicit(&result);
/// assert_eq!(result.unwrap(), &1);
///
/// let result = cell.get_or_try_init(|| async { Err(()) }).await;
///
/// assert_eq!(result.unwrap(), &1);
/// # });
/// ```
pub async fn get_or_try_init<E, Fut: Future<Output = Result<T, E>>>(
&self,
closure: impl FnOnce() -> Fut,
) -> Result<&T, E> {
// Fast path: see if the value is already initialized.
if let Some(value) = self.get() {
return Ok(value);
}
// Slow path: initialize the value.
self.initialize_or_wait(closure, &mut NonBlocking::default())
.await?;
debug_assert!(self.is_initialized());
// SAFETY: We know that the value is initialized, so it is safe to
// read it.
Ok(unsafe { self.get_unchecked() })
}
/// Either get the value or initialize it with the given closure.
///
/// The cell will not be initialized if the closure returns an error.
///
/// # Blocking
///
/// In contrast to the `get_or_try_init` method, this method blocks the current thread of
/// execution instead of awaiting.
///
/// This method should not be used in an asynchronous context. It is intended
/// to be used such that a `OnceCell` can be used in both asynchronous and synchronous contexts.
/// Calling this method in an asynchronous context may result in deadlocks.
///
/// # Example
///
/// ```rust
/// use async_lock::OnceCell;
/// #
/// # // Prevent explicit type errors.
/// # fn _explicit(_: &Result<&i32, ()>) {}
///
/// let cell = OnceCell::new();
///
/// let result = cell.get_or_try_init_blocking(|| Err(()));
/// assert!(result.is_err());
///
/// let result = cell.get_or_try_init_blocking(|| Ok(1));
/// # _explicit(&result);
/// assert_eq!(result.unwrap(), &1);
///
/// let result = cell.get_or_try_init_blocking(|| Err(()));
///
/// assert_eq!(result.unwrap(), &1);
/// ```
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub fn get_or_try_init_blocking<E>(
&self,
closure: impl FnOnce() -> Result<T, E>,
) -> Result<&T, E> {
// Fast path: see if the value is already initialized.
if let Some(value) = self.get() {
return Ok(value);
}
// Slow path: initialize the value.
// The futures provided should never block, so we can use `now_or_never`.
now_or_never(self.initialize_or_wait(
move || core::future::ready(closure()),
&mut event_listener_strategy::Blocking::default(),
))?;
debug_assert!(self.is_initialized());
// SAFETY: We know that the value is initialized, so it is safe to
// read it.
Ok(unsafe { self.get_unchecked() })
}
/// Either get the value or initialize it with the given closure.
///
/// Many tasks may call this function, but the value will only be set once
/// and only one closure will be invoked.
///
/// # Example
///
/// ```rust
/// use async_lock::OnceCell;
///
/// # futures_lite::future::block_on(async {
/// let cell = OnceCell::new();
/// assert_eq!(cell.get_or_init(|| async { 1 }).await, &1);
/// assert_eq!(cell.get_or_init(|| async { 2 }).await, &1);
/// # });
/// ```
pub async fn get_or_init<Fut: Future<Output = T>>(&self, closure: impl FnOnce() -> Fut) -> &T {
// false positive: https://github.com/rust-lang/rust/issues/129352
#[allow(unreachable_patterns)]
match self
.get_or_try_init(move || async move {
let result: Result<T, Infallible> = Ok(closure().await);
result
})
.await
{
Ok(value) => value,
Err(infallible) => match infallible {},
}
}
/// Either get the value or initialize it with the given closure.
///
/// Many tasks may call this function, but the value will only be set once
/// and only one closure will be invoked.
///
/// # Blocking
///
/// In contrast to the `get_or_init` method, this method blocks the current thread of
/// execution instead of awaiting.
///
/// This method should not be used in an asynchronous context. It is intended
/// to be used such that a `OnceCell` can be used in both asynchronous and synchronous contexts.
/// Calling this method in an asynchronous context may result in deadlocks.
///
/// # Example
///
/// ```rust
/// use async_lock::OnceCell;
///
/// let cell = OnceCell::new();
/// assert_eq!(cell.get_or_init_blocking(|| 1), &1);
/// assert_eq!(cell.get_or_init_blocking(|| 2), &1);
/// ```
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub fn get_or_init_blocking(&self, closure: impl FnOnce() -> T + Unpin) -> &T {
let result = self.get_or_try_init_blocking(move || {
let result: Result<T, Infallible> = Ok(closure());
result
});
// false positive: https://github.com/rust-lang/rust/issues/129352
#[allow(unreachable_patterns)]
match result {
Ok(value) => value,
Err(infallible) => match infallible {},
}
}
/// Try to set the value of the cell.
///
/// If the cell is already initialized, this method returns the original
/// value back.
///
/// # Example
///
/// ```rust
/// use async_lock::OnceCell;
///
/// # futures_lite::future::block_on(async {
/// let cell = OnceCell::new();
///
/// assert_eq!(cell.set(1).await, Ok(&1));
/// assert_eq!(cell.get(), Some(&1));
/// assert_eq!(cell.set(2).await, Err(2));
/// # });
/// ```
pub async fn set(&self, value: T) -> Result<&T, T> {
let mut value = Some(value);
self.get_or_init(|| async { value.take().unwrap() }).await;
match value {
Some(value) => Err(value),
None => {
// SAFETY: value was taken, so we are initialized
Ok(unsafe { self.get_unchecked() })
}
}
}
/// Try to set the value of the cell.
///
/// If the cell is already initialized, this method returns the original
/// value back.
///
/// # Blocking
///
/// In contrast to the `set` method, this method blocks the current thread of
/// execution instead of awaiting.
///
/// This method should not be used in an asynchronous context. It is intended
/// to be used such that a `OnceCell` can be used in both asynchronous and synchronous contexts.
/// Calling this method in an asynchronous context may result in deadlocks.
///
/// # Example
///
/// ```rust
/// use async_lock::OnceCell;
///
/// let cell = OnceCell::new();
///
/// assert_eq!(cell.set_blocking(1), Ok(&1));
/// assert_eq!(cell.get(), Some(&1));
/// assert_eq!(cell.set_blocking(2), Err(2));
/// ```
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub fn set_blocking(&self, value: T) -> Result<&T, T> {
let mut value = Some(value);
self.get_or_init_blocking(|| value.take().unwrap());
match value {
Some(value) => Err(value),
None => {
// SAFETY: value was taken, so we are initialized
Ok(unsafe { self.get_unchecked() })
}
}
}
/// Wait for the cell to be initialized, optionally using a closure
/// to initialize the cell if it is not initialized yet.
#[cold]
async fn initialize_or_wait<E, Fut: Future<Output = Result<T, E>>, F: FnOnce() -> Fut>(
&self,
closure: F,
strategy: &mut impl for<'a> Strategy<'a>,
) -> Result<(), E> {
// The event listener we're currently waiting on.
let mut event_listener = None;
let mut closure = Some(closure);
loop {
// Check the current state of the cell.
let state = self.state.load(Ordering::Acquire);
// Determine what we should do based on our state.
match state.into() {
State::Initialized => {
// The cell is initialized now, so we can return.
return Ok(());
}
State::Initializing => {
// The cell is currently initializing, or the cell is uninitialized
// but we do not have the ability to initialize it.
//
// We need to wait the initialization to complete.
if let Some(listener) = event_listener.take() {
strategy.wait(listener).await;
} else {
event_listener = Some(self.active_initializers.listen());
}
}
State::Uninitialized => {
// Try to move the cell into the initializing state.
if self
.state
.compare_exchange(
State::Uninitialized.into(),
State::Initializing.into(),
Ordering::AcqRel,
Ordering::Acquire,
)
.is_err()
{
// The cell was initialized while we were trying to
// initialize it.
continue;
}
// Now that we have an exclusive lock on the cell's value,
// we can try to initialize it.
let _guard = Guard(self);
let initializer = closure.take().unwrap();
match (initializer)().await {
Ok(value) => {
// Write the value into the cell and update the state.
unsafe {
ptr::write(self.value.get().cast(), value);
}
forget(_guard);
self.state
.store(State::Initialized.into(), Ordering::Release);
// Notify the listeners that the value is initialized.
self.active_initializers.notify_additional(usize::MAX);
self.passive_waiters.notify_additional(usize::MAX);
return Ok(());
}
Err(err) => {
// Update the state to indicate that the value is
// uninitialized.
drop(_guard);
return Err(err);
}
}
}
}
}
/// Set the cell's state back to `UNINITIALIZED on drop.
///
/// If the closure panics, this ensures that the cell's state is set back to
/// `UNINITIALIZED` and that the next listener is notified.
struct Guard<'a, T>(&'a OnceCell<T>);
impl<T> Drop for Guard<'_, T> {
fn drop(&mut self) {
self.0
.state
.store(State::Uninitialized.into(), Ordering::Release);
// Notify the next initializer that it's their turn.
self.0.active_initializers.notify(1);
}
}
}
/// Get a reference to the inner value.
///
/// # Safety
///
/// The caller must ensure that the cell is initialized.
///
/// # Example
///
/// ```rust
/// use async_lock::OnceCell;
///
/// # futures_lite::future::block_on(async {
/// let cell = OnceCell::new();
/// cell.set(1).await;
///
/// // SAFETY: We know that the value is initialized, so it is safe to
/// // read it.
/// assert_eq!(unsafe { cell.get_unchecked() }, &1);
/// # });
/// ```
pub unsafe fn get_unchecked(&self) -> &T {
// SAFETY: The caller asserts that the value is initialized
&*self.value.get().cast()
}
}
impl<T> From<T> for OnceCell<T> {
/// Create a new, initialized `OnceCell` from an existing value.
///
/// # Example
///
/// ```rust
/// use async_lock::OnceCell;
///
/// let cell = OnceCell::from(42);
/// assert_eq!(cell.get(), Some(&42));
/// ```
fn from(value: T) -> Self {
Self {
active_initializers: Event::new(),
passive_waiters: Event::new(),
state: AtomicUsize::new(State::Initialized.into()),
value: UnsafeCell::new(MaybeUninit::new(value)),
}
}
}
impl<T: fmt::Debug> fmt::Debug for OnceCell<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
struct Inner<'a, T>(&'a OnceCell<T>);
impl<T: fmt::Debug> fmt::Debug for Inner<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0.state.load(Ordering::Acquire).into() {
State::Uninitialized => f.write_str("<uninitialized>"),
State::Initializing => f.write_str("<initializing>"),
State::Initialized => {
// SAFETY: "value" is initialized.
let value = unsafe { self.0.get_unchecked() };
fmt::Debug::fmt(value, f)
}
}
}
}
f.debug_tuple("OnceCell").field(&Inner(self)).finish()
}
}
impl<T> Drop for OnceCell<T> {
fn drop(&mut self) {
self.state.with_mut(|state| {
if State::from(*state) == State::Initialized {
// SAFETY: We know that the value is initialized, so it is safe to
// drop it.
unsafe { self.value.get().cast::<T>().drop_in_place() }
}
});
}
}
impl<T> Default for OnceCell<T> {
// Calls `OnceCell::new`.
#[inline]
fn default() -> Self {
Self::new()
}
}
/// Either return the result of a future now, or panic.
#[cfg(all(feature = "std", not(target_family = "wasm")))]
fn now_or_never<T>(f: impl Future<Output = T>) -> T {
const NOOP_WAKER: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);
unsafe fn wake(_: *const ()) {}
unsafe fn wake_by_ref(_: *const ()) {}
unsafe fn clone(_: *const ()) -> RawWaker {
RawWaker::new(ptr::null(), &NOOP_WAKER)
}
unsafe fn drop(_: *const ()) {}
pin!(f);
let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &NOOP_WAKER)) };
// Poll the future exactly once.
let mut cx = Context::from_waker(&waker);
match f.poll(&mut cx) {
Poll::Ready(value) => value,
Poll::Pending => unreachable!("future not ready"),
}
}

1468
vendor/async-lock/src/rwlock.rs vendored Normal file

File diff suppressed because it is too large Load Diff

485
vendor/async-lock/src/rwlock/futures.rs vendored Normal file
View File

@@ -0,0 +1,485 @@
use core::fmt;
use core::mem::ManuallyDrop;
use core::pin::Pin;
use core::task::Poll;
use alloc::sync::Arc;
use super::raw::{RawRead, RawUpgradableRead, RawUpgrade, RawWrite};
use super::{
RwLock, RwLockReadGuard, RwLockReadGuardArc, RwLockUpgradableReadGuard,
RwLockUpgradableReadGuardArc, RwLockWriteGuard, RwLockWriteGuardArc,
};
use event_listener_strategy::{easy_wrapper, EventListenerFuture, Strategy};
easy_wrapper! {
/// The future returned by [`RwLock::read`].
pub struct Read<'a, T: ?Sized>(ReadInner<'a, T> => RwLockReadGuard<'a, T>);
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub(crate) wait();
}
pin_project_lite::pin_project! {
/// The future returned by [`RwLock::read`].
struct ReadInner<'a, T: ?Sized> {
// Raw read lock acquisition future, doesn't depend on `T`.
#[pin]
pub(super) raw: RawRead<'a>,
// Pointer to the value protected by the lock. Covariant in `T`.
pub(super) value: *const T,
}
}
unsafe impl<T: Sync + ?Sized> Send for ReadInner<'_, T> {}
unsafe impl<T: Sync + ?Sized> Sync for ReadInner<'_, T> {}
impl<'x, T: ?Sized> Read<'x, T> {
#[inline]
pub(super) fn new(raw: RawRead<'x>, value: *const T) -> Self {
Self::_new(ReadInner { raw, value })
}
}
impl<T: ?Sized> fmt::Debug for Read<'_, T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Read { .. }")
}
}
impl<'a, T: ?Sized> EventListenerFuture for ReadInner<'a, T> {
type Output = RwLockReadGuard<'a, T>;
#[inline]
fn poll_with_strategy<'x, S: Strategy<'x>>(
self: Pin<&mut Self>,
strategy: &mut S,
cx: &mut S::Context,
) -> Poll<Self::Output> {
let mut this = self.project();
ready!(this.raw.as_mut().poll_with_strategy(strategy, cx));
Poll::Ready(RwLockReadGuard {
lock: this.raw.lock,
value: *this.value,
})
}
}
easy_wrapper! {
/// The future returned by [`RwLock::read_arc`].
pub struct ReadArc<'a, T>(ReadArcInner<'a, T> => RwLockReadGuardArc<T>);
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub(crate) wait();
}
pin_project_lite::pin_project! {
/// The future returned by [`RwLock::read_arc`].
struct ReadArcInner<'a, T> {
// Raw read lock acquisition future, doesn't depend on `T`.
#[pin]
pub(super) raw: RawRead<'a>,
// FIXME: Could be covariant in T
pub(super) lock: &'a Arc<RwLock<T>>,
}
}
unsafe impl<T: Send + Sync> Send for ReadArcInner<'_, T> {}
unsafe impl<T: Send + Sync> Sync for ReadArcInner<'_, T> {}
impl<'x, T> ReadArc<'x, T> {
#[inline]
pub(super) fn new(raw: RawRead<'x>, lock: &'x Arc<RwLock<T>>) -> Self {
Self::_new(ReadArcInner { raw, lock })
}
}
impl<T> fmt::Debug for ReadArc<'_, T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("ReadArc { .. }")
}
}
impl<T> EventListenerFuture for ReadArcInner<'_, T> {
type Output = RwLockReadGuardArc<T>;
#[inline]
fn poll_with_strategy<'x, S: Strategy<'x>>(
self: Pin<&mut Self>,
strategy: &mut S,
cx: &mut S::Context,
) -> Poll<Self::Output> {
let mut this = self.project();
ready!(this.raw.as_mut().poll_with_strategy(strategy, cx));
// SAFETY: we just acquired a read lock
Poll::Ready(unsafe { RwLockReadGuardArc::from_arc(this.lock.clone()) })
}
}
easy_wrapper! {
/// The future returned by [`RwLock::upgradable_read`].
pub struct UpgradableRead<'a, T: ?Sized>(
UpgradableReadInner<'a, T> => RwLockUpgradableReadGuard<'a, T>
);
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub(crate) wait();
}
pin_project_lite::pin_project! {
/// The future returned by [`RwLock::upgradable_read`].
struct UpgradableReadInner<'a, T: ?Sized> {
// Raw upgradable read lock acquisition future, doesn't depend on `T`.
#[pin]
pub(super) raw: RawUpgradableRead<'a>,
// Pointer to the value protected by the lock. Invariant in `T`
// as the upgradable lock could provide write access.
pub(super) value: *mut T,
}
}
unsafe impl<T: Send + Sync + ?Sized> Send for UpgradableReadInner<'_, T> {}
unsafe impl<T: Sync + ?Sized> Sync for UpgradableReadInner<'_, T> {}
impl<'x, T: ?Sized> UpgradableRead<'x, T> {
#[inline]
pub(super) fn new(raw: RawUpgradableRead<'x>, value: *mut T) -> Self {
Self::_new(UpgradableReadInner { raw, value })
}
}
impl<T: ?Sized> fmt::Debug for UpgradableRead<'_, T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("UpgradableRead { .. }")
}
}
impl<'a, T: ?Sized> EventListenerFuture for UpgradableReadInner<'a, T> {
type Output = RwLockUpgradableReadGuard<'a, T>;
#[inline]
fn poll_with_strategy<'x, S: Strategy<'x>>(
self: Pin<&mut Self>,
strategy: &mut S,
cx: &mut S::Context,
) -> Poll<Self::Output> {
let mut this = self.project();
ready!(this.raw.as_mut().poll_with_strategy(strategy, cx));
Poll::Ready(RwLockUpgradableReadGuard {
lock: this.raw.lock,
value: *this.value,
})
}
}
easy_wrapper! {
/// The future returned by [`RwLock::upgradable_read_arc`].
pub struct UpgradableReadArc<'a, T: ?Sized>(
UpgradableReadArcInner<'a, T> => RwLockUpgradableReadGuardArc<T>
);
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub(crate) wait();
}
pin_project_lite::pin_project! {
/// The future returned by [`RwLock::upgradable_read_arc`].
struct UpgradableReadArcInner<'a, T: ?Sized> {
// Raw upgradable read lock acquisition future, doesn't depend on `T`.
#[pin]
pub(super) raw: RawUpgradableRead<'a>,
pub(super) lock: &'a Arc<RwLock<T>>,
}
}
unsafe impl<T: Send + Sync + ?Sized> Send for UpgradableReadArcInner<'_, T> {}
unsafe impl<T: Send + Sync + ?Sized> Sync for UpgradableReadArcInner<'_, T> {}
impl<'x, T: ?Sized> UpgradableReadArc<'x, T> {
#[inline]
pub(super) fn new(raw: RawUpgradableRead<'x>, lock: &'x Arc<RwLock<T>>) -> Self {
Self::_new(UpgradableReadArcInner { raw, lock })
}
}
impl<T: ?Sized> fmt::Debug for UpgradableReadArc<'_, T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("UpgradableReadArc { .. }")
}
}
impl<T: ?Sized> EventListenerFuture for UpgradableReadArcInner<'_, T> {
type Output = RwLockUpgradableReadGuardArc<T>;
#[inline]
fn poll_with_strategy<'x, S: Strategy<'x>>(
self: Pin<&mut Self>,
strategy: &mut S,
cx: &mut S::Context,
) -> Poll<Self::Output> {
let mut this = self.project();
ready!(this.raw.as_mut().poll_with_strategy(strategy, cx));
Poll::Ready(RwLockUpgradableReadGuardArc {
lock: this.lock.clone(),
})
}
}
easy_wrapper! {
/// The future returned by [`RwLock::write`].
pub struct Write<'a, T: ?Sized>(WriteInner<'a, T> => RwLockWriteGuard<'a, T>);
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub(crate) wait();
}
pin_project_lite::pin_project! {
/// The future returned by [`RwLock::write`].
struct WriteInner<'a, T: ?Sized> {
// Raw write lock acquisition future, doesn't depend on `T`.
#[pin]
pub(super) raw: RawWrite<'a>,
// Pointer to the value protected by the lock. Invariant in `T`.
pub(super) value: *mut T,
}
}
unsafe impl<T: Send + ?Sized> Send for WriteInner<'_, T> {}
unsafe impl<T: Sync + ?Sized> Sync for WriteInner<'_, T> {}
impl<'x, T: ?Sized> Write<'x, T> {
#[inline]
pub(super) fn new(raw: RawWrite<'x>, value: *mut T) -> Self {
Self::_new(WriteInner { raw, value })
}
}
impl<T: ?Sized> fmt::Debug for Write<'_, T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Write { .. }")
}
}
impl<'a, T: ?Sized> EventListenerFuture for WriteInner<'a, T> {
type Output = RwLockWriteGuard<'a, T>;
#[inline]
fn poll_with_strategy<'x, S: Strategy<'x>>(
self: Pin<&mut Self>,
strategy: &mut S,
cx: &mut S::Context,
) -> Poll<Self::Output> {
let mut this = self.project();
ready!(this.raw.as_mut().poll_with_strategy(strategy, cx));
Poll::Ready(RwLockWriteGuard {
lock: this.raw.lock,
value: *this.value,
})
}
}
easy_wrapper! {
/// The future returned by [`RwLock::write_arc`].
pub struct WriteArc<'a, T: ?Sized>(WriteArcInner<'a, T> => RwLockWriteGuardArc<T>);
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub(crate) wait();
}
pin_project_lite::pin_project! {
/// The future returned by [`RwLock::write_arc`].
struct WriteArcInner<'a, T: ?Sized> {
// Raw write lock acquisition future, doesn't depend on `T`.
#[pin]
pub(super) raw: RawWrite<'a>,
pub(super) lock: &'a Arc<RwLock<T>>,
}
}
unsafe impl<T: Send + Sync + ?Sized> Send for WriteArcInner<'_, T> {}
unsafe impl<T: Send + Sync + ?Sized> Sync for WriteArcInner<'_, T> {}
impl<'x, T: ?Sized> WriteArc<'x, T> {
#[inline]
pub(super) fn new(raw: RawWrite<'x>, lock: &'x Arc<RwLock<T>>) -> Self {
Self::_new(WriteArcInner { raw, lock })
}
}
impl<T: ?Sized> fmt::Debug for WriteArc<'_, T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("WriteArc { .. }")
}
}
impl<T: ?Sized> EventListenerFuture for WriteArcInner<'_, T> {
type Output = RwLockWriteGuardArc<T>;
#[inline]
fn poll_with_strategy<'x, S: Strategy<'x>>(
self: Pin<&mut Self>,
strategy: &mut S,
cx: &mut S::Context,
) -> Poll<Self::Output> {
let mut this = self.project();
ready!(this.raw.as_mut().poll_with_strategy(strategy, cx));
Poll::Ready(RwLockWriteGuardArc {
lock: this.lock.clone(),
})
}
}
easy_wrapper! {
/// The future returned by [`RwLockUpgradableReadGuard::upgrade`].
pub struct Upgrade<'a, T: ?Sized>(UpgradeInner<'a, T> => RwLockWriteGuard<'a, T>);
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub(crate) wait();
}
pin_project_lite::pin_project! {
/// The future returned by [`RwLockUpgradableReadGuard::upgrade`].
struct UpgradeInner<'a, T: ?Sized> {
// Raw read lock upgrade future, doesn't depend on `T`.
#[pin]
pub(super) raw: RawUpgrade<'a>,
// Pointer to the value protected by the lock. Invariant in `T`.
pub(super) value: *mut T,
}
}
unsafe impl<T: Send + ?Sized> Send for UpgradeInner<'_, T> {}
unsafe impl<T: Sync + ?Sized> Sync for UpgradeInner<'_, T> {}
impl<'x, T: ?Sized> Upgrade<'x, T> {
#[inline]
pub(super) fn new(raw: RawUpgrade<'x>, value: *mut T) -> Self {
Self::_new(UpgradeInner { raw, value })
}
}
impl<T: ?Sized> fmt::Debug for Upgrade<'_, T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Upgrade").finish()
}
}
impl<'a, T: ?Sized> EventListenerFuture for UpgradeInner<'a, T> {
type Output = RwLockWriteGuard<'a, T>;
#[inline]
fn poll_with_strategy<'x, S: Strategy<'x>>(
self: Pin<&mut Self>,
strategy: &mut S,
cx: &mut S::Context,
) -> Poll<Self::Output> {
let mut this = self.project();
let lock = ready!(this.raw.as_mut().poll_with_strategy(strategy, cx));
Poll::Ready(RwLockWriteGuard {
lock,
value: *this.value,
})
}
}
easy_wrapper! {
/// The future returned by [`RwLockUpgradableReadGuardArc::upgrade`].
pub struct UpgradeArc<T: ?Sized>(UpgradeArcInner<T> => RwLockWriteGuardArc<T>);
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub(crate) wait();
}
pin_project_lite::pin_project! {
/// The future returned by [`RwLockUpgradableReadGuardArc::upgrade`].
struct UpgradeArcInner<T: ?Sized> {
// Raw read lock upgrade future, doesn't depend on `T`.
// `'static` is a lie, this field is actually referencing the
// `Arc` data. But since this struct also stores said `Arc`, we know
// this value will be alive as long as the struct is.
//
// Yes, one field of the `ArcUpgrade` struct is referencing another.
// Such self-references are usually not sound without pinning.
// However, in this case, there is an indirection via the heap;
// moving the `ArcUpgrade` won't move the heap allocation of the `Arc`,
// so the reference inside `RawUpgrade` isn't invalidated.
#[pin]
pub(super) raw: ManuallyDrop<RawUpgrade<'static>>,
// Pointer to the value protected by the lock. Invariant in `T`.
pub(super) lock: ManuallyDrop<Arc<RwLock<T>>>,
}
impl<T: ?Sized> PinnedDrop for UpgradeArcInner<T> {
fn drop(this: Pin<&mut Self>) {
let this = this.project();
let is_ready = this.raw.is_ready();
// SAFETY: The drop impl for raw assumes that it is pinned.
unsafe {
ManuallyDrop::drop(this.raw.get_unchecked_mut());
}
if !is_ready {
// SAFETY: we drop the `Arc` (decrementing the reference count)
// only if this future was cancelled before returning an
// upgraded lock.
unsafe {
ManuallyDrop::drop(this.lock);
};
}
}
}
}
impl<T: ?Sized> UpgradeArc<T> {
#[inline]
pub(super) unsafe fn new(
raw: ManuallyDrop<RawUpgrade<'static>>,
lock: ManuallyDrop<Arc<RwLock<T>>>,
) -> Self {
Self::_new(UpgradeArcInner { raw, lock })
}
}
impl<T: ?Sized> fmt::Debug for UpgradeArc<T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ArcUpgrade").finish()
}
}
impl<T: ?Sized> EventListenerFuture for UpgradeArcInner<T> {
type Output = RwLockWriteGuardArc<T>;
#[inline]
fn poll_with_strategy<'x, S: Strategy<'x>>(
self: Pin<&mut Self>,
strategy: &mut S,
cx: &mut S::Context,
) -> Poll<Self::Output> {
let this = self.project();
unsafe {
// SAFETY: Practically, this is a pin projection.
ready!(Pin::new_unchecked(&mut **this.raw.get_unchecked_mut())
.poll_with_strategy(strategy, cx));
}
Poll::Ready(RwLockWriteGuardArc {
lock: unsafe { ManuallyDrop::take(this.lock) },
})
}
}

580
vendor/async-lock/src/rwlock/raw.rs vendored Normal file
View File

@@ -0,0 +1,580 @@
//! Raw, unsafe reader-writer locking implementation,
//! doesn't depend on the data protected by the lock.
//! [`RwLock`](super::RwLock) is implemented in terms of this.
//!
//! Splitting the implementation this way allows instantiating
//! the locking code only once, and also lets us make
//! [`RwLockReadGuard`](super::RwLockReadGuard) covariant in `T`.
use core::marker::PhantomPinned;
use core::mem::forget;
use core::pin::Pin;
use core::task::Poll;
use crate::sync::atomic::{AtomicUsize, Ordering};
use event_listener::{Event, EventListener};
use event_listener_strategy::{EventListenerFuture, Strategy};
use crate::futures::Lock;
use crate::Mutex;
const WRITER_BIT: usize = 1;
const ONE_READER: usize = 2;
/// A "raw" RwLock that doesn't hold any data.
pub(super) struct RawRwLock {
/// Acquired by the writer.
mutex: Mutex<()>,
/// Event triggered when the last reader is dropped.
no_readers: Event,
/// Event triggered when the writer is dropped.
no_writer: Event,
/// Current state of the lock.
///
/// The least significant bit (`WRITER_BIT`) is set to 1 when a writer is holding the lock or
/// trying to acquire it.
///
/// The upper bits contain the number of currently active readers. Each active reader
/// increments the state by `ONE_READER`.
state: AtomicUsize,
}
impl RawRwLock {
const_fn! {
const_if: #[cfg(not(loom))];
#[inline]
pub(super) const fn new() -> Self {
RawRwLock {
mutex: Mutex::new(()),
no_readers: Event::new(),
no_writer: Event::new(),
state: AtomicUsize::new(0),
}
}
}
/// Returns `true` iff a read lock was successfully acquired.
pub(super) fn try_read(&self) -> bool {
let mut state = self.state.load(Ordering::Acquire);
loop {
// If there's a writer holding the lock or attempting to acquire it, we cannot acquire
// a read lock here.
if state & WRITER_BIT != 0 {
return false;
}
// Make sure the number of readers doesn't overflow.
if state > isize::MAX as usize {
crate::abort();
}
// Increment the number of readers.
match self.state.compare_exchange(
state,
state + ONE_READER,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => return true,
Err(s) => state = s,
}
}
}
#[inline]
pub(super) fn read(&self) -> RawRead<'_> {
RawRead {
lock: self,
state: self.state.load(Ordering::Acquire),
listener: None,
_pin: PhantomPinned,
}
}
/// Returns `true` iff an upgradable read lock was successfully acquired.
pub(super) fn try_upgradable_read(&self) -> bool {
// First try grabbing the mutex.
let lock = if let Some(lock) = self.mutex.try_lock() {
lock
} else {
return false;
};
forget(lock);
let mut state = self.state.load(Ordering::Acquire);
// Make sure the number of readers doesn't overflow.
if state > isize::MAX as usize {
crate::abort();
}
// Increment the number of readers.
loop {
match self.state.compare_exchange(
state,
state + ONE_READER,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => return true,
Err(s) => state = s,
}
}
}
#[inline]
pub(super) fn upgradable_read(&self) -> RawUpgradableRead<'_> {
RawUpgradableRead {
lock: self,
acquire: self.mutex.lock(),
}
}
/// Returns `true` iff a write lock was successfully acquired.
pub(super) fn try_write(&self) -> bool {
// First try grabbing the mutex.
let lock = if let Some(lock) = self.mutex.try_lock() {
lock
} else {
return false;
};
// If there are no readers, grab the write lock.
if self
.state
.compare_exchange(0, WRITER_BIT, Ordering::AcqRel, Ordering::Acquire)
.is_ok()
{
forget(lock);
true
} else {
drop(lock);
false
}
}
#[inline]
pub(super) fn write(&self) -> RawWrite<'_> {
RawWrite {
lock: self,
no_readers: None,
state: WriteState::Acquiring {
lock: self.mutex.lock(),
},
}
}
/// Returns `true` iff a the upgradable read lock was successfully upgraded to a write lock.
///
/// # Safety
///
/// Caller must hold an upgradable read lock.
/// This will attempt to upgrade it to a write lock.
pub(super) unsafe fn try_upgrade(&self) -> bool {
self.state
.compare_exchange(ONE_READER, WRITER_BIT, Ordering::AcqRel, Ordering::Acquire)
.is_ok()
}
/// # Safety
///
/// Caller must hold an upgradable read lock.
/// This will upgrade it to a write lock.
pub(super) unsafe fn upgrade(&self) -> RawUpgrade<'_> {
// Set `WRITER_BIT` and decrement the number of readers at the same time.
self.state
.fetch_sub(ONE_READER - WRITER_BIT, Ordering::SeqCst);
RawUpgrade {
lock: Some(self),
listener: None,
_pin: PhantomPinned,
}
}
/// # Safety
///
/// Caller must hold an upgradable read lock.
/// This will downgrade it to a standard read lock.
#[inline]
pub(super) unsafe fn downgrade_upgradable_read(&self) {
self.mutex.unlock_unchecked();
}
/// # Safety
///
/// Caller must hold a write lock.
/// This will downgrade it to a read lock.
pub(super) unsafe fn downgrade_write(&self) {
// Atomically downgrade state.
self.state
.fetch_add(ONE_READER - WRITER_BIT, Ordering::SeqCst);
// Release the writer mutex.
self.mutex.unlock_unchecked();
// Trigger the "no writer" event.
self.no_writer.notify(1);
}
/// # Safety
///
/// Caller must hold a write lock.
/// This will downgrade it to an upgradable read lock.
pub(super) unsafe fn downgrade_to_upgradable(&self) {
// Atomically downgrade state.
self.state
.fetch_add(ONE_READER - WRITER_BIT, Ordering::SeqCst);
}
/// # Safety
///
/// Caller must hold a read lock .
/// This will unlock that lock.
pub(super) unsafe fn read_unlock(&self) {
// Decrement the number of readers.
if self.state.fetch_sub(ONE_READER, Ordering::SeqCst) & !WRITER_BIT == ONE_READER {
// If this was the last reader, trigger the "no readers" event.
self.no_readers.notify(1);
}
}
/// # Safety
///
/// Caller must hold an upgradable read lock.
/// This will unlock that lock.
pub(super) unsafe fn upgradable_read_unlock(&self) {
// Decrement the number of readers.
if self.state.fetch_sub(ONE_READER, Ordering::SeqCst) & !WRITER_BIT == ONE_READER {
// If this was the last reader, trigger the "no readers" event.
self.no_readers.notify(1);
}
// SAFETY: upgradable read guards acquire the writer mutex upon creation.
self.mutex.unlock_unchecked();
}
/// # Safety
///
/// Caller must hold a write lock.
/// This will unlock that lock.
pub(super) unsafe fn write_unlock(&self) {
// Unset `WRITER_BIT`.
self.state.fetch_and(!WRITER_BIT, Ordering::SeqCst);
// Trigger the "no writer" event.
self.no_writer.notify(1);
// Release the writer lock.
// SAFETY: `RwLockWriteGuard` always holds a lock on writer mutex.
self.mutex.unlock_unchecked();
}
}
pin_project_lite::pin_project! {
/// The future returned by [`RawRwLock::read`].
pub(super) struct RawRead<'a> {
// The lock that is being acquired.
pub(super) lock: &'a RawRwLock,
// The last-observed state of the lock.
state: usize,
// The listener for the "no writers" event.
listener: Option<EventListener>,
// Making this type `!Unpin` enables future optimizations.
#[pin]
_pin: PhantomPinned
}
}
impl EventListenerFuture for RawRead<'_> {
type Output = ();
fn poll_with_strategy<'x, S: Strategy<'x>>(
self: Pin<&mut Self>,
strategy: &mut S,
cx: &mut S::Context,
) -> Poll<()> {
let this = self.project();
loop {
if *this.state & WRITER_BIT == 0 {
// Make sure the number of readers doesn't overflow.
if *this.state > isize::MAX as usize {
crate::abort();
}
// If nobody is holding a write lock or attempting to acquire it, increment the
// number of readers.
match this.lock.state.compare_exchange(
*this.state,
*this.state + ONE_READER,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => return Poll::Ready(()),
Err(s) => *this.state = s,
}
} else {
// Start listening for "no writer" events.
let load_ordering = if this.listener.is_none() {
*this.listener = Some(this.lock.no_writer.listen());
// Make sure there really is no writer.
Ordering::SeqCst
} else {
// Wait for the writer to finish.
ready!(strategy.poll(this.listener, cx));
// Notify the next reader waiting in list.
this.lock.no_writer.notify(1);
// Check the state again.
Ordering::Acquire
};
// Reload the state.
*this.state = this.lock.state.load(load_ordering);
}
}
}
}
pin_project_lite::pin_project! {
/// The future returned by [`RawRwLock::upgradable_read`].
pub(super) struct RawUpgradableRead<'a> {
// The lock that is being acquired.
pub(super) lock: &'a RawRwLock,
// The mutex we are trying to acquire.
#[pin]
acquire: Lock<'a, ()>,
}
}
impl EventListenerFuture for RawUpgradableRead<'_> {
type Output = ();
fn poll_with_strategy<'x, S: Strategy<'x>>(
self: Pin<&mut Self>,
strategy: &mut S,
cx: &mut S::Context,
) -> Poll<()> {
let this = self.project();
// Acquire the mutex.
let mutex_guard = ready!(this.acquire.poll_with_strategy(strategy, cx));
forget(mutex_guard);
// Load the current state.
let mut state = this.lock.state.load(Ordering::Acquire);
// Make sure the number of readers doesn't overflow.
if state > isize::MAX as usize {
crate::abort();
}
// Increment the number of readers.
loop {
match this.lock.state.compare_exchange(
state,
state + ONE_READER,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => {
return Poll::Ready(());
}
Err(s) => state = s,
}
}
}
}
pin_project_lite::pin_project! {
/// The future returned by [`RawRwLock::write`].
pub(super) struct RawWrite<'a> {
// The lock that is being acquired.
pub(super) lock: &'a RawRwLock,
// Our listener for the "no readers" event.
no_readers: Option<EventListener>,
// Current state of this future.
#[pin]
state: WriteState<'a>,
}
impl PinnedDrop for RawWrite<'_> {
fn drop(this: Pin<&mut Self>) {
let this = this.project();
if matches!(this.state.project(), WriteStateProj::WaitingReaders) {
// Safety: we hold a write lock, more or less.
unsafe {
this.lock.write_unlock();
}
}
}
}
}
pin_project_lite::pin_project! {
#[project = WriteStateProj]
#[project_replace = WriteStateProjReplace]
enum WriteState<'a> {
// We are currently acquiring the inner mutex.
Acquiring { #[pin] lock: Lock<'a, ()> },
// We are currently waiting for readers to finish.
WaitingReaders,
// The future has completed.
Acquired,
}
}
impl EventListenerFuture for RawWrite<'_> {
type Output = ();
fn poll_with_strategy<'x, S: Strategy<'x>>(
self: Pin<&mut Self>,
strategy: &mut S,
cx: &mut S::Context,
) -> Poll<()> {
let mut this = self.project();
loop {
match this.state.as_mut().project() {
WriteStateProj::Acquiring { lock } => {
// First grab the mutex.
let mutex_guard = ready!(lock.poll_with_strategy(strategy, cx));
forget(mutex_guard);
// Set `WRITER_BIT` and create a guard that unsets it in case this future is canceled.
let new_state = this.lock.state.fetch_or(WRITER_BIT, Ordering::SeqCst);
// If we just acquired the lock, return.
if new_state == WRITER_BIT {
this.state.as_mut().set(WriteState::Acquired);
return Poll::Ready(());
}
// Start waiting for the readers to finish.
*this.no_readers = Some(this.lock.no_readers.listen());
this.state.as_mut().set(WriteState::WaitingReaders);
}
WriteStateProj::WaitingReaders => {
let load_ordering = if this.no_readers.is_some() {
Ordering::Acquire
} else {
Ordering::SeqCst
};
// Check the state again.
if this.lock.state.load(load_ordering) == WRITER_BIT {
// We are the only ones holding the lock, return `Ready`.
this.state.as_mut().set(WriteState::Acquired);
return Poll::Ready(());
}
// Wait for the readers to finish.
if this.no_readers.is_none() {
// Register a listener.
*this.no_readers = Some(this.lock.no_readers.listen());
} else {
// Wait for the readers to finish.
ready!(strategy.poll(this.no_readers, cx));
};
}
WriteStateProj::Acquired => panic!("Write lock already acquired"),
}
}
}
}
pin_project_lite::pin_project! {
/// The future returned by [`RawRwLock::upgrade`].
pub(super) struct RawUpgrade<'a> {
lock: Option<&'a RawRwLock>,
// The event listener we are waiting on.
listener: Option<EventListener>,
// Keeping this future `!Unpin` enables future optimizations.
#[pin]
_pin: PhantomPinned
}
impl PinnedDrop for RawUpgrade<'_> {
fn drop(this: Pin<&mut Self>) {
let this = this.project();
if let Some(lock) = this.lock {
// SAFETY: we are dropping the future that would give us a write lock,
// so we don't need said lock anymore.
unsafe {
lock.write_unlock();
}
}
}
}
}
impl<'a> EventListenerFuture for RawUpgrade<'a> {
type Output = &'a RawRwLock;
fn poll_with_strategy<'x, S: Strategy<'x>>(
self: Pin<&mut Self>,
strategy: &mut S,
cx: &mut S::Context,
) -> Poll<&'a RawRwLock> {
let this = self.project();
let lock = this.lock.expect("cannot poll future after completion");
// If there are readers, we need to wait for them to finish.
loop {
let load_ordering = if this.listener.is_some() {
Ordering::Acquire
} else {
Ordering::SeqCst
};
// See if the number of readers is zero.
let state = lock.state.load(load_ordering);
if state == WRITER_BIT {
break;
}
// If there are readers, wait for them to finish.
if this.listener.is_none() {
// Start listening for "no readers" events.
*this.listener = Some(lock.no_readers.listen());
} else {
// Wait for the readers to finish.
ready!(strategy.poll(this.listener, cx));
};
}
// We are done.
Poll::Ready(this.lock.take().unwrap())
}
}
impl RawUpgrade<'_> {
/// Whether the future returned `Poll::Ready(..)` at some point.
#[inline]
pub(super) fn is_ready(&self) -> bool {
self.lock.is_none()
}
}

392
vendor/async-lock/src/semaphore.rs vendored Normal file
View File

@@ -0,0 +1,392 @@
use core::fmt;
use core::marker::PhantomPinned;
use core::mem;
use core::pin::Pin;
use core::task::Poll;
use crate::sync::atomic::{AtomicUsize, Ordering};
use alloc::sync::Arc;
use event_listener::{Event, EventListener};
use event_listener_strategy::{easy_wrapper, EventListenerFuture, Strategy};
/// A counter for limiting the number of concurrent operations.
#[derive(Debug)]
pub struct Semaphore {
count: AtomicUsize,
event: Event,
}
impl Semaphore {
const_fn! {
const_if: #[cfg(not(loom))];
/// Creates a new semaphore with a limit of `n` concurrent operations.
///
/// # Examples
///
/// ```
/// use async_lock::Semaphore;
///
/// let s = Semaphore::new(5);
/// ```
pub const fn new(n: usize) -> Semaphore {
Semaphore {
count: AtomicUsize::new(n),
event: Event::new(),
}
}
}
/// Attempts to get a permit for a concurrent operation.
///
/// If the permit could not be acquired at this time, then [`None`] is returned. Otherwise, a
/// guard is returned that releases the mutex when dropped.
///
/// # Examples
///
/// ```
/// use async_lock::Semaphore;
///
/// let s = Semaphore::new(2);
///
/// let g1 = s.try_acquire().unwrap();
/// let g2 = s.try_acquire().unwrap();
///
/// assert!(s.try_acquire().is_none());
/// drop(g2);
/// assert!(s.try_acquire().is_some());
/// ```
pub fn try_acquire(&self) -> Option<SemaphoreGuard<'_>> {
let mut count = self.count.load(Ordering::Acquire);
loop {
if count == 0 {
return None;
}
match self.count.compare_exchange_weak(
count,
count - 1,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => return Some(SemaphoreGuard(self)),
Err(c) => count = c,
}
}
}
/// Waits for a permit for a concurrent operation.
///
/// Returns a guard that releases the permit when dropped.
///
/// # Examples
///
/// ```
/// # futures_lite::future::block_on(async {
/// use async_lock::Semaphore;
///
/// let s = Semaphore::new(2);
/// let guard = s.acquire().await;
/// # });
/// ```
pub fn acquire(&self) -> Acquire<'_> {
Acquire::_new(AcquireInner {
semaphore: self,
listener: None,
_pin: PhantomPinned,
})
}
/// Waits for a permit for a concurrent operation.
///
/// Returns a guard that releases the permit when dropped.
///
/// # Blocking
///
/// Rather than using asynchronous waiting, like the [`acquire`][Semaphore::acquire] method,
/// this method will block the current thread until the permit is acquired.
///
/// This method should not be used in an asynchronous context. It is intended to be
/// used in a way that a semaphore can be used in both asynchronous and synchronous contexts.
/// Calling this method in an asynchronous context may result in a deadlock.
///
/// # Examples
///
/// ```
/// use async_lock::Semaphore;
///
/// let s = Semaphore::new(2);
/// let guard = s.acquire_blocking();
/// ```
#[cfg(all(feature = "std", not(target_family = "wasm")))]
#[inline]
pub fn acquire_blocking(&self) -> SemaphoreGuard<'_> {
self.acquire().wait()
}
/// Attempts to get an owned permit for a concurrent operation.
///
/// If the permit could not be acquired at this time, then [`None`] is returned. Otherwise, an
/// owned guard is returned that releases the mutex when dropped.
///
/// # Examples
///
/// ```
/// use async_lock::Semaphore;
/// use std::sync::Arc;
///
/// let s = Arc::new(Semaphore::new(2));
///
/// let g1 = s.try_acquire_arc().unwrap();
/// let g2 = s.try_acquire_arc().unwrap();
///
/// assert!(s.try_acquire_arc().is_none());
/// drop(g2);
/// assert!(s.try_acquire_arc().is_some());
/// ```
pub fn try_acquire_arc(self: &Arc<Self>) -> Option<SemaphoreGuardArc> {
let mut count = self.count.load(Ordering::Acquire);
loop {
if count == 0 {
return None;
}
match self.count.compare_exchange_weak(
count,
count - 1,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => return Some(SemaphoreGuardArc(Some(self.clone()))),
Err(c) => count = c,
}
}
}
/// Waits for an owned permit for a concurrent operation.
///
/// Returns a guard that releases the permit when dropped.
///
/// # Examples
///
/// ```
/// # futures_lite::future::block_on(async {
/// use async_lock::Semaphore;
/// use std::sync::Arc;
///
/// let s = Arc::new(Semaphore::new(2));
/// let guard = s.acquire_arc().await;
/// # });
/// ```
pub fn acquire_arc(self: &Arc<Self>) -> AcquireArc {
AcquireArc::_new(AcquireArcInner {
semaphore: self.clone(),
listener: None,
_pin: PhantomPinned,
})
}
/// Waits for an owned permit for a concurrent operation.
///
/// Returns a guard that releases the permit when dropped.
///
/// # Blocking
///
/// Rather than using asynchronous waiting, like the [`acquire_arc`][Semaphore::acquire_arc] method,
/// this method will block the current thread until the permit is acquired.
///
/// This method should not be used in an asynchronous context. It is intended to be
/// used in a way that a semaphore can be used in both asynchronous and synchronous contexts.
/// Calling this method in an asynchronous context may result in a deadlock.
///
/// # Examples
///
/// ```
/// use std::sync::Arc;
/// use async_lock::Semaphore;
///
/// let s = Arc::new(Semaphore::new(2));
/// let guard = s.acquire_arc_blocking();
/// ```
#[cfg(all(feature = "std", not(target_family = "wasm")))]
#[inline]
pub fn acquire_arc_blocking(self: &Arc<Self>) -> SemaphoreGuardArc {
self.acquire_arc().wait()
}
/// Adds `n` additional permits to the semaphore.
///
/// # Examples
///
/// ```
/// use async_lock::Semaphore;
///
/// # futures_lite::future::block_on(async {
/// let s = Semaphore::new(1);
///
/// let _guard = s.acquire().await;
/// assert!(s.try_acquire().is_none());
///
/// s.add_permits(2);
///
/// let _guard = s.acquire().await;
/// let _guard = s.acquire().await;
/// # });
/// ```
pub fn add_permits(&self, n: usize) {
self.count.fetch_add(n, Ordering::AcqRel);
self.event.notify(n);
}
}
easy_wrapper! {
/// The future returned by [`Semaphore::acquire`].
pub struct Acquire<'a>(AcquireInner<'a> => SemaphoreGuard<'a>);
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub(crate) wait();
}
pin_project_lite::pin_project! {
struct AcquireInner<'a> {
// The semaphore being acquired.
semaphore: &'a Semaphore,
// The listener waiting on the semaphore.
listener: Option<EventListener>,
// Keeping this future `!Unpin` enables future optimizations.
#[pin]
_pin: PhantomPinned
}
}
impl fmt::Debug for Acquire<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Acquire { .. }")
}
}
impl<'a> EventListenerFuture for AcquireInner<'a> {
type Output = SemaphoreGuard<'a>;
fn poll_with_strategy<'x, S: Strategy<'x>>(
self: Pin<&mut Self>,
strategy: &mut S,
cx: &mut S::Context,
) -> Poll<Self::Output> {
let this = self.project();
loop {
match this.semaphore.try_acquire() {
Some(guard) => return Poll::Ready(guard),
None => {
// Wait on the listener.
if this.listener.is_none() {
*this.listener = Some(this.semaphore.event.listen());
} else {
ready!(strategy.poll(this.listener, cx));
}
}
}
}
}
}
easy_wrapper! {
/// The future returned by [`Semaphore::acquire_arc`].
pub struct AcquireArc(AcquireArcInner => SemaphoreGuardArc);
#[cfg(all(feature = "std", not(target_family = "wasm")))]
pub(crate) wait();
}
pin_project_lite::pin_project! {
struct AcquireArcInner {
// The semaphore being acquired.
semaphore: Arc<Semaphore>,
// The listener waiting on the semaphore.
listener: Option<EventListener>,
// Keeping this future `!Unpin` enables future optimizations.
#[pin]
_pin: PhantomPinned
}
}
impl fmt::Debug for AcquireArc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("AcquireArc { .. }")
}
}
impl EventListenerFuture for AcquireArcInner {
type Output = SemaphoreGuardArc;
fn poll_with_strategy<'x, S: Strategy<'x>>(
self: Pin<&mut Self>,
strategy: &mut S,
cx: &mut S::Context,
) -> Poll<Self::Output> {
let this = self.project();
loop {
match this.semaphore.try_acquire_arc() {
Some(guard) => return Poll::Ready(guard),
None => {
// Wait on the listener.
if this.listener.is_none() {
*this.listener = Some(this.semaphore.event.listen());
} else {
ready!(strategy.poll(this.listener, cx));
}
}
}
}
}
}
/// A guard that releases the acquired permit.
#[clippy::has_significant_drop]
#[derive(Debug)]
pub struct SemaphoreGuard<'a>(&'a Semaphore);
impl SemaphoreGuard<'_> {
/// Drops the guard _without_ releasing the acquired permit.
#[inline]
pub fn forget(self) {
mem::forget(self);
}
}
impl Drop for SemaphoreGuard<'_> {
fn drop(&mut self) {
self.0.count.fetch_add(1, Ordering::AcqRel);
self.0.event.notify(1);
}
}
/// An owned guard that releases the acquired permit.
#[clippy::has_significant_drop]
#[derive(Debug)]
pub struct SemaphoreGuardArc(Option<Arc<Semaphore>>);
impl SemaphoreGuardArc {
/// Drops the guard _without_ releasing the acquired permit.
/// (Will still decrement the `Arc` reference count.)
#[inline]
pub fn forget(mut self) {
// Drop the inner `Arc` in order to decrement the reference count.
// FIXME: get rid of the `Option` once RFC 3466 or equivalent becomes available.
drop(self.0.take());
mem::forget(self);
}
}
impl Drop for SemaphoreGuardArc {
fn drop(&mut self) {
let opt = self.0.take().unwrap();
opt.count.fetch_add(1, Ordering::AcqRel);
opt.event.notify(1);
}
}

88
vendor/async-lock/tests/barrier.rs vendored Normal file
View File

@@ -0,0 +1,88 @@
use std::sync::Arc;
use std::thread;
use async_lock::Barrier;
use futures_lite::future;
#[test]
#[cfg_attr(miri, ignore)]
fn smoke() {
future::block_on(async move {
const N: usize = 10;
let barrier = Arc::new(Barrier::new(N));
for _ in 0..10 {
let (tx, rx) = flume::unbounded();
for _ in 0..N - 1 {
let c = barrier.clone();
let tx = tx.clone();
thread::spawn(move || {
future::block_on(async move {
let res = c.wait().await;
tx.send_async(res.is_leader()).await.unwrap();
})
});
}
// At this point, all spawned threads should be blocked,
// so we shouldn't get anything from the channel.
let res = rx.try_recv();
assert!(res.is_err());
let mut leader_found = barrier.wait().await.is_leader();
// Now, the barrier is cleared and we should get data.
for _ in 0..N - 1 {
if rx.recv_async().await.unwrap() {
assert!(!leader_found);
leader_found = true;
}
}
assert!(leader_found);
}
});
}
#[cfg(all(feature = "std", not(target_family = "wasm")))]
#[test]
#[cfg_attr(miri, ignore)]
fn smoke_blocking() {
future::block_on(async move {
const N: usize = 10;
let barrier = Arc::new(Barrier::new(N));
for _ in 0..10 {
let (tx, rx) = flume::unbounded();
for _ in 0..N - 1 {
let c = barrier.clone();
let tx = tx.clone();
thread::spawn(move || {
let res = c.wait_blocking();
tx.send(res.is_leader()).unwrap();
});
}
// At this point, all spawned threads should be blocked,
// so we shouldn't get anything from the channel.
let res = rx.try_recv();
assert!(res.is_err());
let mut leader_found = barrier.wait_blocking().is_leader();
// Now, the barrier is cleared and we should get data.
for _ in 0..N - 1 {
if rx.recv_async().await.unwrap() {
assert!(!leader_found);
leader_found = true;
}
}
assert!(leader_found);
}
});
}

21
vendor/async-lock/tests/common/mod.rs vendored Normal file
View File

@@ -0,0 +1,21 @@
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::task::Context;
use futures_lite::prelude::*;
use waker_fn::waker_fn;
pub fn check_yields_when_contended<G>(contending_guard: G, acquire_future: impl Future) {
let was_woken = Arc::new(AtomicBool::new(false));
let waker = {
let was_woken = Arc::clone(&was_woken);
waker_fn(move || was_woken.store(true, Ordering::SeqCst))
};
let mut cx = Context::from_waker(&waker);
futures_lite::pin!(acquire_future);
assert!(acquire_future.as_mut().poll(&mut cx).is_pending());
drop(contending_guard);
assert!(was_woken.load(Ordering::SeqCst));
assert!(acquire_future.poll(&mut cx).is_ready());
}

46
vendor/async-lock/tests/loom.rs vendored Normal file
View File

@@ -0,0 +1,46 @@
#![cfg(loom)]
use loom::sync::{mpsc, Arc};
use loom::thread;
use async_lock::Barrier;
#[ignore]
#[test]
fn barrier_smoke() {
loom::model(|| {
const N: usize = 10;
let barrier = Arc::new(Barrier::new(N));
for _ in 0..10 {
let (tx, rx) = mpsc::channel();
for _ in 0..loom::MAX_THREADS - 1 {
let c = barrier.clone();
let tx = tx.clone();
thread::spawn(move || {
let res = c.wait_blocking();
tx.send(res.is_leader()).unwrap();
});
}
// At this point, all spawned threads should be blocked,
// so we shouldn't get anything from the channel.
let res = rx.try_recv();
assert!(res.is_err());
let mut leader_found = barrier.wait_blocking().is_leader();
// Now, the barrier is cleared and we should get data.
for _ in 0..N - 1 {
if rx.recv().unwrap() {
assert!(!leader_found);
leader_found = true;
}
}
assert!(leader_found);
}
});
}

111
vendor/async-lock/tests/mutex.rs vendored Normal file
View File

@@ -0,0 +1,111 @@
mod common;
use std::sync::Arc;
#[cfg(not(target_family = "wasm"))]
use std::thread;
use async_lock::Mutex;
use futures_lite::future;
use common::check_yields_when_contended;
#[cfg(target_family = "wasm")]
use wasm_bindgen_test::wasm_bindgen_test as test;
#[cfg(target_family = "wasm")]
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
#[test]
fn smoke() {
future::block_on(async {
let m = Mutex::new(());
drop(m.lock().await);
drop(m.lock().await);
})
}
#[cfg(all(feature = "std", not(target_family = "wasm")))]
#[test]
fn smoke_blocking() {
let m = Mutex::new(());
drop(m.lock_blocking());
drop(m.lock_blocking());
}
#[cfg(all(feature = "std", not(target_family = "wasm")))]
#[test]
fn smoke_arc_blocking() {
let m = Arc::new(Mutex::new(()));
drop(m.lock_arc_blocking());
drop(m.lock_arc_blocking());
}
#[test]
fn try_lock() {
let m = Mutex::new(());
*m.try_lock().unwrap() = ();
}
#[test]
fn into_inner() {
let m = Mutex::new(10i32);
assert_eq!(m.into_inner(), 10);
}
#[test]
fn get_mut() {
let mut m = Mutex::new(10i32);
*m.get_mut() = 20;
assert_eq!(m.into_inner(), 20);
}
#[cfg(not(target_family = "wasm"))]
#[test]
fn contention() {
future::block_on(async {
let (tx, rx) = flume::unbounded();
let tx = Arc::new(tx);
let mutex = Arc::new(Mutex::new(0i32));
let num_tasks = 100;
for _ in 0..num_tasks {
let tx = tx.clone();
let mutex = mutex.clone();
thread::spawn(|| {
future::block_on(async move {
let mut lock = mutex.lock().await;
*lock += 1;
tx.send_async(()).await.unwrap();
drop(lock);
})
});
}
for _ in 0..num_tasks {
rx.recv_async().await.unwrap();
}
let lock = mutex.lock().await;
assert_eq!(num_tasks, *lock);
});
}
#[test]
fn lifetime() {
// Show that the future keeps the mutex alive.
let _fut = {
let mutex = Arc::new(Mutex::new(0i32));
mutex.lock_arc()
};
}
#[test]
fn yields_when_contended() {
let m = Mutex::new(());
check_yields_when_contended(m.try_lock().unwrap(), m.lock());
let m = Arc::new(m);
check_yields_when_contended(m.try_lock_arc().unwrap(), m.lock_arc());
}

589
vendor/async-lock/tests/rwlock.rs vendored Normal file
View File

@@ -0,0 +1,589 @@
mod common;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use common::check_yields_when_contended;
#[cfg(not(target_family = "wasm"))]
use futures_lite::prelude::*;
#[cfg(not(target_family = "wasm"))]
use std::thread;
use futures_lite::future;
use async_lock::{
RwLock, RwLockReadGuard, RwLockReadGuardArc, RwLockUpgradableReadGuard,
RwLockUpgradableReadGuardArc,
};
#[cfg(target_family = "wasm")]
use wasm_bindgen_test::wasm_bindgen_test as test;
#[cfg(target_family = "wasm")]
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
#[cfg(not(target_family = "wasm"))]
fn spawn<T: Send + 'static>(f: impl Future<Output = T> + Send + 'static) -> future::Boxed<T> {
let (s, r) = flume::bounded(1);
thread::spawn(move || {
future::block_on(async {
let _ = s.send_async(f.await).await;
})
});
async move { r.recv_async().await.unwrap() }.boxed()
}
#[test]
fn smoke() {
future::block_on(async {
let lock = RwLock::new(());
drop(lock.read().await);
drop(lock.write().await);
drop((lock.read().await, lock.read().await));
drop(lock.write().await);
});
}
#[cfg(all(feature = "std", not(target_family = "wasm")))]
#[test]
fn smoke_blocking() {
let lock = RwLock::new(());
drop(lock.read_blocking());
drop(lock.write_blocking());
drop((lock.read_blocking(), lock.read_blocking()));
let read = lock.read_blocking();
let upgradabe = lock.upgradable_read_blocking();
drop(read);
drop(RwLockUpgradableReadGuard::upgrade_blocking(upgradabe));
drop(lock.write_blocking());
}
#[cfg(all(feature = "std", not(target_family = "wasm")))]
#[test]
fn smoke_arc_blocking() {
let lock = Arc::new(RwLock::new(()));
drop(lock.read_arc_blocking());
drop(lock.write_arc_blocking());
drop((lock.read_arc_blocking(), lock.read_arc_blocking()));
let read = lock.read_arc_blocking();
let upgradabe = lock.upgradable_read_arc_blocking();
drop(read);
drop(RwLockUpgradableReadGuardArc::upgrade_blocking(upgradabe));
drop(lock.write_arc_blocking());
}
#[test]
fn try_write() {
future::block_on(async {
let lock = RwLock::new(0isize);
let read_guard = lock.read().await;
assert!(lock.try_write().is_none());
drop(read_guard);
});
}
#[test]
fn into_inner() {
let lock = RwLock::new(10);
assert_eq!(lock.into_inner(), 10);
}
#[test]
fn into_inner_and_drop() {
struct Counter(Arc<AtomicUsize>);
impl Drop for Counter {
fn drop(&mut self) {
self.0.fetch_add(1, Ordering::SeqCst);
}
}
let cnt = Arc::new(AtomicUsize::new(0));
let lock = RwLock::new(Counter(cnt.clone()));
assert_eq!(cnt.load(Ordering::SeqCst), 0);
{
let _inner = lock.into_inner();
assert_eq!(cnt.load(Ordering::SeqCst), 0);
}
assert_eq!(cnt.load(Ordering::SeqCst), 1);
}
#[test]
fn get_mut() {
let mut lock = RwLock::new(10);
*lock.get_mut() = 20;
assert_eq!(lock.into_inner(), 20);
}
// Miri bug; this works when async is replaced with blocking
#[cfg(not(target_family = "wasm"))]
#[test]
#[cfg_attr(miri, ignore)]
fn contention() {
const N: u32 = 10;
const M: usize = if cfg!(miri) { 100 } else { 1000 };
let (tx, rx) = flume::unbounded();
let tx = Arc::new(tx);
let rw = Arc::new(RwLock::new(()));
// Spawn N tasks that randomly acquire the lock M times.
for _ in 0..N {
let tx = tx.clone();
let rw = rw.clone();
let _spawned = spawn(async move {
for _ in 0..M {
if fastrand::u32(..N) == 0 {
drop(rw.write().await);
} else {
drop(rw.read().await);
}
}
tx.send_async(()).await.unwrap();
});
}
future::block_on(async move {
for _ in 0..N {
rx.recv_async().await.unwrap();
}
});
}
#[cfg(not(target_family = "wasm"))]
#[test]
#[cfg_attr(miri, ignore)]
fn contention_arc() {
const N: u32 = 10;
const M: usize = if cfg!(miri) { 100 } else { 1000 };
let (tx, rx) = flume::unbounded();
let tx = Arc::new(tx);
let rw = Arc::new(RwLock::new(()));
// Spawn N tasks that randomly acquire the lock M times.
for _ in 0..N {
let tx = tx.clone();
let rw = rw.clone();
let _spawned = spawn(async move {
for _ in 0..M {
if fastrand::u32(..N) == 0 {
drop(rw.write_arc().await);
} else {
drop(rw.read_arc().await);
}
}
tx.send_async(()).await.unwrap();
});
}
future::block_on(async move {
for _ in 0..N {
rx.recv_async().await.unwrap();
}
});
}
#[cfg(not(target_family = "wasm"))]
#[test]
fn writer_and_readers() {
let lock = Arc::new(RwLock::new(0i32));
let (tx, rx) = flume::unbounded();
// Spawn a writer task.
let _spawned = spawn({
let lock = lock.clone();
async move {
let mut lock = lock.write().await;
for _ in 0..1000 {
let tmp = *lock;
*lock = -1;
future::yield_now().await;
*lock = tmp + 1;
}
tx.send_async(()).await.unwrap();
}
});
// Readers try to catch the writer in the act.
let mut readers = Vec::new();
for _ in 0..5 {
let lock = lock.clone();
readers.push(spawn(async move {
for _ in 0..1000 {
let lock = lock.read().await;
assert!(*lock >= 0);
}
}));
}
future::block_on(async move {
// Wait for readers to pass their asserts.
for r in readers {
r.await;
}
// Wait for writer to finish.
rx.recv_async().await.unwrap();
let lock = lock.read().await;
assert_eq!(*lock, 1000);
});
}
#[cfg(not(target_family = "wasm"))]
#[test]
fn writer_and_readers_arc() {
let lock = Arc::new(RwLock::new(0i32));
let (tx, rx) = flume::unbounded();
// Spawn a writer task.
let _spawned = spawn({
let lock = lock.clone();
async move {
let mut lock = lock.write_arc().await;
for _ in 0..1000 {
let tmp = *lock;
*lock = -1;
future::yield_now().await;
*lock = tmp + 1;
}
tx.send_async(()).await.unwrap();
}
});
// Readers try to catch the writer in the act.
let mut readers = Vec::new();
for _ in 0..5 {
let lock = lock.clone();
readers.push(spawn(async move {
for _ in 0..1000 {
let lock = lock.read_arc().await;
assert!(*lock >= 0);
}
}));
}
future::block_on(async move {
// Wait for readers to pass their asserts.
for r in readers {
r.await;
}
// Wait for writer to finish.
rx.recv_async().await.unwrap();
let lock = lock.read_arc().await;
assert_eq!(*lock, 1000);
});
}
#[test]
fn upgrade() {
future::block_on(async {
let lock: RwLock<i32> = RwLock::new(0);
let read_guard = lock.read().await;
let read_guard2 = lock.read().await;
// Should be able to obtain an upgradable lock.
let upgradable_guard = lock.upgradable_read().await;
// Should be able to obtain a read lock when an upgradable lock is active.
let read_guard3 = lock.read().await;
assert_eq!(0, *read_guard3);
drop(read_guard);
drop(read_guard2);
drop(read_guard3);
// Writers should not pass.
assert!(lock.try_write().is_none());
let mut write_guard = RwLockUpgradableReadGuard::try_upgrade(upgradable_guard).expect(
"should be able to upgrade an upgradable lock because there are no more readers",
);
*write_guard += 1;
drop(write_guard);
let read_guard = lock.read().await;
assert_eq!(1, *read_guard)
});
}
#[test]
fn upgrade_arc() {
future::block_on(async {
let lock: Arc<RwLock<i32>> = Arc::new(RwLock::new(0));
let read_guard = lock.read_arc().await;
let read_guard2 = lock.read_arc().await;
// Should be able to obtain an upgradable lock.
let upgradable_guard = lock.upgradable_read_arc().await;
// Should be able to obtain a read lock when an upgradable lock is active.
let read_guard3 = lock.read_arc().await;
assert_eq!(0, *read_guard3);
drop(read_guard);
drop(read_guard2);
drop(read_guard3);
// Writers should not pass.
assert!(lock.try_write().is_none());
let mut write_guard = RwLockUpgradableReadGuardArc::try_upgrade(upgradable_guard).expect(
"should be able to upgrade an upgradable lock because there are no more readers",
);
*write_guard += 1;
drop(write_guard);
let read_guard = lock.read_arc().await;
assert_eq!(1, *read_guard)
});
}
#[test]
fn not_upgrade() {
future::block_on(async {
let mutex: RwLock<i32> = RwLock::new(0);
let read_guard = mutex.read().await;
let read_guard2 = mutex.read().await;
// Should be able to obtain an upgradable lock.
let upgradable_guard = mutex.upgradable_read().await;
// Should be able to obtain a shared lock when an upgradable lock is active.
let read_guard3 = mutex.read().await;
assert_eq!(0, *read_guard3);
drop(read_guard);
drop(read_guard2);
drop(read_guard3);
// Drop the upgradable lock.
drop(upgradable_guard);
assert_eq!(0, *(mutex.read().await));
// Should be able to acquire a write lock because there are no more readers.
let mut write_guard = mutex.write().await;
*write_guard += 1;
drop(write_guard);
let read_guard = mutex.read().await;
assert_eq!(1, *read_guard)
});
}
#[test]
fn not_upgrade_arc() {
future::block_on(async {
let mutex: Arc<RwLock<i32>> = Arc::new(RwLock::new(0));
let read_guard = mutex.read_arc().await;
let read_guard2 = mutex.read_arc().await;
// Should be able to obtain an upgradable lock.
let upgradable_guard = mutex.upgradable_read_arc().await;
// Should be able to obtain a shared lock when an upgradable lock is active.
let read_guard3 = mutex.read_arc().await;
assert_eq!(0, *read_guard3);
drop(read_guard);
drop(read_guard2);
drop(read_guard3);
// Drop the upgradable lock.
drop(upgradable_guard);
assert_eq!(0, *(mutex.read_arc().await));
// Should be able to acquire a write lock because there are no more readers.
let mut write_guard = mutex.write_arc().await;
*write_guard += 1;
drop(write_guard);
let read_guard = mutex.read_arc().await;
assert_eq!(1, *read_guard)
});
}
#[test]
fn upgradable_with_concurrent_writer() {
future::block_on(async {
let lock: Arc<RwLock<i32>> = Arc::new(RwLock::new(0));
let lock2 = lock.clone();
let upgradable_guard = lock.upgradable_read().await;
future::or(
async move {
let mut write_guard = lock2.write().await;
*write_guard = 1;
},
async move {
let mut write_guard = RwLockUpgradableReadGuard::upgrade(upgradable_guard).await;
assert_eq!(*write_guard, 0);
*write_guard = 2;
},
)
.await;
assert_eq!(2, *(lock.write().await));
let read_guard = lock.read().await;
assert_eq!(2, *read_guard);
});
}
#[test]
fn upgradable_with_concurrent_writer_arc() {
future::block_on(async {
let lock: Arc<RwLock<i32>> = Arc::new(RwLock::new(0));
let lock2 = lock.clone();
let upgradable_guard = lock.upgradable_read_arc().await;
future::or(
async move {
let mut write_guard = lock2.write_arc().await;
*write_guard = 1;
},
async move {
let mut write_guard = RwLockUpgradableReadGuardArc::upgrade(upgradable_guard).await;
assert_eq!(*write_guard, 0);
*write_guard = 2;
},
)
.await;
assert_eq!(2, *(lock.write_arc().await));
let read_guard = lock.read_arc().await;
assert_eq!(2, *read_guard);
});
}
#[test]
fn yields_when_contended() {
let rw = RwLock::new(());
check_yields_when_contended(rw.try_write().unwrap(), rw.read());
check_yields_when_contended(rw.try_write().unwrap(), rw.upgradable_read());
check_yields_when_contended(rw.try_write().unwrap(), rw.write());
check_yields_when_contended(rw.try_read().unwrap(), rw.write());
check_yields_when_contended(rw.try_upgradable_read().unwrap(), rw.write());
check_yields_when_contended(rw.try_upgradable_read().unwrap(), rw.upgradable_read());
let upgradable = rw.try_upgradable_read().unwrap();
check_yields_when_contended(
rw.try_read().unwrap(),
RwLockUpgradableReadGuard::upgrade(upgradable),
);
}
#[test]
fn yields_when_contended_arc() {
let rw = Arc::new(RwLock::new(()));
check_yields_when_contended(rw.try_write_arc().unwrap(), rw.read_arc());
check_yields_when_contended(rw.try_write_arc().unwrap(), rw.upgradable_read_arc());
check_yields_when_contended(rw.try_write_arc().unwrap(), rw.write_arc());
check_yields_when_contended(rw.try_read_arc().unwrap(), rw.write_arc());
check_yields_when_contended(rw.try_upgradable_read_arc().unwrap(), rw.write_arc());
check_yields_when_contended(
rw.try_upgradable_read_arc().unwrap(),
rw.upgradable_read_arc(),
);
let upgradable = rw.try_upgradable_read_arc().unwrap();
check_yields_when_contended(
rw.try_read_arc().unwrap(),
RwLockUpgradableReadGuardArc::upgrade(upgradable),
);
}
#[test]
fn cancellation() {
future::block_on(async {
let rw = RwLock::new(());
drop(rw.read());
drop(rw.upgradable_read());
drop(rw.write());
let read = rw.read().await;
drop(read);
let upgradable_read = rw.upgradable_read().await;
drop(upgradable_read);
let write = rw.write().await;
drop(write);
let upgradable_read = rw.upgradable_read().await;
drop(RwLockUpgradableReadGuard::upgrade(upgradable_read));
let upgradable_read = rw.upgradable_read().await;
let write = RwLockUpgradableReadGuard::upgrade(upgradable_read).await;
drop(write);
});
}
#[test]
fn arc_rwlock_refcounts() {
future::block_on(async {
let rw = Arc::new(RwLock::new(()));
assert_eq!(Arc::strong_count(&rw), 1);
drop(rw.read_arc());
assert_eq!(Arc::strong_count(&rw), 1);
drop(rw.upgradable_read_arc());
assert_eq!(Arc::strong_count(&rw), 1);
drop(rw.write());
assert_eq!(Arc::strong_count(&rw), 1);
let read = rw.read_arc().await;
assert_eq!(Arc::strong_count(&rw), 2);
drop(read);
assert_eq!(Arc::strong_count(&rw), 1);
let upgradable_read = rw.upgradable_read_arc().await;
assert_eq!(Arc::strong_count(&rw), 2);
drop(upgradable_read);
assert_eq!(Arc::strong_count(&rw), 1);
let write = rw.write_arc().await;
assert_eq!(Arc::strong_count(&rw), 2);
drop(write);
assert_eq!(Arc::strong_count(&rw), 1);
let upgradable_read = rw.upgradable_read_arc().await;
assert_eq!(Arc::strong_count(&rw), 2);
drop(RwLockUpgradableReadGuardArc::upgrade(upgradable_read));
assert_eq!(Arc::strong_count(&rw), 1);
let upgradable_read = rw.upgradable_read_arc().await;
assert_eq!(Arc::strong_count(&rw), 2);
let write = RwLockUpgradableReadGuardArc::upgrade(upgradable_read).await;
assert_eq!(Arc::strong_count(&rw), 2);
drop(write);
assert_eq!(Arc::strong_count(&rw), 1);
});
}
// We are testing that this compiles.
fn _covariance_test<'g>(guard: RwLockReadGuard<'g, &'static ()>) {
let _: RwLockReadGuard<'g, &'g ()> = guard;
}
// We are testing that this compiles.
fn _covariance_test_arc(
guard: RwLockReadGuardArc<&'static ()>,
mut _guard_2: RwLockReadGuardArc<&()>,
) {
_guard_2 = guard;
}

194
vendor/async-lock/tests/semaphore.rs vendored Normal file
View File

@@ -0,0 +1,194 @@
mod common;
use std::future::Future;
use std::mem::forget;
use std::pin::Pin;
use std::sync::{
atomic::{AtomicUsize, Ordering},
mpsc, Arc,
};
use std::task::Context;
use std::task::Poll;
use std::thread;
use common::check_yields_when_contended;
use async_lock::Semaphore;
use futures_lite::{future, pin};
#[test]
fn try_acquire() {
let s = Semaphore::new(2);
let g1 = s.try_acquire().unwrap();
let _g2 = s.try_acquire().unwrap();
assert!(s.try_acquire().is_none());
drop(g1);
assert!(s.try_acquire().is_some());
}
#[test]
fn stress() {
const COUNT: usize = if cfg!(miri) { 500 } else { 10_000 };
let s = Arc::new(Semaphore::new(5));
let (tx, rx) = mpsc::channel::<()>();
for _ in 0..50 {
let s = s.clone();
let tx = tx.clone();
thread::spawn(move || {
future::block_on(async {
for _ in 0..COUNT {
s.acquire().await;
}
drop(tx);
})
});
}
drop(tx);
let _ = rx.recv();
let _g1 = s.try_acquire().unwrap();
let g2 = s.try_acquire().unwrap();
let _g3 = s.try_acquire().unwrap();
let _g4 = s.try_acquire().unwrap();
let _g5 = s.try_acquire().unwrap();
assert!(s.try_acquire().is_none());
drop(g2);
assert!(s.try_acquire().is_some());
}
#[test]
fn as_mutex() {
let s = Arc::new(Semaphore::new(1));
let s2 = s.clone();
let _t = thread::spawn(move || {
future::block_on(async {
let _g = s2.acquire().await;
});
});
future::block_on(async {
let _g = s.acquire().await;
});
}
#[test]
fn multi_resource() {
let s = Arc::new(Semaphore::new(2));
let s2 = s.clone();
let (tx1, rx1) = mpsc::channel();
let (tx2, rx2) = mpsc::channel();
let _t = thread::spawn(move || {
future::block_on(async {
let _g = s2.acquire().await;
let _ = rx2.recv();
tx1.send(()).unwrap();
});
});
future::block_on(async {
let _g = s.acquire().await;
tx2.send(()).unwrap();
rx1.recv().unwrap();
});
}
#[test]
fn lifetime() {
// Show that the future keeps the semaphore alive.
let _fut = {
let mutex = Arc::new(Semaphore::new(2));
mutex.acquire_arc()
};
}
#[test]
fn yields_when_contended() {
let s = Semaphore::new(1);
check_yields_when_contended(s.try_acquire().unwrap(), s.acquire());
let s = Arc::new(s);
check_yields_when_contended(s.try_acquire_arc().unwrap(), s.acquire_arc());
}
#[cfg(all(feature = "std", not(target_family = "wasm")))]
#[test]
fn smoke_blocking() {
let s = Semaphore::new(2);
let g1 = s.acquire_blocking();
let _g2 = s.acquire_blocking();
assert!(s.try_acquire().is_none());
drop(g1);
assert!(s.try_acquire().is_some());
}
#[cfg(all(feature = "std", not(target_family = "wasm")))]
#[test]
fn smoke_arc_blocking() {
let s = Arc::new(Semaphore::new(2));
let g1 = s.acquire_arc_blocking();
let _g2 = s.acquire_arc_blocking();
assert!(s.try_acquire().is_none());
drop(g1);
assert!(s.try_acquire().is_some());
}
#[test]
fn add_permits() {
static COUNTER: AtomicUsize = AtomicUsize::new(0);
let s = Arc::new(Semaphore::new(0));
let (tx, rx) = mpsc::channel::<()>();
for _ in 0..50 {
let s = s.clone();
let tx = tx.clone();
thread::spawn(move || {
future::block_on(async {
let perm = s.acquire().await;
forget(perm);
COUNTER.fetch_add(1, Ordering::Relaxed);
drop(tx);
})
});
}
assert_eq!(COUNTER.load(Ordering::Relaxed), 0);
s.add_permits(50);
drop(tx);
let _ = rx.recv();
assert_eq!(COUNTER.load(Ordering::Relaxed), 50);
}
#[test]
fn add_permits_2() {
future::block_on(AddPermitsTest);
}
struct AddPermitsTest;
impl Future for AddPermitsTest {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
let s = Semaphore::new(0);
let acq = s.acquire();
pin!(acq);
let acq_2 = s.acquire();
pin!(acq_2);
assert!(acq.as_mut().poll(cx).is_pending());
assert!(acq_2.as_mut().poll(cx).is_pending());
s.add_permits(1);
let g = acq.poll(cx);
assert!(g.is_ready());
assert!(acq_2.poll(cx).is_pending());
Poll::Ready(())
}
}