Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
This commit is contained in:
1
vendor/flume/.cargo-checksum.json
vendored
Normal file
1
vendor/flume/.cargo-checksum.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"files":{"CHANGELOG.md":"378edfec4dde51dee9c0d1e8285d88b3d218cb9b8b42ffa3e27405661c23b0b6","Cargo.lock":"cc14608e4a0c130f6f898cc6187e3b8964639f6c960bc9c08589dcac06506526","Cargo.toml":"6246515094dda94c71890606c39275b555aed886b5f4c789eb362ce7b1eea40f","LICENSE-APACHE":"d8621ec2eee5b9ca3c65f8492505f3590de8574fac0fdf5132a77232dba47abc","LICENSE-MIT":"30fefc3a7d6a0041541858293bcbea2dde4caa4c0a5802f996a7f7e8c0085652","README.md":"48f7ca4326cfcd3440931e5c82fc21f7b8a6f40041bc94be817c291ad71b6c5b","benches/basic.rs":"61ecb5f7c092b82382cc20e73ca84677dd4973cc358ea6bff15f92fda227b481","examples/async.rs":"7a0bb8848d94bd1fa9a857ffba0b3fbea6d57d7058ed65d2a7cbcf8518ec8652","examples/perf.rs":"52b67c619932a283ad9109c5fe5b47d32f7d3e7533356170047b686dfac330c9","examples/select.rs":"7659b015889545a59b9bce046fc353fea7bcaa9d54cb59f6bd5c002e15872909","examples/simple.rs":"f96d308b808b5fd66ca03dac9f09c13e5f13141992698551503415a411f6596a","src/async.rs":"851b0db2f8115eb222a9eb3c39d3dcdd8699c5b8e757580f26a03ca71c88d0e4","src/lib.rs":"36f84973b6bb45e54161dfb8eb574b30bace69d4b382e7fe8669d5636473d9ea","src/select.rs":"940cbdfbb26b9a2811bf42df3b26f1a619bd71896b8a6b6f2cdbb350c4fab270","src/signal.rs":"20a1732fdbfe888b9a25438bf16a185393f18fb1ad795926fae969c6817fe43b","tests/after.rs":"53e17263eab8eb733f575e4d1d43e054c6d22556d36e105f3f87c4cfb891880c","tests/array.rs":"2b071429d678e07ca52b79b4792120816a1ec7e64afd29c5781ddddbbbd7888b","tests/async.rs":"45bce43e990694578cf03c27dcf112df8d9ec1806e7c1be866885d76bb5abf85","tests/basic.rs":"0606408fe5ff1512839d43cc5c5f6a98c1e09fe919b5ad843643b5019926100b","tests/check_same_channel.rs":"e9e313d1ada50ac0ab0b9bcf19b901efd8cc226902edac62a8d573cea54e06ca","tests/golang.rs":"9e821cefd322a2353b288c7368902028daca643648da2e223ec1174c0e93e4ef","tests/iter.rs":"82d4f7acd20c9b10d2623211e71f5b6c37e4dafda2e13c871008c03995d76ced","tests/list.rs":"5885ee800d5c93b410d3bfa12d834fd817fd3362bca15a08b0aa7f84de58432e","tests/method_sharing.rs":"4d6c867e689254840ecbb1ae8a70ab3226d45bf92282e3bd2681c83726983ffa","tests/mpsc.rs":"965e18abbfcdebec09380f8ec9bb62e5556ad2aa0176ed088ce091994c1d2500","tests/never.rs":"cb838011c6f39c150c67e6836eb880300d53c22a2ea0312cdec999efb779ca29","tests/ready.rs":"5e1234ce49e8cbf89ec4f28bd2f4fe10641891bf6a7915d2fef6f9ab0c343997","tests/same_channel.rs":"71524e90dc364cc2c8085a9517757abe55f59a25b95600029abb283bc8677ad9","tests/select.rs":"67f8a647a7976f0d77673f4cc8d03b74690f3e8578c47e1bc64caeab68dd7df7","tests/select_macro.rs":"32793ac9775879e72ae3ce3975aa87f7407c6e7023d3d85f50f06a3ac5e308a3","tests/stream.rs":"c6d9500813d7216fd514f35dadb1b7b58282def553f40d76b37032221bb05cd6","tests/thread_locals.rs":"ad92e07a4ef5c3dd8b6ff8620161ab93963b3de241a680db551f2be60c8e3853","tests/tick.rs":"35fabd118073decf0cd830e9245c77a1a2e19227f7b4f73d239589728a591601","tests/zero.rs":"23a15a51681596716d5882242cd2c8cd0925c6ea2d0ef289f80775f3f2d6d10c"},"package":"55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181"}
|
134
vendor/flume/CHANGELOG.md
vendored
Normal file
134
vendor/flume/CHANGELOG.md
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
# Unreleased
|
||||
|
||||
### Added
|
||||
|
||||
### Removed
|
||||
|
||||
### Changed
|
||||
|
||||
### Fixed
|
||||
|
||||
# [0.11.0] - 2023-08-16
|
||||
|
||||
### Added
|
||||
|
||||
- `WeakSender`, a sender that doesn't keep the channel open
|
||||
- `Sender/Receiver::sender_count/receiver_count`, a way to query the number of senders and receivers attached to a channel
|
||||
- `Sender/Receiver::same_channel`, a way to determine whether senders and receivers are attached to the same channel
|
||||
|
||||
### Changed
|
||||
|
||||
- Relaxed some API features
|
||||
- Make all remaining spinlocks opt-in
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed a rare race condition in the async implementation
|
||||
|
||||
# [0.10.14] - 2022-07-21
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed unbounded memory usage in `RecvFut::poll_inner`
|
||||
|
||||
# [0.10.13] - 2022-06-10
|
||||
|
||||
### Added
|
||||
|
||||
- `SendSink::sender`, to get the sender of a `SendSink`
|
||||
|
||||
# [0.10.12] - 2022-03-10
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated `nanorand` to 0.7
|
||||
|
||||
# [0.10.11] - 2022-02-14
|
||||
|
||||
### Fixed
|
||||
|
||||
- Out-of-order bug when using channels asynchronously
|
||||
|
||||
# [0.10.10] - 2022-01-11
|
||||
|
||||
### Added
|
||||
|
||||
- `From<SendError>` and `From<RecvError>` impls for other error types
|
||||
- Marked futures as `#[must_use]`
|
||||
|
||||
### Changes
|
||||
|
||||
- Switched to scheduler-driven locking by default, with a `spin` feature to reenable the old behaviour
|
||||
- Minor doc improvements
|
||||
|
||||
# [0.10.9] - 2021-08-25
|
||||
|
||||
### Changed
|
||||
|
||||
- Switched from `spinning_top` to `spin`
|
||||
|
||||
# [0.10.8] - 2021-08-06
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated `nanorand` to `0.6`
|
||||
|
||||
# [0.10.7] - 2021-06-10
|
||||
|
||||
### Fixed
|
||||
|
||||
- Removed accidental nightly-only syntax
|
||||
|
||||
# [0.10.6] - 2021-06-10
|
||||
|
||||
### Added
|
||||
|
||||
- `fn into_inner(self) -> T` for send errors, allowing for easy access to the unsent message
|
||||
|
||||
# [0.10.5] - 2021-04-26
|
||||
|
||||
### Added
|
||||
|
||||
- `is_disconnected`, `is_empty`, `is_full`, `len`, and `capacity` on future types
|
||||
|
||||
# [0.10.4] - 2021-04-12
|
||||
|
||||
### Fixed
|
||||
|
||||
- Shutdown-related race condition with async recv that caused spurious errors
|
||||
|
||||
# [0.10.3] - 2021-04-09
|
||||
|
||||
### Fixed
|
||||
|
||||
- Compilation error when enabling `select` without `eventual_fairness`
|
||||
|
||||
# [0.10.2] - 2021-02-07
|
||||
|
||||
### Fixed
|
||||
|
||||
- Incorrect pointer comparison in `Selector` causing missing receives
|
||||
|
||||
# [0.10.1] - 2020-12-30
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed `T: Unpin` requirement from async traits using `pin_project`
|
||||
|
||||
# [0.10.0] - 2020-12-09
|
||||
|
||||
### Changed
|
||||
|
||||
- Renamed `SendFuture` to `SendFut` to be consistent with `RecvFut`
|
||||
- Improved async-related documentation
|
||||
|
||||
### Fixed
|
||||
|
||||
- Updated `nanorand` to address security advisory
|
1312
vendor/flume/Cargo.lock
generated
vendored
Normal file
1312
vendor/flume/Cargo.lock
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
110
vendor/flume/Cargo.toml
vendored
Normal file
110
vendor/flume/Cargo.toml
vendored
Normal file
@ -0,0 +1,110 @@
|
||||
# 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 = "2018"
|
||||
name = "flume"
|
||||
version = "0.11.0"
|
||||
authors = ["Joshua Barretto <joshua.s.barretto@gmail.com>"]
|
||||
exclude = [
|
||||
"/.github",
|
||||
"/misc",
|
||||
]
|
||||
description = "A blazingly fast multi-producer channel"
|
||||
documentation = "https://docs.rs/flume"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"mpsc",
|
||||
"fifo",
|
||||
"channel",
|
||||
"thread",
|
||||
"mpmc",
|
||||
]
|
||||
categories = [
|
||||
"concurrency",
|
||||
"data-structures",
|
||||
]
|
||||
license = "Apache-2.0/MIT"
|
||||
repository = "https://github.com/zesterer/flume"
|
||||
|
||||
[[bench]]
|
||||
name = "basic"
|
||||
harness = false
|
||||
|
||||
[dependencies.futures-core]
|
||||
version = "0.3"
|
||||
optional = true
|
||||
default_features = false
|
||||
|
||||
[dependencies.futures-sink]
|
||||
version = "0.3"
|
||||
optional = true
|
||||
default_features = false
|
||||
|
||||
[dependencies.nanorand]
|
||||
version = "0.7"
|
||||
features = ["getrandom"]
|
||||
optional = true
|
||||
|
||||
[dependencies.spin1]
|
||||
version = "0.9.8"
|
||||
features = ["mutex"]
|
||||
package = "spin"
|
||||
|
||||
[dev-dependencies.async-std]
|
||||
version = "1.9.0"
|
||||
features = [
|
||||
"attributes",
|
||||
"unstable",
|
||||
]
|
||||
|
||||
[dev-dependencies.criterion]
|
||||
version = "0.3.4"
|
||||
|
||||
[dev-dependencies.crossbeam-channel]
|
||||
version = "0.5.5"
|
||||
|
||||
[dev-dependencies.crossbeam-utils]
|
||||
version = "0.8.10"
|
||||
|
||||
[dev-dependencies.futures]
|
||||
version = "^0.3"
|
||||
features = ["std"]
|
||||
|
||||
[dev-dependencies.rand]
|
||||
version = "0.8.3"
|
||||
|
||||
[dev-dependencies.tokio]
|
||||
version = "^1.16.1"
|
||||
features = [
|
||||
"rt",
|
||||
"macros",
|
||||
]
|
||||
|
||||
[dev-dependencies.waker-fn]
|
||||
version = "1.1.0"
|
||||
|
||||
[features]
|
||||
async = [
|
||||
"futures-sink",
|
||||
"futures-core",
|
||||
]
|
||||
default = [
|
||||
"async",
|
||||
"select",
|
||||
"eventual-fairness",
|
||||
]
|
||||
eventual-fairness = [
|
||||
"select",
|
||||
"nanorand",
|
||||
]
|
||||
select = []
|
||||
spin = []
|
201
vendor/flume/LICENSE-APACHE
vendored
Normal file
201
vendor/flume/LICENSE-APACHE
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
23
vendor/flume/LICENSE-MIT
vendored
Normal file
23
vendor/flume/LICENSE-MIT
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
86
vendor/flume/README.md
vendored
Normal file
86
vendor/flume/README.md
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
# Flume
|
||||
|
||||
A blazingly fast multi-producer, multi-consumer channel.
|
||||
|
||||
[](
|
||||
https://crates.io/crates/flume)
|
||||
[](
|
||||
https://docs.rs/flume)
|
||||
[](
|
||||
https://github.com/zesterer/flume)
|
||||

|
||||
|
||||
```rust
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
|
||||
let (tx, rx) = flume::unbounded();
|
||||
|
||||
thread::spawn(move || {
|
||||
(0..10).for_each(|i| {
|
||||
tx.send(i).unwrap();
|
||||
})
|
||||
});
|
||||
|
||||
let received: u32 = rx.iter().sum();
|
||||
|
||||
assert_eq!((0..10).sum::<u32>(), received);
|
||||
}
|
||||
```
|
||||
|
||||
## Why Flume?
|
||||
|
||||
- **Featureful**: Unbounded, bounded and rendezvous queues
|
||||
- **Fast**: Always faster than `std::sync::mpsc` and sometimes `crossbeam-channel`
|
||||
- **Safe**: No `unsafe` code anywhere in the codebase!
|
||||
- **Flexible**: `Sender` and `Receiver` both implement `Send + Sync + Clone`
|
||||
- **Familiar**: Drop-in replacement for `std::sync::mpsc`
|
||||
- **Capable**: Additional features like MPMC support and send timeouts/deadlines
|
||||
- **Simple**: Few dependencies, minimal codebase, fast to compile
|
||||
- **Asynchronous**: `async` support, including mix 'n match with sync code
|
||||
- **Ergonomic**: Powerful `select`-like interface
|
||||
|
||||
## Usage
|
||||
|
||||
To use Flume, place the following line under the `[dependencies]` section in your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
flume = "x.y"
|
||||
```
|
||||
|
||||
## Cargo Features
|
||||
|
||||
Flume comes with several optional features:
|
||||
|
||||
- `spin`: use spinlocks instead of OS-level synchronisation primitives internally for some kind of data access (may be more performant on a small number of platforms for specific workloads)
|
||||
|
||||
- `select`: Adds support for the [`Selector`](https://docs.rs/flume/latest/flume/select/struct.Selector.html) API, allowing a thread to wait on several channels/operations at once
|
||||
|
||||
- `async`: Adds support for the [async API](https://docs.rs/flume/latest/flume/async/index.html), including on otherwise synchronous channels
|
||||
|
||||
- `eventual-fairness`: Use randomness in the implementation of `Selector` to avoid biasing/saturating certain events over others
|
||||
|
||||
You can enable these features by changing the dependency in your `Cargo.toml` like so:
|
||||
|
||||
```toml
|
||||
flume = { version = "x.y", default-features = false, features = ["async", "select"] }
|
||||
```
|
||||
|
||||
## [Benchmarks](https://what-if.xkcd.com/147/)
|
||||
|
||||
Although Flume has its own extensive benchmarks, don't take it from here that Flume is quick.
|
||||
The following graph is from the `crossbeam-channel` benchmark suite.
|
||||
|
||||
Tests were performed on an AMD Ryzen 7 3700x with 8/16 cores running Linux kernel 5.11.2 with the bfq scheduler.
|
||||
|
||||
# <img src="misc/benchmarks.png" alt="Flume benchmarks (crossbeam benchmark suite)" width="100%"/>
|
||||
|
||||
## License
|
||||
|
||||
Flume is licensed under either of:
|
||||
|
||||
- Apache License 2.0, (http://www.apache.org/licenses/LICENSE-2.0)
|
||||
|
||||
- MIT license (http://opensource.org/licenses/MIT)
|
474
vendor/flume/benches/basic.rs
vendored
Normal file
474
vendor/flume/benches/basic.rs
vendored
Normal file
@ -0,0 +1,474 @@
|
||||
#[macro_use]
|
||||
extern crate criterion;
|
||||
|
||||
use std::{
|
||||
sync::mpsc,
|
||||
thread,
|
||||
fmt::Debug,
|
||||
};
|
||||
use criterion::{Criterion, Bencher, black_box};
|
||||
use std::time::Instant;
|
||||
|
||||
trait Sender: Clone + Send + Sized + 'static {
|
||||
type Item: Debug + Default;
|
||||
type BoundedSender: Sender<Item=Self::Item>;
|
||||
type Receiver: Receiver<Item=Self::Item>;
|
||||
|
||||
fn unbounded() -> (Self, Self::Receiver);
|
||||
fn bounded(n: usize) -> (Self::BoundedSender, Self::Receiver);
|
||||
fn send(&self, msg: Self::Item);
|
||||
}
|
||||
|
||||
trait Receiver: Send + Sized + 'static {
|
||||
type Item: Default;
|
||||
fn recv(&self) -> Self::Item;
|
||||
fn iter(&self) -> Box<dyn Iterator<Item=Self::Item> + '_>;
|
||||
}
|
||||
|
||||
impl<T: Send + Debug + Default + 'static> Sender for flume::Sender<T> {
|
||||
type Item = T;
|
||||
type BoundedSender = Self;
|
||||
type Receiver = flume::Receiver<T>;
|
||||
|
||||
fn unbounded() -> (Self, Self::Receiver) {
|
||||
flume::unbounded()
|
||||
}
|
||||
|
||||
fn bounded(n: usize) -> (Self::BoundedSender, Self::Receiver) {
|
||||
flume::bounded(n)
|
||||
}
|
||||
|
||||
fn send(&self, msg: T) {
|
||||
flume::Sender::send(self, msg).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Default + 'static> Receiver for flume::Receiver<T> {
|
||||
type Item = T;
|
||||
|
||||
fn recv(&self) -> Self::Item {
|
||||
flume::Receiver::recv(self).unwrap()
|
||||
}
|
||||
|
||||
fn iter(&self) -> Box<dyn Iterator<Item=T> + '_> {
|
||||
Box::new(std::iter::from_fn(move || flume::Receiver::recv(self).ok()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Debug + Default + 'static> Sender for crossbeam_channel::Sender<T> {
|
||||
type Item = T;
|
||||
type BoundedSender = Self;
|
||||
type Receiver = crossbeam_channel::Receiver<T>;
|
||||
|
||||
fn unbounded() -> (Self, Self::Receiver) {
|
||||
crossbeam_channel::unbounded()
|
||||
}
|
||||
|
||||
fn bounded(n: usize) -> (Self::BoundedSender, Self::Receiver) {
|
||||
crossbeam_channel::bounded(n)
|
||||
}
|
||||
|
||||
fn send(&self, msg: T) {
|
||||
crossbeam_channel::Sender::send(self, msg).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Default + 'static> Receiver for crossbeam_channel::Receiver<T> {
|
||||
type Item = T;
|
||||
|
||||
fn recv(&self) -> Self::Item {
|
||||
crossbeam_channel::Receiver::recv(self).unwrap()
|
||||
}
|
||||
|
||||
fn iter(&self) -> Box<dyn Iterator<Item=T> + '_> {
|
||||
Box::new(crossbeam_channel::Receiver::iter(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Debug + Default + 'static> Sender for mpsc::Sender<T> {
|
||||
type Item = T;
|
||||
type BoundedSender = mpsc::SyncSender<T>;
|
||||
type Receiver = mpsc::Receiver<T>;
|
||||
|
||||
fn unbounded() -> (Self, Self::Receiver) {
|
||||
mpsc::channel()
|
||||
}
|
||||
|
||||
fn bounded(n: usize) -> (Self::BoundedSender, Self::Receiver) {
|
||||
mpsc::sync_channel(n)
|
||||
}
|
||||
|
||||
fn send(&self, msg: T) {
|
||||
mpsc::Sender::send(self, msg).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Debug + Default + 'static> Sender for mpsc::SyncSender<T> {
|
||||
type Item = T;
|
||||
type BoundedSender = Self;
|
||||
type Receiver = mpsc::Receiver<T>;
|
||||
|
||||
fn unbounded() -> (Self, Self::Receiver) { unimplemented!() }
|
||||
fn bounded(_: usize) -> (Self::BoundedSender, Self::Receiver) { unimplemented!() }
|
||||
|
||||
fn send(&self, msg: T) {
|
||||
mpsc::SyncSender::send(self, msg).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Default + 'static> Receiver for mpsc::Receiver<T> {
|
||||
type Item = T;
|
||||
|
||||
fn recv(&self) -> Self::Item {
|
||||
mpsc::Receiver::recv(self).unwrap()
|
||||
}
|
||||
|
||||
fn iter(&self) -> Box<dyn Iterator<Item=T> + '_> {
|
||||
Box::new(mpsc::Receiver::iter(self))
|
||||
}
|
||||
}
|
||||
|
||||
fn test_create<S: Sender>(b: &mut Bencher) {
|
||||
b.iter(|| S::unbounded());
|
||||
}
|
||||
|
||||
fn test_oneshot<S: Sender>(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let (tx, rx) = S::unbounded();
|
||||
tx.send(Default::default());
|
||||
black_box(rx.recv());
|
||||
});
|
||||
}
|
||||
|
||||
fn test_inout<S: Sender>(b: &mut Bencher) {
|
||||
let (tx, rx) = S::unbounded();
|
||||
b.iter(|| {
|
||||
tx.send(Default::default());
|
||||
black_box(rx.recv());
|
||||
});
|
||||
}
|
||||
|
||||
fn test_hydra<S: Sender>(b: &mut Bencher, thread_num: usize, msg_num: usize) {
|
||||
let (main_tx, main_rx) = S::unbounded();
|
||||
|
||||
let mut txs = Vec::new();
|
||||
for _ in 0..thread_num {
|
||||
let main_tx = main_tx.clone();
|
||||
let (tx, rx) = S::unbounded();
|
||||
txs.push(tx);
|
||||
|
||||
thread::spawn(move || {
|
||||
for msg in rx.iter() {
|
||||
main_tx.send(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
drop(main_tx);
|
||||
|
||||
b.iter(|| {
|
||||
for tx in &txs {
|
||||
for _ in 0..msg_num {
|
||||
tx.send(Default::default());
|
||||
}
|
||||
}
|
||||
|
||||
for _ in 0..thread_num {
|
||||
for _ in 0..msg_num {
|
||||
black_box(main_rx.recv());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn test_kitsune<S: Sender>(b: &mut Bencher, thread_num: usize, msg_num: usize)
|
||||
where S::Receiver: Clone
|
||||
{
|
||||
let (out_tx, out_rx) = S::unbounded();
|
||||
let (in_tx, in_rx) = S::unbounded();
|
||||
|
||||
for _ in 0..thread_num {
|
||||
let in_tx = in_tx.clone();
|
||||
let out_rx = out_rx.clone();
|
||||
|
||||
thread::spawn(move || {
|
||||
for msg in out_rx.iter() {
|
||||
in_tx.send(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..thread_num {
|
||||
for _ in 0..msg_num {
|
||||
out_tx.send(Default::default());
|
||||
}
|
||||
}
|
||||
|
||||
for _ in 0..thread_num {
|
||||
for _ in 0..msg_num {
|
||||
black_box(in_rx.recv());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn test_robin_u<S: Sender>(b: &mut Bencher, thread_num: usize, msg_num: usize) {
|
||||
let (mut main_tx, main_rx) = S::unbounded();
|
||||
|
||||
for _ in 0..thread_num {
|
||||
let (mut tx, rx) = S::unbounded();
|
||||
std::mem::swap(&mut tx, &mut main_tx);
|
||||
|
||||
thread::spawn(move || {
|
||||
for msg in rx.iter() {
|
||||
tx.send(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..msg_num {
|
||||
main_tx.send(Default::default());
|
||||
}
|
||||
|
||||
for _ in 0..msg_num {
|
||||
black_box(main_rx.recv());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn test_robin_b<S: Sender>(b: &mut Bencher, thread_num: usize, msg_num: usize) {
|
||||
let (mut main_tx, main_rx) = S::bounded(1);
|
||||
|
||||
for _ in 0..thread_num {
|
||||
let (mut tx, rx) = S::bounded(1);
|
||||
std::mem::swap(&mut tx, &mut main_tx);
|
||||
|
||||
thread::spawn(move || {
|
||||
for msg in rx.iter() {
|
||||
tx.send(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
b.iter(|| {
|
||||
let main_tx = main_tx.clone();
|
||||
thread::spawn(move || {
|
||||
for _ in 0..msg_num {
|
||||
main_tx.send(Default::default());
|
||||
}
|
||||
});
|
||||
|
||||
for _ in 0..msg_num {
|
||||
black_box(main_rx.recv());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn test_mpsc_bounded_no_wait<S: Sender>(b: &mut Bencher, thread_num: u64) {
|
||||
b.iter_custom(|iters| {
|
||||
let iters = iters * 1000;
|
||||
let (tx, rx) = S::bounded(iters as usize);
|
||||
let start = Instant::now();
|
||||
|
||||
crossbeam_utils::thread::scope(|scope| {
|
||||
for _ in 0..thread_num {
|
||||
let tx = tx.clone();
|
||||
scope.spawn(move |_| {
|
||||
for _ in 0..iters / thread_num {
|
||||
tx.send(Default::default());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for _ in 0..iters - ((iters / thread_num) * thread_num) {
|
||||
tx.send(Default::default());
|
||||
}
|
||||
|
||||
for _ in 0..iters {
|
||||
black_box(rx.recv());
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
start.elapsed()
|
||||
})
|
||||
}
|
||||
|
||||
fn test_mpsc_bounded<S: Sender>(b: &mut Bencher, bound: usize, thread_num: usize) {
|
||||
b.iter_custom(|iters| {
|
||||
let (tx, rx) = S::bounded(bound);
|
||||
let start = Instant::now();
|
||||
|
||||
crossbeam_utils::thread::scope(|scope| {
|
||||
let msgs = iters as usize * bound.max(1);
|
||||
|
||||
for _ in 0..thread_num {
|
||||
let tx = tx.clone();
|
||||
scope.spawn(move |_| {
|
||||
for _ in 0..msgs / thread_num as usize {
|
||||
tx.send(Default::default());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
scope.spawn(move |_| {
|
||||
// Remainder
|
||||
for _ in 0..msgs - (msgs / thread_num as usize * thread_num) {
|
||||
tx.send(Default::default());
|
||||
}
|
||||
});
|
||||
|
||||
for _ in 0..msgs {
|
||||
black_box(rx.recv());
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
start.elapsed()
|
||||
})
|
||||
}
|
||||
|
||||
fn create(b: &mut Criterion) {
|
||||
b.bench_function("create-flume", |b| test_create::<flume::Sender<u32>>(b));
|
||||
b.bench_function("create-crossbeam", |b| test_create::<crossbeam_channel::Sender<u32>>(b));
|
||||
b.bench_function("create-std", |b| test_create::<mpsc::Sender<u32>>(b));
|
||||
}
|
||||
|
||||
fn oneshot(b: &mut Criterion) {
|
||||
b.bench_function("oneshot-flume", |b| test_oneshot::<flume::Sender<u32>>(b));
|
||||
b.bench_function("oneshot-crossbeam", |b| test_oneshot::<crossbeam_channel::Sender<u32>>(b));
|
||||
b.bench_function("oneshot-std", |b| test_oneshot::<mpsc::Sender<u32>>(b));
|
||||
}
|
||||
|
||||
fn inout(b: &mut Criterion) {
|
||||
b.bench_function("inout-flume", |b| test_inout::<flume::Sender<u32>>(b));
|
||||
b.bench_function("inout-crossbeam", |b| test_inout::<crossbeam_channel::Sender<u32>>(b));
|
||||
b.bench_function("inout-std", |b| test_inout::<mpsc::Sender<u32>>(b));
|
||||
}
|
||||
|
||||
fn hydra_32t_1m(b: &mut Criterion) {
|
||||
b.bench_function("hydra-32t-1m-flume", |b| test_hydra::<flume::Sender<u32>>(b, 32, 1));
|
||||
b.bench_function("hydra-32t-1m-crossbeam", |b| test_hydra::<crossbeam_channel::Sender<u32>>(b, 32, 1));
|
||||
b.bench_function("hydra-32t-1m-std", |b| test_hydra::<mpsc::Sender<u32>>(b, 32, 1));
|
||||
}
|
||||
|
||||
fn hydra_32t_1000m(b: &mut Criterion) {
|
||||
b.bench_function("hydra-32t-1000m-flume", |b| test_hydra::<flume::Sender<u32>>(b, 32, 1000));
|
||||
b.bench_function("hydra-32t-1000m-crossbeam", |b| test_hydra::<crossbeam_channel::Sender<u32>>(b, 32, 1000));
|
||||
b.bench_function("hydra-32t-1000m-std", |b| test_hydra::<mpsc::Sender<u32>>(b, 32, 1000));
|
||||
}
|
||||
|
||||
fn hydra_256t_1m(b: &mut Criterion) {
|
||||
b.bench_function("hydra-256t-1m-flume", |b| test_hydra::<flume::Sender<u32>>(b, 256, 1));
|
||||
b.bench_function("hydra-256t-1m-crossbeam", |b| test_hydra::<crossbeam_channel::Sender<u32>>(b, 256, 1));
|
||||
b.bench_function("hydra-256t-1m-std", |b| test_hydra::<mpsc::Sender<u32>>(b, 256, 1));
|
||||
}
|
||||
|
||||
fn hydra_1t_1000m(b: &mut Criterion) {
|
||||
b.bench_function("hydra-1t-1000m-flume", |b| test_hydra::<flume::Sender<u32>>(b, 1, 1000));
|
||||
b.bench_function("hydra-1t-1000m-crossbeam", |b| test_hydra::<crossbeam_channel::Sender<u32>>(b, 1, 1000));
|
||||
b.bench_function("hydra-1t-1000m-std", |b| test_hydra::<mpsc::Sender<u32>>(b, 1, 1000));
|
||||
}
|
||||
|
||||
fn hydra_4t_10000m(b: &mut Criterion) {
|
||||
b.bench_function("hydra-4t-10000m-flume", |b| test_hydra::<flume::Sender<u32>>(b, 4, 10000));
|
||||
b.bench_function("hydra-4t-10000m-crossbeam", |b| test_hydra::<crossbeam_channel::Sender<u32>>(b, 4, 10000));
|
||||
b.bench_function("hydra-4t-10000m-std", |b| test_hydra::<mpsc::Sender<u32>>(b, 4, 10000));
|
||||
}
|
||||
|
||||
fn kitsune_32t_1m(b: &mut Criterion) {
|
||||
b.bench_function("kitsune-32t-1m-flume", |b| test_kitsune::<flume::Sender<u32>>(b, 32, 1));
|
||||
b.bench_function("kitsune-32t-1m-crossbeam", |b| test_kitsune::<crossbeam_channel::Sender<u32>>(b, 32, 1));
|
||||
//b.bench_function("kitsune-32t-1m-std", |b| test_kitsune::<mpsc::Sender<u32>>(b, 32, 1));
|
||||
}
|
||||
|
||||
fn kitsune_32t_1000m(b: &mut Criterion) {
|
||||
b.bench_function("kitsune-32t-1000m-flume", |b| test_kitsune::<flume::Sender<u32>>(b, 32, 1000));
|
||||
b.bench_function("kitsune-32t-1000m-crossbeam", |b| test_kitsune::<crossbeam_channel::Sender<u32>>(b, 32, 1000));
|
||||
//b.bench_function("kitsune-32t-1000m-std", |b| test_kitsune::<mpsc::Sender<u32>>(b, 32, 1000));
|
||||
}
|
||||
|
||||
fn kitsune_256t_1m(b: &mut Criterion) {
|
||||
b.bench_function("kitsune-256t-1m-flume", |b| test_kitsune::<flume::Sender<u32>>(b, 256, 1));
|
||||
b.bench_function("kitsune-256t-1m-crossbeam", |b| test_kitsune::<crossbeam_channel::Sender<u32>>(b, 256, 1));
|
||||
//b.bench_function("kitsune-256t-1m-std", |b| test_kitsune::<mpsc::Sender<u32>>(b, 256, 1));
|
||||
}
|
||||
|
||||
fn kitsune_1t_1000m(b: &mut Criterion) {
|
||||
b.bench_function("kitsune-1t-1000m-flume", |b| test_kitsune::<flume::Sender<u32>>(b, 1, 1000));
|
||||
b.bench_function("kitsune-1t-1000m-crossbeam", |b| test_kitsune::<crossbeam_channel::Sender<u32>>(b, 1, 1000));
|
||||
//b.bench_function("kitsune-1t-1000m-std", |b| test_kitsune::<mpsc::Sender<u32>>(b, 1, 1000));
|
||||
}
|
||||
|
||||
fn kitsune_4t_10000m(b: &mut Criterion) {
|
||||
b.bench_function("kitsune-4t-10000m-flume", |b| test_kitsune::<flume::Sender<u32>>(b, 4, 10000));
|
||||
b.bench_function("kitsune-4t-10000m-crossbeam", |b| test_kitsune::<crossbeam_channel::Sender<u32>>(b, 4, 10000));
|
||||
//b.bench_function("kitsune-4t-10000m-std", |b| test_kitsune::<mpsc::Sender<u32>>(b, 4, 10000));
|
||||
}
|
||||
|
||||
fn robin_u_32t_1m(b: &mut Criterion) {
|
||||
b.bench_function("robin-u-32t-1m-flume", |b| test_robin_u::<flume::Sender<u32>>(b, 32, 1));
|
||||
b.bench_function("robin-u-32t-1m-crossbeam", |b| test_robin_u::<crossbeam_channel::Sender<u32>>(b, 32, 1));
|
||||
b.bench_function("robin-u-32t-1m-std", |b| test_robin_u::<mpsc::Sender<u32>>(b, 32, 1));
|
||||
}
|
||||
|
||||
fn robin_u_4t_1000m(b: &mut Criterion) {
|
||||
b.bench_function("robin-u-4t-1000m-flume", |b| test_robin_u::<flume::Sender<u32>>(b, 4, 1000));
|
||||
b.bench_function("robin-u-4t-1000m-crossbeam", |b| test_robin_u::<crossbeam_channel::Sender<u32>>(b, 4, 1000));
|
||||
b.bench_function("robin-u-4t-1000m-std", |b| test_robin_u::<mpsc::Sender<u32>>(b, 4, 1000));
|
||||
}
|
||||
|
||||
fn robin_b_32t_16m(b: &mut Criterion) {
|
||||
b.bench_function("robin-b-32t-16m-flume", |b| test_robin_b::<flume::Sender<u32>>(b, 32, 16));
|
||||
b.bench_function("robin-b-32t-16m-crossbeam", |b| test_robin_b::<crossbeam_channel::Sender<u32>>(b, 32, 16));
|
||||
b.bench_function("robin-b-32t-16m-std", |b| test_robin_b::<mpsc::Sender<u32>>(b, 32, 16));
|
||||
}
|
||||
|
||||
fn robin_b_4t_1000m(b: &mut Criterion) {
|
||||
b.bench_function("robin-b-4t-1000m-flume", |b| test_robin_b::<flume::Sender<u32>>(b, 4, 1000));
|
||||
b.bench_function("robin-b-4t-1000m-crossbeam", |b| test_robin_b::<crossbeam_channel::Sender<u32>>(b, 4, 1000));
|
||||
b.bench_function("robin-b-4t-1000m-std", |b| test_robin_b::<mpsc::Sender<u32>>(b, 4, 1000));
|
||||
}
|
||||
|
||||
fn mpsc_bounded_no_wait_4t(b: &mut Criterion) {
|
||||
b.bench_function("mpsc-bounded-no-wait-4t-flume", |b| test_mpsc_bounded_no_wait::<flume::Sender<u32>>(b, 4));
|
||||
b.bench_function("mpsc-bounded-no-wait-4t-crossbeam", |b| test_mpsc_bounded_no_wait::<crossbeam_channel::Sender<u32>>(b, 4));
|
||||
b.bench_function("mpsc-bounded-no-wait-4t-std", |b| test_mpsc_bounded_no_wait::<mpsc::Sender<u32>>(b, 4));
|
||||
}
|
||||
|
||||
fn mpsc_bounded_4t(b: &mut Criterion) {
|
||||
for bound in &[0, 1, 10, 50, 10_000] {
|
||||
let text = format!("mpsc-bounded-small-4t-{}m-", bound);
|
||||
let bound = *bound;
|
||||
|
||||
b.bench_function(&format!("{}{}", text, "flume"), |b| test_mpsc_bounded::<flume::Sender<u32>>(b, bound, 4));
|
||||
b.bench_function(&format!("{}{}", text, "crossbeam"), |b| test_mpsc_bounded::<crossbeam_channel::Sender<u32>>(b, bound, 4));
|
||||
b.bench_function(&format!("{}{}", text, "std"), |b| test_mpsc_bounded::<mpsc::Sender<u32>>(b, bound, 4));
|
||||
}
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
compare,
|
||||
create,
|
||||
oneshot,
|
||||
inout,
|
||||
hydra_32t_1m,
|
||||
hydra_32t_1000m,
|
||||
hydra_256t_1m,
|
||||
hydra_1t_1000m,
|
||||
hydra_4t_10000m,
|
||||
robin_b_32t_16m,
|
||||
robin_b_4t_1000m,
|
||||
robin_u_32t_1m,
|
||||
robin_u_4t_1000m,
|
||||
mpsc_bounded_no_wait_4t,
|
||||
mpsc_bounded_4t,
|
||||
kitsune_32t_1m,
|
||||
kitsune_32t_1000m,
|
||||
kitsune_256t_1m,
|
||||
kitsune_1t_1000m,
|
||||
kitsune_4t_10000m,
|
||||
);
|
||||
criterion_main!(compare);
|
21
vendor/flume/examples/async.rs
vendored
Normal file
21
vendor/flume/examples/async.rs
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
#[cfg(feature = "async")]
|
||||
#[async_std::main]
|
||||
async fn main() {
|
||||
let (tx, rx) = flume::bounded(1);
|
||||
|
||||
let t = async_std::task::spawn(async move {
|
||||
while let Ok(msg) = rx.recv_async().await {
|
||||
println!("Received: {}", msg);
|
||||
}
|
||||
});
|
||||
|
||||
tx.send_async("Hello, world!").await.unwrap();
|
||||
tx.send_async("How are you today?").await.unwrap();
|
||||
|
||||
drop(tx);
|
||||
|
||||
t.await;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "async"))]
|
||||
fn main() {}
|
30
vendor/flume/examples/perf.rs
vendored
Normal file
30
vendor/flume/examples/perf.rs
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
fn main() {
|
||||
let thread_num = 32;
|
||||
let msg_num = 16;
|
||||
|
||||
let (mut main_tx, main_rx) = flume::bounded::<()>(1);
|
||||
|
||||
for _ in 0..thread_num {
|
||||
let (mut tx, rx) = flume::bounded(1);
|
||||
std::mem::swap(&mut tx, &mut main_tx);
|
||||
|
||||
std::thread::spawn(move || {
|
||||
for msg in rx.iter() {
|
||||
tx.send(msg).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for _ in 0..1000 {
|
||||
let main_tx = main_tx.clone();
|
||||
std::thread::spawn(move || {
|
||||
for _ in 0..msg_num {
|
||||
main_tx.send(Default::default()).unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
for _ in 0..msg_num {
|
||||
main_rx.recv().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
25
vendor/flume/examples/select.rs
vendored
Normal file
25
vendor/flume/examples/select.rs
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
#[cfg(feature = "select")]
|
||||
use flume::Selector;
|
||||
|
||||
#[cfg(feature = "select")]
|
||||
fn main() {
|
||||
// Create two channels
|
||||
let (red_tx, red_rx) = flume::unbounded();
|
||||
let (blue_tx, blue_rx) = flume::unbounded();
|
||||
|
||||
// Spawn two threads that each send a message into their respective channel
|
||||
std::thread::spawn(move || { let _ = red_tx.send("Red"); });
|
||||
std::thread::spawn(move || { let _ = blue_tx.send("Blue"); });
|
||||
|
||||
// Race them to see which one sends their message first
|
||||
let winner = Selector::new()
|
||||
.recv(&red_rx, |msg| msg)
|
||||
.recv(&blue_rx, |msg| msg)
|
||||
.wait()
|
||||
.unwrap();
|
||||
|
||||
println!("{} won!", winner);
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "select"))]
|
||||
fn main() {}
|
18
vendor/flume/examples/simple.rs
vendored
Normal file
18
vendor/flume/examples/simple.rs
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
let (tx, rx) = flume::unbounded();
|
||||
|
||||
let t = thread::spawn(move || {
|
||||
for msg in rx.iter() {
|
||||
println!("Received: {}", msg);
|
||||
}
|
||||
});
|
||||
|
||||
tx.send("Hello, world!").unwrap();
|
||||
tx.send("How are you today?").unwrap();
|
||||
|
||||
drop(tx);
|
||||
|
||||
t.join().unwrap();
|
||||
}
|
543
vendor/flume/src/async.rs
vendored
Normal file
543
vendor/flume/src/async.rs
vendored
Normal file
@ -0,0 +1,543 @@
|
||||
//! Futures and other types that allow asynchronous interaction with channels.
|
||||
|
||||
use std::{
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
task::{Context, Poll, Waker},
|
||||
any::Any,
|
||||
ops::Deref,
|
||||
};
|
||||
use crate::*;
|
||||
use futures_core::{stream::{Stream, FusedStream}, future::FusedFuture};
|
||||
use futures_sink::Sink;
|
||||
use spin1::Mutex as Spinlock;
|
||||
|
||||
struct AsyncSignal {
|
||||
waker: Spinlock<Waker>,
|
||||
woken: AtomicBool,
|
||||
stream: bool,
|
||||
}
|
||||
|
||||
impl AsyncSignal {
|
||||
fn new(cx: &Context, stream: bool) -> Self {
|
||||
AsyncSignal {
|
||||
waker: Spinlock::new(cx.waker().clone()),
|
||||
woken: AtomicBool::new(false),
|
||||
stream,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Signal for AsyncSignal {
|
||||
fn fire(&self) -> bool {
|
||||
self.woken.store(true, Ordering::SeqCst);
|
||||
self.waker.lock().wake_by_ref();
|
||||
self.stream
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &(dyn Any + 'static) { self }
|
||||
fn as_ptr(&self) -> *const () { self as *const _ as *const () }
|
||||
}
|
||||
|
||||
impl<T> Hook<T, AsyncSignal> {
|
||||
// Update the hook to point to the given Waker.
|
||||
// Returns whether the hook has been previously awakened
|
||||
fn update_waker(&self, cx_waker: &Waker) -> bool {
|
||||
let mut waker = self.1.waker.lock();
|
||||
let woken = self.1.woken.load(Ordering::SeqCst);
|
||||
if !waker.will_wake(cx_waker) {
|
||||
*waker = cx_waker.clone();
|
||||
|
||||
// Avoid the edge case where the waker was woken just before the wakers were
|
||||
// swapped.
|
||||
if woken {
|
||||
cx_waker.wake_by_ref();
|
||||
}
|
||||
}
|
||||
woken
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum OwnedOrRef<'a, T> {
|
||||
Owned(T),
|
||||
Ref(&'a T),
|
||||
}
|
||||
|
||||
impl<'a, T> Deref for OwnedOrRef<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
match self {
|
||||
OwnedOrRef::Owned(arc) => &arc,
|
||||
OwnedOrRef::Ref(r) => r,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Sender<T> {
|
||||
/// Asynchronously send a value into the channel, returning an error if all receivers have been
|
||||
/// dropped. If the channel is bounded and is full, the returned future will yield to the async
|
||||
/// runtime.
|
||||
///
|
||||
/// In the current implementation, the returned future will not yield to the async runtime if the
|
||||
/// channel is unbounded. This may change in later versions.
|
||||
pub fn send_async(&self, item: T) -> SendFut<T> {
|
||||
SendFut {
|
||||
sender: OwnedOrRef::Ref(&self),
|
||||
hook: Some(SendState::NotYetSent(item)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert this sender into a future that asynchronously sends a single message into the channel,
|
||||
/// returning an error if all receivers have been dropped. If the channel is bounded and is full,
|
||||
/// this future will yield to the async runtime.
|
||||
///
|
||||
/// In the current implementation, the returned future will not yield to the async runtime if the
|
||||
/// channel is unbounded. This may change in later versions.
|
||||
pub fn into_send_async<'a>(self, item: T) -> SendFut<'a, T> {
|
||||
SendFut {
|
||||
sender: OwnedOrRef::Owned(self),
|
||||
hook: Some(SendState::NotYetSent(item)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an asynchronous sink that uses this sender to asynchronously send messages into the
|
||||
/// channel. The sender will continue to be usable after the sink has been dropped.
|
||||
///
|
||||
/// In the current implementation, the returned sink will not yield to the async runtime if the
|
||||
/// channel is unbounded. This may change in later versions.
|
||||
pub fn sink(&self) -> SendSink<'_, T> {
|
||||
SendSink(SendFut {
|
||||
sender: OwnedOrRef::Ref(&self),
|
||||
hook: None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Convert this sender into a sink that allows asynchronously sending messages into the channel.
|
||||
///
|
||||
/// In the current implementation, the returned sink will not yield to the async runtime if the
|
||||
/// channel is unbounded. This may change in later versions.
|
||||
pub fn into_sink<'a>(self) -> SendSink<'a, T> {
|
||||
SendSink(SendFut {
|
||||
sender: OwnedOrRef::Owned(self),
|
||||
hook: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
enum SendState<T> {
|
||||
NotYetSent(T),
|
||||
QueuedItem(Arc<Hook<T, AsyncSignal>>),
|
||||
}
|
||||
|
||||
/// A future that sends a value into a channel.
|
||||
///
|
||||
/// Can be created via [`Sender::send_async`] or [`Sender::into_send_async`].
|
||||
#[must_use = "futures/streams/sinks do nothing unless you `.await` or poll them"]
|
||||
pub struct SendFut<'a, T> {
|
||||
sender: OwnedOrRef<'a, Sender<T>>,
|
||||
// Only none after dropping
|
||||
hook: Option<SendState<T>>,
|
||||
}
|
||||
|
||||
impl<T> std::marker::Unpin for SendFut<'_, T> {}
|
||||
|
||||
impl<'a, T> SendFut<'a, T> {
|
||||
/// Reset the hook, clearing it and removing it from the waiting sender's queue. This is called
|
||||
/// on drop and just before `start_send` in the `Sink` implementation.
|
||||
fn reset_hook(&mut self) {
|
||||
if let Some(SendState::QueuedItem(hook)) = self.hook.take() {
|
||||
let hook: Arc<Hook<T, dyn Signal>> = hook;
|
||||
wait_lock(&self.sender.shared.chan).sending
|
||||
.as_mut()
|
||||
.unwrap().1
|
||||
.retain(|s| s.signal().as_ptr() != hook.signal().as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
/// See [`Sender::is_disconnected`].
|
||||
pub fn is_disconnected(&self) -> bool {
|
||||
self.sender.is_disconnected()
|
||||
}
|
||||
|
||||
/// See [`Sender::is_empty`].
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.sender.is_empty()
|
||||
}
|
||||
|
||||
/// See [`Sender::is_full`].
|
||||
pub fn is_full(&self) -> bool {
|
||||
self.sender.is_full()
|
||||
}
|
||||
|
||||
/// See [`Sender::len`].
|
||||
pub fn len(&self) -> usize {
|
||||
self.sender.len()
|
||||
}
|
||||
|
||||
/// See [`Sender::capacity`].
|
||||
pub fn capacity(&self) -> Option<usize> {
|
||||
self.sender.capacity()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for SendFut<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
self.reset_hook()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'a, T> Future for SendFut<'a, T> {
|
||||
type Output = Result<(), SendError<T>>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
if let Some(SendState::QueuedItem(hook)) = self.hook.as_ref() {
|
||||
if hook.is_empty() {
|
||||
Poll::Ready(Ok(()))
|
||||
} else if self.sender.shared.is_disconnected() {
|
||||
let item = hook.try_take();
|
||||
self.hook = None;
|
||||
match item {
|
||||
Some(item) => Poll::Ready(Err(SendError(item))),
|
||||
None => Poll::Ready(Ok(())),
|
||||
}
|
||||
} else {
|
||||
hook.update_waker(cx.waker());
|
||||
Poll::Pending
|
||||
}
|
||||
} else if let Some(SendState::NotYetSent(item)) = self.hook.take() {
|
||||
let this = self.get_mut();
|
||||
let (shared, this_hook) = (&this.sender.shared, &mut this.hook);
|
||||
|
||||
shared.send(
|
||||
// item
|
||||
item,
|
||||
// should_block
|
||||
true,
|
||||
// make_signal
|
||||
|msg| Hook::slot(Some(msg), AsyncSignal::new(cx, false)),
|
||||
// do_block
|
||||
|hook| {
|
||||
*this_hook = Some(SendState::QueuedItem(hook));
|
||||
Poll::Pending
|
||||
},
|
||||
)
|
||||
.map(|r| r.map_err(|err| match err {
|
||||
TrySendTimeoutError::Disconnected(msg) => SendError(msg),
|
||||
_ => unreachable!(),
|
||||
}))
|
||||
} else { // Nothing to do
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> FusedFuture for SendFut<'a, T> {
|
||||
fn is_terminated(&self) -> bool {
|
||||
self.sender.shared.is_disconnected()
|
||||
}
|
||||
}
|
||||
|
||||
/// A sink that allows sending values into a channel.
|
||||
///
|
||||
/// Can be created via [`Sender::sink`] or [`Sender::into_sink`].
|
||||
pub struct SendSink<'a, T>(SendFut<'a, T>);
|
||||
|
||||
impl<'a, T> SendSink<'a, T> {
|
||||
/// Returns a clone of a sending half of the channel of this sink.
|
||||
pub fn sender(&self) -> &Sender<T> {
|
||||
&self.0.sender
|
||||
}
|
||||
|
||||
/// See [`Sender::is_disconnected`].
|
||||
pub fn is_disconnected(&self) -> bool {
|
||||
self.0.is_disconnected()
|
||||
}
|
||||
|
||||
/// See [`Sender::is_empty`].
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
/// See [`Sender::is_full`].
|
||||
pub fn is_full(&self) -> bool {
|
||||
self.0.is_full()
|
||||
}
|
||||
|
||||
/// See [`Sender::len`].
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
/// See [`Sender::capacity`].
|
||||
pub fn capacity(&self) -> Option<usize> {
|
||||
self.0.capacity()
|
||||
}
|
||||
|
||||
/// Returns whether the SendSinks are belong to the same channel.
|
||||
pub fn same_channel(&self, other: &Self) -> bool {
|
||||
self.sender().same_channel(other.sender())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Sink<T> for SendSink<'a, T> {
|
||||
type Error = SendError<T>;
|
||||
|
||||
fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
Pin::new(&mut self.0).poll(cx)
|
||||
}
|
||||
|
||||
fn start_send(mut self: Pin<&mut Self>, item: T) -> Result<(), Self::Error> {
|
||||
self.0.reset_hook();
|
||||
self.0.hook = Some(SendState::NotYetSent(item));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
Pin::new(&mut self.0).poll(cx) // TODO: A different strategy here?
|
||||
}
|
||||
|
||||
fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
Pin::new(&mut self.0).poll(cx) // TODO: A different strategy here?
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Clone for SendSink<'a, T> {
|
||||
fn clone(&self) -> SendSink<'a, T> {
|
||||
SendSink(SendFut {
|
||||
sender: self.0.sender.clone(),
|
||||
hook: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Receiver<T> {
|
||||
/// Asynchronously receive a value from the channel, returning an error if all senders have been
|
||||
/// dropped. If the channel is empty, the returned future will yield to the async runtime.
|
||||
pub fn recv_async(&self) -> RecvFut<'_, T> {
|
||||
RecvFut::new(OwnedOrRef::Ref(self))
|
||||
}
|
||||
|
||||
/// Convert this receiver into a future that asynchronously receives a single message from the
|
||||
/// channel, returning an error if all senders have been dropped. If the channel is empty, this
|
||||
/// future will yield to the async runtime.
|
||||
pub fn into_recv_async<'a>(self) -> RecvFut<'a, T> {
|
||||
RecvFut::new(OwnedOrRef::Owned(self))
|
||||
}
|
||||
|
||||
/// Create an asynchronous stream that uses this receiver to asynchronously receive messages
|
||||
/// from the channel. The receiver will continue to be usable after the stream has been dropped.
|
||||
pub fn stream(&self) -> RecvStream<'_, T> {
|
||||
RecvStream(RecvFut::new(OwnedOrRef::Ref(self)))
|
||||
}
|
||||
|
||||
/// Convert this receiver into a stream that allows asynchronously receiving messages from the channel.
|
||||
pub fn into_stream<'a>(self) -> RecvStream<'a, T> {
|
||||
RecvStream(RecvFut::new(OwnedOrRef::Owned(self)))
|
||||
}
|
||||
}
|
||||
|
||||
/// A future which allows asynchronously receiving a message.
|
||||
///
|
||||
/// Can be created via [`Receiver::recv_async`] or [`Receiver::into_recv_async`].
|
||||
#[must_use = "futures/streams/sinks do nothing unless you `.await` or poll them"]
|
||||
pub struct RecvFut<'a, T> {
|
||||
receiver: OwnedOrRef<'a, Receiver<T>>,
|
||||
hook: Option<Arc<Hook<T, AsyncSignal>>>,
|
||||
}
|
||||
|
||||
impl<'a, T> RecvFut<'a, T> {
|
||||
fn new(receiver: OwnedOrRef<'a, Receiver<T>>) -> Self {
|
||||
Self {
|
||||
receiver,
|
||||
hook: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Reset the hook, clearing it and removing it from the waiting receivers queue and waking
|
||||
/// another receiver if this receiver has been woken, so as not to cause any missed wakeups.
|
||||
/// This is called on drop and after a new item is received in `Stream::poll_next`.
|
||||
fn reset_hook(&mut self) {
|
||||
if let Some(hook) = self.hook.take() {
|
||||
let hook: Arc<Hook<T, dyn Signal>> = hook;
|
||||
let mut chan = wait_lock(&self.receiver.shared.chan);
|
||||
// We'd like to use `Arc::ptr_eq` here but it doesn't seem to work consistently with wide pointers?
|
||||
chan.waiting.retain(|s| s.signal().as_ptr() != hook.signal().as_ptr());
|
||||
if hook.signal().as_any().downcast_ref::<AsyncSignal>().unwrap().woken.load(Ordering::SeqCst) {
|
||||
// If this signal has been fired, but we're being dropped (and so not listening to it),
|
||||
// pass the signal on to another receiver
|
||||
chan.try_wake_receiver_if_pending();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_inner(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context,
|
||||
stream: bool,
|
||||
) -> Poll<Result<T, RecvError>> {
|
||||
if self.hook.is_some() {
|
||||
match self.receiver.shared.recv_sync(None) {
|
||||
Ok(msg) => return Poll::Ready(Ok(msg)),
|
||||
Err(TryRecvTimeoutError::Disconnected) => {
|
||||
return Poll::Ready(Err(RecvError::Disconnected))
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let hook = self.hook.as_ref().map(Arc::clone).unwrap();
|
||||
if hook.update_waker(cx.waker()) {
|
||||
// If the previous hook was awakened, we need to insert it back to the
|
||||
// queue, otherwise, it remains valid.
|
||||
wait_lock(&self.receiver.shared.chan)
|
||||
.waiting
|
||||
.push_back(hook);
|
||||
}
|
||||
// To avoid a missed wakeup, re-check disconnect status here because the channel might have
|
||||
// gotten shut down before we had a chance to push our hook
|
||||
if self.receiver.shared.is_disconnected() {
|
||||
// And now, to avoid a race condition between the first recv attempt and the disconnect check we
|
||||
// just performed, attempt to recv again just in case we missed something.
|
||||
Poll::Ready(
|
||||
self.receiver
|
||||
.shared
|
||||
.recv_sync(None)
|
||||
.map(Ok)
|
||||
.unwrap_or(Err(RecvError::Disconnected)),
|
||||
)
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
} else {
|
||||
let mut_self = self.get_mut();
|
||||
let (shared, this_hook) = (&mut_self.receiver.shared, &mut mut_self.hook);
|
||||
|
||||
shared.recv(
|
||||
// should_block
|
||||
true,
|
||||
// make_signal
|
||||
|| Hook::trigger(AsyncSignal::new(cx, stream)),
|
||||
// do_block
|
||||
|hook| {
|
||||
*this_hook = Some(hook);
|
||||
Poll::Pending
|
||||
},
|
||||
)
|
||||
.map(|r| r.map_err(|err| match err {
|
||||
TryRecvTimeoutError::Disconnected => RecvError::Disconnected,
|
||||
_ => unreachable!(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
/// See [`Receiver::is_disconnected`].
|
||||
pub fn is_disconnected(&self) -> bool {
|
||||
self.receiver.is_disconnected()
|
||||
}
|
||||
|
||||
/// See [`Receiver::is_empty`].
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.receiver.is_empty()
|
||||
}
|
||||
|
||||
/// See [`Receiver::is_full`].
|
||||
pub fn is_full(&self) -> bool {
|
||||
self.receiver.is_full()
|
||||
}
|
||||
|
||||
/// See [`Receiver::len`].
|
||||
pub fn len(&self) -> usize {
|
||||
self.receiver.len()
|
||||
}
|
||||
|
||||
/// See [`Receiver::capacity`].
|
||||
pub fn capacity(&self) -> Option<usize> {
|
||||
self.receiver.capacity()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for RecvFut<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
self.reset_hook();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Future for RecvFut<'a, T> {
|
||||
type Output = Result<T, RecvError>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
self.poll_inner(cx, false) // stream = false
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> FusedFuture for RecvFut<'a, T> {
|
||||
fn is_terminated(&self) -> bool {
|
||||
self.receiver.shared.is_disconnected() && self.receiver.shared.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
/// A stream which allows asynchronously receiving messages.
|
||||
///
|
||||
/// Can be created via [`Receiver::stream`] or [`Receiver::into_stream`].
|
||||
pub struct RecvStream<'a, T>(RecvFut<'a, T>);
|
||||
|
||||
impl<'a, T> RecvStream<'a, T> {
|
||||
/// See [`Receiver::is_disconnected`].
|
||||
pub fn is_disconnected(&self) -> bool {
|
||||
self.0.is_disconnected()
|
||||
}
|
||||
|
||||
/// See [`Receiver::is_empty`].
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
/// See [`Receiver::is_full`].
|
||||
pub fn is_full(&self) -> bool {
|
||||
self.0.is_full()
|
||||
}
|
||||
|
||||
/// See [`Receiver::len`].
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
/// See [`Receiver::capacity`].
|
||||
pub fn capacity(&self) -> Option<usize> {
|
||||
self.0.capacity()
|
||||
}
|
||||
|
||||
/// Returns whether the SendSinks are belong to the same channel.
|
||||
pub fn same_channel(&self, other: &Self) -> bool {
|
||||
self.0.receiver.same_channel(&*other.0.receiver)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Clone for RecvStream<'a, T> {
|
||||
fn clone(&self) -> RecvStream<'a, T> {
|
||||
RecvStream(RecvFut::new(self.0.receiver.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Stream for RecvStream<'a, T> {
|
||||
type Item = T;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
match Pin::new(&mut self.0).poll_inner(cx, true) { // stream = true
|
||||
Poll::Pending => Poll::Pending,
|
||||
Poll::Ready(item) => {
|
||||
self.0.reset_hook();
|
||||
Poll::Ready(item.ok())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> FusedStream for RecvStream<'a, T> {
|
||||
fn is_terminated(&self) -> bool {
|
||||
self.0.is_terminated()
|
||||
}
|
||||
}
|
1142
vendor/flume/src/lib.rs
vendored
Normal file
1142
vendor/flume/src/lib.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
405
vendor/flume/src/select.rs
vendored
Normal file
405
vendor/flume/src/select.rs
vendored
Normal file
@ -0,0 +1,405 @@
|
||||
//! Types that permit waiting upon multiple blocking operations using the [`Selector`] interface.
|
||||
|
||||
use crate::*;
|
||||
use spin1::Mutex as Spinlock;
|
||||
use std::{any::Any, marker::PhantomData};
|
||||
|
||||
#[cfg(feature = "eventual-fairness")]
|
||||
use nanorand::Rng;
|
||||
|
||||
// A unique token corresponding to an event in a selector
|
||||
type Token = usize;
|
||||
|
||||
struct SelectSignal(
|
||||
thread::Thread,
|
||||
Token,
|
||||
AtomicBool,
|
||||
Arc<Spinlock<VecDeque<Token>>>,
|
||||
);
|
||||
|
||||
impl Signal for SelectSignal {
|
||||
fn fire(&self) -> bool {
|
||||
self.2.store(true, Ordering::SeqCst);
|
||||
self.3.lock().push_back(self.1);
|
||||
self.0.unpark();
|
||||
false
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &(dyn Any + 'static) {
|
||||
self
|
||||
}
|
||||
fn as_ptr(&self) -> *const () {
|
||||
self as *const _ as *const ()
|
||||
}
|
||||
}
|
||||
|
||||
trait Selection<'a, T> {
|
||||
fn init(&mut self) -> Option<T>;
|
||||
fn poll(&mut self) -> Option<T>;
|
||||
fn deinit(&mut self);
|
||||
}
|
||||
|
||||
/// An error that may be emitted when attempting to wait for a value on a receiver.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum SelectError {
|
||||
/// A timeout occurred when waiting on a `Selector`.
|
||||
Timeout,
|
||||
}
|
||||
|
||||
impl fmt::Display for SelectError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
SelectError::Timeout => "timeout occurred".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for SelectError {}
|
||||
|
||||
/// A type used to wait upon multiple blocking operations at once.
|
||||
///
|
||||
/// A [`Selector`] implements [`select`](https://en.wikipedia.org/wiki/Select_(Unix))-like behaviour,
|
||||
/// allowing a thread to wait upon the result of more than one operation at once.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// let (tx0, rx0) = flume::unbounded();
|
||||
/// let (tx1, rx1) = flume::unbounded();
|
||||
///
|
||||
/// std::thread::spawn(move || {
|
||||
/// tx0.send(true).unwrap();
|
||||
/// tx1.send(42).unwrap();
|
||||
/// });
|
||||
///
|
||||
/// flume::Selector::new()
|
||||
/// .recv(&rx0, |b| println!("Received {:?}", b))
|
||||
/// .recv(&rx1, |n| println!("Received {:?}", n))
|
||||
/// .wait();
|
||||
/// ```
|
||||
pub struct Selector<'a, T: 'a> {
|
||||
selections: Vec<Box<dyn Selection<'a, T> + 'a>>,
|
||||
next_poll: usize,
|
||||
signalled: Arc<Spinlock<VecDeque<Token>>>,
|
||||
#[cfg(feature = "eventual-fairness")]
|
||||
rng: nanorand::WyRand,
|
||||
phantom: PhantomData<*const ()>,
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> Default for Selector<'a, T> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> fmt::Debug for Selector<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Selector").finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Selector<'a, T> {
|
||||
/// Create a new selector.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
selections: Vec::new(),
|
||||
next_poll: 0,
|
||||
signalled: Arc::default(),
|
||||
phantom: PhantomData::default(),
|
||||
#[cfg(feature = "eventual-fairness")]
|
||||
rng: nanorand::WyRand::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a send operation to the selector that sends the provided value.
|
||||
///
|
||||
/// Once added, the selector can be used to run the provided handler function on completion of this operation.
|
||||
pub fn send<U, F: FnMut(Result<(), SendError<U>>) -> T + 'a>(
|
||||
mut self,
|
||||
sender: &'a Sender<U>,
|
||||
msg: U,
|
||||
mapper: F,
|
||||
) -> Self {
|
||||
struct SendSelection<'a, T, F, U> {
|
||||
sender: &'a Sender<U>,
|
||||
msg: Option<U>,
|
||||
token: Token,
|
||||
signalled: Arc<Spinlock<VecDeque<Token>>>,
|
||||
hook: Option<Arc<Hook<U, SelectSignal>>>,
|
||||
mapper: F,
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'a, T, F, U> Selection<'a, T> for SendSelection<'a, T, F, U>
|
||||
where
|
||||
F: FnMut(Result<(), SendError<U>>) -> T,
|
||||
{
|
||||
fn init(&mut self) -> Option<T> {
|
||||
let token = self.token;
|
||||
let signalled = self.signalled.clone();
|
||||
let r = self.sender.shared.send(
|
||||
self.msg.take().unwrap(),
|
||||
true,
|
||||
|msg| {
|
||||
Hook::slot(
|
||||
Some(msg),
|
||||
SelectSignal(
|
||||
thread::current(),
|
||||
token,
|
||||
AtomicBool::new(false),
|
||||
signalled,
|
||||
),
|
||||
)
|
||||
},
|
||||
// Always runs
|
||||
|h| {
|
||||
self.hook = Some(h);
|
||||
Ok(())
|
||||
},
|
||||
);
|
||||
|
||||
if self.hook.is_none() {
|
||||
Some((self.mapper)(match r {
|
||||
Ok(()) => Ok(()),
|
||||
Err(TrySendTimeoutError::Disconnected(msg)) => Err(SendError(msg)),
|
||||
_ => unreachable!(),
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn poll(&mut self) -> Option<T> {
|
||||
let res = if self.sender.shared.is_disconnected() {
|
||||
// Check the hook one last time
|
||||
if let Some(msg) = self.hook.as_ref()?.try_take() {
|
||||
Err(SendError(msg))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
} else if self.hook.as_ref().unwrap().is_empty() {
|
||||
// The message was sent
|
||||
Ok(())
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
Some((&mut self.mapper)(res))
|
||||
}
|
||||
|
||||
fn deinit(&mut self) {
|
||||
if let Some(hook) = self.hook.take() {
|
||||
// Remove hook
|
||||
let hook: Arc<Hook<U, dyn Signal>> = hook;
|
||||
wait_lock(&self.sender.shared.chan)
|
||||
.sending
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.1
|
||||
.retain(|s| s.signal().as_ptr() != hook.signal().as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let token = self.selections.len();
|
||||
self.selections.push(Box::new(SendSelection {
|
||||
sender,
|
||||
msg: Some(msg),
|
||||
token,
|
||||
signalled: self.signalled.clone(),
|
||||
hook: None,
|
||||
mapper,
|
||||
phantom: Default::default(),
|
||||
}));
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a receive operation to the selector.
|
||||
///
|
||||
/// Once added, the selector can be used to run the provided handler function on completion of this operation.
|
||||
pub fn recv<U, F: FnMut(Result<U, RecvError>) -> T + 'a>(
|
||||
mut self,
|
||||
receiver: &'a Receiver<U>,
|
||||
mapper: F,
|
||||
) -> Self {
|
||||
struct RecvSelection<'a, T, F, U> {
|
||||
receiver: &'a Receiver<U>,
|
||||
token: Token,
|
||||
signalled: Arc<Spinlock<VecDeque<Token>>>,
|
||||
hook: Option<Arc<Hook<U, SelectSignal>>>,
|
||||
mapper: F,
|
||||
received: bool,
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'a, T, F, U> Selection<'a, T> for RecvSelection<'a, T, F, U>
|
||||
where
|
||||
F: FnMut(Result<U, RecvError>) -> T,
|
||||
{
|
||||
fn init(&mut self) -> Option<T> {
|
||||
let token = self.token;
|
||||
let signalled = self.signalled.clone();
|
||||
let r = self.receiver.shared.recv(
|
||||
true,
|
||||
|| {
|
||||
Hook::trigger(SelectSignal(
|
||||
thread::current(),
|
||||
token,
|
||||
AtomicBool::new(false),
|
||||
signalled,
|
||||
))
|
||||
},
|
||||
// Always runs
|
||||
|h| {
|
||||
self.hook = Some(h);
|
||||
Err(TryRecvTimeoutError::Timeout)
|
||||
},
|
||||
);
|
||||
|
||||
if self.hook.is_none() {
|
||||
Some((self.mapper)(match r {
|
||||
Ok(msg) => Ok(msg),
|
||||
Err(TryRecvTimeoutError::Disconnected) => Err(RecvError::Disconnected),
|
||||
_ => unreachable!(),
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn poll(&mut self) -> Option<T> {
|
||||
let res = if let Ok(msg) = self.receiver.try_recv() {
|
||||
self.received = true;
|
||||
Ok(msg)
|
||||
} else if self.receiver.shared.is_disconnected() {
|
||||
Err(RecvError::Disconnected)
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
Some((&mut self.mapper)(res))
|
||||
}
|
||||
|
||||
fn deinit(&mut self) {
|
||||
if let Some(hook) = self.hook.take() {
|
||||
// Remove hook
|
||||
let hook: Arc<Hook<U, dyn Signal>> = hook;
|
||||
wait_lock(&self.receiver.shared.chan)
|
||||
.waiting
|
||||
.retain(|s| s.signal().as_ptr() != hook.signal().as_ptr());
|
||||
// If we were woken, but never polled, wake up another
|
||||
if !self.received
|
||||
&& hook
|
||||
.signal()
|
||||
.as_any()
|
||||
.downcast_ref::<SelectSignal>()
|
||||
.unwrap()
|
||||
.2
|
||||
.load(Ordering::SeqCst)
|
||||
{
|
||||
wait_lock(&self.receiver.shared.chan).try_wake_receiver_if_pending();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let token = self.selections.len();
|
||||
self.selections.push(Box::new(RecvSelection {
|
||||
receiver,
|
||||
token,
|
||||
signalled: self.signalled.clone(),
|
||||
hook: None,
|
||||
mapper,
|
||||
received: false,
|
||||
phantom: Default::default(),
|
||||
}));
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
fn wait_inner(mut self, deadline: Option<Instant>) -> Option<T> {
|
||||
#[cfg(feature = "eventual-fairness")]
|
||||
{
|
||||
self.next_poll = self.rng.generate_range(0..self.selections.len());
|
||||
}
|
||||
|
||||
let res = 'outer: loop {
|
||||
// Init signals
|
||||
for _ in 0..self.selections.len() {
|
||||
if let Some(val) = self.selections[self.next_poll].init() {
|
||||
break 'outer Some(val);
|
||||
}
|
||||
self.next_poll = (self.next_poll + 1) % self.selections.len();
|
||||
}
|
||||
|
||||
// Speculatively poll
|
||||
if let Some(msg) = self.poll() {
|
||||
break 'outer Some(msg);
|
||||
}
|
||||
|
||||
loop {
|
||||
if let Some(deadline) = deadline {
|
||||
if let Some(dur) = deadline.checked_duration_since(Instant::now()) {
|
||||
thread::park_timeout(dur);
|
||||
}
|
||||
} else {
|
||||
thread::park();
|
||||
}
|
||||
|
||||
if deadline.map(|d| Instant::now() >= d).unwrap_or(false) {
|
||||
break 'outer self.poll();
|
||||
}
|
||||
|
||||
let token = if let Some(token) = self.signalled.lock().pop_front() {
|
||||
token
|
||||
} else {
|
||||
// Spurious wakeup, park again
|
||||
continue;
|
||||
};
|
||||
|
||||
// Attempt to receive a message
|
||||
if let Some(msg) = self.selections[token].poll() {
|
||||
break 'outer Some(msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Deinit signals
|
||||
for s in &mut self.selections {
|
||||
s.deinit();
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
fn poll(&mut self) -> Option<T> {
|
||||
for _ in 0..self.selections.len() {
|
||||
if let Some(val) = self.selections[self.next_poll].poll() {
|
||||
return Some(val);
|
||||
}
|
||||
self.next_poll = (self.next_poll + 1) % self.selections.len();
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Wait until one of the events associated with this [`Selector`] has completed. If the `eventual-fairness`
|
||||
/// feature flag is enabled, this method is fair and will handle a random event of those that are ready.
|
||||
pub fn wait(self) -> T {
|
||||
self.wait_inner(None).unwrap()
|
||||
}
|
||||
|
||||
/// Wait until one of the events associated with this [`Selector`] has completed or the timeout has expired. If the
|
||||
/// `eventual-fairness` feature flag is enabled, this method is fair and will handle a random event of those that
|
||||
/// are ready.
|
||||
pub fn wait_timeout(self, dur: Duration) -> Result<T, SelectError> {
|
||||
self.wait_inner(Some(Instant::now() + dur))
|
||||
.ok_or(SelectError::Timeout)
|
||||
}
|
||||
|
||||
/// Wait until one of the events associated with this [`Selector`] has completed or the deadline has been reached.
|
||||
/// If the `eventual-fairness` feature flag is enabled, this method is fair and will handle a random event of those
|
||||
/// that are ready.
|
||||
pub fn wait_deadline(self, deadline: Instant) -> Result<T, SelectError> {
|
||||
self.wait_inner(Some(deadline)).ok_or(SelectError::Timeout)
|
||||
}
|
||||
}
|
33
vendor/flume/src/signal.rs
vendored
Normal file
33
vendor/flume/src/signal.rs
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
use std::{thread::{self, Thread}, time::Duration, any::Any};
|
||||
|
||||
pub trait Signal: Send + Sync + 'static {
|
||||
/// Fire the signal, returning whether it is a stream signal. This is because streams do not
|
||||
/// acquire a message when woken, so signals must be fired until one that does acquire a message
|
||||
/// is fired, otherwise a wakeup could be missed, leading to a lost message until one is eagerly
|
||||
/// grabbed by a receiver.
|
||||
fn fire(&self) -> bool;
|
||||
fn as_any(&self) -> &(dyn Any + 'static);
|
||||
fn as_ptr(&self) -> *const ();
|
||||
}
|
||||
|
||||
pub struct SyncSignal(Thread);
|
||||
|
||||
impl Default for SyncSignal {
|
||||
fn default() -> Self {
|
||||
Self(thread::current())
|
||||
}
|
||||
}
|
||||
|
||||
impl Signal for SyncSignal {
|
||||
fn fire(&self) -> bool {
|
||||
self.0.unpark();
|
||||
false
|
||||
}
|
||||
fn as_any(&self) -> &(dyn Any + 'static) { self }
|
||||
fn as_ptr(&self) -> *const () { self as *const _ as *const () }
|
||||
}
|
||||
|
||||
impl SyncSignal {
|
||||
pub fn wait(&self) { thread::park(); }
|
||||
pub fn wait_timeout(&self, dur: Duration) { thread::park_timeout(dur); }
|
||||
}
|
339
vendor/flume/tests/after.rs
vendored
Normal file
339
vendor/flume/tests/after.rs
vendored
Normal file
@ -0,0 +1,339 @@
|
||||
// //! Tests for the after channel flavor.
|
||||
|
||||
// #[macro_use]
|
||||
// extern crate crossbeam_channel;
|
||||
// extern crate crossbeam_utils;
|
||||
// extern crate rand;
|
||||
|
||||
// use std::sync::atomic::AtomicUsize;
|
||||
// use std::sync::atomic::Ordering;
|
||||
// use std::thread;
|
||||
// use std::time::{Duration, Instant};
|
||||
|
||||
// use crossbeam_channel::{after, Select, TryRecvError};
|
||||
// use crossbeam_utils::thread::scope;
|
||||
|
||||
// fn ms(ms: u64) -> Duration {
|
||||
// Duration::from_millis(ms)
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn fire() {
|
||||
// let start = Instant::now();
|
||||
// let r = after(ms(50));
|
||||
|
||||
// assert_eq!(r.try_recv(), Err(TryRecvError::Empty));
|
||||
// thread::sleep(ms(100));
|
||||
|
||||
// let fired = r.try_recv().unwrap();
|
||||
// assert!(start < fired);
|
||||
// assert!(fired - start >= ms(50));
|
||||
|
||||
// let now = Instant::now();
|
||||
// assert!(fired < now);
|
||||
// assert!(now - fired >= ms(50));
|
||||
|
||||
// assert_eq!(r.try_recv(), Err(TryRecvError::Empty));
|
||||
|
||||
// select! {
|
||||
// recv(r) -> _ => panic!(),
|
||||
// default => {}
|
||||
// }
|
||||
|
||||
// select! {
|
||||
// recv(r) -> _ => panic!(),
|
||||
// recv(after(ms(200))) -> _ => {}
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn capacity() {
|
||||
// const COUNT: usize = 10;
|
||||
|
||||
// for i in 0..COUNT {
|
||||
// let r = after(ms(i as u64));
|
||||
// assert_eq!(r.capacity(), Some(1));
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn len_empty_full() {
|
||||
// let r = after(ms(50));
|
||||
|
||||
// assert_eq!(r.len(), 0);
|
||||
// assert_eq!(r.is_empty(), true);
|
||||
// assert_eq!(r.is_full(), false);
|
||||
|
||||
// thread::sleep(ms(100));
|
||||
|
||||
// assert_eq!(r.len(), 1);
|
||||
// assert_eq!(r.is_empty(), false);
|
||||
// assert_eq!(r.is_full(), true);
|
||||
|
||||
// r.try_recv().unwrap();
|
||||
|
||||
// assert_eq!(r.len(), 0);
|
||||
// assert_eq!(r.is_empty(), true);
|
||||
// assert_eq!(r.is_full(), false);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn try_recv() {
|
||||
// let r = after(ms(200));
|
||||
// assert!(r.try_recv().is_err());
|
||||
|
||||
// thread::sleep(ms(100));
|
||||
// assert!(r.try_recv().is_err());
|
||||
|
||||
// thread::sleep(ms(200));
|
||||
// assert!(r.try_recv().is_ok());
|
||||
// assert!(r.try_recv().is_err());
|
||||
|
||||
// thread::sleep(ms(200));
|
||||
// assert!(r.try_recv().is_err());
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn recv() {
|
||||
// let start = Instant::now();
|
||||
// let r = after(ms(50));
|
||||
|
||||
// let fired = r.recv().unwrap();
|
||||
// assert!(start < fired);
|
||||
// assert!(fired - start >= ms(50));
|
||||
|
||||
// let now = Instant::now();
|
||||
// assert!(fired < now);
|
||||
// assert!(now - fired < fired - start);
|
||||
|
||||
// assert_eq!(r.try_recv(), Err(TryRecvError::Empty));
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn recv_timeout() {
|
||||
// let start = Instant::now();
|
||||
// let r = after(ms(200));
|
||||
|
||||
// assert!(r.recv_timeout(ms(100)).is_err());
|
||||
// let now = Instant::now();
|
||||
// assert!(now - start >= ms(100));
|
||||
// assert!(now - start <= ms(150));
|
||||
|
||||
// let fired = r.recv_timeout(ms(200)).unwrap();
|
||||
// assert!(fired - start >= ms(200));
|
||||
// assert!(fired - start <= ms(250));
|
||||
|
||||
// assert!(r.recv_timeout(ms(200)).is_err());
|
||||
// let now = Instant::now();
|
||||
// assert!(now - start >= ms(400));
|
||||
// assert!(now - start <= ms(450));
|
||||
|
||||
// assert_eq!(r.try_recv(), Err(TryRecvError::Empty));
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn recv_two() {
|
||||
// let r1 = after(ms(50));
|
||||
// let r2 = after(ms(50));
|
||||
|
||||
// scope(|scope| {
|
||||
// scope.spawn(|_| {
|
||||
// select! {
|
||||
// recv(r1) -> _ => {}
|
||||
// recv(r2) -> _ => {}
|
||||
// }
|
||||
// });
|
||||
// scope.spawn(|_| {
|
||||
// select! {
|
||||
// recv(r1) -> _ => {}
|
||||
// recv(r2) -> _ => {}
|
||||
// }
|
||||
// });
|
||||
// })
|
||||
// .unwrap();
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn recv_race() {
|
||||
// select! {
|
||||
// recv(after(ms(50))) -> _ => {}
|
||||
// recv(after(ms(100))) -> _ => panic!(),
|
||||
// }
|
||||
|
||||
// select! {
|
||||
// recv(after(ms(100))) -> _ => panic!(),
|
||||
// recv(after(ms(50))) -> _ => {}
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn stress_default() {
|
||||
// const COUNT: usize = 10;
|
||||
|
||||
// for _ in 0..COUNT {
|
||||
// select! {
|
||||
// recv(after(ms(0))) -> _ => {}
|
||||
// default => panic!(),
|
||||
// }
|
||||
// }
|
||||
|
||||
// for _ in 0..COUNT {
|
||||
// select! {
|
||||
// recv(after(ms(100))) -> _ => panic!(),
|
||||
// default => {}
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn select() {
|
||||
// const THREADS: usize = 4;
|
||||
// const COUNT: usize = 1000;
|
||||
// const TIMEOUT_MS: u64 = 100;
|
||||
|
||||
// let v = (0..COUNT)
|
||||
// .map(|i| after(ms(i as u64 / TIMEOUT_MS / 2)))
|
||||
// .collect::<Vec<_>>();
|
||||
// let hits = AtomicUsize::new(0);
|
||||
|
||||
// scope(|scope| {
|
||||
// for _ in 0..THREADS {
|
||||
// scope.spawn(|_| {
|
||||
// let v: Vec<&_> = v.iter().collect();
|
||||
|
||||
// loop {
|
||||
// let timeout = after(ms(TIMEOUT_MS));
|
||||
// let mut sel = Select::new();
|
||||
// for r in &v {
|
||||
// sel.recv(r);
|
||||
// }
|
||||
// let oper_timeout = sel.recv(&timeout);
|
||||
|
||||
// let oper = sel.select();
|
||||
// match oper.index() {
|
||||
// i if i == oper_timeout => {
|
||||
// oper.recv(&timeout).unwrap();
|
||||
// break;
|
||||
// }
|
||||
// i => {
|
||||
// oper.recv(&v[i]).unwrap();
|
||||
// hits.fetch_add(1, Ordering::SeqCst);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// })
|
||||
// .unwrap();
|
||||
|
||||
// assert_eq!(hits.load(Ordering::SeqCst), COUNT);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn ready() {
|
||||
// const THREADS: usize = 4;
|
||||
// const COUNT: usize = 1000;
|
||||
// const TIMEOUT_MS: u64 = 100;
|
||||
|
||||
// let v = (0..COUNT)
|
||||
// .map(|i| after(ms(i as u64 / TIMEOUT_MS / 2)))
|
||||
// .collect::<Vec<_>>();
|
||||
// let hits = AtomicUsize::new(0);
|
||||
|
||||
// scope(|scope| {
|
||||
// for _ in 0..THREADS {
|
||||
// scope.spawn(|_| {
|
||||
// let v: Vec<&_> = v.iter().collect();
|
||||
|
||||
// loop {
|
||||
// let timeout = after(ms(TIMEOUT_MS));
|
||||
// let mut sel = Select::new();
|
||||
// for r in &v {
|
||||
// sel.recv(r);
|
||||
// }
|
||||
// let oper_timeout = sel.recv(&timeout);
|
||||
|
||||
// loop {
|
||||
// let i = sel.ready();
|
||||
// if i == oper_timeout {
|
||||
// timeout.try_recv().unwrap();
|
||||
// return;
|
||||
// } else if v[i].try_recv().is_ok() {
|
||||
// hits.fetch_add(1, Ordering::SeqCst);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// })
|
||||
// .unwrap();
|
||||
|
||||
// assert_eq!(hits.load(Ordering::SeqCst), COUNT);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn stress_clone() {
|
||||
// const RUNS: usize = 1000;
|
||||
// const THREADS: usize = 10;
|
||||
// const COUNT: usize = 50;
|
||||
|
||||
// for i in 0..RUNS {
|
||||
// let r = after(ms(i as u64));
|
||||
|
||||
// scope(|scope| {
|
||||
// for _ in 0..THREADS {
|
||||
// scope.spawn(|_| {
|
||||
// let r = r.clone();
|
||||
// let _ = r.try_recv();
|
||||
|
||||
// for _ in 0..COUNT {
|
||||
// drop(r.clone());
|
||||
// thread::yield_now();
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// })
|
||||
// .unwrap();
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn fairness() {
|
||||
// const COUNT: usize = 1000;
|
||||
|
||||
// for &dur in &[0, 1] {
|
||||
// let mut hits = [0usize; 2];
|
||||
|
||||
// for _ in 0..COUNT {
|
||||
// select! {
|
||||
// recv(after(ms(dur))) -> _ => hits[0] += 1,
|
||||
// recv(after(ms(dur))) -> _ => hits[1] += 1,
|
||||
// }
|
||||
// }
|
||||
|
||||
// assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2));
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn fairness_duplicates() {
|
||||
// const COUNT: usize = 1000;
|
||||
|
||||
// for &dur in &[0, 1] {
|
||||
// let mut hits = [0usize; 5];
|
||||
|
||||
// for _ in 0..COUNT {
|
||||
// let r = after(ms(dur));
|
||||
// select! {
|
||||
// recv(r) -> _ => hits[0] += 1,
|
||||
// recv(r) -> _ => hits[1] += 1,
|
||||
// recv(r) -> _ => hits[2] += 1,
|
||||
// recv(r) -> _ => hits[3] += 1,
|
||||
// recv(r) -> _ => hits[4] += 1,
|
||||
// }
|
||||
// }
|
||||
|
||||
// assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2));
|
||||
// }
|
||||
// }
|
657
vendor/flume/tests/array.rs
vendored
Normal file
657
vendor/flume/tests/array.rs
vendored
Normal file
@ -0,0 +1,657 @@
|
||||
//! Tests for the array channel flavor.
|
||||
|
||||
extern crate crossbeam_utils;
|
||||
extern crate rand;
|
||||
|
||||
use std::any::Any;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use flume::{bounded, Receiver};
|
||||
use flume::{RecvError, RecvTimeoutError, TryRecvError};
|
||||
use flume::{SendError, SendTimeoutError, TrySendError};
|
||||
use crossbeam_utils::thread::scope;
|
||||
use rand::{thread_rng, Rng};
|
||||
|
||||
fn ms(ms: u64) -> Duration {
|
||||
Duration::from_millis(ms)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn smoke() {
|
||||
let (s, r) = bounded(1);
|
||||
s.send(7).unwrap();
|
||||
assert_eq!(r.try_recv(), Ok(7));
|
||||
|
||||
s.send(8).unwrap();
|
||||
assert_eq!(r.recv(), Ok(8));
|
||||
|
||||
assert_eq!(r.try_recv(), Err(TryRecvError::Empty));
|
||||
assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn capacity() {
|
||||
for i in 1..10 {
|
||||
let (s, r) = bounded::<()>(i);
|
||||
assert_eq!(s.capacity(), Some(i));
|
||||
assert_eq!(r.capacity(), Some(i));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn len_empty_full() {
|
||||
let (s, r) = bounded(2);
|
||||
|
||||
assert_eq!(s.len(), 0);
|
||||
assert_eq!(s.is_empty(), true);
|
||||
assert_eq!(s.is_full(), false);
|
||||
assert_eq!(r.len(), 0);
|
||||
assert_eq!(r.is_empty(), true);
|
||||
assert_eq!(r.is_full(), false);
|
||||
|
||||
s.send(()).unwrap();
|
||||
|
||||
assert_eq!(s.len(), 1);
|
||||
assert_eq!(s.is_empty(), false);
|
||||
assert_eq!(s.is_full(), false);
|
||||
assert_eq!(r.len(), 1);
|
||||
assert_eq!(r.is_empty(), false);
|
||||
assert_eq!(r.is_full(), false);
|
||||
|
||||
s.send(()).unwrap();
|
||||
|
||||
assert_eq!(s.len(), 2);
|
||||
assert_eq!(s.is_empty(), false);
|
||||
assert_eq!(s.is_full(), true);
|
||||
assert_eq!(r.len(), 2);
|
||||
assert_eq!(r.is_empty(), false);
|
||||
assert_eq!(r.is_full(), true);
|
||||
|
||||
r.recv().unwrap();
|
||||
|
||||
assert_eq!(s.len(), 1);
|
||||
assert_eq!(s.is_empty(), false);
|
||||
assert_eq!(s.is_full(), false);
|
||||
assert_eq!(r.len(), 1);
|
||||
assert_eq!(r.is_empty(), false);
|
||||
assert_eq!(r.is_full(), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_recv() {
|
||||
let (s, r) = bounded(100);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
assert_eq!(r.try_recv(), Err(TryRecvError::Empty));
|
||||
thread::sleep(ms(1500));
|
||||
assert_eq!(r.try_recv(), Ok(7));
|
||||
thread::sleep(ms(500));
|
||||
assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected));
|
||||
});
|
||||
scope.spawn(move |_| {
|
||||
thread::sleep(ms(1000));
|
||||
s.send(7).unwrap();
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recv() {
|
||||
let (s, r) = bounded(100);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
assert_eq!(r.recv(), Ok(7));
|
||||
thread::sleep(ms(1000));
|
||||
assert_eq!(r.recv(), Ok(8));
|
||||
thread::sleep(ms(1000));
|
||||
assert_eq!(r.recv(), Ok(9));
|
||||
assert!(r.recv().is_err());
|
||||
});
|
||||
scope.spawn(move |_| {
|
||||
thread::sleep(ms(1500));
|
||||
s.send(7).unwrap();
|
||||
s.send(8).unwrap();
|
||||
s.send(9).unwrap();
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recv_timeout() {
|
||||
let (s, r) = bounded::<i32>(100);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout));
|
||||
assert_eq!(r.recv_timeout(ms(1000)), Ok(7));
|
||||
assert_eq!(
|
||||
r.recv_timeout(ms(1000)),
|
||||
Err(RecvTimeoutError::Disconnected)
|
||||
);
|
||||
});
|
||||
scope.spawn(move |_| {
|
||||
thread::sleep(ms(1500));
|
||||
s.send(7).unwrap();
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_send() {
|
||||
let (s, r) = bounded(1);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
assert_eq!(s.try_send(1), Ok(()));
|
||||
assert_eq!(s.try_send(2), Err(TrySendError::Full(2)));
|
||||
thread::sleep(ms(1500));
|
||||
assert_eq!(s.try_send(3), Ok(()));
|
||||
thread::sleep(ms(500));
|
||||
assert_eq!(s.try_send(4), Err(TrySendError::Disconnected(4)));
|
||||
});
|
||||
scope.spawn(move |_| {
|
||||
thread::sleep(ms(1000));
|
||||
assert_eq!(r.try_recv(), Ok(1));
|
||||
assert_eq!(r.try_recv(), Err(TryRecvError::Empty));
|
||||
assert_eq!(r.recv(), Ok(3));
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send() {
|
||||
let (s, r) = bounded(1);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(|_| {
|
||||
s.send(7).unwrap();
|
||||
thread::sleep(ms(1000));
|
||||
s.send(8).unwrap();
|
||||
thread::sleep(ms(1000));
|
||||
s.send(9).unwrap();
|
||||
thread::sleep(ms(1000));
|
||||
s.send(10).unwrap();
|
||||
});
|
||||
scope.spawn(|_| {
|
||||
thread::sleep(ms(1500));
|
||||
assert_eq!(r.recv(), Ok(7));
|
||||
assert_eq!(r.recv(), Ok(8));
|
||||
assert_eq!(r.recv(), Ok(9));
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_timeout() {
|
||||
let (s, r) = bounded(2);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
assert_eq!(s.send_timeout(1, ms(1000)), Ok(()));
|
||||
assert_eq!(s.send_timeout(2, ms(1000)), Ok(()));
|
||||
assert_eq!(
|
||||
s.send_timeout(3, ms(500)),
|
||||
Err(SendTimeoutError::Timeout(3))
|
||||
);
|
||||
thread::sleep(ms(1000));
|
||||
assert_eq!(s.send_timeout(4, ms(1000)), Ok(()));
|
||||
thread::sleep(ms(1000));
|
||||
assert_eq!(s.send(5), Err(SendError(5)));
|
||||
});
|
||||
scope.spawn(move |_| {
|
||||
thread::sleep(ms(1000));
|
||||
assert_eq!(r.recv(), Ok(1));
|
||||
thread::sleep(ms(1000));
|
||||
assert_eq!(r.recv(), Ok(2));
|
||||
assert_eq!(r.recv(), Ok(4));
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_after_disconnect() {
|
||||
let (s, r) = bounded(100);
|
||||
|
||||
s.send(1).unwrap();
|
||||
s.send(2).unwrap();
|
||||
s.send(3).unwrap();
|
||||
|
||||
drop(r);
|
||||
|
||||
assert_eq!(s.send(4), Err(SendError(4)));
|
||||
assert_eq!(s.try_send(5), Err(TrySendError::Disconnected(5)));
|
||||
assert_eq!(
|
||||
s.send_timeout(6, ms(500)),
|
||||
Err(SendTimeoutError::Disconnected(6))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recv_after_disconnect() {
|
||||
let (s, r) = bounded(100);
|
||||
|
||||
s.send(1).unwrap();
|
||||
s.send(2).unwrap();
|
||||
s.send(3).unwrap();
|
||||
|
||||
drop(s);
|
||||
|
||||
assert_eq!(r.recv(), Ok(1));
|
||||
assert_eq!(r.recv(), Ok(2));
|
||||
assert_eq!(r.recv(), Ok(3));
|
||||
assert!(r.recv().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn len() {
|
||||
const COUNT: usize = 25_000;
|
||||
const CAP: usize = 1000;
|
||||
|
||||
let (s, r) = bounded(CAP);
|
||||
|
||||
assert_eq!(s.len(), 0);
|
||||
assert_eq!(r.len(), 0);
|
||||
|
||||
for _ in 0..CAP / 10 {
|
||||
for i in 0..50 {
|
||||
s.send(i).unwrap();
|
||||
assert_eq!(s.len(), i + 1);
|
||||
}
|
||||
|
||||
for i in 0..50 {
|
||||
r.recv().unwrap();
|
||||
assert_eq!(r.len(), 50 - i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(s.len(), 0);
|
||||
assert_eq!(r.len(), 0);
|
||||
|
||||
for i in 0..CAP {
|
||||
s.send(i).unwrap();
|
||||
assert_eq!(s.len(), i + 1);
|
||||
}
|
||||
|
||||
for _ in 0..CAP {
|
||||
r.recv().unwrap();
|
||||
}
|
||||
|
||||
assert_eq!(s.len(), 0);
|
||||
assert_eq!(r.len(), 0);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(|_| {
|
||||
for i in 0..COUNT {
|
||||
assert_eq!(r.recv(), Ok(i));
|
||||
let len = r.len();
|
||||
assert!(len <= CAP);
|
||||
}
|
||||
});
|
||||
|
||||
scope.spawn(|_| {
|
||||
for i in 0..COUNT {
|
||||
s.send(i).unwrap();
|
||||
let len = s.len();
|
||||
assert!(len <= CAP);
|
||||
}
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(s.len(), 0);
|
||||
assert_eq!(r.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disconnect_wakes_sender() {
|
||||
let (s, r) = bounded(1);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
assert_eq!(s.send(()), Ok(()));
|
||||
assert_eq!(s.send(()), Err(SendError(())));
|
||||
});
|
||||
scope.spawn(move |_| {
|
||||
thread::sleep(ms(1000));
|
||||
drop(r);
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disconnect_wakes_receiver() {
|
||||
let (s, r) = bounded::<()>(1);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
assert!(r.recv().is_err());
|
||||
});
|
||||
scope.spawn(move |_| {
|
||||
thread::sleep(ms(1000));
|
||||
drop(s);
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spsc() {
|
||||
const COUNT: usize = 100_000;
|
||||
|
||||
let (s, r) = bounded(3);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
for i in 0..COUNT {
|
||||
assert_eq!(r.recv(), Ok(i));
|
||||
}
|
||||
assert!(r.recv().is_err());
|
||||
});
|
||||
scope.spawn(move |_| {
|
||||
for i in 0..COUNT {
|
||||
s.send(i).unwrap();
|
||||
}
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mpmc() {
|
||||
const COUNT: usize = 25_000;
|
||||
const THREADS: usize = 4;
|
||||
|
||||
let (s, r) = bounded::<usize>(3);
|
||||
let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::<Vec<_>>();
|
||||
|
||||
scope(|scope| {
|
||||
for _ in 0..THREADS {
|
||||
scope.spawn(|_| {
|
||||
for _ in 0..COUNT {
|
||||
let n = r.recv().unwrap();
|
||||
v[n].fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
});
|
||||
}
|
||||
for _ in 0..THREADS {
|
||||
scope.spawn(|_| {
|
||||
for i in 0..COUNT {
|
||||
s.send(i).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
for c in v {
|
||||
assert_eq!(c.load(Ordering::SeqCst), THREADS);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stress_oneshot() {
|
||||
const COUNT: usize = 10_000;
|
||||
|
||||
for _ in 0..COUNT {
|
||||
let (s, r) = bounded(1);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(|_| r.recv().unwrap());
|
||||
scope.spawn(|_| s.send(0).unwrap());
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stress_iter() {
|
||||
const COUNT: usize = 100_000;
|
||||
|
||||
let (request_s, request_r) = bounded(1);
|
||||
let (response_s, response_r) = bounded(1);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
let mut count = 0;
|
||||
loop {
|
||||
for x in response_r.try_iter() {
|
||||
count += x;
|
||||
if count == COUNT {
|
||||
return;
|
||||
}
|
||||
}
|
||||
request_s.send(()).unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
for _ in request_r.iter() {
|
||||
if response_s.send(1).is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stress_timeout_two_threads() {
|
||||
const COUNT: usize = 100;
|
||||
|
||||
let (s, r) = bounded(2);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(|_| {
|
||||
for i in 0..COUNT {
|
||||
if i % 2 == 0 {
|
||||
thread::sleep(ms(50));
|
||||
}
|
||||
loop {
|
||||
if let Ok(()) = s.send_timeout(i, ms(10)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
scope.spawn(|_| {
|
||||
for i in 0..COUNT {
|
||||
if i % 2 == 0 {
|
||||
thread::sleep(ms(50));
|
||||
}
|
||||
loop {
|
||||
if let Ok(x) = r.recv_timeout(ms(10)) {
|
||||
assert_eq!(x, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drops() {
|
||||
const RUNS: usize = 100;
|
||||
|
||||
static DROPS: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct DropCounter;
|
||||
|
||||
impl Drop for DropCounter {
|
||||
fn drop(&mut self) {
|
||||
DROPS.fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
let mut rng = thread_rng();
|
||||
|
||||
for _ in 0..RUNS {
|
||||
let steps = rng.gen_range(0..10_000);
|
||||
let additional = rng.gen_range(0..50);
|
||||
|
||||
DROPS.store(0, Ordering::SeqCst);
|
||||
let (s, r) = bounded::<DropCounter>(50);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(|_| {
|
||||
for _ in 0..steps {
|
||||
r.recv().unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
scope.spawn(|_| {
|
||||
for _ in 0..steps {
|
||||
s.send(DropCounter).unwrap();
|
||||
}
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
for _ in 0..additional {
|
||||
s.send(DropCounter).unwrap();
|
||||
}
|
||||
|
||||
assert_eq!(DROPS.load(Ordering::SeqCst), steps);
|
||||
drop(s);
|
||||
drop(r);
|
||||
assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn linearizable() {
|
||||
const COUNT: usize = 25_000;
|
||||
const THREADS: usize = 4;
|
||||
|
||||
let (s, r) = bounded(THREADS);
|
||||
|
||||
scope(|scope| {
|
||||
for _ in 0..THREADS {
|
||||
scope.spawn(|_| {
|
||||
for _ in 0..COUNT {
|
||||
s.send(0).unwrap();
|
||||
r.try_recv().unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn fairness() {
|
||||
// const COUNT: usize = 10_000;
|
||||
|
||||
// let (s1, r1) = bounded::<()>(COUNT);
|
||||
// let (s2, r2) = bounded::<()>(COUNT);
|
||||
|
||||
// for _ in 0..COUNT {
|
||||
// s1.send(()).unwrap();
|
||||
// s2.send(()).unwrap();
|
||||
// }
|
||||
|
||||
// let mut hits = [0usize; 2];
|
||||
// for _ in 0..COUNT {
|
||||
// select! {
|
||||
// recv(r1) -> _ => hits[0] += 1,
|
||||
// recv(r2) -> _ => hits[1] += 1,
|
||||
// }
|
||||
// }
|
||||
// assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2));
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn fairness_duplicates() {
|
||||
// const COUNT: usize = 10_000;
|
||||
|
||||
// let (s, r) = bounded::<()>(COUNT);
|
||||
|
||||
// for _ in 0..COUNT {
|
||||
// s.send(()).unwrap();
|
||||
// }
|
||||
|
||||
// let mut hits = [0usize; 5];
|
||||
// for _ in 0..COUNT {
|
||||
// select! {
|
||||
// recv(r) -> _ => hits[0] += 1,
|
||||
// recv(r) -> _ => hits[1] += 1,
|
||||
// recv(r) -> _ => hits[2] += 1,
|
||||
// recv(r) -> _ => hits[3] += 1,
|
||||
// recv(r) -> _ => hits[4] += 1,
|
||||
// }
|
||||
// }
|
||||
// assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2));
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn recv_in_send() {
|
||||
// let (s, _r) = bounded(1);
|
||||
// s.send(()).unwrap();
|
||||
|
||||
// #[allow(unreachable_code)]
|
||||
// {
|
||||
// select! {
|
||||
// send(s, panic!()) -> _ => panic!(),
|
||||
// default => {}
|
||||
// }
|
||||
// }
|
||||
|
||||
// let (s, r) = bounded(2);
|
||||
// s.send(()).unwrap();
|
||||
|
||||
// select! {
|
||||
// send(s, assert_eq!(r.recv(), Ok(()))) -> _ => {}
|
||||
// }
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn channel_through_channel() {
|
||||
const COUNT: usize = 1000;
|
||||
|
||||
type T = Box<dyn Any + Send>;
|
||||
|
||||
let (s, r) = bounded::<T>(1);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
let mut s = s;
|
||||
|
||||
for _ in 0..COUNT {
|
||||
let (new_s, new_r) = bounded(1);
|
||||
let new_r: T = Box::new(Some(new_r));
|
||||
|
||||
s.send(new_r).unwrap();
|
||||
s = new_s;
|
||||
}
|
||||
});
|
||||
|
||||
scope.spawn(move |_| {
|
||||
let mut r = r;
|
||||
|
||||
for _ in 0..COUNT {
|
||||
r = r
|
||||
.recv()
|
||||
.unwrap()
|
||||
.downcast_mut::<Option<Receiver<T>>>()
|
||||
.unwrap()
|
||||
.take()
|
||||
.unwrap()
|
||||
}
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
276
vendor/flume/tests/async.rs
vendored
Normal file
276
vendor/flume/tests/async.rs
vendored
Normal file
@ -0,0 +1,276 @@
|
||||
#[cfg(feature = "async")]
|
||||
use {
|
||||
flume::*,
|
||||
futures::{stream::FuturesUnordered, StreamExt, TryFutureExt, Future},
|
||||
futures::task::{Context, Waker, Poll},
|
||||
async_std::prelude::FutureExt,
|
||||
std::{time::Duration, sync::{atomic::{AtomicUsize, Ordering}, Arc}},
|
||||
};
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[test]
|
||||
fn r#async_recv() {
|
||||
let (tx, rx) = unbounded();
|
||||
|
||||
let t = std::thread::spawn(move || {
|
||||
std::thread::sleep(std::time::Duration::from_millis(250));
|
||||
tx.send(42u32).unwrap();
|
||||
});
|
||||
|
||||
async_std::task::block_on(async {
|
||||
assert_eq!(rx.recv_async().await.unwrap(), 42);
|
||||
});
|
||||
|
||||
t.join().unwrap();
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[test]
|
||||
fn r#async_send() {
|
||||
let (tx, rx) = bounded(1);
|
||||
|
||||
let t = std::thread::spawn(move || {
|
||||
std::thread::sleep(std::time::Duration::from_millis(250));
|
||||
assert_eq!(rx.recv(), Ok(42));
|
||||
});
|
||||
|
||||
async_std::task::block_on(async {
|
||||
tx.send_async(42u32).await.unwrap();
|
||||
});
|
||||
|
||||
t.join().unwrap();
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[test]
|
||||
fn r#async_recv_disconnect() {
|
||||
let (tx, rx) = bounded::<i32>(0);
|
||||
|
||||
let t = std::thread::spawn(move || {
|
||||
std::thread::sleep(std::time::Duration::from_millis(250));
|
||||
drop(tx)
|
||||
});
|
||||
|
||||
async_std::task::block_on(async {
|
||||
assert_eq!(rx.recv_async().await, Err(RecvError::Disconnected));
|
||||
});
|
||||
|
||||
t.join().unwrap();
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[test]
|
||||
fn r#async_send_disconnect() {
|
||||
let (tx, rx) = bounded(0);
|
||||
|
||||
let t = std::thread::spawn(move || {
|
||||
std::thread::sleep(std::time::Duration::from_millis(250));
|
||||
drop(rx)
|
||||
});
|
||||
|
||||
async_std::task::block_on(async {
|
||||
assert_eq!(tx.send_async(42u32).await, Err(SendError(42)));
|
||||
});
|
||||
|
||||
t.join().unwrap();
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[test]
|
||||
fn r#async_recv_drop_recv() {
|
||||
let (tx, rx) = bounded::<i32>(10);
|
||||
|
||||
let recv_fut = rx.recv_async();
|
||||
|
||||
async_std::task::block_on(async {
|
||||
let res = async_std::future::timeout(std::time::Duration::from_millis(500), rx.recv_async()).await;
|
||||
assert!(res.is_err());
|
||||
});
|
||||
|
||||
let rx2 = rx.clone();
|
||||
let t = std::thread::spawn(move || {
|
||||
async_std::task::block_on(async {
|
||||
rx2.recv_async().await
|
||||
})
|
||||
});
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_millis(500));
|
||||
|
||||
tx.send(42).unwrap();
|
||||
|
||||
drop(recv_fut);
|
||||
|
||||
assert_eq!(t.join().unwrap(), Ok(42))
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[async_std::test]
|
||||
async fn r#async_send_1_million_no_drop_or_reorder() {
|
||||
#[derive(Debug)]
|
||||
enum Message {
|
||||
Increment {
|
||||
old: u64,
|
||||
},
|
||||
ReturnCount,
|
||||
}
|
||||
|
||||
let (tx, rx) = unbounded();
|
||||
|
||||
let t = async_std::task::spawn(async move {
|
||||
let mut count = 0u64;
|
||||
|
||||
while let Ok(Message::Increment { old }) = rx.recv_async().await {
|
||||
assert_eq!(old, count);
|
||||
count += 1;
|
||||
}
|
||||
|
||||
count
|
||||
});
|
||||
|
||||
for next in 0..1_000_000 {
|
||||
tx.send(Message::Increment { old: next }).unwrap();
|
||||
}
|
||||
|
||||
tx.send(Message::ReturnCount).unwrap();
|
||||
|
||||
let count = t.await;
|
||||
assert_eq!(count, 1_000_000)
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[async_std::test]
|
||||
async fn parallel_async_receivers() {
|
||||
let (tx, rx) = flume::unbounded();
|
||||
let send_fut = async move {
|
||||
let n_sends: usize = 100000;
|
||||
for _ in 0..n_sends {
|
||||
tx.send_async(()).await.unwrap();
|
||||
}
|
||||
};
|
||||
|
||||
async_std::task::spawn(
|
||||
send_fut
|
||||
.timeout(Duration::from_secs(5))
|
||||
.map_err(|_| panic!("Send timed out!"))
|
||||
);
|
||||
|
||||
let mut futures_unordered = (0..250)
|
||||
.map(|_| async {
|
||||
while let Ok(()) = rx.recv_async().await
|
||||
/* rx.recv() is OK */
|
||||
{}
|
||||
})
|
||||
.collect::<FuturesUnordered<_>>();
|
||||
|
||||
let recv_fut = async {
|
||||
while futures_unordered.next().await.is_some() {}
|
||||
};
|
||||
|
||||
recv_fut
|
||||
.timeout(Duration::from_secs(5))
|
||||
.map_err(|_| panic!("Receive timed out!"))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
println!("recv end");
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[test]
|
||||
fn change_waker() {
|
||||
let (tx, rx) = flume::bounded(1);
|
||||
tx.send(()).unwrap();
|
||||
|
||||
struct DebugWaker(Arc<AtomicUsize>, Waker);
|
||||
|
||||
impl DebugWaker {
|
||||
fn new() -> Self {
|
||||
let woken = Arc::new(AtomicUsize::new(0));
|
||||
let woken_cloned = woken.clone();
|
||||
let waker = waker_fn::waker_fn(move || {
|
||||
woken.fetch_add(1, Ordering::SeqCst);
|
||||
});
|
||||
DebugWaker(woken_cloned, waker)
|
||||
}
|
||||
|
||||
fn woken(&self) -> usize {
|
||||
self.0.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
fn ctx(&self) -> Context {
|
||||
Context::from_waker(&self.1)
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the waker is correctly updated when sending tasks change their wakers
|
||||
{
|
||||
let send_fut = tx.send_async(());
|
||||
futures::pin_mut!(send_fut);
|
||||
|
||||
let (waker1, waker2) = (DebugWaker::new(), DebugWaker::new());
|
||||
|
||||
// Set the waker to waker1
|
||||
assert_eq!(send_fut.as_mut().poll(&mut waker1.ctx()), Poll::Pending);
|
||||
|
||||
// Change the waker to waker2
|
||||
assert_eq!(send_fut.poll(&mut waker2.ctx()), Poll::Pending);
|
||||
|
||||
// Wake the future
|
||||
rx.recv().unwrap();
|
||||
|
||||
// Check that waker2 was woken and waker1 was not
|
||||
assert_eq!(waker1.woken(), 0);
|
||||
assert_eq!(waker2.woken(), 1);
|
||||
}
|
||||
|
||||
// Check that the waker is correctly updated when receiving tasks change their wakers
|
||||
{
|
||||
rx.recv().unwrap();
|
||||
let recv_fut = rx.recv_async();
|
||||
futures::pin_mut!(recv_fut);
|
||||
|
||||
let (waker1, waker2) = (DebugWaker::new(), DebugWaker::new());
|
||||
|
||||
// Set the waker to waker1
|
||||
assert_eq!(recv_fut.as_mut().poll(&mut waker1.ctx()), Poll::Pending);
|
||||
|
||||
// Change the waker to waker2
|
||||
assert_eq!(recv_fut.poll(&mut waker2.ctx()), Poll::Pending);
|
||||
|
||||
// Wake the future
|
||||
tx.send(()).unwrap();
|
||||
|
||||
// Check that waker2 was woken and waker1 was not
|
||||
assert_eq!(waker1.woken(), 0);
|
||||
assert_eq!(waker2.woken(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[test]
|
||||
fn spsc_single_threaded_value_ordering() {
|
||||
async fn test() {
|
||||
let (tx, rx) = flume::bounded(4);
|
||||
tokio::select! {
|
||||
_ = producer(tx) => {},
|
||||
_ = consumer(rx) => {},
|
||||
}
|
||||
}
|
||||
|
||||
async fn producer(tx: flume::Sender<usize>) {
|
||||
for i in 0..100 {
|
||||
tx.send_async(i).await.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
async fn consumer(rx: flume::Receiver<usize>) {
|
||||
let mut expected = 0;
|
||||
while let Ok(value) = rx.recv_async().await {
|
||||
assert_eq!(value, expected);
|
||||
expected += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let rt = tokio::runtime::Builder::new_current_thread().build().unwrap();
|
||||
rt.block_on(test());
|
||||
}
|
428
vendor/flume/tests/basic.rs
vendored
Normal file
428
vendor/flume/tests/basic.rs
vendored
Normal file
@ -0,0 +1,428 @@
|
||||
use std::time::{Instant, Duration};
|
||||
use flume::*;
|
||||
|
||||
#[test]
|
||||
fn send_recv() {
|
||||
let (tx, rx) = unbounded();
|
||||
for i in 0..1000 { tx.send(i).unwrap(); }
|
||||
for i in 0..1000 { assert_eq!(rx.try_recv().unwrap(), i); }
|
||||
assert!(rx.try_recv().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iter() {
|
||||
let (tx, rx) = unbounded();
|
||||
for i in 0..1000 { tx.send(i).unwrap(); }
|
||||
drop(tx);
|
||||
assert_eq!(rx.iter().sum::<u32>(), (0..1000).sum());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_iter() {
|
||||
let (tx, rx) = unbounded();
|
||||
for i in 0..1000 { tx.send(i).unwrap(); }
|
||||
assert_eq!(rx.try_iter().sum::<u32>(), (0..1000).sum());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iter_threaded() {
|
||||
let (tx, rx) = unbounded();
|
||||
for i in 0..1000 {
|
||||
let tx = tx.clone();
|
||||
std::thread::spawn(move || tx.send(i).unwrap());
|
||||
}
|
||||
drop(tx);
|
||||
assert_eq!(rx.iter().sum::<u32>(), (0..1000).sum());
|
||||
}
|
||||
|
||||
#[cfg_attr(any(target_os = "macos", windows), ignore)] // FIXME #41
|
||||
#[test]
|
||||
fn send_timeout() {
|
||||
let dur = Duration::from_millis(350);
|
||||
let max_error = Duration::from_millis(5);
|
||||
let dur_min = dur.checked_sub(max_error).unwrap();
|
||||
let dur_max = dur.checked_add(max_error).unwrap();
|
||||
|
||||
let (tx, rx) = bounded(1);
|
||||
|
||||
assert!(tx.send_timeout(42, dur).is_ok());
|
||||
|
||||
let then = Instant::now();
|
||||
assert!(tx.send_timeout(43, dur).is_err());
|
||||
let now = Instant::now();
|
||||
|
||||
let this = now.duration_since(then);
|
||||
if !(dur_min < this && this < dur_max) {
|
||||
panic!("timeout exceeded: {:?}", this);
|
||||
}
|
||||
|
||||
assert_eq!(rx.drain().count(), 1);
|
||||
|
||||
drop(rx);
|
||||
|
||||
assert!(tx.send_timeout(42, Duration::from_millis(350)).is_err());
|
||||
}
|
||||
|
||||
#[cfg_attr(any(target_os = "macos", windows), ignore)] // FIXME #41
|
||||
#[test]
|
||||
fn recv_timeout() {
|
||||
let dur = Duration::from_millis(350);
|
||||
let max_error = Duration::from_millis(5);
|
||||
let dur_min = dur.checked_sub(max_error).unwrap();
|
||||
let dur_max = dur.checked_add(max_error).unwrap();
|
||||
|
||||
let (tx, rx) = unbounded();
|
||||
let then = Instant::now();
|
||||
assert!(rx.recv_timeout(dur).is_err());
|
||||
let now = Instant::now();
|
||||
|
||||
let this = now.duration_since(then);
|
||||
if !(dur_min < this && this < dur_max) {
|
||||
panic!("timeout exceeded: {:?}", this);
|
||||
}
|
||||
|
||||
tx.send(42).unwrap();
|
||||
assert_eq!(rx.recv_timeout(dur), Ok(42));
|
||||
assert!(Instant::now().duration_since(now) < max_error);
|
||||
}
|
||||
|
||||
#[cfg_attr(any(target_os = "macos", windows), ignore)] // FIXME #41
|
||||
#[test]
|
||||
fn recv_deadline() {
|
||||
let dur = Duration::from_millis(350);
|
||||
let max_error = Duration::from_millis(5);
|
||||
let dur_min = dur.checked_sub(max_error).unwrap();
|
||||
let dur_max = dur.checked_add(max_error).unwrap();
|
||||
|
||||
let (tx, rx) = unbounded();
|
||||
let then = Instant::now();
|
||||
assert!(rx.recv_deadline(then.checked_add(dur).unwrap()).is_err());
|
||||
let now = Instant::now();
|
||||
|
||||
let this = now.duration_since(then);
|
||||
if !(dur_min < this && this < dur_max) {
|
||||
panic!("timeout exceeded: {:?}", this);
|
||||
}
|
||||
|
||||
tx.send(42).unwrap();
|
||||
assert_eq!(rx.recv_deadline(now.checked_add(dur).unwrap()), Ok(42));
|
||||
assert!(Instant::now().duration_since(now) < max_error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recv_timeout_missed_send() {
|
||||
let (tx, rx) = bounded(10);
|
||||
|
||||
assert!(rx.recv_timeout(Duration::from_millis(100)).is_err());
|
||||
|
||||
tx.send(42).unwrap();
|
||||
|
||||
assert_eq!(rx.recv(), Ok(42));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disconnect_tx() {
|
||||
let (tx, rx) = unbounded::<()>();
|
||||
drop(tx);
|
||||
assert!(rx.recv().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disconnect_rx() {
|
||||
let (tx, rx) = unbounded();
|
||||
drop(rx);
|
||||
assert!(tx.send(0).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drain() {
|
||||
let (tx, rx) = unbounded();
|
||||
|
||||
for i in 0..100 {
|
||||
tx.send(i).unwrap();
|
||||
}
|
||||
|
||||
assert_eq!(rx.drain().sum::<u32>(), (0..100).sum());
|
||||
|
||||
for i in 0..100 {
|
||||
tx.send(i).unwrap();
|
||||
}
|
||||
|
||||
for i in 0..100 {
|
||||
tx.send(i).unwrap();
|
||||
}
|
||||
|
||||
rx.recv().unwrap();
|
||||
|
||||
(1u32..100).chain(0..100).zip(rx).for_each(|(l, r)| assert_eq!(l, r));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_send() {
|
||||
let (tx, rx) = bounded(5);
|
||||
|
||||
for i in 0..5 {
|
||||
tx.try_send(i).unwrap();
|
||||
}
|
||||
|
||||
assert!(tx.try_send(42).is_err());
|
||||
|
||||
assert_eq!(rx.recv(), Ok(0));
|
||||
|
||||
assert_eq!(tx.try_send(42), Ok(()));
|
||||
|
||||
assert_eq!(rx.recv(), Ok(1));
|
||||
drop(rx);
|
||||
|
||||
assert!(tx.try_send(42).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_bounded() {
|
||||
let (tx, rx) = bounded(5);
|
||||
|
||||
for _ in 0..5 {
|
||||
tx.send(42).unwrap();
|
||||
}
|
||||
|
||||
let _ = rx.recv().unwrap();
|
||||
|
||||
tx.send(42).unwrap();
|
||||
|
||||
assert!(tx.try_send(42).is_err());
|
||||
|
||||
rx.drain();
|
||||
|
||||
let mut ts = Vec::new();
|
||||
for _ in 0..100 {
|
||||
let tx = tx.clone();
|
||||
ts.push(std::thread::spawn(move || {
|
||||
for i in 0..10000 {
|
||||
tx.send(i).unwrap();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
drop(tx);
|
||||
|
||||
assert_eq!(rx.iter().sum::<u64>(), (0..10000).sum::<u64>() * 100);
|
||||
|
||||
for t in ts {
|
||||
t.join().unwrap();
|
||||
}
|
||||
|
||||
assert!(rx.recv().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rendezvous() {
|
||||
let (tx, rx) = bounded(0);
|
||||
|
||||
for i in 0..5 {
|
||||
let tx = tx.clone();
|
||||
let t = std::thread::spawn(move || {
|
||||
assert!(tx.try_send(()).is_err());
|
||||
|
||||
let then = Instant::now();
|
||||
tx.send(()).unwrap();
|
||||
let now = Instant::now();
|
||||
|
||||
assert!(now.duration_since(then) > Duration::from_millis(100), "iter = {}", i);
|
||||
});
|
||||
|
||||
std::thread::sleep(Duration::from_millis(1000));
|
||||
rx.recv().unwrap();
|
||||
|
||||
t.join().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hydra() {
|
||||
let thread_num = 32;
|
||||
let msg_num = 1000;
|
||||
|
||||
let (main_tx, main_rx) = unbounded::<()>();
|
||||
|
||||
let mut txs = Vec::new();
|
||||
for _ in 0..thread_num {
|
||||
let main_tx = main_tx.clone();
|
||||
let (tx, rx) = unbounded();
|
||||
txs.push(tx);
|
||||
|
||||
std::thread::spawn(move || {
|
||||
for msg in rx.iter() {
|
||||
main_tx.send(msg).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
drop(main_tx);
|
||||
|
||||
for _ in 0..10 {
|
||||
for tx in &txs {
|
||||
for _ in 0..msg_num {
|
||||
tx.send(Default::default()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
for _ in 0..thread_num {
|
||||
for _ in 0..msg_num {
|
||||
main_rx.recv().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drop(txs);
|
||||
assert!(main_rx.recv().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn robin() {
|
||||
let thread_num = 32;
|
||||
let msg_num = 10;
|
||||
|
||||
let (mut main_tx, main_rx) = bounded::<()>(1);
|
||||
|
||||
for _ in 0..thread_num {
|
||||
let (mut tx, rx) = bounded(100);
|
||||
std::mem::swap(&mut tx, &mut main_tx);
|
||||
|
||||
std::thread::spawn(move || {
|
||||
for msg in rx.iter() {
|
||||
tx.send(msg).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for _ in 0..10 {
|
||||
let main_tx = main_tx.clone();
|
||||
std::thread::spawn(move || {
|
||||
for _ in 0..msg_num {
|
||||
main_tx.send(Default::default()).unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
for _ in 0..msg_num {
|
||||
main_rx.recv().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "select")]
|
||||
#[test]
|
||||
fn select_general() {
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct Foo(usize);
|
||||
|
||||
let (tx0, rx0) = bounded(1);
|
||||
let (tx1, rx1) = unbounded();
|
||||
|
||||
for (i, t) in vec![tx0.clone(), tx1].into_iter().enumerate() {
|
||||
std::thread::spawn(move || {
|
||||
std::thread::sleep(std::time::Duration::from_millis(250));
|
||||
let _ = t.send(Foo(i));
|
||||
});
|
||||
}
|
||||
|
||||
let x = Selector::new()
|
||||
.recv(&rx0, |x| x)
|
||||
.recv(&rx1, |x| x)
|
||||
.wait()
|
||||
.unwrap();
|
||||
|
||||
if x == Foo(0) {
|
||||
assert!(rx1.recv().unwrap() == Foo(1));
|
||||
} else {
|
||||
assert!(rx0.recv().unwrap() == Foo(0));
|
||||
}
|
||||
|
||||
tx0.send(Foo(42)).unwrap();
|
||||
|
||||
let t = std::thread::spawn(move || {
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
assert_eq!(rx0.recv().unwrap(), Foo(42));
|
||||
assert_eq!(rx0.recv().unwrap(), Foo(43));
|
||||
|
||||
});
|
||||
|
||||
Selector::new()
|
||||
.send(&tx0, Foo(43), |x| x)
|
||||
.wait()
|
||||
.unwrap();
|
||||
|
||||
t.join().unwrap();
|
||||
}
|
||||
|
||||
struct MessageWithoutDebug(u32);
|
||||
|
||||
#[test]
|
||||
// This is a 'does it build' test, to make sure that the error types can turn
|
||||
// into a std::error::Error without requiring the payload (which is not used
|
||||
// there) to impl Debug.
|
||||
fn std_error_without_debug() {
|
||||
let (tx, rx) = unbounded::<MessageWithoutDebug>();
|
||||
|
||||
match tx.send(MessageWithoutDebug(1)) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
let _std_err: &dyn std::error::Error = &e;
|
||||
}
|
||||
}
|
||||
|
||||
match rx.recv() {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
let _std_err: &dyn std::error::Error = &e;
|
||||
}
|
||||
}
|
||||
|
||||
match tx.try_send(MessageWithoutDebug(2)) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
let _std_err: &dyn std::error::Error = &e;
|
||||
}
|
||||
}
|
||||
|
||||
match rx.try_recv() {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
let _std_err: &dyn std::error::Error = &e;
|
||||
}
|
||||
}
|
||||
|
||||
match tx.send_timeout(MessageWithoutDebug(3), Duration::from_secs(1000000)) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
let _std_err: &dyn std::error::Error = &e;
|
||||
}
|
||||
}
|
||||
|
||||
match rx.recv_timeout(Duration::from_secs(10000000)) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
let _std_err: &dyn std::error::Error = &e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn weak_close() {
|
||||
let (tx, rx) = unbounded::<()>();
|
||||
let weak = tx.downgrade();
|
||||
drop(tx);
|
||||
assert!(weak.upgrade().is_none());
|
||||
assert!(rx.is_disconnected());
|
||||
assert!(rx.try_recv().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn weak_upgrade() {
|
||||
let (tx, rx) = unbounded();
|
||||
let weak = tx.downgrade();
|
||||
let tx2 = weak.upgrade().unwrap();
|
||||
drop(tx);
|
||||
assert!(!rx.is_disconnected());
|
||||
tx2.send(()).unwrap();
|
||||
assert!(rx.try_recv().is_ok());
|
||||
}
|
57
vendor/flume/tests/check_same_channel.rs
vendored
Normal file
57
vendor/flume/tests/check_same_channel.rs
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
#[test]
|
||||
fn same_sender() {
|
||||
let (tx1, _rx) = flume::unbounded::<()>();
|
||||
let tx2 = tx1.clone();
|
||||
|
||||
assert!(tx1.same_channel(&tx2));
|
||||
|
||||
let (tx3, _rx) = flume::unbounded::<()>();
|
||||
|
||||
assert!(!tx1.same_channel(&tx3));
|
||||
assert!(!tx2.same_channel(&tx3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn same_receiver() {
|
||||
let (_tx, rx1) = flume::unbounded::<()>();
|
||||
let rx2 = rx1.clone();
|
||||
|
||||
assert!(rx1.same_channel(&rx2));
|
||||
|
||||
let (_tx, rx3) = flume::unbounded::<()>();
|
||||
|
||||
assert!(!rx1.same_channel(&rx3));
|
||||
assert!(!rx2.same_channel(&rx3));
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[test]
|
||||
fn same_send_sink() {
|
||||
let (tx1, _rx) = flume::unbounded::<()>();
|
||||
let tx1 = tx1.into_sink();
|
||||
let tx2 = tx1.clone();
|
||||
|
||||
assert!(tx1.same_channel(&tx2));
|
||||
|
||||
let (tx3, _rx) = flume::unbounded::<()>();
|
||||
let tx3 = tx3.into_sink();
|
||||
|
||||
assert!(!tx1.same_channel(&tx3));
|
||||
assert!(!tx2.same_channel(&tx3));
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[test]
|
||||
fn same_recv_stream() {
|
||||
let (_tx, rx1) = flume::unbounded::<()>();
|
||||
let rx1 = rx1.into_stream();
|
||||
let rx2 = rx1.clone();
|
||||
|
||||
assert!(rx1.same_channel(&rx2));
|
||||
|
||||
let (_tx, rx3) = flume::unbounded::<()>();
|
||||
let rx3 = rx3.into_stream();
|
||||
|
||||
assert!(!rx1.same_channel(&rx3));
|
||||
assert!(!rx2.same_channel(&rx3));
|
||||
}
|
1445
vendor/flume/tests/golang.rs
vendored
Normal file
1445
vendor/flume/tests/golang.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
112
vendor/flume/tests/iter.rs
vendored
Normal file
112
vendor/flume/tests/iter.rs
vendored
Normal file
@ -0,0 +1,112 @@
|
||||
//! Tests for iteration over receivers.
|
||||
|
||||
extern crate crossbeam_utils;
|
||||
|
||||
use flume::unbounded;
|
||||
use crossbeam_utils::thread::scope;
|
||||
|
||||
#[test]
|
||||
fn nested_recv_iter() {
|
||||
let (s, r) = unbounded::<i32>();
|
||||
let (total_s, total_r) = unbounded::<i32>();
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
let mut acc = 0;
|
||||
for x in r.iter() {
|
||||
acc += x;
|
||||
}
|
||||
total_s.send(acc).unwrap();
|
||||
});
|
||||
|
||||
s.send(3).unwrap();
|
||||
s.send(1).unwrap();
|
||||
s.send(2).unwrap();
|
||||
drop(s);
|
||||
assert_eq!(total_r.recv().unwrap(), 6);
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recv_iter_break() {
|
||||
let (s, r) = unbounded::<i32>();
|
||||
let (count_s, count_r) = unbounded();
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
let mut count = 0;
|
||||
for x in r.iter() {
|
||||
if count >= 3 {
|
||||
break;
|
||||
} else {
|
||||
count += x;
|
||||
}
|
||||
}
|
||||
count_s.send(count).unwrap();
|
||||
});
|
||||
|
||||
s.send(2).unwrap();
|
||||
s.send(2).unwrap();
|
||||
s.send(2).unwrap();
|
||||
let _ = s.send(2);
|
||||
drop(s);
|
||||
assert_eq!(count_r.recv().unwrap(), 4);
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recv_try_iter() {
|
||||
let (request_s, request_r) = unbounded();
|
||||
let (response_s, response_r) = unbounded();
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
let mut count = 0;
|
||||
loop {
|
||||
for x in response_r.try_iter() {
|
||||
count += x;
|
||||
if count == 6 {
|
||||
return;
|
||||
}
|
||||
}
|
||||
request_s.send(()).unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
for _ in request_r.iter() {
|
||||
if response_s.send(2).is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recv_into_iter_owned() {
|
||||
let mut iter = {
|
||||
let (s, r) = unbounded::<i32>();
|
||||
s.send(1).unwrap();
|
||||
s.send(2).unwrap();
|
||||
r.into_iter()
|
||||
};
|
||||
|
||||
assert_eq!(iter.next().unwrap(), 1);
|
||||
assert_eq!(iter.next().unwrap(), 2);
|
||||
assert_eq!(iter.next().is_none(), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recv_into_iter_borrowed() {
|
||||
let (s, r) = unbounded::<i32>();
|
||||
s.send(1).unwrap();
|
||||
s.send(2).unwrap();
|
||||
drop(s);
|
||||
|
||||
let mut iter = (&r).into_iter();
|
||||
assert_eq!(iter.next().unwrap(), 1);
|
||||
assert_eq!(iter.next().unwrap(), 2);
|
||||
assert_eq!(iter.next().is_none(), true);
|
||||
}
|
536
vendor/flume/tests/list.rs
vendored
Normal file
536
vendor/flume/tests/list.rs
vendored
Normal file
@ -0,0 +1,536 @@
|
||||
//! Tests for the list channel flavor.
|
||||
|
||||
extern crate crossbeam_utils;
|
||||
extern crate rand;
|
||||
|
||||
use std::any::Any;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use flume::{unbounded, Receiver};
|
||||
use flume::{RecvError, RecvTimeoutError, TryRecvError};
|
||||
use flume::{SendError, SendTimeoutError, TrySendError};
|
||||
use crossbeam_utils::thread::scope;
|
||||
use rand::{thread_rng, Rng};
|
||||
|
||||
fn ms(ms: u64) -> Duration {
|
||||
Duration::from_millis(ms)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn smoke() {
|
||||
let (s, r) = unbounded();
|
||||
s.try_send(7).unwrap();
|
||||
assert_eq!(r.try_recv(), Ok(7));
|
||||
|
||||
s.send(8).unwrap();
|
||||
assert_eq!(r.recv(), Ok(8));
|
||||
|
||||
assert_eq!(r.try_recv(), Err(TryRecvError::Empty));
|
||||
assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn capacity() {
|
||||
let (s, r) = unbounded::<()>();
|
||||
assert_eq!(s.capacity(), None);
|
||||
assert_eq!(r.capacity(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn len_empty_full() {
|
||||
let (s, r) = unbounded();
|
||||
|
||||
assert_eq!(s.len(), 0);
|
||||
assert_eq!(s.is_empty(), true);
|
||||
assert_eq!(s.is_full(), false);
|
||||
assert_eq!(r.len(), 0);
|
||||
assert_eq!(r.is_empty(), true);
|
||||
assert_eq!(r.is_full(), false);
|
||||
|
||||
s.send(()).unwrap();
|
||||
|
||||
assert_eq!(s.len(), 1);
|
||||
assert_eq!(s.is_empty(), false);
|
||||
assert_eq!(s.is_full(), false);
|
||||
assert_eq!(r.len(), 1);
|
||||
assert_eq!(r.is_empty(), false);
|
||||
assert_eq!(r.is_full(), false);
|
||||
|
||||
r.recv().unwrap();
|
||||
|
||||
assert_eq!(s.len(), 0);
|
||||
assert_eq!(s.is_empty(), true);
|
||||
assert_eq!(s.is_full(), false);
|
||||
assert_eq!(r.len(), 0);
|
||||
assert_eq!(r.is_empty(), true);
|
||||
assert_eq!(r.is_full(), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_recv() {
|
||||
let (s, r) = unbounded();
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
assert_eq!(r.try_recv(), Err(TryRecvError::Empty));
|
||||
thread::sleep(ms(1500));
|
||||
assert_eq!(r.try_recv(), Ok(7));
|
||||
thread::sleep(ms(500));
|
||||
assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected));
|
||||
});
|
||||
scope.spawn(move |_| {
|
||||
thread::sleep(ms(1000));
|
||||
s.send(7).unwrap();
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recv() {
|
||||
let (s, r) = unbounded();
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
assert_eq!(r.recv(), Ok(7));
|
||||
thread::sleep(ms(1000));
|
||||
assert_eq!(r.recv(), Ok(8));
|
||||
thread::sleep(ms(1000));
|
||||
assert_eq!(r.recv(), Ok(9));
|
||||
assert!(r.recv().is_err());
|
||||
});
|
||||
scope.spawn(move |_| {
|
||||
thread::sleep(ms(1500));
|
||||
s.send(7).unwrap();
|
||||
s.send(8).unwrap();
|
||||
s.send(9).unwrap();
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recv_timeout() {
|
||||
let (s, r) = unbounded::<i32>();
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout));
|
||||
assert_eq!(r.recv_timeout(ms(1000)), Ok(7));
|
||||
assert_eq!(
|
||||
r.recv_timeout(ms(1000)),
|
||||
Err(RecvTimeoutError::Disconnected)
|
||||
);
|
||||
});
|
||||
scope.spawn(move |_| {
|
||||
thread::sleep(ms(1500));
|
||||
s.send(7).unwrap();
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_send() {
|
||||
let (s, r) = unbounded();
|
||||
for i in 0..1000 {
|
||||
assert_eq!(s.try_send(i), Ok(()));
|
||||
}
|
||||
|
||||
drop(r);
|
||||
assert_eq!(s.try_send(777), Err(TrySendError::Disconnected(777)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send() {
|
||||
let (s, r) = unbounded();
|
||||
for i in 0..1000 {
|
||||
assert_eq!(s.send(i), Ok(()));
|
||||
}
|
||||
|
||||
drop(r);
|
||||
assert_eq!(s.send(777), Err(SendError(777)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_timeout() {
|
||||
let (s, r) = unbounded();
|
||||
for i in 0..1000 {
|
||||
assert_eq!(s.send_timeout(i, ms(i as u64)), Ok(()));
|
||||
}
|
||||
|
||||
drop(r);
|
||||
assert_eq!(
|
||||
s.send_timeout(777, ms(0)),
|
||||
Err(SendTimeoutError::Disconnected(777))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_after_disconnect() {
|
||||
let (s, r) = unbounded();
|
||||
|
||||
s.send(1).unwrap();
|
||||
s.send(2).unwrap();
|
||||
s.send(3).unwrap();
|
||||
|
||||
drop(r);
|
||||
|
||||
assert_eq!(s.send(4), Err(SendError(4)));
|
||||
assert_eq!(s.try_send(5), Err(TrySendError::Disconnected(5)));
|
||||
assert_eq!(
|
||||
s.send_timeout(6, ms(0)),
|
||||
Err(SendTimeoutError::Disconnected(6))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recv_after_disconnect() {
|
||||
let (s, r) = unbounded();
|
||||
|
||||
s.send(1).unwrap();
|
||||
s.send(2).unwrap();
|
||||
s.send(3).unwrap();
|
||||
|
||||
drop(s);
|
||||
|
||||
assert_eq!(r.recv(), Ok(1));
|
||||
assert_eq!(r.recv(), Ok(2));
|
||||
assert_eq!(r.recv(), Ok(3));
|
||||
assert!(r.recv().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn len() {
|
||||
let (s, r) = unbounded();
|
||||
|
||||
assert_eq!(s.len(), 0);
|
||||
assert_eq!(r.len(), 0);
|
||||
|
||||
for i in 0..50 {
|
||||
s.send(i).unwrap();
|
||||
assert_eq!(s.len(), i + 1);
|
||||
}
|
||||
|
||||
for i in 0..50 {
|
||||
r.recv().unwrap();
|
||||
assert_eq!(r.len(), 50 - i - 1);
|
||||
}
|
||||
|
||||
assert_eq!(s.len(), 0);
|
||||
assert_eq!(r.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disconnect_wakes_receiver() {
|
||||
let (s, r) = unbounded::<()>();
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
assert!(r.recv().is_err());
|
||||
});
|
||||
scope.spawn(move |_| {
|
||||
thread::sleep(ms(1000));
|
||||
drop(s);
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spsc() {
|
||||
const COUNT: usize = 100_000;
|
||||
|
||||
let (s, r) = unbounded();
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
for i in 0..COUNT {
|
||||
assert_eq!(r.recv(), Ok(i));
|
||||
}
|
||||
assert!(r.recv().is_err());
|
||||
});
|
||||
scope.spawn(move |_| {
|
||||
for i in 0..COUNT {
|
||||
s.send(i).unwrap();
|
||||
}
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mpmc() {
|
||||
const COUNT: usize = 25_000;
|
||||
const THREADS: usize = 4;
|
||||
|
||||
let (s, r) = unbounded::<usize>();
|
||||
let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::<Vec<_>>();
|
||||
|
||||
scope(|scope| {
|
||||
for _ in 0..THREADS {
|
||||
scope.spawn(|_| {
|
||||
for _ in 0..COUNT {
|
||||
let n = r.recv().unwrap();
|
||||
v[n].fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
});
|
||||
}
|
||||
for _ in 0..THREADS {
|
||||
scope.spawn(|_| {
|
||||
for i in 0..COUNT {
|
||||
s.send(i).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(r.try_recv(), Err(TryRecvError::Empty));
|
||||
|
||||
for c in v {
|
||||
assert_eq!(c.load(Ordering::SeqCst), THREADS);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stress_oneshot() {
|
||||
const COUNT: usize = 10_000;
|
||||
|
||||
for _ in 0..COUNT {
|
||||
let (s, r) = unbounded();
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(|_| r.recv().unwrap());
|
||||
scope.spawn(|_| s.send(0).unwrap());
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stress_iter() {
|
||||
const COUNT: usize = 100_000;
|
||||
|
||||
let (request_s, request_r) = unbounded();
|
||||
let (response_s, response_r) = unbounded();
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
let mut count = 0;
|
||||
loop {
|
||||
for x in response_r.try_iter() {
|
||||
count += x;
|
||||
if count == COUNT {
|
||||
return;
|
||||
}
|
||||
}
|
||||
request_s.send(()).unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
for _ in request_r.iter() {
|
||||
if response_s.send(1).is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stress_timeout_two_threads() {
|
||||
const COUNT: usize = 100;
|
||||
|
||||
let (s, r) = unbounded();
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(|_| {
|
||||
for i in 0..COUNT {
|
||||
if i % 2 == 0 {
|
||||
thread::sleep(ms(50));
|
||||
}
|
||||
s.send(i).unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
scope.spawn(|_| {
|
||||
for i in 0..COUNT {
|
||||
if i % 2 == 0 {
|
||||
thread::sleep(ms(50));
|
||||
}
|
||||
loop {
|
||||
if let Ok(x) = r.recv_timeout(ms(10)) {
|
||||
assert_eq!(x, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drops() {
|
||||
static DROPS: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct DropCounter;
|
||||
|
||||
impl Drop for DropCounter {
|
||||
fn drop(&mut self) {
|
||||
DROPS.fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
let mut rng = thread_rng();
|
||||
|
||||
for _ in 0..100 {
|
||||
let steps = rng.gen_range(0..10_000);
|
||||
let additional = rng.gen_range(0..1000);
|
||||
|
||||
DROPS.store(0, Ordering::SeqCst);
|
||||
let (s, r) = unbounded::<DropCounter>();
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(|_| {
|
||||
for _ in 0..steps {
|
||||
r.recv().unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
scope.spawn(|_| {
|
||||
for _ in 0..steps {
|
||||
s.send(DropCounter).unwrap();
|
||||
}
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
for _ in 0..additional {
|
||||
s.try_send(DropCounter).unwrap();
|
||||
}
|
||||
|
||||
assert_eq!(DROPS.load(Ordering::SeqCst), steps);
|
||||
drop(s);
|
||||
drop(r);
|
||||
assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn linearizable() {
|
||||
const COUNT: usize = 25_000;
|
||||
const THREADS: usize = 4;
|
||||
|
||||
let (s, r) = unbounded();
|
||||
|
||||
scope(|scope| {
|
||||
for _ in 0..THREADS {
|
||||
scope.spawn(|_| {
|
||||
for _ in 0..COUNT {
|
||||
s.send(0).unwrap();
|
||||
r.try_recv().unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn fairness() {
|
||||
// const COUNT: usize = 10_000;
|
||||
|
||||
// let (s1, r1) = unbounded::<()>();
|
||||
// let (s2, r2) = unbounded::<()>();
|
||||
|
||||
// for _ in 0..COUNT {
|
||||
// s1.send(()).unwrap();
|
||||
// s2.send(()).unwrap();
|
||||
// }
|
||||
|
||||
// let mut hits = [0usize; 2];
|
||||
// for _ in 0..COUNT {
|
||||
// select! {
|
||||
// recv(r1) -> _ => hits[0] += 1,
|
||||
// recv(r2) -> _ => hits[1] += 1,
|
||||
// }
|
||||
// }
|
||||
// assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2));
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn fairness_duplicates() {
|
||||
// const COUNT: usize = 10_000;
|
||||
|
||||
// let (s, r) = unbounded();
|
||||
|
||||
// for _ in 0..COUNT {
|
||||
// s.send(()).unwrap();
|
||||
// }
|
||||
|
||||
// let mut hits = [0usize; 5];
|
||||
// for _ in 0..COUNT {
|
||||
// select! {
|
||||
// recv(r) -> _ => hits[0] += 1,
|
||||
// recv(r) -> _ => hits[1] += 1,
|
||||
// recv(r) -> _ => hits[2] += 1,
|
||||
// recv(r) -> _ => hits[3] += 1,
|
||||
// recv(r) -> _ => hits[4] += 1,
|
||||
// }
|
||||
// }
|
||||
// assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2));
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn recv_in_send() {
|
||||
// let (s, r) = unbounded();
|
||||
// s.send(()).unwrap();
|
||||
|
||||
// select! {
|
||||
// send(s, assert_eq!(r.recv(), Ok(()))) -> _ => {}
|
||||
// }
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn channel_through_channel() {
|
||||
const COUNT: usize = 1000;
|
||||
|
||||
type T = Box<dyn Any + Send>;
|
||||
|
||||
let (s, r) = unbounded::<T>();
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
let mut s = s;
|
||||
|
||||
for _ in 0..COUNT {
|
||||
let (new_s, new_r) = unbounded();
|
||||
let new_r: T = Box::new(Some(new_r));
|
||||
|
||||
s.send(new_r).unwrap();
|
||||
s = new_s;
|
||||
}
|
||||
});
|
||||
|
||||
scope.spawn(move |_| {
|
||||
let mut r = r;
|
||||
|
||||
for _ in 0..COUNT {
|
||||
r = r
|
||||
.recv()
|
||||
.unwrap()
|
||||
.downcast_mut::<Option<Receiver<T>>>()
|
||||
.unwrap()
|
||||
.take()
|
||||
.unwrap()
|
||||
}
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
39
vendor/flume/tests/method_sharing.rs
vendored
Normal file
39
vendor/flume/tests/method_sharing.rs
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
#[cfg(feature = "async")]
|
||||
use flume::*;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[async_std::test]
|
||||
async fn sender() {
|
||||
let (sender, receiver) = bounded(1);
|
||||
|
||||
let sender_fut = sender.send_async(());
|
||||
assert_eq!(sender.is_disconnected(), sender_fut.is_disconnected());
|
||||
assert_eq!(sender.is_empty(), sender_fut.is_empty());
|
||||
assert_eq!(sender.is_full(), sender_fut.is_full());
|
||||
assert_eq!(sender.len(), sender_fut.len());
|
||||
assert_eq!(sender.capacity(), sender_fut.capacity());
|
||||
|
||||
let sender_sink = sender.sink();
|
||||
assert_eq!(sender.is_disconnected(), sender_sink.is_disconnected());
|
||||
assert_eq!(sender.is_empty(), sender_sink.is_empty());
|
||||
assert_eq!(sender.is_full(), sender_sink.is_full());
|
||||
assert_eq!(sender.len(), sender_sink.len());
|
||||
assert_eq!(sender.capacity(), sender_sink.capacity());
|
||||
|
||||
let receiver_fut = receiver.recv_async();
|
||||
assert_eq!(receiver.is_disconnected(), receiver_fut.is_disconnected());
|
||||
assert_eq!(receiver.is_empty(), receiver_fut.is_empty());
|
||||
assert_eq!(receiver.is_full(), receiver_fut.is_full());
|
||||
assert_eq!(receiver.len(), receiver_fut.len());
|
||||
assert_eq!(receiver.capacity(), receiver_fut.capacity());
|
||||
|
||||
let receiver_stream = receiver.stream();
|
||||
assert_eq!(
|
||||
receiver.is_disconnected(),
|
||||
receiver_stream.is_disconnected()
|
||||
);
|
||||
assert_eq!(receiver.is_empty(), receiver_stream.is_empty());
|
||||
assert_eq!(receiver.is_full(), receiver_stream.is_full());
|
||||
assert_eq!(receiver.len(), receiver_stream.len());
|
||||
assert_eq!(receiver.capacity(), receiver_stream.capacity());
|
||||
}
|
2095
vendor/flume/tests/mpsc.rs
vendored
Normal file
2095
vendor/flume/tests/mpsc.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
99
vendor/flume/tests/never.rs
vendored
Normal file
99
vendor/flume/tests/never.rs
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
// //! Tests for the never channel flavor.
|
||||
|
||||
// #[macro_use]
|
||||
// extern crate crossbeam_channel;
|
||||
// extern crate rand;
|
||||
|
||||
// use std::thread;
|
||||
// use std::time::{Duration, Instant};
|
||||
|
||||
// use crossbeam_channel::{never, tick, unbounded};
|
||||
|
||||
// fn ms(ms: u64) -> Duration {
|
||||
// Duration::from_millis(ms)
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn smoke() {
|
||||
// select! {
|
||||
// recv(never::<i32>()) -> _ => panic!(),
|
||||
// default => {}
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn optional() {
|
||||
// let (s, r) = unbounded::<i32>();
|
||||
// s.send(1).unwrap();
|
||||
// s.send(2).unwrap();
|
||||
|
||||
// let mut r = Some(&r);
|
||||
// select! {
|
||||
// recv(r.unwrap_or(&never())) -> _ => {}
|
||||
// default => panic!(),
|
||||
// }
|
||||
|
||||
// r = None;
|
||||
// select! {
|
||||
// recv(r.unwrap_or(&never())) -> _ => panic!(),
|
||||
// default => {}
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn tick_n() {
|
||||
// let mut r = tick(ms(100));
|
||||
// let mut step = 0;
|
||||
|
||||
// loop {
|
||||
// select! {
|
||||
// recv(r) -> _ => step += 1,
|
||||
// default(ms(500)) => break,
|
||||
// }
|
||||
|
||||
// if step == 10 {
|
||||
// r = never();
|
||||
// }
|
||||
// }
|
||||
|
||||
// assert_eq!(step, 10);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn capacity() {
|
||||
// let r = never::<i32>();
|
||||
// assert_eq!(r.capacity(), Some(0));
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn len_empty_full() {
|
||||
// let r = never::<i32>();
|
||||
// assert_eq!(r.len(), 0);
|
||||
// assert_eq!(r.is_empty(), true);
|
||||
// assert_eq!(r.is_full(), true);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn try_recv() {
|
||||
// let r = never::<i32>();
|
||||
// assert!(r.try_recv().is_err());
|
||||
|
||||
// thread::sleep(ms(100));
|
||||
// assert!(r.try_recv().is_err());
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn recv_timeout() {
|
||||
// let start = Instant::now();
|
||||
// let r = never::<i32>();
|
||||
|
||||
// assert!(r.recv_timeout(ms(100)).is_err());
|
||||
// let now = Instant::now();
|
||||
// assert!(now - start >= ms(100));
|
||||
// assert!(now - start <= ms(150));
|
||||
|
||||
// assert!(r.recv_timeout(ms(100)).is_err());
|
||||
// let now = Instant::now();
|
||||
// assert!(now - start >= ms(200));
|
||||
// assert!(now - start <= ms(250));
|
||||
// }
|
837
vendor/flume/tests/ready.rs
vendored
Normal file
837
vendor/flume/tests/ready.rs
vendored
Normal file
@ -0,0 +1,837 @@
|
||||
// //! Tests for channel readiness using the `Select` struct.
|
||||
|
||||
// extern crate crossbeam_channel;
|
||||
// extern crate crossbeam_utils;
|
||||
|
||||
// use std::any::Any;
|
||||
// use std::cell::Cell;
|
||||
// use std::thread;
|
||||
// use std::time::{Duration, Instant};
|
||||
|
||||
// use crossbeam_channel::{after, bounded, tick, unbounded};
|
||||
// use crossbeam_channel::{Receiver, Select, TryRecvError, TrySendError};
|
||||
// use crossbeam_utils::thread::scope;
|
||||
|
||||
// fn ms(ms: u64) -> Duration {
|
||||
// Duration::from_millis(ms)
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn smoke1() {
|
||||
// let (s1, r1) = unbounded::<usize>();
|
||||
// let (s2, r2) = unbounded::<usize>();
|
||||
|
||||
// s1.send(1).unwrap();
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r1);
|
||||
// sel.recv(&r2);
|
||||
// assert_eq!(sel.ready(), 0);
|
||||
// assert_eq!(r1.try_recv(), Ok(1));
|
||||
|
||||
// s2.send(2).unwrap();
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r1);
|
||||
// sel.recv(&r2);
|
||||
// assert_eq!(sel.ready(), 1);
|
||||
// assert_eq!(r2.try_recv(), Ok(2));
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn smoke2() {
|
||||
// let (_s1, r1) = unbounded::<i32>();
|
||||
// let (_s2, r2) = unbounded::<i32>();
|
||||
// let (_s3, r3) = unbounded::<i32>();
|
||||
// let (_s4, r4) = unbounded::<i32>();
|
||||
// let (s5, r5) = unbounded::<i32>();
|
||||
|
||||
// s5.send(5).unwrap();
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r1);
|
||||
// sel.recv(&r2);
|
||||
// sel.recv(&r3);
|
||||
// sel.recv(&r4);
|
||||
// sel.recv(&r5);
|
||||
// assert_eq!(sel.ready(), 4);
|
||||
// assert_eq!(r5.try_recv(), Ok(5));
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn disconnected() {
|
||||
// let (s1, r1) = unbounded::<i32>();
|
||||
// let (s2, r2) = unbounded::<i32>();
|
||||
|
||||
// scope(|scope| {
|
||||
// scope.spawn(|_| {
|
||||
// drop(s1);
|
||||
// thread::sleep(ms(500));
|
||||
// s2.send(5).unwrap();
|
||||
// });
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r1);
|
||||
// sel.recv(&r2);
|
||||
// match sel.ready_timeout(ms(1000)) {
|
||||
// Ok(0) => assert_eq!(r1.try_recv(), Err(TryRecvError::Disconnected)),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
|
||||
// r2.recv().unwrap();
|
||||
// })
|
||||
// .unwrap();
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r1);
|
||||
// sel.recv(&r2);
|
||||
// match sel.ready_timeout(ms(1000)) {
|
||||
// Ok(0) => assert_eq!(r1.try_recv(), Err(TryRecvError::Disconnected)),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
|
||||
// scope(|scope| {
|
||||
// scope.spawn(|_| {
|
||||
// thread::sleep(ms(500));
|
||||
// drop(s2);
|
||||
// });
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r2);
|
||||
// match sel.ready_timeout(ms(1000)) {
|
||||
// Ok(0) => assert_eq!(r2.try_recv(), Err(TryRecvError::Disconnected)),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
// })
|
||||
// .unwrap();
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn default() {
|
||||
// let (s1, r1) = unbounded::<i32>();
|
||||
// let (s2, r2) = unbounded::<i32>();
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r1);
|
||||
// sel.recv(&r2);
|
||||
// assert!(sel.try_ready().is_err());
|
||||
|
||||
// drop(s1);
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r1);
|
||||
// sel.recv(&r2);
|
||||
// match sel.try_ready() {
|
||||
// Ok(0) => assert!(r1.try_recv().is_err()),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
|
||||
// s2.send(2).unwrap();
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r2);
|
||||
// match sel.try_ready() {
|
||||
// Ok(0) => assert_eq!(r2.try_recv(), Ok(2)),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r2);
|
||||
// assert!(sel.try_ready().is_err());
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// assert!(sel.try_ready().is_err());
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn timeout() {
|
||||
// let (_s1, r1) = unbounded::<i32>();
|
||||
// let (s2, r2) = unbounded::<i32>();
|
||||
|
||||
// scope(|scope| {
|
||||
// scope.spawn(|_| {
|
||||
// thread::sleep(ms(1500));
|
||||
// s2.send(2).unwrap();
|
||||
// });
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r1);
|
||||
// sel.recv(&r2);
|
||||
// assert!(sel.ready_timeout(ms(1000)).is_err());
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r1);
|
||||
// sel.recv(&r2);
|
||||
// match sel.ready_timeout(ms(1000)) {
|
||||
// Ok(1) => assert_eq!(r2.try_recv(), Ok(2)),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
// })
|
||||
// .unwrap();
|
||||
|
||||
// scope(|scope| {
|
||||
// let (s, r) = unbounded::<i32>();
|
||||
|
||||
// scope.spawn(move |_| {
|
||||
// thread::sleep(ms(500));
|
||||
// drop(s);
|
||||
// });
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// assert!(sel.ready_timeout(ms(1000)).is_err());
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r);
|
||||
// match sel.try_ready() {
|
||||
// Ok(0) => assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
// })
|
||||
// .unwrap();
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn default_when_disconnected() {
|
||||
// let (_, r) = unbounded::<i32>();
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r);
|
||||
// match sel.try_ready() {
|
||||
// Ok(0) => assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
|
||||
// let (_, r) = unbounded::<i32>();
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r);
|
||||
// match sel.ready_timeout(ms(1000)) {
|
||||
// Ok(0) => assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
|
||||
// let (s, _) = bounded::<i32>(0);
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.send(&s);
|
||||
// match sel.try_ready() {
|
||||
// Ok(0) => assert_eq!(s.try_send(0), Err(TrySendError::Disconnected(0))),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
|
||||
// let (s, _) = bounded::<i32>(0);
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.send(&s);
|
||||
// match sel.ready_timeout(ms(1000)) {
|
||||
// Ok(0) => assert_eq!(s.try_send(0), Err(TrySendError::Disconnected(0))),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn default_only() {
|
||||
// let start = Instant::now();
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// assert!(sel.try_ready().is_err());
|
||||
// let now = Instant::now();
|
||||
// assert!(now - start <= ms(50));
|
||||
|
||||
// let start = Instant::now();
|
||||
// let mut sel = Select::new();
|
||||
// assert!(sel.ready_timeout(ms(500)).is_err());
|
||||
// let now = Instant::now();
|
||||
// assert!(now - start >= ms(450));
|
||||
// assert!(now - start <= ms(550));
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn unblocks() {
|
||||
// let (s1, r1) = bounded::<i32>(0);
|
||||
// let (s2, r2) = bounded::<i32>(0);
|
||||
|
||||
// scope(|scope| {
|
||||
// scope.spawn(|_| {
|
||||
// thread::sleep(ms(500));
|
||||
// s2.send(2).unwrap();
|
||||
// });
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r1);
|
||||
// sel.recv(&r2);
|
||||
// match sel.ready_timeout(ms(1000)) {
|
||||
// Ok(1) => assert_eq!(r2.try_recv(), Ok(2)),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
// })
|
||||
// .unwrap();
|
||||
|
||||
// scope(|scope| {
|
||||
// scope.spawn(|_| {
|
||||
// thread::sleep(ms(500));
|
||||
// assert_eq!(r1.recv().unwrap(), 1);
|
||||
// });
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// let oper1 = sel.send(&s1);
|
||||
// let oper2 = sel.send(&s2);
|
||||
// let oper = sel.select_timeout(ms(1000));
|
||||
// match oper {
|
||||
// Err(_) => panic!(),
|
||||
// Ok(oper) => match oper.index() {
|
||||
// i if i == oper1 => oper.send(&s1, 1).unwrap(),
|
||||
// i if i == oper2 => panic!(),
|
||||
// _ => unreachable!(),
|
||||
// },
|
||||
// }
|
||||
// })
|
||||
// .unwrap();
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn both_ready() {
|
||||
// let (s1, r1) = bounded(0);
|
||||
// let (s2, r2) = bounded(0);
|
||||
|
||||
// scope(|scope| {
|
||||
// scope.spawn(|_| {
|
||||
// thread::sleep(ms(500));
|
||||
// s1.send(1).unwrap();
|
||||
// assert_eq!(r2.recv().unwrap(), 2);
|
||||
// });
|
||||
|
||||
// for _ in 0..2 {
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r1);
|
||||
// sel.send(&s2);
|
||||
// match sel.ready() {
|
||||
// 0 => assert_eq!(r1.try_recv(), Ok(1)),
|
||||
// 1 => s2.try_send(2).unwrap(),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
// .unwrap();
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn cloning1() {
|
||||
// scope(|scope| {
|
||||
// let (s1, r1) = unbounded::<i32>();
|
||||
// let (_s2, r2) = unbounded::<i32>();
|
||||
// let (s3, r3) = unbounded::<()>();
|
||||
|
||||
// scope.spawn(move |_| {
|
||||
// r3.recv().unwrap();
|
||||
// drop(s1.clone());
|
||||
// assert!(r3.try_recv().is_err());
|
||||
// s1.send(1).unwrap();
|
||||
// r3.recv().unwrap();
|
||||
// });
|
||||
|
||||
// s3.send(()).unwrap();
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r1);
|
||||
// sel.recv(&r2);
|
||||
// match sel.ready() {
|
||||
// 0 => drop(r1.try_recv()),
|
||||
// 1 => drop(r2.try_recv()),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
|
||||
// s3.send(()).unwrap();
|
||||
// })
|
||||
// .unwrap();
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn cloning2() {
|
||||
// let (s1, r1) = unbounded::<()>();
|
||||
// let (s2, r2) = unbounded::<()>();
|
||||
// let (_s3, _r3) = unbounded::<()>();
|
||||
|
||||
// scope(|scope| {
|
||||
// scope.spawn(move |_| {
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r1);
|
||||
// sel.recv(&r2);
|
||||
// match sel.ready() {
|
||||
// 0 => panic!(),
|
||||
// 1 => drop(r2.try_recv()),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
// });
|
||||
|
||||
// thread::sleep(ms(500));
|
||||
// drop(s1.clone());
|
||||
// s2.send(()).unwrap();
|
||||
// })
|
||||
// .unwrap();
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn preflight1() {
|
||||
// let (s, r) = unbounded();
|
||||
// s.send(()).unwrap();
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r);
|
||||
// match sel.ready() {
|
||||
// 0 => drop(r.try_recv()),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn preflight2() {
|
||||
// let (s, r) = unbounded();
|
||||
// drop(s.clone());
|
||||
// s.send(()).unwrap();
|
||||
// drop(s);
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r);
|
||||
// match sel.ready() {
|
||||
// 0 => assert_eq!(r.try_recv(), Ok(())),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
|
||||
// assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected));
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn preflight3() {
|
||||
// let (s, r) = unbounded();
|
||||
// drop(s.clone());
|
||||
// s.send(()).unwrap();
|
||||
// drop(s);
|
||||
// r.recv().unwrap();
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r);
|
||||
// match sel.ready() {
|
||||
// 0 => assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn duplicate_operations() {
|
||||
// let (s, r) = unbounded::<i32>();
|
||||
// let hit = vec![Cell::new(false); 4];
|
||||
|
||||
// while hit.iter().map(|h| h.get()).any(|hit| !hit) {
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r);
|
||||
// sel.recv(&r);
|
||||
// sel.send(&s);
|
||||
// sel.send(&s);
|
||||
// match sel.ready() {
|
||||
// 0 => {
|
||||
// assert!(r.try_recv().is_ok());
|
||||
// hit[0].set(true);
|
||||
// }
|
||||
// 1 => {
|
||||
// assert!(r.try_recv().is_ok());
|
||||
// hit[1].set(true);
|
||||
// }
|
||||
// 2 => {
|
||||
// assert!(s.try_send(0).is_ok());
|
||||
// hit[2].set(true);
|
||||
// }
|
||||
// 3 => {
|
||||
// assert!(s.try_send(0).is_ok());
|
||||
// hit[3].set(true);
|
||||
// }
|
||||
// _ => panic!(),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn nesting() {
|
||||
// let (s, r) = unbounded::<i32>();
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.send(&s);
|
||||
// match sel.ready() {
|
||||
// 0 => {
|
||||
// assert!(s.try_send(0).is_ok());
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r);
|
||||
// match sel.ready() {
|
||||
// 0 => {
|
||||
// assert_eq!(r.try_recv(), Ok(0));
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.send(&s);
|
||||
// match sel.ready() {
|
||||
// 0 => {
|
||||
// assert!(s.try_send(1).is_ok());
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r);
|
||||
// match sel.ready() {
|
||||
// 0 => {
|
||||
// assert_eq!(r.try_recv(), Ok(1));
|
||||
// }
|
||||
// _ => panic!(),
|
||||
// }
|
||||
// }
|
||||
// _ => panic!(),
|
||||
// }
|
||||
// }
|
||||
// _ => panic!(),
|
||||
// }
|
||||
// }
|
||||
// _ => panic!(),
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn stress_recv() {
|
||||
// const COUNT: usize = 10_000;
|
||||
|
||||
// let (s1, r1) = unbounded();
|
||||
// let (s2, r2) = bounded(5);
|
||||
// let (s3, r3) = bounded(0);
|
||||
|
||||
// scope(|scope| {
|
||||
// scope.spawn(|_| {
|
||||
// for i in 0..COUNT {
|
||||
// s1.send(i).unwrap();
|
||||
// r3.recv().unwrap();
|
||||
|
||||
// s2.send(i).unwrap();
|
||||
// r3.recv().unwrap();
|
||||
// }
|
||||
// });
|
||||
|
||||
// for i in 0..COUNT {
|
||||
// for _ in 0..2 {
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r1);
|
||||
// sel.recv(&r2);
|
||||
// match sel.ready() {
|
||||
// 0 => assert_eq!(r1.try_recv(), Ok(i)),
|
||||
// 1 => assert_eq!(r2.try_recv(), Ok(i)),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
|
||||
// s3.send(()).unwrap();
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
// .unwrap();
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn stress_send() {
|
||||
// const COUNT: usize = 10_000;
|
||||
|
||||
// let (s1, r1) = bounded(0);
|
||||
// let (s2, r2) = bounded(0);
|
||||
// let (s3, r3) = bounded(100);
|
||||
|
||||
// scope(|scope| {
|
||||
// scope.spawn(|_| {
|
||||
// for i in 0..COUNT {
|
||||
// assert_eq!(r1.recv().unwrap(), i);
|
||||
// assert_eq!(r2.recv().unwrap(), i);
|
||||
// r3.recv().unwrap();
|
||||
// }
|
||||
// });
|
||||
|
||||
// for i in 0..COUNT {
|
||||
// for _ in 0..2 {
|
||||
// let mut sel = Select::new();
|
||||
// sel.send(&s1);
|
||||
// sel.send(&s2);
|
||||
// match sel.ready() {
|
||||
// 0 => assert!(s1.try_send(i).is_ok()),
|
||||
// 1 => assert!(s2.try_send(i).is_ok()),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
// }
|
||||
// s3.send(()).unwrap();
|
||||
// }
|
||||
// })
|
||||
// .unwrap();
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn stress_mixed() {
|
||||
// const COUNT: usize = 10_000;
|
||||
|
||||
// let (s1, r1) = bounded(0);
|
||||
// let (s2, r2) = bounded(0);
|
||||
// let (s3, r3) = bounded(100);
|
||||
|
||||
// scope(|scope| {
|
||||
// scope.spawn(|_| {
|
||||
// for i in 0..COUNT {
|
||||
// s1.send(i).unwrap();
|
||||
// assert_eq!(r2.recv().unwrap(), i);
|
||||
// r3.recv().unwrap();
|
||||
// }
|
||||
// });
|
||||
|
||||
// for i in 0..COUNT {
|
||||
// for _ in 0..2 {
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r1);
|
||||
// sel.send(&s2);
|
||||
// match sel.ready() {
|
||||
// 0 => assert_eq!(r1.try_recv(), Ok(i)),
|
||||
// 1 => assert!(s2.try_send(i).is_ok()),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
// }
|
||||
// s3.send(()).unwrap();
|
||||
// }
|
||||
// })
|
||||
// .unwrap();
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn stress_timeout_two_threads() {
|
||||
// const COUNT: usize = 20;
|
||||
|
||||
// let (s, r) = bounded(2);
|
||||
|
||||
// scope(|scope| {
|
||||
// scope.spawn(|_| {
|
||||
// for i in 0..COUNT {
|
||||
// if i % 2 == 0 {
|
||||
// thread::sleep(ms(500));
|
||||
// }
|
||||
|
||||
// let done = false;
|
||||
// while !done {
|
||||
// let mut sel = Select::new();
|
||||
// sel.send(&s);
|
||||
// match sel.ready_timeout(ms(100)) {
|
||||
// Err(_) => {}
|
||||
// Ok(0) => {
|
||||
// assert!(s.try_send(i).is_ok());
|
||||
// break;
|
||||
// }
|
||||
// Ok(_) => panic!(),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// scope.spawn(|_| {
|
||||
// for i in 0..COUNT {
|
||||
// if i % 2 == 0 {
|
||||
// thread::sleep(ms(500));
|
||||
// }
|
||||
|
||||
// let mut done = false;
|
||||
// while !done {
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r);
|
||||
// match sel.ready_timeout(ms(100)) {
|
||||
// Err(_) => {}
|
||||
// Ok(0) => {
|
||||
// assert_eq!(r.try_recv(), Ok(i));
|
||||
// done = true;
|
||||
// }
|
||||
// Ok(_) => panic!(),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// })
|
||||
// .unwrap();
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn send_recv_same_channel() {
|
||||
// let (s, r) = bounded::<i32>(0);
|
||||
// let mut sel = Select::new();
|
||||
// sel.send(&s);
|
||||
// sel.recv(&r);
|
||||
// assert!(sel.ready_timeout(ms(100)).is_err());
|
||||
|
||||
// let (s, r) = unbounded::<i32>();
|
||||
// let mut sel = Select::new();
|
||||
// sel.send(&s);
|
||||
// sel.recv(&r);
|
||||
// match sel.ready_timeout(ms(100)) {
|
||||
// Err(_) => panic!(),
|
||||
// Ok(0) => assert!(s.try_send(0).is_ok()),
|
||||
// Ok(_) => panic!(),
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn channel_through_channel() {
|
||||
// const COUNT: usize = 1000;
|
||||
|
||||
// type T = Box<dyn Any + Send>;
|
||||
|
||||
// for cap in 1..4 {
|
||||
// let (s, r) = bounded::<T>(cap);
|
||||
|
||||
// scope(|scope| {
|
||||
// scope.spawn(move |_| {
|
||||
// let mut s = s;
|
||||
|
||||
// for _ in 0..COUNT {
|
||||
// let (new_s, new_r) = bounded(cap);
|
||||
// let new_r: T = Box::new(Some(new_r));
|
||||
|
||||
// {
|
||||
// let mut sel = Select::new();
|
||||
// sel.send(&s);
|
||||
// match sel.ready() {
|
||||
// 0 => assert!(s.try_send(new_r).is_ok()),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
// }
|
||||
|
||||
// s = new_s;
|
||||
// }
|
||||
// });
|
||||
|
||||
// scope.spawn(move |_| {
|
||||
// let mut r = r;
|
||||
|
||||
// for _ in 0..COUNT {
|
||||
// let new = {
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r);
|
||||
// match sel.ready() {
|
||||
// 0 => r
|
||||
// .try_recv()
|
||||
// .unwrap()
|
||||
// .downcast_mut::<Option<Receiver<T>>>()
|
||||
// .unwrap()
|
||||
// .take()
|
||||
// .unwrap(),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
// };
|
||||
// r = new;
|
||||
// }
|
||||
// });
|
||||
// })
|
||||
// .unwrap();
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn fairness1() {
|
||||
// const COUNT: usize = 10_000;
|
||||
|
||||
// let (s1, r1) = bounded::<()>(COUNT);
|
||||
// let (s2, r2) = unbounded::<()>();
|
||||
|
||||
// for _ in 0..COUNT {
|
||||
// s1.send(()).unwrap();
|
||||
// s2.send(()).unwrap();
|
||||
// }
|
||||
|
||||
// let hits = vec![Cell::new(0usize); 4];
|
||||
// for _ in 0..COUNT {
|
||||
// let after = after(ms(0));
|
||||
// let tick = tick(ms(0));
|
||||
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r1);
|
||||
// sel.recv(&r2);
|
||||
// sel.recv(&after);
|
||||
// sel.recv(&tick);
|
||||
// match sel.ready() {
|
||||
// 0 => {
|
||||
// r1.try_recv().unwrap();
|
||||
// hits[0].set(hits[0].get() + 1);
|
||||
// }
|
||||
// 1 => {
|
||||
// r2.try_recv().unwrap();
|
||||
// hits[1].set(hits[1].get() + 1);
|
||||
// }
|
||||
// 2 => {
|
||||
// after.try_recv().unwrap();
|
||||
// hits[2].set(hits[2].get() + 1);
|
||||
// }
|
||||
// 3 => {
|
||||
// tick.try_recv().unwrap();
|
||||
// hits[3].set(hits[3].get() + 1);
|
||||
// }
|
||||
// _ => panic!(),
|
||||
// }
|
||||
// }
|
||||
// assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 2));
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn fairness2() {
|
||||
// const COUNT: usize = 10_000;
|
||||
|
||||
// let (s1, r1) = unbounded::<()>();
|
||||
// let (s2, r2) = bounded::<()>(1);
|
||||
// let (s3, r3) = bounded::<()>(0);
|
||||
|
||||
// scope(|scope| {
|
||||
// scope.spawn(|_| {
|
||||
// for _ in 0..COUNT {
|
||||
// let mut sel = Select::new();
|
||||
// let mut oper1 = None;
|
||||
// let mut oper2 = None;
|
||||
// if s1.is_empty() {
|
||||
// oper1 = Some(sel.send(&s1));
|
||||
// }
|
||||
// if s2.is_empty() {
|
||||
// oper2 = Some(sel.send(&s2));
|
||||
// }
|
||||
// let oper3 = sel.send(&s3);
|
||||
// let oper = sel.select();
|
||||
// match oper.index() {
|
||||
// i if Some(i) == oper1 => assert!(oper.send(&s1, ()).is_ok()),
|
||||
// i if Some(i) == oper2 => assert!(oper.send(&s2, ()).is_ok()),
|
||||
// i if i == oper3 => assert!(oper.send(&s3, ()).is_ok()),
|
||||
// _ => unreachable!(),
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// let hits = vec![Cell::new(0usize); 3];
|
||||
// for _ in 0..COUNT {
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r1);
|
||||
// sel.recv(&r2);
|
||||
// sel.recv(&r3);
|
||||
// loop {
|
||||
// match sel.ready() {
|
||||
// 0 => {
|
||||
// if r1.try_recv().is_ok() {
|
||||
// hits[0].set(hits[0].get() + 1);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// 1 => {
|
||||
// if r2.try_recv().is_ok() {
|
||||
// hits[1].set(hits[1].get() + 1);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// 2 => {
|
||||
// if r3.try_recv().is_ok() {
|
||||
// hits[2].set(hits[2].get() + 1);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// _ => unreachable!(),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 10));
|
||||
// })
|
||||
// .unwrap();
|
||||
// }
|
114
vendor/flume/tests/same_channel.rs
vendored
Normal file
114
vendor/flume/tests/same_channel.rs
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
// extern crate crossbeam_channel;
|
||||
|
||||
// use std::time::Duration;
|
||||
|
||||
// use crossbeam_channel::{after, bounded, never, tick, unbounded};
|
||||
|
||||
// fn ms(ms: u64) -> Duration {
|
||||
// Duration::from_millis(ms)
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn after_same_channel() {
|
||||
// let r = after(ms(50));
|
||||
|
||||
// let r2 = r.clone();
|
||||
// assert!(r.same_channel(&r2));
|
||||
|
||||
// let r3 = after(ms(50));
|
||||
// assert!(!r.same_channel(&r3));
|
||||
// assert!(!r2.same_channel(&r3));
|
||||
|
||||
// let r4 = after(ms(100));
|
||||
// assert!(!r.same_channel(&r4));
|
||||
// assert!(!r2.same_channel(&r4));
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn array_same_channel() {
|
||||
// let (s, r) = bounded::<usize>(1);
|
||||
|
||||
// let s2 = s.clone();
|
||||
// assert!(s.same_channel(&s2));
|
||||
|
||||
// let r2 = r.clone();
|
||||
// assert!(r.same_channel(&r2));
|
||||
|
||||
// let (s3, r3) = bounded::<usize>(1);
|
||||
// assert!(!s.same_channel(&s3));
|
||||
// assert!(!s2.same_channel(&s3));
|
||||
// assert!(!r.same_channel(&r3));
|
||||
// assert!(!r2.same_channel(&r3));
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn list_same_channel() {
|
||||
// let (s, r) = unbounded::<usize>();
|
||||
|
||||
// let s2 = s.clone();
|
||||
// assert!(s.same_channel(&s2));
|
||||
|
||||
// let r2 = r.clone();
|
||||
// assert!(r.same_channel(&r2));
|
||||
|
||||
// let (s3, r3) = unbounded::<usize>();
|
||||
// assert!(!s.same_channel(&s3));
|
||||
// assert!(!s2.same_channel(&s3));
|
||||
// assert!(!r.same_channel(&r3));
|
||||
// assert!(!r2.same_channel(&r3));
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn never_same_channel() {
|
||||
// let r = never::<usize>();
|
||||
|
||||
// let r2 = r.clone();
|
||||
// assert!(r.same_channel(&r2));
|
||||
|
||||
// // Never channel are always equal to one another.
|
||||
// let r3 = never::<usize>();
|
||||
// assert!(r.same_channel(&r3));
|
||||
// assert!(r2.same_channel(&r3));
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn tick_same_channel() {
|
||||
// let r = tick(ms(50));
|
||||
|
||||
// let r2 = r.clone();
|
||||
// assert!(r.same_channel(&r2));
|
||||
|
||||
// let r3 = tick(ms(50));
|
||||
// assert!(!r.same_channel(&r3));
|
||||
// assert!(!r2.same_channel(&r3));
|
||||
|
||||
// let r4 = tick(ms(100));
|
||||
// assert!(!r.same_channel(&r4));
|
||||
// assert!(!r2.same_channel(&r4));
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn zero_same_channel() {
|
||||
// let (s, r) = bounded::<usize>(0);
|
||||
|
||||
// let s2 = s.clone();
|
||||
// assert!(s.same_channel(&s2));
|
||||
|
||||
// let r2 = r.clone();
|
||||
// assert!(r.same_channel(&r2));
|
||||
|
||||
// let (s3, r3) = bounded::<usize>(0);
|
||||
// assert!(!s.same_channel(&s3));
|
||||
// assert!(!s2.same_channel(&s3));
|
||||
// assert!(!r.same_channel(&r3));
|
||||
// assert!(!r2.same_channel(&r3));
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn different_flavors_same_channel() {
|
||||
// let (s1, r1) = bounded::<usize>(0);
|
||||
// let (s2, r2) = unbounded::<usize>();
|
||||
|
||||
// assert!(!s1.same_channel(&s2));
|
||||
// assert!(!r1.same_channel(&r2));
|
||||
// }
|
1304
vendor/flume/tests/select.rs
vendored
Normal file
1304
vendor/flume/tests/select.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1440
vendor/flume/tests/select_macro.rs
vendored
Normal file
1440
vendor/flume/tests/select_macro.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
255
vendor/flume/tests/stream.rs
vendored
Normal file
255
vendor/flume/tests/stream.rs
vendored
Normal file
@ -0,0 +1,255 @@
|
||||
#[cfg(feature = "async")]
|
||||
use {
|
||||
flume::*,
|
||||
futures::{stream::FuturesUnordered, StreamExt, TryFutureExt},
|
||||
async_std::prelude::FutureExt,
|
||||
std::time::Duration,
|
||||
};
|
||||
use futures::{stream, Stream};
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[test]
|
||||
fn stream_recv() {
|
||||
let (tx, rx) = unbounded();
|
||||
|
||||
let t = std::thread::spawn(move || {
|
||||
std::thread::sleep(std::time::Duration::from_millis(250));
|
||||
tx.send(42u32).unwrap();
|
||||
println!("sent");
|
||||
});
|
||||
|
||||
async_std::task::block_on(async {
|
||||
println!("receiving...");
|
||||
let x = rx.stream().next().await;
|
||||
println!("received");
|
||||
assert_eq!(x, Some(42));
|
||||
});
|
||||
|
||||
t.join().unwrap();
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[test]
|
||||
fn stream_recv_disconnect() {
|
||||
let (tx, rx) = bounded::<i32>(0);
|
||||
|
||||
let t = std::thread::spawn(move || {
|
||||
tx.send(42);
|
||||
std::thread::sleep(std::time::Duration::from_millis(250));
|
||||
drop(tx)
|
||||
});
|
||||
|
||||
async_std::task::block_on(async {
|
||||
let mut stream = rx.into_stream();
|
||||
assert_eq!(stream.next().await, Some(42));
|
||||
assert_eq!(stream.next().await, None);
|
||||
});
|
||||
|
||||
t.join().unwrap();
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[test]
|
||||
fn stream_recv_drop_recv() {
|
||||
let (tx, rx) = bounded::<i32>(10);
|
||||
|
||||
let rx2 = rx.clone();
|
||||
let mut stream = rx.into_stream();
|
||||
|
||||
async_std::task::block_on(async {
|
||||
let res = async_std::future::timeout(
|
||||
std::time::Duration::from_millis(500),
|
||||
stream.next()
|
||||
).await;
|
||||
|
||||
assert!(res.is_err());
|
||||
});
|
||||
|
||||
let t = std::thread::spawn(move || {
|
||||
async_std::task::block_on(async {
|
||||
rx2.stream().next().await
|
||||
})
|
||||
});
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_millis(500));
|
||||
|
||||
tx.send(42).unwrap();
|
||||
|
||||
drop(stream);
|
||||
|
||||
assert_eq!(t.join().unwrap(), Some(42))
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[test]
|
||||
fn r#stream_drop_send_disconnect() {
|
||||
let (tx, rx) = bounded::<i32>(1);
|
||||
|
||||
let t = std::thread::spawn(move || {
|
||||
std::thread::sleep(std::time::Duration::from_millis(250));
|
||||
drop(tx);
|
||||
});
|
||||
|
||||
async_std::task::block_on(async {
|
||||
let mut stream = rx.into_stream();
|
||||
assert_eq!(stream.next().await, None);
|
||||
});
|
||||
|
||||
t.join().unwrap();
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[async_std::test]
|
||||
async fn stream_send_1_million_no_drop_or_reorder() {
|
||||
#[derive(Debug)]
|
||||
enum Message {
|
||||
Increment {
|
||||
old: u64,
|
||||
},
|
||||
ReturnCount,
|
||||
}
|
||||
|
||||
let (tx, rx) = unbounded();
|
||||
|
||||
let t = async_std::task::spawn(async move {
|
||||
let mut count = 0u64;
|
||||
let mut stream = rx.into_stream();
|
||||
|
||||
while let Some(Message::Increment { old }) = stream.next().await {
|
||||
assert_eq!(old, count);
|
||||
count += 1;
|
||||
}
|
||||
|
||||
count
|
||||
});
|
||||
|
||||
for next in 0..1_000_000 {
|
||||
tx.send(Message::Increment { old: next }).unwrap();
|
||||
}
|
||||
|
||||
tx.send(Message::ReturnCount).unwrap();
|
||||
|
||||
let count = t.await;
|
||||
assert_eq!(count, 1_000_000)
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[async_std::test]
|
||||
async fn parallel_streams_and_async_recv() {
|
||||
let (tx, rx) = flume::unbounded();
|
||||
let rx = ℞
|
||||
let send_fut = async move {
|
||||
let n_sends: usize = 100000;
|
||||
for _ in 0..n_sends {
|
||||
tx.send_async(()).await.unwrap();
|
||||
}
|
||||
};
|
||||
|
||||
async_std::task::spawn(
|
||||
send_fut
|
||||
.timeout(Duration::from_secs(5))
|
||||
.map_err(|_| panic!("Send timed out!"))
|
||||
);
|
||||
|
||||
let mut futures_unordered = (0..250)
|
||||
.map(|n| async move {
|
||||
if n % 2 == 0 {
|
||||
let mut stream = rx.stream();
|
||||
while let Some(()) = stream.next().await {}
|
||||
} else {
|
||||
while let Ok(()) = rx.recv_async().await {}
|
||||
}
|
||||
|
||||
})
|
||||
.collect::<FuturesUnordered<_>>();
|
||||
|
||||
let recv_fut = async {
|
||||
while futures_unordered.next().await.is_some() {}
|
||||
};
|
||||
|
||||
recv_fut
|
||||
.timeout(Duration::from_secs(5))
|
||||
.map_err(|_| panic!("Receive timed out!"))
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[test]
|
||||
fn stream_no_double_wake() {
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::pin::Pin;
|
||||
use std::task::Context;
|
||||
use futures::task::{waker, ArcWake};
|
||||
use futures::Stream;
|
||||
|
||||
let count = Arc::new(AtomicUsize::new(0));
|
||||
|
||||
// all this waker does is count how many times it is called
|
||||
struct CounterWaker {
|
||||
count: Arc<AtomicUsize>,
|
||||
}
|
||||
|
||||
impl ArcWake for CounterWaker {
|
||||
fn wake_by_ref(arc_self: &Arc<Self>) {
|
||||
arc_self.count.fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
// create waker and context
|
||||
let w = CounterWaker {
|
||||
count: count.clone(),
|
||||
};
|
||||
let w = waker(Arc::new(w));
|
||||
let cx = &mut Context::from_waker(&w);
|
||||
|
||||
// create unbounded channel
|
||||
let (tx, rx) = unbounded::<()>();
|
||||
let mut stream = rx.stream();
|
||||
|
||||
// register waker with stream
|
||||
let _ = Pin::new(&mut stream).poll_next(cx);
|
||||
|
||||
// send multiple items
|
||||
tx.send(()).unwrap();
|
||||
tx.send(()).unwrap();
|
||||
tx.send(()).unwrap();
|
||||
|
||||
// verify that stream is only woken up once.
|
||||
assert_eq!(count.load(Ordering::SeqCst), 1);
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[async_std::test]
|
||||
async fn stream_forward_issue_55() { // https://github.com/zesterer/flume/issues/55
|
||||
fn dummy_stream() -> impl Stream<Item = usize> {
|
||||
stream::unfold(0, |count| async move {
|
||||
if count < 1000 {
|
||||
Some((count, count + 1))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let (send_task, recv_task) = {
|
||||
use futures::SinkExt;
|
||||
let (tx, rx) = flume::bounded(100);
|
||||
|
||||
let send_task = dummy_stream()
|
||||
.map(|i| Ok(i))
|
||||
.forward(tx.into_sink().sink_map_err(|e| {
|
||||
panic!("send error:{:#?}", e)
|
||||
}));
|
||||
|
||||
let recv_task = rx
|
||||
.into_stream()
|
||||
.for_each(|item| async move {});
|
||||
(send_task, recv_task)
|
||||
};
|
||||
|
||||
let jh = async_std::task::spawn(send_task);
|
||||
async_std::task::block_on(recv_task);
|
||||
jh.await.unwrap();
|
||||
}
|
53
vendor/flume/tests/thread_locals.rs
vendored
Normal file
53
vendor/flume/tests/thread_locals.rs
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
// //! Tests that make sure accessing thread-locals while exiting the thread doesn't cause panics.
|
||||
|
||||
// extern crate crossbeam_utils;
|
||||
|
||||
// use std::thread;
|
||||
// use std::time::Duration;
|
||||
|
||||
// use flume::unbounded;
|
||||
// use crossbeam_utils::thread::scope;
|
||||
|
||||
// fn ms(ms: u64) -> Duration {
|
||||
// Duration::from_millis(ms)
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// #[cfg_attr(target_os = "macos", ignore = "TLS is destroyed too early on macOS")]
|
||||
// fn use_while_exiting() {
|
||||
// struct Foo;
|
||||
|
||||
// impl Drop for Foo {
|
||||
// fn drop(&mut self) {
|
||||
// // A blocking operation after the thread-locals have been dropped. This will attempt to
|
||||
// // use the thread-locals and must not panic.
|
||||
// let (_s, r) = unbounded::<()>();
|
||||
// select! {
|
||||
// recv(r) -> _ => {}
|
||||
// default(ms(100)) => {}
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// thread_local! {
|
||||
// static FOO: Foo = Foo;
|
||||
// }
|
||||
|
||||
// let (s, r) = unbounded::<()>();
|
||||
|
||||
// scope(|scope| {
|
||||
// scope.spawn(|_| {
|
||||
// // First initialize `FOO`, then the thread-locals related to crossbeam-channel.
|
||||
// FOO.with(|_| ());
|
||||
// r.recv().unwrap();
|
||||
// // At thread exit, thread-locals related to crossbeam-channel get dropped first and
|
||||
// // `FOO` is dropped last.
|
||||
// });
|
||||
|
||||
// scope.spawn(|_| {
|
||||
// thread::sleep(ms(100));
|
||||
// s.send(()).unwrap();
|
||||
// });
|
||||
// })
|
||||
// .unwrap();
|
||||
// }
|
353
vendor/flume/tests/tick.rs
vendored
Normal file
353
vendor/flume/tests/tick.rs
vendored
Normal file
@ -0,0 +1,353 @@
|
||||
// //! Tests for the tick channel flavor.
|
||||
|
||||
// #[macro_use]
|
||||
// extern crate crossbeam_channel;
|
||||
// extern crate crossbeam_utils;
|
||||
// extern crate rand;
|
||||
|
||||
// use std::sync::atomic::AtomicUsize;
|
||||
// use std::sync::atomic::Ordering;
|
||||
// use std::thread;
|
||||
// use std::time::{Duration, Instant};
|
||||
|
||||
// use crossbeam_channel::{after, tick, Select, TryRecvError};
|
||||
// use crossbeam_utils::thread::scope;
|
||||
|
||||
// fn ms(ms: u64) -> Duration {
|
||||
// Duration::from_millis(ms)
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn fire() {
|
||||
// let start = Instant::now();
|
||||
// let r = tick(ms(50));
|
||||
|
||||
// assert_eq!(r.try_recv(), Err(TryRecvError::Empty));
|
||||
// thread::sleep(ms(100));
|
||||
|
||||
// let fired = r.try_recv().unwrap();
|
||||
// assert!(start < fired);
|
||||
// assert!(fired - start >= ms(50));
|
||||
|
||||
// let now = Instant::now();
|
||||
// assert!(fired < now);
|
||||
// assert!(now - fired >= ms(50));
|
||||
|
||||
// assert_eq!(r.try_recv(), Err(TryRecvError::Empty));
|
||||
|
||||
// select! {
|
||||
// recv(r) -> _ => panic!(),
|
||||
// default => {}
|
||||
// }
|
||||
|
||||
// select! {
|
||||
// recv(r) -> _ => {}
|
||||
// recv(tick(ms(200))) -> _ => panic!(),
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn intervals() {
|
||||
// let start = Instant::now();
|
||||
// let r = tick(ms(50));
|
||||
|
||||
// let t1 = r.recv().unwrap();
|
||||
// assert!(start + ms(50) <= t1);
|
||||
// assert!(start + ms(100) > t1);
|
||||
|
||||
// thread::sleep(ms(300));
|
||||
// let t2 = r.try_recv().unwrap();
|
||||
// assert!(start + ms(100) <= t2);
|
||||
// assert!(start + ms(150) > t2);
|
||||
|
||||
// assert_eq!(r.try_recv(), Err(TryRecvError::Empty));
|
||||
// let t3 = r.recv().unwrap();
|
||||
// assert!(start + ms(400) <= t3);
|
||||
// assert!(start + ms(450) > t3);
|
||||
|
||||
// assert_eq!(r.try_recv(), Err(TryRecvError::Empty));
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn capacity() {
|
||||
// const COUNT: usize = 10;
|
||||
|
||||
// for i in 0..COUNT {
|
||||
// let r = tick(ms(i as u64));
|
||||
// assert_eq!(r.capacity(), Some(1));
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn len_empty_full() {
|
||||
// let r = tick(ms(50));
|
||||
|
||||
// assert_eq!(r.len(), 0);
|
||||
// assert_eq!(r.is_empty(), true);
|
||||
// assert_eq!(r.is_full(), false);
|
||||
|
||||
// thread::sleep(ms(100));
|
||||
|
||||
// assert_eq!(r.len(), 1);
|
||||
// assert_eq!(r.is_empty(), false);
|
||||
// assert_eq!(r.is_full(), true);
|
||||
|
||||
// r.try_recv().unwrap();
|
||||
|
||||
// assert_eq!(r.len(), 0);
|
||||
// assert_eq!(r.is_empty(), true);
|
||||
// assert_eq!(r.is_full(), false);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn try_recv() {
|
||||
// let r = tick(ms(200));
|
||||
// assert!(r.try_recv().is_err());
|
||||
|
||||
// thread::sleep(ms(100));
|
||||
// assert!(r.try_recv().is_err());
|
||||
|
||||
// thread::sleep(ms(200));
|
||||
// assert!(r.try_recv().is_ok());
|
||||
// assert!(r.try_recv().is_err());
|
||||
|
||||
// thread::sleep(ms(200));
|
||||
// assert!(r.try_recv().is_ok());
|
||||
// assert!(r.try_recv().is_err());
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn recv() {
|
||||
// let start = Instant::now();
|
||||
// let r = tick(ms(50));
|
||||
|
||||
// let fired = r.recv().unwrap();
|
||||
// assert!(start < fired);
|
||||
// assert!(fired - start >= ms(50));
|
||||
|
||||
// let now = Instant::now();
|
||||
// assert!(fired < now);
|
||||
// assert!(now - fired < fired - start);
|
||||
|
||||
// assert_eq!(r.try_recv(), Err(TryRecvError::Empty));
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn recv_timeout() {
|
||||
// let start = Instant::now();
|
||||
// let r = tick(ms(200));
|
||||
|
||||
// assert!(r.recv_timeout(ms(100)).is_err());
|
||||
// let now = Instant::now();
|
||||
// assert!(now - start >= ms(100));
|
||||
// assert!(now - start <= ms(150));
|
||||
|
||||
// let fired = r.recv_timeout(ms(200)).unwrap();
|
||||
// assert!(fired - start >= ms(200));
|
||||
// assert!(fired - start <= ms(250));
|
||||
|
||||
// assert!(r.recv_timeout(ms(100)).is_err());
|
||||
// let now = Instant::now();
|
||||
// assert!(now - start >= ms(300));
|
||||
// assert!(now - start <= ms(350));
|
||||
|
||||
// let fired = r.recv_timeout(ms(200)).unwrap();
|
||||
// assert!(fired - start >= ms(400));
|
||||
// assert!(fired - start <= ms(450));
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn recv_two() {
|
||||
// let r1 = tick(ms(50));
|
||||
// let r2 = tick(ms(50));
|
||||
|
||||
// scope(|scope| {
|
||||
// scope.spawn(|_| {
|
||||
// for _ in 0..10 {
|
||||
// select! {
|
||||
// recv(r1) -> _ => {}
|
||||
// recv(r2) -> _ => {}
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// scope.spawn(|_| {
|
||||
// for _ in 0..10 {
|
||||
// select! {
|
||||
// recv(r1) -> _ => {}
|
||||
// recv(r2) -> _ => {}
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// })
|
||||
// .unwrap();
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn recv_race() {
|
||||
// select! {
|
||||
// recv(tick(ms(50))) -> _ => {}
|
||||
// recv(tick(ms(100))) -> _ => panic!(),
|
||||
// }
|
||||
|
||||
// select! {
|
||||
// recv(tick(ms(100))) -> _ => panic!(),
|
||||
// recv(tick(ms(50))) -> _ => {}
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn stress_default() {
|
||||
// const COUNT: usize = 10;
|
||||
|
||||
// for _ in 0..COUNT {
|
||||
// select! {
|
||||
// recv(tick(ms(0))) -> _ => {}
|
||||
// default => panic!(),
|
||||
// }
|
||||
// }
|
||||
|
||||
// for _ in 0..COUNT {
|
||||
// select! {
|
||||
// recv(tick(ms(100))) -> _ => panic!(),
|
||||
// default => {}
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn select() {
|
||||
// const THREADS: usize = 4;
|
||||
|
||||
// let hits = AtomicUsize::new(0);
|
||||
// let r1 = tick(ms(200));
|
||||
// let r2 = tick(ms(300));
|
||||
|
||||
// scope(|scope| {
|
||||
// for _ in 0..THREADS {
|
||||
// scope.spawn(|_| {
|
||||
// let timeout = after(ms(1100));
|
||||
// loop {
|
||||
// let mut sel = Select::new();
|
||||
// let oper1 = sel.recv(&r1);
|
||||
// let oper2 = sel.recv(&r2);
|
||||
// let oper3 = sel.recv(&timeout);
|
||||
// let oper = sel.select();
|
||||
// match oper.index() {
|
||||
// i if i == oper1 => {
|
||||
// oper.recv(&r1).unwrap();
|
||||
// hits.fetch_add(1, Ordering::SeqCst);
|
||||
// }
|
||||
// i if i == oper2 => {
|
||||
// oper.recv(&r2).unwrap();
|
||||
// hits.fetch_add(1, Ordering::SeqCst);
|
||||
// }
|
||||
// i if i == oper3 => {
|
||||
// oper.recv(&timeout).unwrap();
|
||||
// break;
|
||||
// }
|
||||
// _ => unreachable!(),
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// })
|
||||
// .unwrap();
|
||||
|
||||
// assert_eq!(hits.load(Ordering::SeqCst), 8);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn ready() {
|
||||
// const THREADS: usize = 4;
|
||||
|
||||
// let hits = AtomicUsize::new(0);
|
||||
// let r1 = tick(ms(200));
|
||||
// let r2 = tick(ms(300));
|
||||
|
||||
// scope(|scope| {
|
||||
// for _ in 0..THREADS {
|
||||
// scope.spawn(|_| {
|
||||
// let timeout = after(ms(1100));
|
||||
// 'outer: loop {
|
||||
// let mut sel = Select::new();
|
||||
// sel.recv(&r1);
|
||||
// sel.recv(&r2);
|
||||
// sel.recv(&timeout);
|
||||
// loop {
|
||||
// match sel.ready() {
|
||||
// 0 => {
|
||||
// if r1.try_recv().is_ok() {
|
||||
// hits.fetch_add(1, Ordering::SeqCst);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// 1 => {
|
||||
// if r2.try_recv().is_ok() {
|
||||
// hits.fetch_add(1, Ordering::SeqCst);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// 2 => {
|
||||
// if timeout.try_recv().is_ok() {
|
||||
// break 'outer;
|
||||
// }
|
||||
// }
|
||||
// _ => unreachable!(),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// })
|
||||
// .unwrap();
|
||||
|
||||
// assert_eq!(hits.load(Ordering::SeqCst), 8);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn fairness() {
|
||||
// const COUNT: usize = 30;
|
||||
|
||||
// for &dur in &[0, 1] {
|
||||
// let mut hits = [0usize; 2];
|
||||
|
||||
// for _ in 0..COUNT {
|
||||
// let r1 = tick(ms(dur));
|
||||
// let r2 = tick(ms(dur));
|
||||
|
||||
// for _ in 0..COUNT {
|
||||
// select! {
|
||||
// recv(r1) -> _ => hits[0] += 1,
|
||||
// recv(r2) -> _ => hits[1] += 1,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2));
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn fairness_duplicates() {
|
||||
// const COUNT: usize = 30;
|
||||
|
||||
// for &dur in &[0, 1] {
|
||||
// let mut hits = [0usize; 5];
|
||||
|
||||
// for _ in 0..COUNT {
|
||||
// let r = tick(ms(dur));
|
||||
|
||||
// for _ in 0..COUNT {
|
||||
// select! {
|
||||
// recv(r) -> _ => hits[0] += 1,
|
||||
// recv(r) -> _ => hits[1] += 1,
|
||||
// recv(r) -> _ => hits[2] += 1,
|
||||
// recv(r) -> _ => hits[3] += 1,
|
||||
// recv(r) -> _ => hits[4] += 1,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2));
|
||||
// }
|
||||
// }
|
557
vendor/flume/tests/zero.rs
vendored
Normal file
557
vendor/flume/tests/zero.rs
vendored
Normal file
@ -0,0 +1,557 @@
|
||||
//! Tests for the zero channel flavor.
|
||||
|
||||
extern crate crossbeam_utils;
|
||||
extern crate rand;
|
||||
|
||||
use std::any::Any;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use flume::{bounded, Receiver};
|
||||
use flume::{RecvError, RecvTimeoutError, TryRecvError};
|
||||
use flume::{SendError, SendTimeoutError, TrySendError};
|
||||
use crossbeam_utils::thread::scope;
|
||||
use rand::{thread_rng, Rng};
|
||||
|
||||
fn ms(ms: u64) -> Duration {
|
||||
Duration::from_millis(ms)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn smoke() {
|
||||
let (s, r) = bounded(0);
|
||||
assert_eq!(s.try_send(7), Err(TrySendError::Full(7)));
|
||||
assert_eq!(r.try_recv(), Err(TryRecvError::Empty));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn capacity() {
|
||||
let (s, r) = bounded::<()>(0);
|
||||
assert_eq!(s.capacity(), Some(0));
|
||||
assert_eq!(r.capacity(), Some(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn len_empty_full() {
|
||||
let (s, r) = bounded(0);
|
||||
|
||||
assert_eq!(s.len(), 0);
|
||||
assert_eq!(s.is_empty(), true);
|
||||
assert_eq!(s.is_full(), true);
|
||||
assert_eq!(r.len(), 0);
|
||||
assert_eq!(r.is_empty(), true);
|
||||
assert_eq!(r.is_full(), true);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(|_| s.send(0).unwrap());
|
||||
scope.spawn(|_| r.recv().unwrap());
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(s.len(), 0);
|
||||
assert_eq!(s.is_empty(), true);
|
||||
assert_eq!(s.is_full(), true);
|
||||
assert_eq!(r.len(), 0);
|
||||
assert_eq!(r.is_empty(), true);
|
||||
assert_eq!(r.is_full(), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_recv() {
|
||||
let (s, r) = bounded(0);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
assert_eq!(r.try_recv(), Err(TryRecvError::Empty));
|
||||
thread::sleep(ms(1500));
|
||||
assert_eq!(r.try_recv(), Ok(7));
|
||||
thread::sleep(ms(500));
|
||||
assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected));
|
||||
});
|
||||
scope.spawn(move |_| {
|
||||
thread::sleep(ms(1000));
|
||||
s.send(7).unwrap();
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recv() {
|
||||
let (s, r) = bounded(0);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
assert_eq!(r.recv(), Ok(7));
|
||||
thread::sleep(ms(1000));
|
||||
assert_eq!(r.recv(), Ok(8));
|
||||
thread::sleep(ms(1000));
|
||||
assert_eq!(r.recv(), Ok(9));
|
||||
assert!(r.recv().is_err());
|
||||
});
|
||||
scope.spawn(move |_| {
|
||||
thread::sleep(ms(1500));
|
||||
s.send(7).unwrap();
|
||||
s.send(8).unwrap();
|
||||
s.send(9).unwrap();
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recv_timeout() {
|
||||
let (s, r) = bounded::<i32>(0);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout));
|
||||
assert_eq!(r.recv_timeout(ms(1000)), Ok(7));
|
||||
assert_eq!(
|
||||
r.recv_timeout(ms(1000)),
|
||||
Err(RecvTimeoutError::Disconnected)
|
||||
);
|
||||
});
|
||||
scope.spawn(move |_| {
|
||||
thread::sleep(ms(1500));
|
||||
s.send(7).unwrap();
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_send() {
|
||||
let (s, r) = bounded(0);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
assert_eq!(s.try_send(7), Err(TrySendError::Full(7)));
|
||||
thread::sleep(ms(1500));
|
||||
assert_eq!(s.try_send(8), Ok(()));
|
||||
thread::sleep(ms(500));
|
||||
assert_eq!(s.try_send(9), Err(TrySendError::Disconnected(9)));
|
||||
});
|
||||
scope.spawn(move |_| {
|
||||
thread::sleep(ms(1000));
|
||||
assert_eq!(r.recv(), Ok(8));
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send() {
|
||||
let (s, r) = bounded(0);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
s.send(7).unwrap();
|
||||
thread::sleep(ms(1000));
|
||||
s.send(8).unwrap();
|
||||
thread::sleep(ms(1000));
|
||||
s.send(9).unwrap();
|
||||
});
|
||||
scope.spawn(move |_| {
|
||||
thread::sleep(ms(1500));
|
||||
assert_eq!(r.recv(), Ok(7));
|
||||
assert_eq!(r.recv(), Ok(8));
|
||||
assert_eq!(r.recv(), Ok(9));
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_timeout() {
|
||||
let (s, r) = bounded(0);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
assert_eq!(
|
||||
s.send_timeout(7, ms(1000)),
|
||||
Err(SendTimeoutError::Timeout(7))
|
||||
);
|
||||
assert_eq!(s.send_timeout(8, ms(1000)), Ok(()));
|
||||
assert_eq!(
|
||||
s.send_timeout(9, ms(1000)),
|
||||
Err(SendTimeoutError::Disconnected(9))
|
||||
);
|
||||
});
|
||||
scope.spawn(move |_| {
|
||||
thread::sleep(ms(1500));
|
||||
assert_eq!(r.recv(), Ok(8));
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn len() {
|
||||
const COUNT: usize = 25_000;
|
||||
|
||||
let (s, r) = bounded(0);
|
||||
|
||||
assert_eq!(s.len(), 0);
|
||||
assert_eq!(r.len(), 0);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(|_| {
|
||||
for i in 0..COUNT {
|
||||
assert_eq!(r.recv(), Ok(i));
|
||||
assert_eq!(r.len(), 0);
|
||||
}
|
||||
});
|
||||
|
||||
scope.spawn(|_| {
|
||||
for i in 0..COUNT {
|
||||
s.send(i).unwrap();
|
||||
assert_eq!(s.len(), 0);
|
||||
}
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(s.len(), 0);
|
||||
assert_eq!(r.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disconnect_wakes_sender() {
|
||||
let (s, r) = bounded(0);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
assert_eq!(s.send(()), Err(SendError(())));
|
||||
});
|
||||
scope.spawn(move |_| {
|
||||
thread::sleep(ms(1000));
|
||||
drop(r);
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disconnect_wakes_receiver() {
|
||||
let (s, r) = bounded::<()>(0);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
assert!(r.recv().is_err());
|
||||
});
|
||||
scope.spawn(move |_| {
|
||||
thread::sleep(ms(1000));
|
||||
drop(s);
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spsc() {
|
||||
const COUNT: usize = 100_000;
|
||||
|
||||
let (s, r) = bounded(0);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
for i in 0..COUNT {
|
||||
assert_eq!(r.recv(), Ok(i));
|
||||
}
|
||||
assert!(r.recv().is_err());
|
||||
});
|
||||
scope.spawn(move |_| {
|
||||
for i in 0..COUNT {
|
||||
s.send(i).unwrap();
|
||||
}
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mpmc() {
|
||||
const COUNT: usize = 25_000;
|
||||
const THREADS: usize = 4;
|
||||
|
||||
let (s, r) = bounded::<usize>(0);
|
||||
let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::<Vec<_>>();
|
||||
|
||||
scope(|scope| {
|
||||
for _ in 0..THREADS {
|
||||
scope.spawn(|_| {
|
||||
for _ in 0..COUNT {
|
||||
let n = r.recv().unwrap();
|
||||
v[n].fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
});
|
||||
}
|
||||
for _ in 0..THREADS {
|
||||
scope.spawn(|_| {
|
||||
for i in 0..COUNT {
|
||||
s.send(i).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
for c in v {
|
||||
assert_eq!(c.load(Ordering::SeqCst), THREADS);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stress_oneshot() {
|
||||
const COUNT: usize = 10_000;
|
||||
|
||||
for _ in 0..COUNT {
|
||||
let (s, r) = bounded(1);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(|_| r.recv().unwrap());
|
||||
scope.spawn(|_| s.send(0).unwrap());
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stress_iter() {
|
||||
const COUNT: usize = 1000;
|
||||
|
||||
let (request_s, request_r) = bounded(0);
|
||||
let (response_s, response_r) = bounded(0);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
let mut count = 0;
|
||||
loop {
|
||||
for x in response_r.try_iter() {
|
||||
count += x;
|
||||
if count == COUNT {
|
||||
return;
|
||||
}
|
||||
}
|
||||
let _ = request_s.try_send(());
|
||||
}
|
||||
});
|
||||
|
||||
for _ in request_r.iter() {
|
||||
if response_s.send(1).is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stress_timeout_two_threads() {
|
||||
const COUNT: usize = 100;
|
||||
|
||||
let (s, r) = bounded(0);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(|_| {
|
||||
for i in 0..COUNT {
|
||||
if i % 2 == 0 {
|
||||
thread::sleep(ms(50));
|
||||
}
|
||||
loop {
|
||||
if let Ok(()) = s.send_timeout(i, ms(10)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
scope.spawn(|_| {
|
||||
for i in 0..COUNT {
|
||||
if i % 2 == 0 {
|
||||
thread::sleep(ms(50));
|
||||
}
|
||||
loop {
|
||||
if let Ok(x) = r.recv_timeout(ms(10)) {
|
||||
assert_eq!(x, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drops() {
|
||||
static DROPS: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct DropCounter;
|
||||
|
||||
impl Drop for DropCounter {
|
||||
fn drop(&mut self) {
|
||||
DROPS.fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
let mut rng = thread_rng();
|
||||
|
||||
for _ in 0..100 {
|
||||
let steps = rng.gen_range(0..3_000);
|
||||
|
||||
DROPS.store(0, Ordering::SeqCst);
|
||||
let (s, r) = bounded::<DropCounter>(0);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(|_| {
|
||||
for _ in 0..steps {
|
||||
r.recv().unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
scope.spawn(|_| {
|
||||
for _ in 0..steps {
|
||||
s.send(DropCounter).unwrap();
|
||||
}
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(DROPS.load(Ordering::SeqCst), steps);
|
||||
drop(s);
|
||||
drop(r);
|
||||
assert_eq!(DROPS.load(Ordering::SeqCst), steps);
|
||||
}
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn fairness() {
|
||||
// const COUNT: usize = 10_000;
|
||||
|
||||
// let (s1, r1) = bounded::<()>(0);
|
||||
// let (s2, r2) = bounded::<()>(0);
|
||||
|
||||
// scope(|scope| {
|
||||
// scope.spawn(|_| {
|
||||
// let mut hits = [0usize; 2];
|
||||
// for _ in 0..COUNT {
|
||||
// select! {
|
||||
// recv(r1) -> _ => hits[0] += 1,
|
||||
// recv(r2) -> _ => hits[1] += 1,
|
||||
// }
|
||||
// }
|
||||
// assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2));
|
||||
// });
|
||||
|
||||
// let mut hits = [0usize; 2];
|
||||
// for _ in 0..COUNT {
|
||||
// select! {
|
||||
// send(s1, ()) -> _ => hits[0] += 1,
|
||||
// send(s2, ()) -> _ => hits[1] += 1,
|
||||
// }
|
||||
// }
|
||||
// assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2));
|
||||
// })
|
||||
// .unwrap();
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn fairness_duplicates() {
|
||||
// const COUNT: usize = 10_000;
|
||||
|
||||
// let (s, r) = bounded::<()>(0);
|
||||
|
||||
// scope(|scope| {
|
||||
// scope.spawn(|_| {
|
||||
// let mut hits = [0usize; 5];
|
||||
// for _ in 0..COUNT {
|
||||
// select! {
|
||||
// recv(r) -> _ => hits[0] += 1,
|
||||
// recv(r) -> _ => hits[1] += 1,
|
||||
// recv(r) -> _ => hits[2] += 1,
|
||||
// recv(r) -> _ => hits[3] += 1,
|
||||
// recv(r) -> _ => hits[4] += 1,
|
||||
// }
|
||||
// }
|
||||
// assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2));
|
||||
// });
|
||||
|
||||
// let mut hits = [0usize; 5];
|
||||
// for _ in 0..COUNT {
|
||||
// select! {
|
||||
// send(s, ()) -> _ => hits[0] += 1,
|
||||
// send(s, ()) -> _ => hits[1] += 1,
|
||||
// send(s, ()) -> _ => hits[2] += 1,
|
||||
// send(s, ()) -> _ => hits[3] += 1,
|
||||
// send(s, ()) -> _ => hits[4] += 1,
|
||||
// }
|
||||
// }
|
||||
// assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2));
|
||||
// })
|
||||
// .unwrap();
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn recv_in_send() {
|
||||
// let (s, r) = bounded(0);
|
||||
|
||||
// scope(|scope| {
|
||||
// scope.spawn(|_| {
|
||||
// thread::sleep(ms(100));
|
||||
// r.recv()
|
||||
// });
|
||||
|
||||
// scope.spawn(|_| {
|
||||
// thread::sleep(ms(500));
|
||||
// s.send(()).unwrap();
|
||||
// });
|
||||
|
||||
// select! {
|
||||
// send(s, r.recv().unwrap()) -> _ => {}
|
||||
// }
|
||||
// })
|
||||
// .unwrap();
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn channel_through_channel() {
|
||||
const COUNT: usize = 1000;
|
||||
|
||||
type T = Box<dyn Any + Send>;
|
||||
|
||||
let (s, r) = bounded::<T>(0);
|
||||
|
||||
scope(|scope| {
|
||||
scope.spawn(move |_| {
|
||||
let mut s = s;
|
||||
|
||||
for _ in 0..COUNT {
|
||||
let (new_s, new_r) = bounded(0);
|
||||
let new_r: T = Box::new(Some(new_r));
|
||||
|
||||
s.send(new_r).unwrap();
|
||||
s = new_s;
|
||||
}
|
||||
});
|
||||
|
||||
scope.spawn(move |_| {
|
||||
let mut r = r;
|
||||
|
||||
for _ in 0..COUNT {
|
||||
r = r
|
||||
.recv()
|
||||
.unwrap()
|
||||
.downcast_mut::<Option<Receiver<T>>>()
|
||||
.unwrap()
|
||||
.take()
|
||||
.unwrap()
|
||||
}
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
Reference in New Issue
Block a user