pax_global_header00006660000000000000000000000064144671567050014531gustar00rootroot0000000000000052 comment=ee6fe6adb98856edbda47d1cc867cbc255ff0d88 flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/000077500000000000000000000000001446715670500203355ustar00rootroot00000000000000flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/.github/000077500000000000000000000000001446715670500216755ustar00rootroot00000000000000flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/.github/FUNDING.yml000066400000000000000000000000231446715670500235050ustar00rootroot00000000000000github: [zesterer] flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/.github/workflows/000077500000000000000000000000001446715670500237325ustar00rootroot00000000000000flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/.github/workflows/rust.yml000066400000000000000000000033231446715670500254530ustar00rootroot00000000000000name: Rust on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: runs-on: ${{ matrix.os }} env: RUST_BACKTRACE: 1 strategy: matrix: build: [linux64, macos, win32, win64] include: - build: linux64 os: ubuntu-latest channel: stable target: x86_64-unknown-linux-gnu #- build: linux32 # os: ubuntu-latest # channel: stable # target: i686-unknown-linux-gnu - build: macos os: macos-latest channel: stable target: x86_64-apple-darwin - build: win32 os: windows-latest channel: stable target: i686-pc-windows-msvc - build: win64 os: windows-latest channel: stable target: x86_64-pc-windows-msvc steps: - uses: actions/checkout@v2 - run: | TOOLCHAIN=${{ matrix.channel }}-${{ matrix.target }} rustup toolchain install --no-self-update $TOOLCHAIN rustup default $TOOLCHAIN shell: bash - name: Rust version run: | set -ex rustc -Vv cargo -V rustup show shell: bash # Check build to fail fast - run: cargo check --target ${{ matrix.target }} - run: cargo build --target ${{ matrix.target }} - run: cargo test --target ${{ matrix.target }} # FIXME(#41): Some timeout/deadline tests make more sense to run in release mode. #- run: cargo test --release --target ${{ matrix.target }} - run: cargo build --all-targets --target ${{ matrix.target }} - run: cargo build --all-targets --no-default-features --target ${{ matrix.target }} flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/.gitignore000066400000000000000000000000231446715670500223200ustar00rootroot00000000000000target/ Cargo.lock flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/CHANGELOG.md000066400000000000000000000047751446715670500221630ustar00rootroot00000000000000# 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` and `From` 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 flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/Cargo.toml000066400000000000000000000025761446715670500222770ustar00rootroot00000000000000[package] name = "flume" version = "0.11.0" authors = ["Joshua Barretto "] edition = "2018" description = "A blazingly fast multi-producer channel" repository = "https://github.com/zesterer/flume" documentation = "https://docs.rs/flume" keywords = ["mpsc", "fifo", "channel", "thread", "mpmc"] categories = ["concurrency", "data-structures"] license = "Apache-2.0/MIT" readme = "README.md" exclude = [ "/.github", "/misc", ] [features] # Use a spinlock internally (may be faster on some platforms) spin = [] select = [] async = ["futures-sink", "futures-core"] eventual-fairness = ["select", "nanorand"] default = ["async", "select", "eventual-fairness"] [dependencies] spin1 = { package = "spin", version = "0.9.8", features = ["mutex"] } futures-sink = { version = "0.3", default_features = false, optional = true } futures-core = { version = "0.3", default_features = false, optional = true } nanorand = { version = "0.7", features = ["getrandom"], optional = true } [dev-dependencies] #flume-test = { path = "../flume-test" } crossbeam-channel = "0.5.5" crossbeam-utils = "0.8.10" criterion = "0.3.4" rand = "0.8.3" async-std = { version = "1.9.0", features = ["attributes", "unstable"] } futures = { version = "^0.3", features = ["std"] } waker-fn = "1.1.0" tokio = { version = "^1.16.1", features = ["rt", "macros"] } [[bench]] name = "basic" harness = false flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/LICENSE-APACHE000066400000000000000000000260761446715670500222740ustar00rootroot00000000000000 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.flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/LICENSE-MIT000066400000000000000000000017761446715670500220040ustar00rootroot00000000000000Permission 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.flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/README.md000066400000000000000000000056661446715670500216310ustar00rootroot00000000000000# Flume A blazingly fast multi-producer, multi-consumer channel. [![Cargo](https://img.shields.io/crates/v/flume.svg)]( https://crates.io/crates/flume) [![Documentation](https://docs.rs/flume/badge.svg)]( https://docs.rs/flume) [![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)]( https://github.com/zesterer/flume) ![actions-badge](https://github.com/zesterer/flume/workflows/Rust/badge.svg?branch=master) ```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::(), 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. # Flume benchmarks (crossbeam benchmark suite) ## 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) flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/benches/000077500000000000000000000000001446715670500217445ustar00rootroot00000000000000flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/benches/basic.rs000066400000000000000000000361311446715670500233770ustar00rootroot00000000000000#[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; type Receiver: Receiver; 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 + '_>; } impl Sender for flume::Sender { type Item = T; type BoundedSender = Self; type Receiver = flume::Receiver; 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 Receiver for flume::Receiver { type Item = T; fn recv(&self) -> Self::Item { flume::Receiver::recv(self).unwrap() } fn iter(&self) -> Box + '_> { Box::new(std::iter::from_fn(move || flume::Receiver::recv(self).ok())) } } impl Sender for crossbeam_channel::Sender { type Item = T; type BoundedSender = Self; type Receiver = crossbeam_channel::Receiver; 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 Receiver for crossbeam_channel::Receiver { type Item = T; fn recv(&self) -> Self::Item { crossbeam_channel::Receiver::recv(self).unwrap() } fn iter(&self) -> Box + '_> { Box::new(crossbeam_channel::Receiver::iter(self)) } } impl Sender for mpsc::Sender { type Item = T; type BoundedSender = mpsc::SyncSender; type Receiver = mpsc::Receiver; 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 Sender for mpsc::SyncSender { type Item = T; type BoundedSender = Self; type Receiver = mpsc::Receiver; 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 Receiver for mpsc::Receiver { type Item = T; fn recv(&self) -> Self::Item { mpsc::Receiver::recv(self).unwrap() } fn iter(&self) -> Box + '_> { Box::new(mpsc::Receiver::iter(self)) } } fn test_create(b: &mut Bencher) { b.iter(|| S::unbounded()); } fn test_oneshot(b: &mut Bencher) { b.iter(|| { let (tx, rx) = S::unbounded(); tx.send(Default::default()); black_box(rx.recv()); }); } fn test_inout(b: &mut Bencher) { let (tx, rx) = S::unbounded(); b.iter(|| { tx.send(Default::default()); black_box(rx.recv()); }); } fn test_hydra(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(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(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(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(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(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::>(b)); b.bench_function("create-crossbeam", |b| test_create::>(b)); b.bench_function("create-std", |b| test_create::>(b)); } fn oneshot(b: &mut Criterion) { b.bench_function("oneshot-flume", |b| test_oneshot::>(b)); b.bench_function("oneshot-crossbeam", |b| test_oneshot::>(b)); b.bench_function("oneshot-std", |b| test_oneshot::>(b)); } fn inout(b: &mut Criterion) { b.bench_function("inout-flume", |b| test_inout::>(b)); b.bench_function("inout-crossbeam", |b| test_inout::>(b)); b.bench_function("inout-std", |b| test_inout::>(b)); } fn hydra_32t_1m(b: &mut Criterion) { b.bench_function("hydra-32t-1m-flume", |b| test_hydra::>(b, 32, 1)); b.bench_function("hydra-32t-1m-crossbeam", |b| test_hydra::>(b, 32, 1)); b.bench_function("hydra-32t-1m-std", |b| test_hydra::>(b, 32, 1)); } fn hydra_32t_1000m(b: &mut Criterion) { b.bench_function("hydra-32t-1000m-flume", |b| test_hydra::>(b, 32, 1000)); b.bench_function("hydra-32t-1000m-crossbeam", |b| test_hydra::>(b, 32, 1000)); b.bench_function("hydra-32t-1000m-std", |b| test_hydra::>(b, 32, 1000)); } fn hydra_256t_1m(b: &mut Criterion) { b.bench_function("hydra-256t-1m-flume", |b| test_hydra::>(b, 256, 1)); b.bench_function("hydra-256t-1m-crossbeam", |b| test_hydra::>(b, 256, 1)); b.bench_function("hydra-256t-1m-std", |b| test_hydra::>(b, 256, 1)); } fn hydra_1t_1000m(b: &mut Criterion) { b.bench_function("hydra-1t-1000m-flume", |b| test_hydra::>(b, 1, 1000)); b.bench_function("hydra-1t-1000m-crossbeam", |b| test_hydra::>(b, 1, 1000)); b.bench_function("hydra-1t-1000m-std", |b| test_hydra::>(b, 1, 1000)); } fn hydra_4t_10000m(b: &mut Criterion) { b.bench_function("hydra-4t-10000m-flume", |b| test_hydra::>(b, 4, 10000)); b.bench_function("hydra-4t-10000m-crossbeam", |b| test_hydra::>(b, 4, 10000)); b.bench_function("hydra-4t-10000m-std", |b| test_hydra::>(b, 4, 10000)); } fn kitsune_32t_1m(b: &mut Criterion) { b.bench_function("kitsune-32t-1m-flume", |b| test_kitsune::>(b, 32, 1)); b.bench_function("kitsune-32t-1m-crossbeam", |b| test_kitsune::>(b, 32, 1)); //b.bench_function("kitsune-32t-1m-std", |b| test_kitsune::>(b, 32, 1)); } fn kitsune_32t_1000m(b: &mut Criterion) { b.bench_function("kitsune-32t-1000m-flume", |b| test_kitsune::>(b, 32, 1000)); b.bench_function("kitsune-32t-1000m-crossbeam", |b| test_kitsune::>(b, 32, 1000)); //b.bench_function("kitsune-32t-1000m-std", |b| test_kitsune::>(b, 32, 1000)); } fn kitsune_256t_1m(b: &mut Criterion) { b.bench_function("kitsune-256t-1m-flume", |b| test_kitsune::>(b, 256, 1)); b.bench_function("kitsune-256t-1m-crossbeam", |b| test_kitsune::>(b, 256, 1)); //b.bench_function("kitsune-256t-1m-std", |b| test_kitsune::>(b, 256, 1)); } fn kitsune_1t_1000m(b: &mut Criterion) { b.bench_function("kitsune-1t-1000m-flume", |b| test_kitsune::>(b, 1, 1000)); b.bench_function("kitsune-1t-1000m-crossbeam", |b| test_kitsune::>(b, 1, 1000)); //b.bench_function("kitsune-1t-1000m-std", |b| test_kitsune::>(b, 1, 1000)); } fn kitsune_4t_10000m(b: &mut Criterion) { b.bench_function("kitsune-4t-10000m-flume", |b| test_kitsune::>(b, 4, 10000)); b.bench_function("kitsune-4t-10000m-crossbeam", |b| test_kitsune::>(b, 4, 10000)); //b.bench_function("kitsune-4t-10000m-std", |b| test_kitsune::>(b, 4, 10000)); } fn robin_u_32t_1m(b: &mut Criterion) { b.bench_function("robin-u-32t-1m-flume", |b| test_robin_u::>(b, 32, 1)); b.bench_function("robin-u-32t-1m-crossbeam", |b| test_robin_u::>(b, 32, 1)); b.bench_function("robin-u-32t-1m-std", |b| test_robin_u::>(b, 32, 1)); } fn robin_u_4t_1000m(b: &mut Criterion) { b.bench_function("robin-u-4t-1000m-flume", |b| test_robin_u::>(b, 4, 1000)); b.bench_function("robin-u-4t-1000m-crossbeam", |b| test_robin_u::>(b, 4, 1000)); b.bench_function("robin-u-4t-1000m-std", |b| test_robin_u::>(b, 4, 1000)); } fn robin_b_32t_16m(b: &mut Criterion) { b.bench_function("robin-b-32t-16m-flume", |b| test_robin_b::>(b, 32, 16)); b.bench_function("robin-b-32t-16m-crossbeam", |b| test_robin_b::>(b, 32, 16)); b.bench_function("robin-b-32t-16m-std", |b| test_robin_b::>(b, 32, 16)); } fn robin_b_4t_1000m(b: &mut Criterion) { b.bench_function("robin-b-4t-1000m-flume", |b| test_robin_b::>(b, 4, 1000)); b.bench_function("robin-b-4t-1000m-crossbeam", |b| test_robin_b::>(b, 4, 1000)); b.bench_function("robin-b-4t-1000m-std", |b| test_robin_b::>(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::>(b, 4)); b.bench_function("mpsc-bounded-no-wait-4t-crossbeam", |b| test_mpsc_bounded_no_wait::>(b, 4)); b.bench_function("mpsc-bounded-no-wait-4t-std", |b| test_mpsc_bounded_no_wait::>(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::>(b, bound, 4)); b.bench_function(&format!("{}{}", text, "crossbeam"), |b| test_mpsc_bounded::>(b, bound, 4)); b.bench_function(&format!("{}{}", text, "std"), |b| test_mpsc_bounded::>(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); flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/examples/000077500000000000000000000000001446715670500221535ustar00rootroot00000000000000flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/examples/async.rs000066400000000000000000000006771446715670500236500ustar00rootroot00000000000000#[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() {} flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/examples/perf.rs000066400000000000000000000012621446715670500234560ustar00rootroot00000000000000fn 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(); } } } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/examples/select.rs000066400000000000000000000013001446715670500237720ustar00rootroot00000000000000#[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() {} flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/examples/simple.rs000066400000000000000000000005031446715670500240100ustar00rootroot00000000000000use 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(); } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/misc/000077500000000000000000000000001446715670500212705ustar00rootroot00000000000000flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/misc/benchmarks.png000066400000000000000000002526761446715670500241350ustar00rootroot00000000000000PNG  IHDRM9tEXtSoftwareMatplotlib version3.3.4, https://matplotlib.org/T̺ pHYsaa?iIDATx{\Tu?0\"b j)hf abYw%[-jbjV~ۖZnpßgAEEf^c93=B t"""""""@'"""""",Љ, t""""""" @'"""""",Љ, t""""""" @'"""""",Љ, t""""""" @'"""""",Љ, t""""""" @'"""""",Љ, t""""""" @'"""""",Љ, t""""""" @'"""""",Љ, tsׯL&3y4iaaaعsëL9sZdHLL|n?}sɓ' JLe˖Zߖhر7bO>3}QQQׯC͚5ǂ ?r̘1SLA֭$"7_2'ٳu588ΞjϠppp=L_~&M(++IOOL&{pśL&Ù3g0rHT*h4?zd݂DEE /".^Xm;F4jZŠ+,wyprr;QXXXty95VѣM7߄;0x`\rd}􁗗ѪU+|(..6YnرP(HMMEP({?ƒ%KSOAPk׮8vXmp۷7|S}qӧOchܸ13 >>^j}aEEVZ%]y?eee7oZjgϞ8r䈴̊+УGxxxmڴE\`}:/!0h 9rfBNpj?={,BBBj'=z-aW"44vvvXr%4 6mڄŜ{7oZhl_`@Fe_u 07oFff&N^{ 퓖ѿL28<_~1Y &?CRa֬Y&ˮXO?ݲ3gHKKJ߿/":wիWCRa˖->|8JJJ0v.\xxx;ܰqF;W^Ŵi0`=z]vŐ!C{ݷϊ Ĕ)SЫW/TTTرctBBBFz HIIA\\Ο?/n#`޼yصk,X7n`rx7jǎɓqe=k,̟?{JӧO###uQ ={̙3Jի1m4ri˗==}4M6&󽼼.y122ZW%+#غu*F+W,zj@|7& ~B&uUy>bٳh"&M$hBg@|&Uo߾iӦBכ,#ׅBB&d^x@߿Kjqڵ{.s{N4dE]zFQ"%%Ej3fLCE˖-ۯC6mDEE4_~W_}%{EEyyI/B!_}3bѨQ#q%NNNBI?O!6l k>p*++Eyyذak/?uȸonnn{"""13Fsvvcƌ ͻ|sνDEEFU(sbeN֒$BCCjfÆ _믿bϞ=3f ?|o>8;;cȐ!&t~z7n۶-n޼k׮ 3DDD,wY~ PQQ!=7oJ߿AAAh׮}NII 8aÆmOvbԨQ\.BCCΝ3Y_&Unb۶mx&ܩ8ogٸpN?___cǎEII =P={w'O"<<nnn~=z4*++\R5jF#~gݻ7T*Y/G݋Z[XXڵkgryի!0qKt9# {Yczw2VZUIMFFM^{ j2-Lo_VZZ lmm,i2 |gϪ}o޼}U_/6Uerss}u]t ݻwG˖-駟_?~h4Uߎ_~A>}kעiӦ' 5~O[o_.\@@@֮]!C<}憛7oNNN&mׯ_ǟZ 1֞GͿd]XEi۶-{\x>,pq!L ׮]CEE@J\wߨq7Ix999&5nr$ͭYWWWrdee=fӾ}p$&&JN6}t uppof=r,={lڴd͛MгgO>K,34oW^ſ/xƍ#::gφ6mTe@~зo_;>>>~:Ν;'NJKK-:{,0w{n[6m;v ...&gM&ME!)) y+f̘3g}9s_oY___ʿKOOpg غu+SN&W3-A.*J<3bɒ%͛&h%lmm>}zzxׅF_lnnnqIt:?~PI UTǏ/|||hҤ  ,0Yٳ^UL0A_z{C 777aoo/Z;v?noǯj^uwc=rڵprrM48qD;3F8;;Ws/lu,%%E 6Lxxx;;;)z%V^}߸ԩS_*Jۋv5BYf-Z{{{&z%9"-cѮ]; |||ԩSwhh cǎQFKV_|!Zl)5j$… ?*Q!nSNA( Ѿ}*wMNNݺuNNN@w{ FO?TJٳg P}Qce;W %B'Q0Ջv0yd,Z=2_Ox;I/ ~msDDDd6$$9plڴ >>>1mĝ :`NDDDDDDdXY݂F\r...d ?/7kʿ,-ȕ+Wk01effiӦj:XCenA\\\zc)J3GCDD_"͚/ t r:RQ=ˤ_""` ~_ODDDDDDd%XYDDDDDDD:`NDDDDDDdXYDDDDDDD:`NDDDDDDdXYDDDDDDD:`NDDDDDDdXYDOPnn.zRC;ZLNgP%ɐl0qew.[s@d֬Y\N6g$''cuḋ t R;zBﴴ4=0IԖ ߚQ0/w:w'dСʕ+P(A,V۷?Ν;P(P(aaaXl|rr2d24iӦO>pvvƞ={PTThZxxx`2?PTƯzm&M6i߱c7oZcǢPTT* =z@JJޜ9s/#&&jZ_>vXDEEaĈpqqA˖-(c֬Yh֬+W!"""q]ւ:"""&MBQQ&Lpe XK(**BQQQgX`лwo?ׯ_o4#&&BテgwFzz:rrr0ydevڅ'Nٳi&hĨQW}6lu֭`(,,ڷlق'B!22cǎ׿8t#Fxuḋ.k5j}Yd2a۶mX|9j51o<|ר q9!__jݹs'gggۣgϞ&̙3JׯJÇ30w\\x:`ȑ刌`ŋW^7n222!V\%K X`>'nḋ'_ Zwzz:F#LANN"##hdff"<<1JJJкukig"##͚53nw~ ,]vލׯK˃Oue2M>ɽo(,,hDqq1za=233]p :QQ(())KJJPPP MWwCή̝W\N7oބlmm;w.]ܹsjKj?OCH} NNN8~6"$$'"".+DuC8z(Ο?7ob&Dj4ddddz׮]âE4hbbbABB`߾}HNNFEEtԽ>:`a֬Y(..`kppp@ƍQTTW666{']Zor"""j8w=DuW^x7͛M6pqqڇ R wwwj;///W^>|gPԩJ%w.}Gի9r$j5z)T*̞=~ ~G$%%A +VѶh4F׮]k^M-\]vE^?Oj9⸫pUd6}ZQPPJ^Rip!8^?u#"߬83DDDDDDD:`NDDDDDDd;HR;-0Q]3 c…ԩѯ_?\~&MZF-p@XXN0k׮8wג%Kj|R޽{ѹsgjxyya…uDDDDd8>% >N~~~M6"##CܸqCnZ4kL|B̘1CiF!Dhhhܸ8r(++E\\pA8::s !)))B!N8!֭[`:N=znTDTnzC|q'O5_AkҤIjP0`1dr9O`1]v=̙WرcB̙3(--FA۶mk֬#ꫯ* ]t1&XS)TeZfgg///\|͚5C||} 99-ZQ)@' rdgg0l0߿W^Ev A355,u:@'Ǐ`yФIt.\޽{QZZ {{{( q(|WHHH@EEz=;f-!""""kubNTǏWWWݻ۷o- fΜ F777۷ׯt۶mC\\\]]ѪU+8pBDDDDVS$?g) OУ0h L2v""s8T*/ ǧÚ򯭹EDDT0w""""""" 3De˖aРAsAOϠYADߨ's̿Ddn6xQu8FmXS燲2ġC0glذ7n܀NCpp0=p0@O`Fvv6F#N]GQ5abN >>ر#j5QZZzu^|EhӦ qt֭"&""""k1j#b@RACT;""zHb{8^ ;;#GĢE+_駟#==ƍ;U⣏>B~qasnn3uTBCCaccݻ'um۶!77j0o<aԉb'"OXࠢM6R= 899!((ԩS1`{xy:u-NNNRҼ=]TTHOOhD@@666ɁOKDD5LODTwڵ?6m`СXv-nܸa$MwEEE̼׮]Õ+W6())/___ʕ+t͛LDD9DdmXػw/ك֭[>C˖-vd2}utt-:t/HNNƗ_~}yzzbРAA^^ '' .2`zGad2t sɓ'aoo/SRRPZZ*-{1( 4m뺸?Y>pQj3fc~zjt JݻwGRRR-EKDDOs0=*#;4`ǏO?>}Ǐk۷믿ƶm/cƌq0n8,\񈎎78|0&O\%T*a7Lq^RipK֔D)&qJ%~g,[ '|~믿?-ZG(++È#0gΜ cƌ͛7tR/; rx&,)3 ;:۷oeM5D<׮|݈7k:;Tk֯_gya<K=11'a%ؙn,Љ,ׯ'Uj#|CA\Օ:s<Q3V111jP*ԩ233 K.prrٳg}͚5òeˤ~лwoT*[n()),YZV ?$XAbʕ&m[lA۶m09rԶi&Z3gĝHdXbZn gggDFF>|8J%ڷowݻ;wZ.\h>|xxx@ј쏓'O瞃+4i#G"??_j ѷo_( tNh"t... Eff~5DDDޘ2e -DD԰03Q bz@o}f^]^yѷo_qeQYY)N8!rss ϟLlRL:U%6m$bȑ7A qaQVV&.\ ŹsB䈔!֭r\Ɗ2q"8 b׮]G$%%Jm6*B޽[\pAFqI!6n(mѫW/' ?(//G/='غu0 BӉGJڊE /rHMMB,<( ݻwwhh'N"**JJ~~~"((HTO3F!h;w(..yyy",,L̘1C!JG:#ߺx܅99gMy=''GUK.:$J(++ʼn^xA!ѣExxxI?AlݺU[N(Ja0yb„ B!/-[fNHHذaC6IĞ={CÇKӷ-ƍWmۺuF1׼ysujOHH͛7CCC/M:tH( iOZJ޸qB/WWWQYY)" @MTX!:s>>___|'tң| 7x/_^GttFDDPTT3gH'55Ξ=lܸc/<<BTT7nz ~)F#\\\b L8Jqqq>|x:`۶m+Zjh%K`ΝP*8p ^}ZK.cǎ|2ZjJ<""NODB&jzlPTP*_7"͚\Y/c""zXyy.͝;j Æ î]ФIL<vvv ŨQo 1=i,www+WygφN_ deeddeeeDDDV4@`` 7sMV{lZZ6m#""jIc^d2|駈w\v 3gk׮aʕyf=ڜY c""zXĮ]{nBT{ҥKѸqcٳ7n&NUV3wDDDV$B;* /tC}P*jpA{w3DEDD5eMPUs3wDDD λ7^NDDDDDDdXSիJ%jpjMzz:d2t:CL&Crr ""zh;DևSk֬\.N?Ù3g} ,DDR9U`ZZ`kKEElmV$""2G0DDC">>+WB/ dZFbb"oߎ?;wBBaٲeɐdtXXM>}{AQQbbbjѣGC0~xCR!88=Gxx84iWWW <ؤ}ǎh޼9j5Ǝr@QQT*)))zs/jhZ|Rرc#F-[Dbb^^^YfYfpssCxx8\RBqdoEDD&M"L04x饗PTT?`w?~<_~ iii(//GLL >>)))HMMNw}OOj-..F޽t`&ڵ 'Nٳg?bӦMшQF!-- W^E1l0K=u|,X: -[`ĉtرc8|0:lbĈ5gDDDc@'5j}Yd2a۶mX|9j51o<|ר q9!__jݹs'gggۣgϞ&̙3JׯJÇ30w\\x:`ȑ刌`ŋW^7n222!V\%K X`>' ;5VNOOhD@@2666Add$L?FII Zn--YdddYf&OН;ݻqu{tyyy񩲮L&ɧw 0(..F=LbGff= DDDt p@dxKPD.))AAA4]`^';;2w \r:Nzܼy>>>Ell,RRRp9\t s΅V.+**VKjO>ARR:#u7777899&XZZRp=:t_:tѣGqyܼyӧO7W ##&|wv-ZtĠA<@NNCrr2***Ku fBqq1 _m-((7n"hAtt4{=鲴|YjD  t^z7@HH7o6mEj:t(J%ݡV^za|CVSNP*޽WbȑPxꩧR0{jQ(V ///XFB.C 88]vz5pBtz ?~ ""27jD L58T+ RT*=$'nDD5y@'"""""",Љ,T*s DD /5TZA'z,\:u3ׯcҤIPhѢ9 ԩStΝZd Z-\\\?\jۻw/:w Z ///,\η6}L𸓟hӦ7n[͚5~3fmڴB*7n,9"DllhѢ(//.\ܹsB!rrrDJJB'NGGGuVa0NG7 =q^oP!0 q83D50i$hZj 02dr9FӧO`0F]sիWq1r!pBѠm۶5k`ĈxWaggJ.]s|XՀSi!JJJ~~~Rpe4k X|94 d@FFZhQ7CDDDDt tZ!]^^l իh׮"##:%^""""GűobNT˾k?~C&MХK\p{Eii)P(`k{W_!!!8v옙8],Љj{akk 3gB :tmWWWj 0=ǾK&R7X-ģ[aРA2eJDD^R4w8TC̿D5_[s@UYa%""s%DDDDDDD:Q-JLL4%>O?on0 ajcߺ;d EQK֎ :U111jP*ԩ233/^D.]Pi>L6 ~~~pqqA֭JmP 777L6η, t"رccǎAa͚5pttlذ7oFnn.1sLiv_NìY4NCaŊHLL#""j, t"իHHH5k oHJJ֍r9F~GڅXp!ЪU+ODDDOs=ebNDUdddQFjն{zzJ;;;P^t)RVqiIJNNN\̚5 Vo&3{l n .6m 6 .]«6mVXJ-[X'iNNNP&EEEtF}666ɁOKDDu9n㘁z @o۶\.@]&}׮]vWWWlΝ[x7?wxWHNNFݥA}lrF#;; \''c"G.q;Qd2y2 `4^uEdd$N:;>8::ffաC|嗨@rr2G BLL 999HHHp17 3=W?cǎI߸q/^O?-Ett4;{Xv-[g <(}W>pQj3fc~zjt JݻwGRRR-EKDDւ9ᘁɄY0<3Xl4SL)Sy2 Pٳ'駟B+SLA~7n7߄?ke˖ ӡRp1o6~wk׿`ooğgdeeAT_ҥKnnnطoNPr<3֭}O?jC]`_""2ua%&&gϞqEk䇈!qeFDTYqAǶ~z<3Xr쉉umĒcgN'bNDDDDDDd YR=xGK\A'9?AVRDN ,\]tΞ=Th֬uлwoT*[n()),YZ...nCll,ܠjrJ-[m۶Ϥ9rDj۴iV3g d2VX֭[~:R?{EΝV充 ϟ?h4&ɓx&M`ȑϗ0}t :tSv,Z]t BCC)_v 7Ln Y7tt"jY ^/+"+._,*++ʼn'Dnn󢢢B-[SR"ĦMB9R`0 >,ą 8wB"bݺuB.XQVV&9"\\\āBڵK$QYY)m&\]]E^^Bݻw .(N<)<<<ƍm z%DVVAAAb_~=qptt[nAt:qQ)v[[[h"a0\.B!`999{_ ĉ\DEEPO?C~1c!0sw"//O3f!ؿPT5~IqܡCx$waNgN'cMy=''GUK.:$J(++ʼn^xA!ѣExxxI?AlݺU[N(Ja0yb„ B!/-[fNHHذaC6IĞ={CÇKӷ -ƍWmۺuF1׼ysujOHH͛7CCC/M:tH( iOZJ޸qB/WWWQYY)" @dNTY!995_^n222ШQ#hjooo7d YYYŋ{?̙шf͚!>>˗/FA>}, ;;;i/_#66jZz$''K=BBBJիW#//d<==LuiBB@PPZhqwg_B@jj*ooo(JkY^NOON_ W3V""nD԰@~~~(++3ԝll27mW\Ayy4/-- M6xxx`ʕΝ;zj$$$ իh׮"##>ҥKO>N`00x`|2z=@(**BQQΜ9#G/::>>>8{, qZi/<<gFYPVVӧOc3f oK J\.-.\{P(ߏc0 8~86mڄ@LL /^$!PRRYYY(++͛7Fؼys(|WHHH@EEz=;Vu RL,^ԩZ-f̘B!={sQœ~DdX[xcǎPՈFiiisN$%%xw1j(@RRBBBP(еkWL00 9s&4 ܰo>_^788!C={^z%|GBƍSOO?h VX'BT"..Ç}ӡCl۶ qqqpuuEVpdܹJīZkqrر/_FVR0`G>3@DDց9ޘӉDm]C* z-̗HqJd!*> DDŚ:EDDT0w""""""" 9tWWW(JbHOO7whDDD s3hIJ>>:We;Я_?ΝCAA8߿ Y~17Qmb^O![o!66SLFxyywqЭ[7jn_}9&""ZDDTX/^Dzz}D_Ĉ#UV!** Hf""m,뉼[y{{KΝ Z BaÆa׮]hҤ &O ;;;bԨQ7WDDDVj zpiٳYYY7Y/ YYYu*QLDDz=???|7\iӦUM>興f""m, LO?qqqk׮rssq@q5\8x 6oތѣG3t"""LDDz=2p@ڵ wF`` J%w,]7ƞ={qFaĉXj{9sNDDd6ɄA-PTp=q^RipοLDdy)ښ;vnEDDT0w""""""" @'"""""",Љ, t""""""" @'"""""",Љ, t""""""" @'"""""",Љ, t""""""" @'"""""",Љ, t""""""" @'"""""",Љ, t""""""" @'"""""",Љ, t""""""" @'"۷; ""D t""""""" `kߨ'sAD`0wDu ϠQ &&ZJ:uBff&ŋҥ \\\*iӦ...hݺ5[-11j9|}}iӦW<6YDDTccǎEjj*;N5kal޼pvv̙3ڵk_:fBdd$ҤB:u ;:+V 117^ⱙz@'"z*fx{{۷; &&ppp@DDu#""\#F駟Ƒ#Gv!.\j !!!&Qxl&.,ЉF222ШQ#hj===QXX(M/]AAAPTP8}4vR ''{ODD㱙Ⱥ@'"CYYkСC3g6l؀7n@!88B&GDDf"jD`Fvv6F#N]GQY7 t""xcǎPՈFii}yꫯM6ƙ3gЭ[:Ld=dױXT*J+YCz=Jábzf"֔mUco,""žY \nn.zR&Mg1wHDDDda8^ "'ӷm5k@.CaÆ Xlٓyb""" $o}t瘁"3 \ZZ`c÷U"aGٰ0L<SLAƍhfcܸqpqqAfͰg@bb"d2vڅv;wƩS>ׯ_Z;we˖prr!CP\\xqƘСC+WBP 2 efҾb nΈ1|p(Joϟ/**BLL Z-<<<0zh'DDTG DDu* tA_~ɓobС 'зo_DFFDZgԩ믿(//KJJ[lo$&&bؽ{7vލ/k֭֬[uF-[;Ν;իWCP龸o4i ŋ?GѶm[L6MZv~:~7111IDDdf̿և"cAo׮f̘>}:>##** 0k,Z ٳ /5hڴ)0l0@yy9VZf͚ /W^B@֭ѳgO߿Çŋ7`޽ݻ7 A]:u*AÇĉ̶ܺmې Z 7o~GJDDdy:/Ռm۶pssC6myp5v*e˖8w4IyFk׮!Z[g9<==dz{XedccIDDd1Ru8^ "-Le2|G666r j#<""@̿  DDj(;&} \xO?#צMF8p6«s:t_~ $''/|<==1h // )"O?ӧOcرpwwǠA?3ǏۑD|7gѣPx1f̘x;uRݻ#))%"~xX%⣏>oڵÿ/?VVBll,&M|hZwt'mcǎرcvڙl݄ s;:Nvqq%KdɒLjMC̿ DDuC&>j6@ٳ'nܸarӒVPPJ"KDDĝj3Ϙ;Gbɱ'&&uJDDdyA,9vx" t""""""" w,J؅0}: B:ԩSR?-Z.]̔گ]x{{SLAYY}xx"jY ^/k+"+._,*++ʼn'Dnn󢢢B-[SR"ĦMB9R`0 >,ą 8wB"bݺuB.XQVV&9"\\\āBڵK$QYY)m&\]]E^^Bݻw .(N<)<<<ƍm z%DVVAAAb_=qptt[nAt:qQ)v[[[h"a0\.B!`999{_ ĉ\DEEPO?C~1c!0sw"//O3f!ؿPT^""zCI?ODճ݂SF`Ŋ8q"J%0|Z7:tmWWWj ѺK,Ν;T*1p@ꫵ\.ǎ;pej *  x3DDd9L5< R|Y8C|#9#'F)>xsz=PXDDD//q'"""""",Љ,/q@KR0wڻWw!|8v***鉾}ރ:$֖8s88w p`9ncnx뭷)S@;`ܸq?֭j5Znʜa5xDDt'VŋHOOot:1brssj*DEEu)݉9 ys΅ZBaðk.4i'OBCC1j(Ǜ+l""9 ߺ̕+WygφN_ deeUL@@2T"""s8݉ {.ӴiSKKKCӦMptDDDt/DDt'V@&O?E\\ڵk\9sп\v +WDEE<͛7c Ac'";@Į]{nBT{ҥKѸqcٳ7n&NUV3wDDD s8&BsA@RACT;""zH>+WB/ dZFbb"oߎ?;wBBaٲeɐdtXXM>}{AQQbbbjѣGC0~xCR!88=Gxx84iWWW <ؤ}ǎh޼9j5Ǝr@QQT*)))zs/jhZ|Rرc#F-[Dbb^^^YfYfpssCxx8\R13aNU|IPTT &sA!66/PTTTY~=,X"Ǐo!-- 刉#%%tYmݻ7L|O`==Dfja4` rrrlDGG#33QRR֭[K˟={h֬%vwxggg.x{n\~]N^^^|||+h}@aa!F#ѣG푙yQ}| =Ϡ) H%%%(((dggWY|}}acc+W@I7oEJJ Ν;K.aܹjҥvEEEjarZM}'HJJ¡CPPPtx'''?~dKKK={{"2?@:tѣGqyܼyӧO7DX ##&|wv-ZtĠA<@NNCrr2***u fBqq1 _m-((7n"hAtt4{=| }`'W^x7͛M6pqqڇ R wwwj;///W^>|gPԩJ%w.}Wի9r$j5z)T*̞=~ ~G$%%A +VѶh4F׮]k^M-\]vE^?Oj9}a'G%q-ՊT*z:~^RYqz4οu5_$@=_;̿DDdnĝ@'"""""",Љ, t""""""" @'"""""",Љ, t""""""" @'"""""",Љ, t""""""" @G۷; """, t""""""" `kߨ'3=(a'&""23s_z<t@BTSN\x]t BCC0m4[Ʒ~+%&&BV?/0mڴ:6"""NQ}kرHMMűcǠf8::6l؀͛7#77Θ9s^v믿Ba֬YDZZ^XXSNǡCb $&&+tOW^EBB֬Yoooؠ}pww @RRnDD<<< 1b<8r.… VZ!$$d}"""G g,222ШQ#hj===QXX(M/]AAAPTP8}4vR ''{ODDD(8~!:ݓLUœ9saܸq:7p!""'"X=i4 8Άhɓ' `kk&Mh4/ӧ(j"""j8~!:W||<|}}ѱcGjDGGxWѦMx{{̙3֭[ELDDD /DT_۱PTЯt"zG:P*j"/=_4kʿ1L7QKDDfK܉, t""""""" `zzz:d2 QLDDT{@mls05d,П`$`"",@ߺu+ڴiGGGw(..[Z~i\}={BFAdd$vшoh޼95jV8SO=h߾=d2رc1h ,\ ļy|ipFawLDDd~3k9r$-ZW^y8x Xv-fϞ˗}8y$1cTWhh(dǰaðo>ӱvZ,]=qy/g}?#`oo_m駟T*w^!ЪU+믿^?3RRR`ccQQLDDd!HJJDzzz6___yfy]vB&'O !9sӧ򙙙p(((5k׮61cF#LEIlܸ}z@?/Yzo9nDDt5- zvϣM6۷/!C0a+**R+)) B@ӡ ?|nC6m|?oZ}N""LDDd,@ػw/9~}׿bǎkעsU֩h/oUڼ7sgrۉ,E} K&[n;w.N< {{{>|>>>͛js0YǏO?>}ǏGnn.Zj9s୷ނRD~PVV?q}*}ڵk1rHL:HMMŖ-[vZ888Ǵi`oonݺ!77gΜ GGGFӦMpK'++ o&1`]tFDDؘ,ٳgE߾}E&MDFD``ϤM6gyFۋƍ=zNQ e.^(^yVxŔ)ShBQYY),X j?_v666"443F 8P6}S!yѬY3QXXXkQCT_ =׍nL!OAAT*z=JùcٲeHNN6w(͒cOLLĠA =r'S u ;s7eE}[~.={{dC^ hv:]z6A{>:vX &&ZJ:uBff&pBtNNN8{,RSSѷo_YfXlOZZz JWWWt %%%%K@MbZ-V\iҶemj:u‘#GM6!88...j9s&L&Ê+кuk8;;#22ׯ_áT*Ѿ}{?g޽ܹ3j5pBd!!A4o\ 4}!P(i???j*izƍ"88X!/"\]]Eee?!<5BCR:s7s7=9֔y{=FAV~,x{{^,ŋ޽{śhDf˗CѠO>&wO4˗/ Z-=!!!pwwJիg NNNUܺNP@P ((H?-Z/pvvFaa! 557J%^{,r}CU/C իW+Ynn"`^QwڴiS\rҼ44mၕ+W"##;wի6lߏW]vK.O>:Nz>`o6È@QQpi>RٳgQPP7>rlw~U DDd}XCDtt4a4qIB`֬Y(++ӧ|r37ҥKB@RA..\޽{QZZ {{{( Ř?> ?M6!""ŋ#)) BDVVpMQF8~86o\'** _}PQQ^cǎh݂@T"33/:uV3fBddd`Ϟ=DDdT||<|}}ѱcGjDGGrvvvعs'p5j )) !!!P(ڵ+&Lp ̜9nnnطo֯_/ xyyaȐ!CϞ=/>#DEEqxꩧ駟h4+VĉT*ÇСmۆ8UV8p@]d v RW_r9v؁˗/UVPT0`#1 "ޘnں[AAT*-ȢIqJeGr@̿yNXStK}dɹW}CbNDDDDDDdXYܡCпBT"00'OFzzC#""jИa>xkKR0TA{w;v`ԨQ?>֭[FllٲǸq*d""z^&6 z=%[oXL2wyGJЭ[7jn_}9&""zDDXS/^Dzz}T_Ĉ#UV!** Hh""zT,멼<4oܹPP(6lvڅ&M`ɰChh(FxsMDDdQ@o}ʕ+ҼٳgC/ o^@@2T""9 z*00~~~oLӦM)6-- M6}5\DDXS2 ~)׮]̙3ڵkXr%***pAl޼G6gDDDV9 zlصkvލ@(JtXt)7n={`ƍpssĉj*9gΜ!"2 ?;CQǍȠ :,A@TCHII\|;w=0}txyy-[ď?(8pj| <==ӧU:1c !!ǎVŪU`kk Xn6n܈tr̚5KצM8qZgFHHl9sbbb|r8pWDDDDdtn޼hZ 033C۶m CF`cc#G"66V;rH8;;Æ s=#GHBDFF-Z@.] t""""2:ɰFUz.ˑ-MJZٳg!+J=?@'""""兂WELL """n:ܹsZ7#"  Pqqq̬_VV,,,P~}oٳgk(j"RTT<==Ѿ}{j"??>/2^{5j 8wvZC=>F#++ * :Jcqvj@A7,:=Sʿ( Ďj7^NDDDDDDdXIIId7X cƌ2e3i0P'L&V%""2DDDOϤ t""""""ڪZ ~ Z-ѳgO֬Y-Z=VXQXϟG>}P(ₐdddHOѤIX[[C`… ڶm L*ܹs R'Pj+((;ggg^'ĠGzA&a̘1zN>puuEDDDc"""z``""2!)ݸqCXXX%KD˗lj*&l"\"l"ڵkB$&& "..NI|… ԩS⥗^=z^o^zbڵ"!!A:tH^Z!!_UG?zhP(Dpp8{رc_ywصk8w=zWb˖-tHMMZV!P*"""B\|YDEE L&Sa,:N:VMǙ'3nt=66VIII<==ƍ͟?_ !ʟ̚5KKo)fee kkkdAWG"77WrJP(DIIbÆ R{aapww-B~@ܹsGol /С1cFQ]Tq̿DD)-6m_DVлwo Fqq1RRR0n8?^Z*±bcc~(rm7Z- />mNCNNRRRPTT]J햖ر#.\ȱ[n7[nU_DDTg1W9j.ͱw^9r{W_}>۷o^:u*ק"ׯ>rmnnnrӆXd2 !ͫe1KKK/H""+LDDM$N&k׮;w.`eeÇW\A&Me7yPvp9x{{#ѴiS~?}4cǎAPAhҤ #ɓhѢS.bf&""ԟ?~zggg?~hѢ""";@T"((8y$ܹSի1|pL6 NNNHHHMzj`ƌ>}:еkWܹs7nakkhРlllz) 1n8̜9ɘ3g`ff\z ӦM4 -Z<7L;vO>A""LDD tRK.EVV#((`ggŋchժLRX8|0f̘޽{^^^xafvYfgƍ7{+ca_7ofϞnݺ\_|M6EQPPaÆ'|R ;;۷/z<<<0w\|x70j(])QU03i/xeeeARAAT:vZ,]sj  QRT1G1ؙSǁj:=U=ݻw[n5MU;{O .Bw%""zPOS'}o,A@TCHII7"##ѹsgHHH@޽ƍcҥ8ٳ'T*еkW,YF{{{x{{oы!<<h4Xb^ۦMкukjtG6l___C`֬Y[2 ˗/G˖-!۷o#88Jm۶ŋ+>{ENVH...z#../P~} >R{@@>C ڵÙ3gvooo,Z;w="ߺu #G;1eT.DD5.`TT""ht:@xWE޽EII8uHOO^^^YfŋX͛iӦ|qi&6l bbĉPÇq%akk+.\ "--M>}Z!Ě5kȑ#^BBi4m@.#;;Jzr)V i <7o|hDDl12=-u u߾ ƍ(**%&&AgggXرckDGG͛hӦ BBB1իxzz?VPXXAaĉ~:t:BCC/8FܹsIHHxBCC#++ ׯ gggʝQaNT"'sqqT"..N+e:v̞=8{,-[ѣG~\zBT*.]޽{+++( XXrss1|ذaF  ŋ !믿ڵk(((ݻwkkk?~7n3~x|Fqq1t:;VYYYRDJJ /^\mqu3gDvv6HNNݻ50V9XCV#44喳Ď; WWWSNň#ҥ  0n85k\\\}aڵҸ(.. GW^y| ƏzaÆ/QZZ {{{,_&LR… \ۦ]vزe .\hR%K`ǎP*0`^{j۷oѢE T*? "p̩DD&u}=,T*( q=q\RLT*2)_G/B5NjQKDDK܉ t"""""""#A>}Rf͚aHJJ2thDDDT p"A7BKNgFQD}?h7}v1ǚ5kTlڴ oQ!zOs8t&;#pL2...777ɓ'ѵkWjl!&""É&&HJJwLZ-^~e 6 Xr%ƏÇ`DDDt?p" KΝ Z BCbΝ_>&O KKKcĈ2TDDDus8Q݄99.ۍ7yśVᅬB\v z5jk׮dDDDtp" k֬?|r 4ihذ!{ۢE ;rZhQZl)yp<==[իDDDLD0tDdXǏo^zǏGzz:Zh;P* BAAN<;w`ԩ>|8>c 8pssC\\iӦaСh׮^|El߾[nůZBCCcԩ8q"bccvZeL 4k w}~ wޢ~Z4kL|WR ?/DzD֭[$k R)Dǥ+VF KKKѬY3n: T*fizI&ZtM|z7 7֢~"$$DdddTF"""zA2!"""""""zt"""""""#@'""""""2,Љ t"""""""#@'""""""2,Љ t"""""""#@'""""""2,Љ t"""""""#@'""""""2,Љ t"""""""#@'""""""2,Љ t"""""""#@'""""""2,Љ t"""""""#jڵk!G@@vaD&!"";pd28cmߓ'O>}`F:M8CRA&aҥ613f }ضm[NRR?iӦrdȨ%"㇯/h쀀>Ets,I* b͚58z(9UV c"556mѣG1l0CL͚5 zE~>EEEl|""""SeanE_~~022ugϞdPjDƍk{n|ט#H˔]Zvr>xWerΝáR₱cBB_~/_0 #F3ѢE ,_r/^/ ;;;899!44UN/^kkkh45Jo{@vv6z-899 7ټy3z777ڢEܘ1cP(>}@P^>Ò%KаaC( رcɓ߿?`ccm~xٳg1`ԫW666x%]jW\\+WJcWC-`ccGGGGY|9wgggrj -* reBΝakk ̚5 %%%zΝ;:uJ%ڵk?BqƍBB??Rd2"**JHJJ"##˽Lݻ7ϟXDDեR}ݡT*ѳgO\t>U96|U?~NQRRb!pM,^1bݻwѣGߘ;w.ZnC!22عsk`7gΜ~oB 8GٳѡC>|O]ϟ?.]@?+~;9s7oބ?,--b `Æ  ŖO /'''̛7M6Ejj*~gZZ7D߾}qF`ڴixױo>i })S qE|?"ƍ{gχJٳ]|9{9ݳfB>}Jؿ?^~et _5T*6mڄ`a̘1U&e.].]׿c̘1y&O}ѣ{U:fqq1p!L2(..ƱcpUtcĈhذ!pi,\/^ʤaذa0o<ܹ ,;wl2i$L8p1L<ׯ_޳g1h {PT8{,^GE`` zYfJ%ѿ|ט>}:ͥ>˖-;^}*O?m۶ŋ1o޼*!"nڵ+deeaƌׯ.\wʱ$xNB fZXBoٯZ?O?T{B(5k֔{=bΜ99sh"&M$lllDiiBݻw /[n…ݻhРtzˆ qm!3f2L-K/ bo/00Pjq֭.S}'M7ѢEHMM_ii(**ӧѣGW#7o.MVZbi!^sωmۊ"1_y&JJJB߿JfذaZ\zUo~PPZV@ە'֭իlQTT$֭['ͥ}/?>Ǐfff"991͛'+Wsss1rJc=zқ'ѣ-[yׯ_bܹN_xB#G \.͕不W:уutٱO>z8z4f9 ѳK ֭['Nĉؽ{7F~[S}A.cz}ߞ7ݺukܽ{npT9rr{G~ë ;;;K>}ݻҥTڴiS1tPԯ_'W\# sssXZZp2ܽZn]'}dNHHŋm6KMM}%o>ԛ?fѣ5޽666;vlšpttQPRRRC{{rfĈ(-->={JƜ={6233ѽ{ocM6zB~אd0ac`aܹJ.vl9%d-Z(wdL>:j5233Z{ΰ@fft٥XLXXX[Uo:33ꫯW_UZe? kpܹ̊s%%%hР#~999֭lll`4k vvvHIIAƦܘw}׾y&_aS\pss+7]j\pwwǼz*u͛/7lll.]\\ʍQb?ЫW/`hРm6,\P3==7QU|M\t 5ի1x*&M²e0uj {~'Lqqq{Gerl9bNFu_pet8~8z ֭[(..HoJɲz4իsss<̲XEcVvC۷7nw@V)o~! T2͛71Zn~Mh^qԯ_111(--}hm6b֭W|ى٦M`ii;v蝀kNg̘~ ADL͛7k,ǯʱ$sgA={uVݻQ|r=IIIhժbbbO>R2dxߢqhӦ *%իwӧ#77۷ÇI_^@n[oHHHۥN2~- HwLxbbZd ^xt |4i7oƿJ ]tAz9s6l( B޽1fxxx۸pN:Uߜ9scgφ6l؀;wbѢEҝZñfҥKѣJKKqqhÆ K/+++ >ӧOݻwrJܹs1[oիh֬vڅիW㭷ޒ޷o_,Y#F >܉71|K?sydddTVZؾ};`oo Ih"oymw)S`ؽ{SCDuWƍŋCբO>ʼn''}UTs}<'!z {:k*J?Xd{򙙙"44T %>rt:o !E~DRRC`JLLiZ1vXVx饗ŋˍ)Ľ;VxxxKKKQ~}ѥK`Ο?/^z%acc#ĸqUϟC Jh41fi{lj'Ut#G???agg'ׯ/|Mqԩrw=zb)ۖowUN>-*puu믿49sׯPTJiwѭ]܅"??_̞=[4mTXYY GGG(9"-}vѦMacc#<<<ĴiӤ;۷Ms~+7o.EFDddSoT{wС Bm۶{.k׮Nлq 򪴭*Vyw"zbʕ}NXYYM3flerǏ?7;?α$\U?B|)))` ce%"Qh4$QFz˘!-- !!!HMMEhh(RRRп|gC˖-ϟ?d4nXﲾ \.,{v۷fddã\_L[[[wQZZ\t]/6+++<0KD?A 鼼喹'p hZq]xxx8}4.\Wbܹh4}999h4wi\U}爍ELL O4փaggǏc~~>t`e%" :]v8z(.^w?{())uVt:ܺu -5\]]1p@!##h}b8 /۷/ 0{l械ҺfeeCNNëԯ*{O.33SF7DDDsoua%"S ĉѥK4iZ>d(J899AV  Dpp#_gڵPСJ%u&}?͛>|8j56lJ9sT8BXh4aUZשS..._UUdd${{{={5c>̽Ddd:3jJ@@YmrՌNRY}qzEe%"9y8#a%""C%DDDDDDDF:`nT*d2YFdd$:t\ ܾ}&MZFӦMq@@@M.\Zd 4 oFjۻw/:uZ 777DFF̆!""z'q?|""|زe _Wcǎ Dff& Pi?Dff&1`˘9s&كl?~;va>}:qEPKDDTg1&fҤIh4P۷/0x`c8{, Æ 7oرc077ΝC~~>\\\кukU0l0kJBΝ DDDus>anb\]]vvv妅xyyImpssѸqcDEEaٲepqqA^HNNFӦMkfe衘L :,99Yz^TTTxxx͛hӦ BBBK  s>Qۼy3?B̛7GΝq%ݻB`bt:;vkBDDDa'"XacǎŌ3{b۶m@aa!f͚8::b߾}Xv-]vزe .\h4QjB:'++ * :JV@@)SQmdJq~NDDDDDDdX C@A=ۗ80z󲲲Z͛7֭[/_FΝq9kׯ'`ؼy3n߾ OOO̝;C :`0w\aܸqXhѳ]A""Uڌbe9|ԨQشif͚NDd :Iƌ;v ZV-`ݺuظq#!1k,_6mp hZ̞=!!!HLLڳq_q^="""NDdX͛ƪU333mNNN04j6669r$bcc#G31l0""NDd:X @hh(RSSQZZ8dffV/++ _>JKKٳ551$'ڷoZPW_kVZΝC׮]k(b"""ÉLL:&Jj@Y?2:IqJPxDDSʿtc4TT򇕞`''aaah4pvvƨQٺJEj G駟ЪU+={Dnn.`͚5hѢlllsaŊz}m666h߾=%?bȑ4irrr`nnclݺ˗gtaaa}6ZnӧKˎ;oƟD!,,'""*cc>&"g7Djj*EW_Evv6:!V^9s`ٲeh۶-0~xr=xW#11W 0m48::affnݺ1an~eCV͛]NFTsA,+b 4^^^VZϟ? 4lϟǿo=6l@II [׮][oe)*=}tNN )) hԨ^333ãF%"TsA,+ѦMhժz^za(..FJJ ƍKCR.\6m?c˓SSSx,OOOƍzADD|?c""zz%ͱw^޽-[W_}͛ʕ+իW#>>^z={ǎ! svwߡx,WWW 8aaa!::%""Pmc>&"'d2v특s"..VVV8|0<<rZ”)S ۷oGhh(ڶm-[O?kf5""".b^-ZCG#F|8233|ݻ7 ڵk3gHXh:w {{{#%%EjuF wwwcʔ)(((t]zT}}*%$&& "..vN' Deꫢw뢤D:uJ ///ѬY3qEQ\\, DŴiD~~8}pss6lB1|p1qDQXX( ÇEAAt钰.\B&N>-b͚5\qaoo/<(bΝCƊe 222BڵK\tI8,֯_/(222ĵkׄ(**F{6?uꔰ?(,,ZV=zTB,ZH sss ">>^:tH4ѭ[7oJc wwwq)QTT$Ə/v///#o/ѣBN:S\!̙3B߿_T'8:z@e9Iaf&gJy=--M_|4#J(((-\PKB!F%/._7NBB?k[fP*P*ƍ'O>bҥz}t"֭[W6xw*{nizȐ!"88X.;xPoTضf7I&⧟~phѤIi_̘1C B+Wׯ_/|}}BAH{5B0VtPTΜ͜MDφ)_^^%''_v 5j׮],^ٳ'R4nQQQXl\\\ЫW/R_xx8j􈏏tNNNPT믥x-*=+7ޥw  >>>iڴCc\.Gvv6 !! ;J%^JcR,k/;)) Zv]VpsspB+O>Q^=4l_~%JKKaoo˗c„ P*Xp!u۴k[l… -ZUdرJ 577quh* }}Ov`~8l""@&zjYYYPTtP*QfJq~nBbbbЧO888@TYfMq4oΜ9jxQXXk׮[_Fpڵ  h֬?C^^Zl)-y$''qz=wr9Z- ??vڅ۷oKȀG2 z?86dgg޽^lVVVHIIy !0O}.\իW1w\h4钽h4xyyֻܭ>s"&&YYYHJJ'A1??]ty񉈨nbf& ]v8z(.^w?{g())uVt:ܺu -5\]]1p@!##h}b6 /.۷/ 0{l械ҺfeeCNNëԯ*{OT.33S5DDDyz0OQU@' ĉѥK4iZ>d(J899AV  Dpp#_gڵPСJ%u&}͛>|8j56lJ9sT8BXh4aUZשS..._UUdd${{{={5na>DT2QPʂJNR4t8DDx߈j7S:t"""""""#@7B* 2:7"##ѡCrۘ4ij56m#G0m4~~~p4֒%Kh`ooooo|7R޽{ѩS'j!22f؉HMXODDeX[lqUtİa*-D``  b\|3gĞ={Ǐcǎ8 0ӧOGzz:.^=zju$뉈`Nd&MFZ} 9gϢ0l0 y&;sss!p9[Z Æ kKKKT*tِLDTXODD t"*=+7-@^^Kj_ƍ#** ˖- zx@rr26mZ3+CDDⱞD&%99Yz^TTTxxx͛hӦ BBB;KHH0HDDx'"2],ЉL͛qqb޼y_>:wK.a޽χ ,,,ǏhCرc^""z뉈L t"2vX̘1ػw/m b֬Ypqq#ۇkڵk-[`…ppp@-pAî=DDK&ʂJ2td`O/bʔ)UYq\AT:"C_뉈)_~nt:| m'""èKm۶: "22,Љ qC@DDDD1A:zl#/YBxx8~ghZ4o[n\|;wƹsЮ];_ӧc͸}6<==1w\ 2>ܹsqaѢE5DD}< K܉1c !!ǎVŪU`kk Xn6n܈tr̚5KצM8qZgFHHl9sbbb|r~BDDdx>@D:3pMDGGcժUpwwڶm '''@XX5j9Rߑ#G6l{99rDjB 22666hѢtןq@'zamm FSa\.#;;[/JZg"##CjW*{h"""2< BAARRR_LL """n:ܹsZI""ZDX=...0`BCCR!33~YYY@QZZogϞ:| tg$** h߾=j5BCC_i_~Zjwww;w]v|LZJNR'O@BO{'è''aaah4pvvƨQ "" UͿ(APPt:>l}iӦ333t  &w-[ ==j0o<`ڵOtADDusp1O>wrP\\A ЪU+ ~-yaڴi?#.X}]i^jhNJe999$QFz̐j?c&"2}@6m/UV2dV^;wI~~~AJJJ}oݺ7n_uz\.G^^4cyzz 7n܀Vwe'"RrpU0O`nn{bhٲ%+4od5xvCqq1w=X8p HKKCtttuKDDuD]U`Ŝuk׮ҥK~ 08B:"z eqNRipjcGMjcsḇ3G?SʿIRK.EVV#((7oƋ/M{(((aȾ0zhܽ{_|}899aƣaU1`_""24Zh.3w\̝;N8'N|)""2j9AFR: %%ވDΝagg#!!{7nKJ$&&gϞPTppp@׮];.YF7|Cxx8hb M6uwߎ9"mذFYp,d2/_-[B.#$$oFpp0J%ڶm/V}݋N:AV zχ3\\\G\\^x888~>|8233|ݻ7 ڵk3gHXh:w {{{#%%EjuF wwwcʔ)(((t]vaf&"z**5zh1`y-N' ăꫢw뢤D:uJ ///ѬY3qEQ\\, DŴiD~~8}pss6lB1|p1qDQXX( ÇEAAt钰.\B&N>-b͚5\qaoo/<(bΝCƊe 222BڵK\tI8,֯_/(222ĵkׄ(**F{6>^:tH4ѭ[7oJc wwwq)QTT$Ə/v///#o/ѣBN:S\!̙3B߿_T{!"#u:Cbj*Ws4s4}ҥKtE[u~w,{nizȐ!"88X.;xPoTضf7I&⧟~phѤIi_̘1C B+Wׯ_/|}}BAH{5B0 S:AK@gf&"0KkdX[[CT~k׮VVVҼFڵkŋ={7"""PZZƍ#** ˖- zwWUwwwXZZJ^^^~: )) P#>>^j_ХK899AR믿~ήtNN{) ( HۧiӦ~r 0P*x+M.K\m,M\FF]7w\j( :;wD1ydXZZ#F@TT&"""""sX8'{߸qC7ghZ(,,ĵkׯQFvZMJDDDDDT@7q͚5~ᇇ.ӠArwsOLLD qtDDDDDDTd/pB_­[8wO>uVXb:t7nĨQ :Q0`v܉]vYfP*֭_^zؽ{7֯_GGGL0+W /`Љ ̚1nɓ'ѻwo㏆Z$%%aÆsj)G&!..?C!xߪ0͔*VZssshZU~GDDm۶ `.&"zx; y Au)..!""-=d (X 8p2jmcǎP(P(,]TZ>>>2LѫW/r޽999 F3FN(((رcJ___8q__>0h ۷I&P3f 9990`Rн{w>}Z~!,, j7onjcذaGqgFƍ$\\LD5R2?#FI&!''ƍ{8p + ''999Uk׮ł ={bر}6O$&&aaa(>} jغu+\]]+777={/ɓ'-sN:u ϟǯ 6JKK1b$&&͛h۶-o/k׮Ă o";;[jߴi&LV3Fj裏pa 55͚5ðaê͈L /s1s1 toĈر#d2rrre,[ jr͛QRRKKKdgg… BYfp;v .\.z衷LDDJ%XRDpp0r9lll0w\\|Yva077GHH qeo߾ 9x $''#33BXK,`>|)))` UM?F#=OJJBii)5jT"%%g}喹'p hZq]xxx8}4.\Wbܹh4|999h4'E?AVVz#pquG.]z|""2]Dl@Z]v8z(.^w?{())uVt:ܺu -5\]]1p@!##h}b7 /H۷/ 0{l械ҺfeeCNNëԯ*{O.33S6DDDa.D Tbĉҥ 4iVZ^j2dJ%V?OOO"88vZjtJݺuvM >j 6Jœ9s*GP_Ell,4 ܰ|*ԩSannϯJ*22~~~ =`Ϟ=DDdzs1O&YYYPTtIDMq\Aq`}8b" L)&qFHjQKDDK܉ t"""""""#T*d2>Lq?oooDFFC ۷1i$j4mG`ڴi=pi%K@o{SNPpssCdddQ̿UDDH|زe _Wcǎ Dff& Pi?Dff&1`˘9s&كl?~;va>}:qEPKDDsѳHL4 j} sss >gϞEaa!`ذa󃕕"""pM;v Bܹsχ Zn Xj ^{ PTܹ!Wj*"g:puuٕB //%YZZ ׯ_Gƍe˖zB||< 99M6!""\EDl@'EEEHMM`Сؿ?n޼6m $$KDDuscNT m޼ǏGaa!͛sθt݋|XYYAP0~x|Fqq1t:;f5!""S\EDXBcǎŌ3{b۶m@aa!f͚8::b߾}Xv-]vزe .\h4b""z|2!0ttOVVT*t:J!#bʔ)O=7.]>XDxmV3WQzRt'DDDDDDDF:0tTT cu`6 JVV?Cբyغu+ܹ3Ν;vaL>7o۷鉹sbȐ!8pg}s"//ƍâEj={̿զJMx^Bp3f p1hZZ uaƍHOO\.ǬY~mڴ'j1{l 11Qjƙ3g_!&&˗/ǁjzy ñ@'2q7oDtt4VZwwwm۶prrQFȑ#+9r$annaÆÑ#Gv!"##acc-ZK.zʱ@'2qɰFUz.ˑ-MJZٳg!+J=?x^BT9D& HIIy~111uphZHDDDO%DcNd\\\0`"55Cfff`aa룴~-Ξ=[CQ)y QXQQQDVJxЪU+ܹsڵk ELDDD%D'.hdeeARAPg^i5!HqJP13dJn'JOOGpp0N< kkkxxx >>#""2EO0%&dժU077Vŋ Q>ݺuN I.}"cyzz 7n܀0`y]`dzd{7|)--t|M\r!!!8s ڷo `kk[?vCqq1w=X8p HKKCtttuKDD&`yOرc;wxy ֭[{a}Rp!rW_ѣP՘1cFT]j:tRDnc 9`&"*uxwyyy/Bo-/믿3gΈ F# Br劈;vCB!ŠAĉ'˗źuŋ+O BUSy\T?32afKₖUbN.e(4YZ.վ-W_n7*h* 4#_uT\ǃs>|}y3gYbha<k=))IZ z(GcKq~>c;>,Ν; ; CϞ=ѤI,^鉟~ %%%>˗[pDDD֎9jZuegg6OD̖ر#>|>o\V~?IUKD`2ꙴDDT5sQ_ЭV T|UIQQbccF6m 775k{9ȑ#D=FaJ?YYY֭Z-<<<СCnsE`` /,8xzz"00P憯O?r={5k֠YfpssC`` L L7AZhz)bС|2F-[?۷]vpww/f͚e>sLx{{lcǎ@1x`\tIiҥ &M=z@VUV8tٳg瞃"""_xQQQtt7n ]豳{>>"a<ݸʕ+~ʵ_nꫯJ=̙3RQQ!| Pߥ\ 4iD{=)++YFDD,G(FQv-A;&rQ9>>f7n,֭򉉉Ҹqce:""B&NLZVdɒ%tBB4kLDD~𐊊 }۶m""PfKڤFGDSܩɁ#~>>޽;ӕ>t: pׯJOOW ZK.Ug{C ]\\n.))pAZ ZM*'tHt:h4wU}gggCC/Å *cc#"j  nVyٳfʂ?/FNN6mڄK"110`$%%… hѢqkOϠWii)}Fk=z4Μ9B@Dj_DEE%%%POffC???9rEEEHHHxnoooRXXx n_}DdXSHܹs0LHKK3 m۶N Çc…>|8oӧ!"j=;۷ PհJKK1sLF۷k֬ATT 66sAjj*DW^ŏ?< 􄣣#ۇkVW_}D{uF\̙3jӦ 1ydCD[V{*澻c#:hVB@@Zn wwwĠ֭M6!55 4@>}0~x 2pjo#GD>}`41e(]rofP^^___ڵ+_hԫW 6Ă `2EaԨQh4tߴj ׯG||<<<<;v׺sŦMh_ⲳƍqA⥗^z_ƌu"""C U,6UbN/gϞUM6 z`4`BBBWY=BCCoeo{VVstDDDDDD5 tzh* ,@||<>s\x @޽qE,^صk֮]aÆY2t""""""Idd$6oތ-[ 44:u7͛za֭HHH'F%KcǎȪ.:wΝ;W޶m[ٳ#""""""yX[-$٣f͚'''!<ܘ-_n-[;;;z̙3MNXۨ,4mu#&""6DDt'|̚NL~BwAR/Ă ̖STHKK3<?>;$''+ .ĢE^{ ,'lݺ5W_}'|PRR=_|ZC""~1Oѽ׶]t1c0n8ԫW>>>XlJKKo 5֭[PTؼy3Zh'''kR\r%ݱi&4i...ׯJKKj*^z3f *** &L8::'>׿(FII  6`׮]8~8mۆΝ;#66/_O? &(˾[|2~7deeڵkM""|7f%""4mS[hɓ'&M?^^^L:K,o3m40]%KQF~'.\Zz ]vERRǏoە[T>x 4PvqqtII ;;&SΟ???jo`&"M6[?vvvD͕y>>>/*o߾&Mѣ<epp`o}||pE@zz:Q[h\]]~8wC:uٳpqqc}tDD͞^n]iJe6ORL&]ycލ>q6m@ѠSNHMMhՖ{j/=a|􄏏 }}1|p[ѢE ŋuuʕ+G#F(-Z@zzzH}ҫi777̝;s}+Wbwvkeͱ'''o߾f&-e+yښӽXs̭D |;v,N8-Zᅦ#d3.]@uIuyDDD:5l-]ʕ+fwAnEEEj(,dzލ5S~/;'/ oan5J`l8kЩZ!66h4hӦ rssYf瞃 9LhԨϟnݺA:tPx;w\ /b'xbO?rޞ={5k֠YfpssC`` LbvJ¢ESOC˗1p@h4l]Ѯ];f2k9s&c?бcGxxx~|L&i׮?^JKK@t"'OZ};'eqҡ̭̭̭̿DU/ t+R88۶=((H͛LF̋_|QDD &}Ǐ)NNNn:zYۊ+DшhTȑ#EDw2|uewƎk֭[țoyǶ+Vټƍ˺u|bb4nX'*)))V頠 Yd2 ͚5_~E<<}`2d 55Ph߾=F>}h4bʔ)񁧧'~'\RYf(///xt/?Ftt4ի b0LpssâE0j(h4cUoZj#>> Î;kݹsbӦMh4믿^eqaƍ8s  jK/=/DDT[+JD5 nEO yQ-bKaMj\en%"2cKދP+,j?,"",h4 Ř1cmЈ`N`ƍիwG;v@HH,ܸ݊vbSpRY:~K/oAHHFI&U1vXddd@aʔ)s\x @޽qE,^صk֮]aÆY2t"""""!,ЉDFFbزe BCChЩS'x{{c޼yWn݊xzzbԨQXd :vhЉF1kV&> ??ѣG_tHU";; 6ĕ+WnpnRgyҡMjqjƼmD--l˖-z=Թ ӧOGzz: 0oY7N$++ M6g*>DDDyȺ@ֿZ /ZF@@k;wᣏ>¦MVV]tӡR.]`„ ޽;\]]uV 66ưaPXX0 x뭷Vf͚_tN8>}~kf־qF4n1b]())Add$jѹsgC޽aUmm"zxIY@lL&-SN?CŹs\~)^zJYȑ#AFNͻ⻺B׿[l˗k wۺ* f7d2;w6\uD0 :UZW*W^EQQ2}ܺιsn[PN={z^y󃽽=pA=zOƌ3WRR@ɓx' ~gHMMEJJ ׭<==}mcYY"""y`&"LV?I&}ボTTTaŋ={]ߣA۷/bccQPP8<?Q^^foE^z% L:0HJJm-**իzN:_WԸK.ݬQ1oW m"J,Щ<=z4Ѹqc4onnnJ{hwww_" ?<xYr%ѦMh4tI… >>h֬ڷo_ݯYf}xg}۶m "ڍy0oQUQIUCUZ@!éٍxaa!4=6:[ʿI*,j+"",YDDDDDDDV:`NDDDDDDdXYDDDDDDDV:`NDDDDDDdXYDD'88} """j3=>,Љ t"""""""+`o.Ȇ ɢ"ᅦ^G&Mas!##ZBBB&L7|˗/# 3f@۷/>S̘1W^ȑ#1{V"zx̿DTqdqj#F 33{^Dze Xz5֮]|bʔ)z-Z ^SbСRڋq!8q)))Xh{󈈈LՏ:*.\@bb"-[N:ue˖"$$NNNBjjnTTaggA'Ğ={vY䄰0ODDDTSpd,ЉVɁ#ޠAoWWW+CӦMjÇ@ih4pqqt}"""c&`NDJPP rsshL>Wƕ+WѬY3ȽW&"""a8f DT 221118wL&pҥWTT{{{ԯ_& ?pjzqd,ЉYjкuk#&&eeew]gϞxѼyst:dddC1Q㘩X"hZ.4| QU8^XFcp>1:f[@ EDDT0)PTHOOt(DDD s0QձqADDdDDT@LFC ""}ݺuh޼9nݺb O>$/^|׾9޽{CVCEAAn2'qpttD``  6l* ]tg#F@߾}1k,t:>N3{A>}йsgL=DDD s0YMΝ;cxWQ\\]vAD|rL6 .D˖-hbw+""ј;w.0qD 0?`ҤIX|9͛;ܹs ڶmM6}mh4l߾"0oD,];wQU}7BDDs0+*$;;Yvټ3gJED$++KHZZL2Ewn|nncǎIQQ8::˭ݏÇ 'O7778qHBBB} ),,%""QS=ύޢE h޼9zݻ_~(//Gnn.Fherh;$N< ^^xJy}O?GUIDDvvvؾ};كm۶/wlܸ|rkud2W^'|r[/N:Uw ;;;dggVۉU]RСC̘1iiipppݻSNqf7UVquuO<ggg?7xmoa$''#773g|>s0YMo>|Gؿ?N> 6 ??aaa>}:f͚ 8tVXsޱwy/_/ԩSضmz-TTT 'NĄ zj<<8qիW=@? y))))h`0(_aÆI>}fdff[}b h4b4y1112rHݻ̟?lpYzرc͒+ٺu2ݿ8p2}c`Qy7ضb 1׸qcYnOLLƍ+2qDe:%%Ej2$K,QYf""/TTT(۶ma'4[ Xǝ@gf&gKߧ[s=8::"007˃NS}!!!̙3~~~֭1}tL&4jV… ݻ]Pn]e:((gΜdgg#..+==]i///hZ,]fРAoۦKJJ\? OVCViӦy'*7\nqq1 33th4x7Ke7Ά^_ .T+QMgk9~0O3OQ `0ff7 8{,]ʂ?Yx1rrri&,] )) .\@-0tP[<}4ϠWii)}Fk=z4Μ9BĘ] PRRddd('339"$$$hZǎQVVj~9s&F#ۇ5k ** 9s 55"WD^^ xzzڵktDGG㫯Bbb"QXXx-**4 rss1gΜ*M6 ɓQ\\ ANNnZeADD<}wDdXbVB@@Zn wwwĠ֭M6!55 4@>}0~x 2pjo#GD>}`41e?V\۬Y3C||\]]1ee-Z_^ԩS1tPdee)8tN8,ZսyDDDdakU:).\D,[ :uA˖-EHHTeݨ(x{{ “O>={("Yf aaa7[lDw999pttD``4hbez޼yhڴ)Z-qa(...ODDDc cND  >z)))>}:V^+W@ףYf{LDDDDw>>>DLL Ν;Ʉ4\tׇd?>|&""c cNDfVZnAYY]ٳ'^u4o:СC5ELDDD5 DS EEEj(,,Ft8DDxlt/DDDDDDDVzvv6T*-È#зow.]0nܸ7ѣ`&"">6 PTDDDւ9TNDDDDDDTSUIn:4oDnPZZ Xb'|/k_GA޽VメC@i7LOиqc8::"00 Zl J.]6̘1h4=z4Ff0NNNر#~W1ڵ+^zPT1bY&L4hӧwLDDDLDD6Dٳg^Ν+YYYoɢEX-[&~z9uꔬ_^<<77WIEEE nukc!ʼ%KZ )))uʚ5kv(:NfϞ-""III@\bwDDtl^6mdĉwŖaF}gKDTqQoѢ^x4o=z@ѯ_?#77#GDtt|yy9ZJMMERRjmm'O^` /a߶ ...tQRR\ڵkС^n]mGgO?ٴ/.^XuQ|wDDT?A}!??aaa>}:}]h4 Ǖ+W0~zw|r <˗/&N &:t@~~>2220rHx{{''JO廙hȑ#1yd`ڴiE:u?Ox@̞=W^ȑ#AAAPTشiz gg;"HDDTȶs|:u*:u{n /'x;w`Ad2aС(..F֭?^z???̘1>|M 6 +W|}ZSL&SOQb9ȆYudΚ>XXX(nZN>-AAAGIvI~79qt]ի'!!!2ojw."z0|Y||KDΚ㏊Qa"ɫ*=z3gHEE8p@%((HBCCr1 ҤIyL<(#r,G(FQv-A;&Jb>\DDL&kNƏ/RPP ]tɓ' D- jߛ02уkk;wZ:<3 T2`8b 2:%%E4 e^||""2l0ӧ?~ܬLqrruիWVX!FF2/&&FF)""{盭.W~;vYR [nU/To H*#oVX!>>>f7n,֭򉉉Ҹqce:""왽)))V頠 Yd2 ͚5_~E<<}~~~|gʫ>F#^{5=gΜAaa!bbb "/PRRddd('339"$$$>>DLL Ν;Ʉ4\te۶m L:… 1|p~ӧOCDjagg{{{;v ۷oGYYVao߇ b̙0طo֬Y(@ll,̙T^yyy0 ? GGG۷k׮ (//Gaa!{_ 3gNզMb(.. ''[n "|{w̷DT@j*upwwGLL n[nݺشiRSSѠAǏǐ!CZF1rHFSL<==O?=&Yf(///xt/?Ftt4ի b0LpssâE0j(h4cUoZj#>> Î;kݹsbӦMh4믿^eqaƍ8s  jK/=DD1VjT=ȊjQ@c`뷮!" Xő/-#kE5QKDDS܉,,%%{4 BCC1fdgg[:4"""""F,Љ,hƍիwG;v@HH,U#^nEn\;1m)8,=R`ԨQ4iR߿cǎEFFt:LWGDlڄQfKqNd!ǏGvv]rѳgO 4Xd {j t" )((t:eތ3Z`ͨ_>ƌu"""C U,6=&,Љ,gϞUM6 z`4`BBBWQ5`Nd! ·~[2=++ 9:"""""n,Љ,DRa/󑑑ݻ7.^ŋvڵk1l0KNDDDDD t" ͛eBѠSNƼyP^=lݺ ĨQdtҡQc֬-=6qfFDTqYDDDDDDDV:`NDDDDDDdXYDDDDDDDV:`NDDDDDDdXYDDDDDDDV:`NDDDDDDdXYDDDDDDDV:`NDDDDDDdXY{K@%"" GBDDj_"͖/ t+R\\ p$DD(j-'_""` W%50L8{,ܠR,= Aqq1t:Ud5/QfK:_/DDDDDDDV:`n%/^  >,ve鐬Ν;+@ARᄈtHVg֬YhӦ 퍾}رc,YO?44 4 ڷo[Z:,7k,T*7ҡXӧCR4h`0l 5 |77n#-- :uB^piKfUJKKѢE ,\ҡX;vw޽{}v{(--thV1ߏGdd$222,_l2<Ӗ*5mΝS^tHtm ]ܭ@vЪU+,YD}b֬YzT*$&&o߾Ū;v@Ν-U9s0rHKbuJJJЪU+,^~!y̟?aYӧCzzCl8V=n_-h4"55ݻw7߽{wٳBQ(,,pGwVQQh߾ñJ^z%tҡX'N@ӡaÆ4hN:e>0,*gojTTTlΟ?oƏ;Yf:t۷ZD{9T*eۛ?D0m4oC s0݊:Q-ggg۷c֭xꩧ_I&8u`HOOW^޽{"rۼu޶dR~NСCq!n_|=#""$`" t"JB0c wN:ƍ6l| CJJټ={ ,,c{ꩧ N@@@bbba=,9nfoȲۇ?޽;o>#,, ӧOǻ F^z`0`r Ə㣏>B߾}1k,"-- :۷{gUVxqFlذ?}> Ǐѣ+W-3n8 r ~Ys0Ʋ9rDz!GGG /Bi_f<3 ՓΝ;ˆ lyEшnZۧ/^XBBBnݺ*W6{h6Oʊ+7JƍQ:u$?nP+5GGG_ :T n'=Dt+}\\BDDDDDDDA'"""""",Љ t"""""""+ @'"""""",Љ t"""""""+ @'"""""",Љ t"""""""+ @'"""""",ЉYչ*;IENDB`flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/src/000077500000000000000000000000001446715670500211245ustar00rootroot00000000000000flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/src/async.rs000066400000000000000000000416431446715670500226170ustar00rootroot00000000000000//! 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, 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 Hook { // 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 Sender { /// 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 { 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 { NotYetSent(T), QueuedItem(Arc>), } /// 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>, // Only none after dropping hook: Option>, } impl 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; 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 { 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>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 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 { &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 { 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 for SendSink<'a, T> { type Error = SendError; fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { 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> { Pin::new(&mut self.0).poll(cx) // TODO: A different strategy here? } fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { 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 Receiver { /// 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>, hook: Option>>, } impl<'a, T> RecvFut<'a, T> { fn new(receiver: OwnedOrRef<'a, Receiver>) -> 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; 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::().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> { 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 { 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; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 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 { 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> { 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() } } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/src/lib.rs000066400000000000000000001124071446715670500222450ustar00rootroot00000000000000//! # Flume //! //! A blazingly fast multi-producer, multi-consumer channel. //! //! *"Do not communicate by sharing memory; instead, share memory by communicating."* //! //! ## 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 //! //! ## Example //! //! ``` //! let (tx, rx) = flume::unbounded(); //! //! tx.send(42).unwrap(); //! assert_eq!(rx.recv().unwrap(), 42); //! ``` #![deny(missing_docs)] #[cfg(feature = "select")] pub mod select; #[cfg(feature = "async")] pub mod r#async; mod signal; // Reexports #[cfg(feature = "select")] pub use select::Selector; use std::{ collections::VecDeque, sync::{Arc, atomic::{AtomicUsize, AtomicBool, Ordering}, Weak}, time::{Duration, Instant}, marker::PhantomData, thread, fmt, }; #[cfg(feature = "spin")] use spin1::{Mutex as Spinlock, MutexGuard as SpinlockGuard}; use crate::signal::{Signal, SyncSignal}; /// An error that may be emitted when attempting to send a value into a channel on a sender when /// all receivers are dropped. #[derive(Copy, Clone, PartialEq, Eq)] pub struct SendError(pub T); impl SendError { /// Consume the error, yielding the message that failed to send. pub fn into_inner(self) -> T { self.0 } } impl fmt::Debug for SendError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { "SendError(..)".fmt(f) } } impl fmt::Display for SendError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { "sending on a closed channel".fmt(f) } } impl std::error::Error for SendError {} /// An error that may be emitted when attempting to send a value into a channel on a sender when /// the channel is full or all receivers are dropped. #[derive(Copy, Clone, PartialEq, Eq)] pub enum TrySendError { /// The channel the message is sent on has a finite capacity and was full when the send was attempted. Full(T), /// All channel receivers were dropped and so the message has nobody to receive it. Disconnected(T), } impl TrySendError { /// Consume the error, yielding the message that failed to send. pub fn into_inner(self) -> T { match self { Self::Full(msg) | Self::Disconnected(msg) => msg, } } } impl fmt::Debug for TrySendError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { TrySendError::Full(..) => "Full(..)".fmt(f), TrySendError::Disconnected(..) => "Disconnected(..)".fmt(f), } } } impl fmt::Display for TrySendError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { TrySendError::Full(..) => "sending on a full channel".fmt(f), TrySendError::Disconnected(..) => "sending on a closed channel".fmt(f), } } } impl std::error::Error for TrySendError {} impl From> for TrySendError { fn from(err: SendError) -> Self { match err { SendError(item) => Self::Disconnected(item), } } } /// An error that may be emitted when sending a value into a channel on a sender with a timeout when /// the send operation times out or all receivers are dropped. #[derive(Copy, Clone, PartialEq, Eq)] pub enum SendTimeoutError { /// A timeout occurred when attempting to send the message. Timeout(T), /// All channel receivers were dropped and so the message has nobody to receive it. Disconnected(T), } impl SendTimeoutError { /// Consume the error, yielding the message that failed to send. pub fn into_inner(self) -> T { match self { Self::Timeout(msg) | Self::Disconnected(msg) => msg, } } } impl fmt::Debug for SendTimeoutError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { "SendTimeoutError(..)".fmt(f) } } impl fmt::Display for SendTimeoutError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { SendTimeoutError::Timeout(..) => "timed out sending on a full channel".fmt(f), SendTimeoutError::Disconnected(..) => "sending on a closed channel".fmt(f), } } } impl std::error::Error for SendTimeoutError {} impl From> for SendTimeoutError { fn from(err: SendError) -> Self { match err { SendError(item) => Self::Disconnected(item), } } } enum TrySendTimeoutError { Full(T), Disconnected(T), Timeout(T), } /// An error that may be emitted when attempting to wait for a value on a receiver when all senders /// are dropped and there are no more messages in the channel. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum RecvError { /// All senders were dropped and no messages are waiting in the channel, so no further messages can be received. Disconnected, } impl fmt::Display for RecvError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { RecvError::Disconnected => "receiving on a closed channel".fmt(f), } } } impl std::error::Error for RecvError {} /// An error that may be emitted when attempting to fetch a value on a receiver when there are no /// messages in the channel. If there are no messages in the channel and all senders are dropped, /// then `TryRecvError::Disconnected` will be returned. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum TryRecvError { /// The channel was empty when the receive was attempted. Empty, /// All senders were dropped and no messages are waiting in the channel, so no further messages can be received. Disconnected, } impl fmt::Display for TryRecvError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { TryRecvError::Empty => "receiving on an empty channel".fmt(f), TryRecvError::Disconnected => "channel is empty and closed".fmt(f), } } } impl std::error::Error for TryRecvError {} impl From for TryRecvError { fn from(err: RecvError) -> Self { match err { RecvError::Disconnected => Self::Disconnected, } } } /// An error that may be emitted when attempting to wait for a value on a receiver with a timeout /// when the receive operation times out or all senders are dropped and there are no values left /// in the channel. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum RecvTimeoutError { /// A timeout occurred when attempting to receive a message. Timeout, /// All senders were dropped and no messages are waiting in the channel, so no further messages can be received. Disconnected, } impl fmt::Display for RecvTimeoutError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { RecvTimeoutError::Timeout => "timed out waiting on a channel".fmt(f), RecvTimeoutError::Disconnected => "channel is empty and closed".fmt(f), } } } impl std::error::Error for RecvTimeoutError {} impl From for RecvTimeoutError { fn from(err: RecvError) -> Self { match err { RecvError::Disconnected => Self::Disconnected, } } } enum TryRecvTimeoutError { Empty, Timeout, Disconnected, } // TODO: Investigate some sort of invalidation flag for timeouts #[cfg(feature = "spin")] struct Hook(Option>>, S); #[cfg(not(feature = "spin"))] struct Hook(Option>>, S); #[cfg(feature = "spin")] impl Hook { pub fn slot(msg: Option, signal: S) -> Arc where S: Sized, { Arc::new(Self(Some(Spinlock::new(msg)), signal)) } fn lock(&self) -> Option>> { self.0.as_ref().map(|s| s.lock()) } } #[cfg(not(feature = "spin"))] impl Hook { pub fn slot(msg: Option, signal: S) -> Arc where S: Sized, { Arc::new(Self(Some(Mutex::new(msg)), signal)) } fn lock(&self) -> Option>> { self.0.as_ref().map(|s| s.lock().unwrap()) } } impl Hook { pub fn fire_recv(&self) -> (T, &S) { let msg = self.lock().unwrap().take().unwrap(); (msg, self.signal()) } pub fn fire_send(&self, msg: T) -> (Option, &S) { let ret = match self.lock() { Some(mut lock) => { *lock = Some(msg); None } None => Some(msg), }; (ret, self.signal()) } pub fn is_empty(&self) -> bool { self.lock().map(|s| s.is_none()).unwrap_or(true) } pub fn try_take(&self) -> Option { self.lock().unwrap().take() } pub fn trigger(signal: S) -> Arc where S: Sized, { Arc::new(Self(None, signal)) } pub fn signal(&self) -> &S { &self.1 } pub fn fire_nothing(&self) -> bool { self.signal().fire() } } impl Hook { pub fn wait_recv(&self, abort: &AtomicBool) -> Option { loop { let disconnected = abort.load(Ordering::SeqCst); // Check disconnect *before* msg let msg = self.lock().unwrap().take(); if let Some(msg) = msg { break Some(msg); } else if disconnected { break None; } else { self.signal().wait() } } } // Err(true) if timeout pub fn wait_deadline_recv(&self, abort: &AtomicBool, deadline: Instant) -> Result { loop { let disconnected = abort.load(Ordering::SeqCst); // Check disconnect *before* msg let msg = self.lock().unwrap().take(); if let Some(msg) = msg { break Ok(msg); } else if disconnected { break Err(false); } else if let Some(dur) = deadline.checked_duration_since(Instant::now()) { self.signal().wait_timeout(dur); } else { break Err(true); } } } pub fn wait_send(&self, abort: &AtomicBool) { loop { let disconnected = abort.load(Ordering::SeqCst); // Check disconnect *before* msg if disconnected || self.lock().unwrap().is_none() { break; } self.signal().wait(); } } // Err(true) if timeout pub fn wait_deadline_send(&self, abort: &AtomicBool, deadline: Instant) -> Result<(), bool> { loop { let disconnected = abort.load(Ordering::SeqCst); // Check disconnect *before* msg if self.lock().unwrap().is_none() { break Ok(()); } else if disconnected { break Err(false); } else if let Some(dur) = deadline.checked_duration_since(Instant::now()) { self.signal().wait_timeout(dur); } else { break Err(true); } } } } #[cfg(feature = "spin")] #[inline] fn wait_lock(lock: &Spinlock) -> SpinlockGuard { let mut i = 4; loop { for _ in 0..10 { if let Some(guard) = lock.try_lock() { return guard; } thread::yield_now(); } // Sleep for at most ~1 ms thread::sleep(Duration::from_nanos(1 << i.min(20))); i += 1; } } #[cfg(not(feature = "spin"))] #[inline] fn wait_lock<'a, T>(lock: &'a Mutex) -> MutexGuard<'a, T> { lock.lock().unwrap() } #[cfg(not(feature = "spin"))] use std::sync::{Mutex, MutexGuard}; #[cfg(feature = "spin")] type ChanLock = Spinlock; #[cfg(not(feature = "spin"))] type ChanLock = Mutex; type SignalVec = VecDeque>>; struct Chan { sending: Option<(usize, SignalVec)>, queue: VecDeque, waiting: SignalVec, } impl Chan { fn pull_pending(&mut self, pull_extra: bool) { if let Some((cap, sending)) = &mut self.sending { let effective_cap = *cap + pull_extra as usize; while self.queue.len() < effective_cap { if let Some(s) = sending.pop_front() { let (msg, signal) = s.fire_recv(); signal.fire(); self.queue.push_back(msg); } else { break; } } } } fn try_wake_receiver_if_pending(&mut self) { if !self.queue.is_empty() { while Some(false) == self.waiting.pop_front().map(|s| s.fire_nothing()) {} } } } struct Shared { chan: ChanLock>, disconnected: AtomicBool, sender_count: AtomicUsize, receiver_count: AtomicUsize, } impl Shared { fn new(cap: Option) -> Self { Self { chan: ChanLock::new(Chan { sending: cap.map(|cap| (cap, VecDeque::new())), queue: VecDeque::new(), waiting: VecDeque::new(), }), disconnected: AtomicBool::new(false), sender_count: AtomicUsize::new(1), receiver_count: AtomicUsize::new(1), } } fn send>>>( &self, msg: T, should_block: bool, make_signal: impl FnOnce(T) -> Arc>, do_block: impl FnOnce(Arc>) -> R, ) -> R { let mut chan = wait_lock(&self.chan); if self.is_disconnected() { Err(TrySendTimeoutError::Disconnected(msg)).into() } else if !chan.waiting.is_empty() { let mut msg = Some(msg); loop { let slot = chan.waiting.pop_front(); match slot.as_ref().map(|r| r.fire_send(msg.take().unwrap())) { // No more waiting receivers and msg in queue, so break out of the loop None if msg.is_none() => break, // No more waiting receivers, so add msg to queue and break out of the loop None => { chan.queue.push_back(msg.unwrap()); break; } Some((Some(m), signal)) => { if signal.fire() { // Was async and a stream, so didn't acquire the message. Wake another // receiver, and do not yet push the message. msg.replace(m); continue; } else { // Was async and not a stream, so it did acquire the message. Push the // message to the queue for it to be received. chan.queue.push_back(m); drop(chan); break; } }, Some((None, signal)) => { drop(chan); signal.fire(); break; // Was sync, so it has acquired the message }, } } Ok(()).into() } else if chan.sending.as_ref().map(|(cap, _)| chan.queue.len() < *cap).unwrap_or(true) { chan.queue.push_back(msg); Ok(()).into() } else if should_block { // Only bounded from here on let hook = make_signal(msg); chan.sending.as_mut().unwrap().1.push_back(hook.clone()); drop(chan); do_block(hook) } else { Err(TrySendTimeoutError::Full(msg)).into() } } fn send_sync( &self, msg: T, block: Option>, ) -> Result<(), TrySendTimeoutError> { self.send( // msg msg, // should_block block.is_some(), // make_signal |msg| Hook::slot(Some(msg), SyncSignal::default()), // do_block |hook| if let Some(deadline) = block.unwrap() { hook.wait_deadline_send(&self.disconnected, deadline) .or_else(|timed_out| { if timed_out { // Remove our signal let hook: Arc> = hook.clone(); wait_lock(&self.chan).sending .as_mut() .unwrap().1 .retain(|s| s.signal().as_ptr() != hook.signal().as_ptr()); } hook.try_take().map(|msg| if self.is_disconnected() { Err(TrySendTimeoutError::Disconnected(msg)) } else { Err(TrySendTimeoutError::Timeout(msg)) }) .unwrap_or(Ok(())) }) } else { hook.wait_send(&self.disconnected); match hook.try_take() { Some(msg) => Err(TrySendTimeoutError::Disconnected(msg)), None => Ok(()), } }, ) } fn recv>>( &self, should_block: bool, make_signal: impl FnOnce() -> Arc>, do_block: impl FnOnce(Arc>) -> R, ) -> R { let mut chan = wait_lock(&self.chan); chan.pull_pending(true); if let Some(msg) = chan.queue.pop_front() { drop(chan); Ok(msg).into() } else if self.is_disconnected() { drop(chan); Err(TryRecvTimeoutError::Disconnected).into() } else if should_block { let hook = make_signal(); chan.waiting.push_back(hook.clone()); drop(chan); do_block(hook) } else { drop(chan); Err(TryRecvTimeoutError::Empty).into() } } fn recv_sync(&self, block: Option>) -> Result { self.recv( // should_block block.is_some(), // make_signal || Hook::slot(None, SyncSignal::default()), // do_block |hook| if let Some(deadline) = block.unwrap() { hook.wait_deadline_recv(&self.disconnected, deadline) .or_else(|timed_out| { if timed_out { // Remove our signal let hook: Arc> = hook.clone(); wait_lock(&self.chan).waiting .retain(|s| s.signal().as_ptr() != hook.signal().as_ptr()); } match hook.try_take() { Some(msg) => Ok(msg), None => { let disconnected = self.is_disconnected(); // Check disconnect *before* msg if let Some(msg) = wait_lock(&self.chan).queue.pop_front() { Ok(msg) } else if disconnected { Err(TryRecvTimeoutError::Disconnected) } else { Err(TryRecvTimeoutError::Timeout) } }, } }) } else { hook.wait_recv(&self.disconnected) .or_else(|| wait_lock(&self.chan).queue.pop_front()) .ok_or(TryRecvTimeoutError::Disconnected) }, ) } /// Disconnect anything listening on this channel (this will not prevent receivers receiving /// msgs that have already been sent) fn disconnect_all(&self) { self.disconnected.store(true, Ordering::Relaxed); let mut chan = wait_lock(&self.chan); chan.pull_pending(false); if let Some((_, sending)) = chan.sending.as_ref() { sending.iter().for_each(|hook| { hook.signal().fire(); }) } chan.waiting.iter().for_each(|hook| { hook.signal().fire(); }); } fn is_disconnected(&self) -> bool { self.disconnected.load(Ordering::SeqCst) } fn is_empty(&self) -> bool { self.len() == 0 } fn is_full(&self) -> bool { self.capacity().map(|cap| cap == self.len()).unwrap_or(false) } fn len(&self) -> usize { let mut chan = wait_lock(&self.chan); chan.pull_pending(false); chan.queue.len() } fn capacity(&self) -> Option { wait_lock(&self.chan).sending.as_ref().map(|(cap, _)| *cap) } fn sender_count(&self) -> usize { self.sender_count.load(Ordering::Relaxed) } fn receiver_count(&self) -> usize { self.receiver_count.load(Ordering::Relaxed) } } /// A transmitting end of a channel. pub struct Sender { shared: Arc>, } impl Sender { /// Attempt to send a value into the channel. If the channel is bounded and full, or all /// receivers have been dropped, an error is returned. If the channel associated with this /// sender is unbounded, this method has the same behaviour as [`Sender::send`]. pub fn try_send(&self, msg: T) -> Result<(), TrySendError> { self.shared.send_sync(msg, None).map_err(|err| match err { TrySendTimeoutError::Full(msg) => TrySendError::Full(msg), TrySendTimeoutError::Disconnected(msg) => TrySendError::Disconnected(msg), _ => unreachable!(), }) } /// Send a value into the channel, returning an error if all receivers have been dropped. /// If the channel is bounded and is full, this method will block until space is available /// or all receivers have been dropped. If the channel is unbounded, this method will not /// block. pub fn send(&self, msg: T) -> Result<(), SendError> { self.shared.send_sync(msg, Some(None)).map_err(|err| match err { TrySendTimeoutError::Disconnected(msg) => SendError(msg), _ => unreachable!(), }) } /// Send a value into the channel, returning an error if all receivers have been dropped /// or the deadline has passed. If the channel is bounded and is full, this method will /// block until space is available, the deadline is reached, or all receivers have been /// dropped. pub fn send_deadline(&self, msg: T, deadline: Instant) -> Result<(), SendTimeoutError> { self.shared.send_sync(msg, Some(Some(deadline))).map_err(|err| match err { TrySendTimeoutError::Disconnected(msg) => SendTimeoutError::Disconnected(msg), TrySendTimeoutError::Timeout(msg) => SendTimeoutError::Timeout(msg), _ => unreachable!(), }) } /// Send a value into the channel, returning an error if all receivers have been dropped /// or the timeout has expired. If the channel is bounded and is full, this method will /// block until space is available, the timeout has expired, or all receivers have been /// dropped. pub fn send_timeout(&self, msg: T, dur: Duration) -> Result<(), SendTimeoutError> { self.send_deadline(msg, Instant::now().checked_add(dur).unwrap()) } /// Returns true if all receivers for this channel have been dropped. pub fn is_disconnected(&self) -> bool { self.shared.is_disconnected() } /// Returns true if the channel is empty. /// Note: Zero-capacity channels are always empty. pub fn is_empty(&self) -> bool { self.shared.is_empty() } /// Returns true if the channel is full. /// Note: Zero-capacity channels are always full. pub fn is_full(&self) -> bool { self.shared.is_full() } /// Returns the number of messages in the channel pub fn len(&self) -> usize { self.shared.len() } /// If the channel is bounded, returns its capacity. pub fn capacity(&self) -> Option { self.shared.capacity() } /// Get the number of senders that currently exist, including this one. pub fn sender_count(&self) -> usize { self.shared.sender_count() } /// Get the number of receivers that currently exist. /// /// Note that this method makes no guarantees that a subsequent send will succeed; it's /// possible that between `receiver_count()` being called and a `send()`, all open receivers /// could drop. pub fn receiver_count(&self) -> usize { self.shared.receiver_count() } /// Creates a [`WeakSender`] that does not keep the channel open. /// /// The channel is closed once all `Sender`s are dropped, even if there /// are still active `WeakSender`s. pub fn downgrade(&self) -> WeakSender { WeakSender { shared: Arc::downgrade(&self.shared), } } /// Returns whether the senders are belong to the same channel. pub fn same_channel(&self, other: &Sender) -> bool { Arc::ptr_eq(&self.shared, &other.shared) } } impl Clone for Sender { /// Clone this sender. [`Sender`] acts as a handle to the ending a channel. Remaining channel /// contents will only be cleaned up when all senders and the receiver have been dropped. fn clone(&self) -> Self { self.shared.sender_count.fetch_add(1, Ordering::Relaxed); Self { shared: self.shared.clone() } } } impl fmt::Debug for Sender { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Sender").finish() } } impl Drop for Sender { fn drop(&mut self) { // Notify receivers that all senders have been dropped if the number of senders drops to 0. if self.shared.sender_count.fetch_sub(1, Ordering::Relaxed) == 1 { self.shared.disconnect_all(); } } } /// A sender that does not prevent the channel from being closed. /// /// Weak senders do not count towards the number of active senders on the channel. As soon as /// all normal [`Sender`]s are dropped, the channel is closed, even if there is still a /// `WeakSender`. /// /// To send messages, a `WeakSender` must first be upgraded to a `Sender` using the [`upgrade`] /// method. pub struct WeakSender { shared: Weak>, } impl WeakSender { /// Tries to upgrade the `WeakSender` to a [`Sender`], in order to send messages. /// /// Returns `None` if the channel was closed already. Note that a `Some` return value /// does not guarantee that the channel is still open. pub fn upgrade(&self) -> Option> { self.shared .upgrade() // check that there are still live senders .filter(|shared| { shared .sender_count .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |count| { if count == 0 { // all senders are closed already -> don't increase the sender count None } else { // there is still at least one active sender Some(count + 1) } }) .is_ok() }) .map(|shared| Sender { shared }) } } /// The receiving end of a channel. /// /// Note: Cloning the receiver *does not* turn this channel into a broadcast channel. /// Each message will only be received by a single receiver. This is useful for /// implementing work stealing for concurrent programs. pub struct Receiver { shared: Arc>, } impl Receiver { /// Attempt to fetch an incoming value from the channel associated with this receiver, /// returning an error if the channel is empty or if all senders have been dropped. pub fn try_recv(&self) -> Result { self.shared.recv_sync(None).map_err(|err| match err { TryRecvTimeoutError::Disconnected => TryRecvError::Disconnected, TryRecvTimeoutError::Empty => TryRecvError::Empty, _ => unreachable!(), }) } /// Wait for an incoming value from the channel associated with this receiver, returning an /// error if all senders have been dropped. pub fn recv(&self) -> Result { self.shared.recv_sync(Some(None)).map_err(|err| match err { TryRecvTimeoutError::Disconnected => RecvError::Disconnected, _ => unreachable!(), }) } /// Wait for an incoming value from the channel associated with this receiver, returning an /// error if all senders have been dropped or the deadline has passed. pub fn recv_deadline(&self, deadline: Instant) -> Result { self.shared.recv_sync(Some(Some(deadline))).map_err(|err| match err { TryRecvTimeoutError::Disconnected => RecvTimeoutError::Disconnected, TryRecvTimeoutError::Timeout => RecvTimeoutError::Timeout, _ => unreachable!(), }) } /// Wait for an incoming value from the channel associated with this receiver, returning an /// error if all senders have been dropped or the timeout has expired. pub fn recv_timeout(&self, dur: Duration) -> Result { self.recv_deadline(Instant::now().checked_add(dur).unwrap()) } /// Create a blocking iterator over the values received on the channel that finishes iteration /// when all senders have been dropped. /// /// You can also create a self-owned iterator with [`Receiver::into_iter`]. pub fn iter(&self) -> Iter { Iter { receiver: &self } } /// A non-blocking iterator over the values received on the channel that finishes iteration /// when all senders have been dropped or the channel is empty. pub fn try_iter(&self) -> TryIter { TryIter { receiver: &self } } /// Take all msgs currently sitting in the channel and produce an iterator over them. Unlike /// `try_iter`, the iterator will not attempt to fetch any more values from the channel once /// the function has been called. pub fn drain(&self) -> Drain { let mut chan = wait_lock(&self.shared.chan); chan.pull_pending(false); let queue = std::mem::take(&mut chan.queue); Drain { queue, _phantom: PhantomData } } /// Returns true if all senders for this channel have been dropped. pub fn is_disconnected(&self) -> bool { self.shared.is_disconnected() } /// Returns true if the channel is empty. /// Note: Zero-capacity channels are always empty. pub fn is_empty(&self) -> bool { self.shared.is_empty() } /// Returns true if the channel is full. /// Note: Zero-capacity channels are always full. pub fn is_full(&self) -> bool { self.shared.is_full() } /// Returns the number of messages in the channel. pub fn len(&self) -> usize { self.shared.len() } /// If the channel is bounded, returns its capacity. pub fn capacity(&self) -> Option { self.shared.capacity() } /// Get the number of senders that currently exist. pub fn sender_count(&self) -> usize { self.shared.sender_count() } /// Get the number of receivers that currently exist, including this one. pub fn receiver_count(&self) -> usize { self.shared.receiver_count() } /// Returns whether the receivers are belong to the same channel. pub fn same_channel(&self, other: &Receiver) -> bool { Arc::ptr_eq(&self.shared, &other.shared) } } impl Clone for Receiver { /// Clone this receiver. [`Receiver`] acts as a handle to the ending a channel. Remaining /// channel contents will only be cleaned up when all senders and the receiver have been /// dropped. /// /// Note: Cloning the receiver *does not* turn this channel into a broadcast channel. /// Each message will only be received by a single receiver. This is useful for /// implementing work stealing for concurrent programs. fn clone(&self) -> Self { self.shared.receiver_count.fetch_add(1, Ordering::Relaxed); Self { shared: self.shared.clone() } } } impl fmt::Debug for Receiver { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Receiver").finish() } } impl Drop for Receiver { fn drop(&mut self) { // Notify senders that all receivers have been dropped if the number of receivers drops // to 0. if self.shared.receiver_count.fetch_sub(1, Ordering::Relaxed) == 1 { self.shared.disconnect_all(); } } } /// This exists as a shorthand for [`Receiver::iter`]. impl<'a, T> IntoIterator for &'a Receiver { type Item = T; type IntoIter = Iter<'a, T>; fn into_iter(self) -> Self::IntoIter { Iter { receiver: self } } } impl IntoIterator for Receiver { type Item = T; type IntoIter = IntoIter; /// Creates a self-owned but semantically equivalent alternative to [`Receiver::iter`]. fn into_iter(self) -> Self::IntoIter { IntoIter { receiver: self } } } /// An iterator over the msgs received from a channel. pub struct Iter<'a, T> { receiver: &'a Receiver, } impl<'a, T> Iterator for Iter<'a, T> { type Item = T; fn next(&mut self) -> Option { self.receiver.recv().ok() } } /// An non-blocking iterator over the msgs received from a channel. pub struct TryIter<'a, T> { receiver: &'a Receiver, } impl<'a, T> Iterator for TryIter<'a, T> { type Item = T; fn next(&mut self) -> Option { self.receiver.try_recv().ok() } } /// An fixed-sized iterator over the msgs drained from a channel. #[derive(Debug)] pub struct Drain<'a, T> { queue: VecDeque, /// A phantom field used to constrain the lifetime of this iterator. We do this because the /// implementation may change and we don't want to unintentionally constrain it. Removing this /// lifetime later is a possibility. _phantom: PhantomData<&'a ()>, } impl<'a, T> Iterator for Drain<'a, T> { type Item = T; fn next(&mut self) -> Option { self.queue.pop_front() } } impl<'a, T> ExactSizeIterator for Drain<'a, T> { fn len(&self) -> usize { self.queue.len() } } /// An owned iterator over the msgs received from a channel. pub struct IntoIter { receiver: Receiver, } impl Iterator for IntoIter { type Item = T; fn next(&mut self) -> Option { self.receiver.recv().ok() } } /// Create a channel with no maximum capacity. /// /// Create an unbounded channel with a [`Sender`] and [`Receiver`] connected to each end respectively. Values sent in /// one end of the channel will be received on the other end. The channel is thread-safe, and both [`Sender`] and /// [`Receiver`] may be sent to or shared between threads as necessary. In addition, both [`Sender`] and [`Receiver`] /// may be cloned. /// /// # Examples /// ``` /// let (tx, rx) = flume::unbounded(); /// /// tx.send(42).unwrap(); /// assert_eq!(rx.recv().unwrap(), 42); /// ``` pub fn unbounded() -> (Sender, Receiver) { let shared = Arc::new(Shared::new(None)); ( Sender { shared: shared.clone() }, Receiver { shared }, ) } /// Create a channel with a maximum capacity. /// /// Create a bounded channel with a [`Sender`] and [`Receiver`] connected to each end respectively. Values sent in one /// end of the channel will be received on the other end. The channel is thread-safe, and both [`Sender`] and /// [`Receiver`] may be sent to or shared between threads as necessary. In addition, both [`Sender`] and [`Receiver`] /// may be cloned. /// /// Unlike an [`unbounded`] channel, if there is no space left for new messages, calls to /// [`Sender::send`] will block (unblocking once a receiver has made space). If blocking behaviour /// is not desired, [`Sender::try_send`] may be used. /// /// Like `std::sync::mpsc`, `flume` supports 'rendezvous' channels. A bounded queue with a maximum capacity of zero /// will block senders until a receiver is available to take the value. You can imagine a rendezvous channel as a /// ['Glienicke Bridge'](https://en.wikipedia.org/wiki/Glienicke_Bridge)-style location at which senders and receivers /// perform a handshake and transfer ownership of a value. /// /// # Examples /// ``` /// let (tx, rx) = flume::bounded(32); /// /// for i in 1..33 { /// tx.send(i).unwrap(); /// } /// assert!(tx.try_send(33).is_err()); /// /// assert_eq!(rx.try_iter().sum::(), (1..33).sum()); /// ``` pub fn bounded(cap: usize) -> (Sender, Receiver) { let shared = Arc::new(Shared::new(Some(cap))); ( Sender { shared: shared.clone() }, Receiver { shared }, ) } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/src/select.rs000066400000000000000000000316131446715670500227550ustar00rootroot00000000000000//! 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>>, ); 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; fn poll(&mut self) -> Option; 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 + 'a>>, next_poll: usize, signalled: Arc>>, #[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>) -> T + 'a>( mut self, sender: &'a Sender, msg: U, mapper: F, ) -> Self { struct SendSelection<'a, T, F, U> { sender: &'a Sender, msg: Option, token: Token, signalled: Arc>>, hook: Option>>, mapper: F, phantom: PhantomData, } impl<'a, T, F, U> Selection<'a, T> for SendSelection<'a, T, F, U> where F: FnMut(Result<(), SendError>) -> T, { fn init(&mut self) -> Option { 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 { 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; 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) -> T + 'a>( mut self, receiver: &'a Receiver, mapper: F, ) -> Self { struct RecvSelection<'a, T, F, U> { receiver: &'a Receiver, token: Token, signalled: Arc>>, hook: Option>>, mapper: F, received: bool, phantom: PhantomData, } impl<'a, T, F, U> Selection<'a, T> for RecvSelection<'a, T, F, U> where F: FnMut(Result) -> T, { fn init(&mut self) -> Option { 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 { 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; 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::() .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) -> Option { #[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 { 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 { 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 { self.wait_inner(Some(deadline)).ok_or(SelectError::Timeout) } } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/src/signal.rs000066400000000000000000000020241446715670500227450ustar00rootroot00000000000000use 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); } } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/tests/000077500000000000000000000000001446715670500214775ustar00rootroot00000000000000flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/tests/after.rs000066400000000000000000000207011446715670500231460ustar00rootroot00000000000000// //! 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::>(); // 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::>(); // 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)); // } // } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/tests/array.rs000066400000000000000000000352211446715670500231660ustar00rootroot00000000000000//! 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::(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::(3); let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); 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::(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; let (s, r) = bounded::(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::>>() .unwrap() .take() .unwrap() } }); }) .unwrap(); } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/tests/async.rs000066400000000000000000000151741446715670500231720ustar00rootroot00000000000000#[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::(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::(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::>(); 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, 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) { for i in 0..100 { tx.send_async(i).await.unwrap(); } } async fn consumer(rx: flume::Receiver) { 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()); } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/tests/basic.rs000066400000000000000000000226661446715670500231420ustar00rootroot00000000000000use 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::(), (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::(), (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::(), (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::(), (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::(), (0..10000).sum::() * 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::(); 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()); } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/tests/check_same_channel.rs000066400000000000000000000023511446715670500256200ustar00rootroot00000000000000#[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)); } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/tests/golang.rs000066400000000000000000001200331446715670500233130ustar00rootroot00000000000000// //! Tests copied from Go and manually rewritten in Rust. // //! // //! Source: // //! - https://github.com/golang/go // //! // //! Copyright & License: // //! - Copyright (c) 2009 The Go Authors // //! - https://golang.org/AUTHORS // //! - https://golang.org/LICENSE // //! - https://golang.org/PATENTS // use std::any::Any; // use std::cell::Cell; // use std::collections::HashMap; // use std::sync::{Arc, Condvar, Mutex}; // use std::thread; // use std::time::Duration; // use flume::{bounded, tick, Receiver, Select, Sender}; // fn ms(ms: u64) -> Duration { // Duration::from_millis(ms) // } // struct Chan { // inner: Arc>>, // } // struct ChanInner { // s: Option>, // r: Receiver, // } // impl Clone for Chan { // fn clone(&self) -> Chan { // Chan { // inner: self.inner.clone(), // } // } // } // impl Chan { // fn send(&self, msg: T) { // let s = self // .inner // .lock() // .unwrap() // .s // .as_ref() // .expect("sending into closed channel") // .clone(); // let _ = s.send(msg); // } // fn try_recv(&self) -> Option { // let r = self.inner.lock().unwrap().r.clone(); // r.try_recv().ok() // } // fn recv(&self) -> Option { // let r = self.inner.lock().unwrap().r.clone(); // r.recv().ok() // } // fn close(&self) { // self.inner // .lock() // .unwrap() // .s // .take() // .expect("channel already closed"); // } // fn rx(&self) -> Receiver { // self.inner.lock().unwrap().r.clone() // } // fn tx(&self) -> Sender { // match self.inner.lock().unwrap().s.as_ref() { // None => { // let (s, r) = bounded(0); // std::mem::forget(r); // s // } // Some(s) => s.clone(), // } // } // } // impl Iterator for Chan { // type Item = T; // fn next(&mut self) -> Option { // self.recv() // } // } // impl<'a, T> IntoIterator for &'a Chan { // type Item = T; // type IntoIter = Chan; // fn into_iter(self) -> Self::IntoIter { // self.clone() // } // } // fn make(cap: usize) -> Chan { // let (s, r) = bounded(cap); // Chan { // inner: Arc::new(Mutex::new(ChanInner { s: Some(s), r })), // } // } // #[derive(Clone)] // struct WaitGroup(Arc); // struct WaitGroupInner { // cond: Condvar, // count: Mutex, // } // impl WaitGroup { // fn new() -> WaitGroup { // WaitGroup(Arc::new(WaitGroupInner { // cond: Condvar::new(), // count: Mutex::new(0), // })) // } // fn add(&self, delta: i32) { // let mut count = self.0.count.lock().unwrap(); // *count += delta; // assert!(*count >= 0); // self.0.cond.notify_all(); // } // fn done(&self) { // self.add(-1); // } // fn wait(&self) { // let mut count = self.0.count.lock().unwrap(); // while *count > 0 { // count = self.0.cond.wait(count).unwrap(); // } // } // } // struct Defer { // f: Option>, // } // impl Drop for Defer { // fn drop(&mut self) { // let f = self.f.take().unwrap(); // let mut f = Some(f); // let mut f = move || f.take().unwrap()(); // f(); // } // } // macro_rules! defer { // ($body:expr) => { // let _defer = Defer { // f: Some(Box::new(|| $body)), // }; // }; // } // macro_rules! go { // (@parse ref $v:ident, $($tail:tt)*) => {{ // let ref $v = $v; // go!(@parse $($tail)*) // }}; // (@parse move $v:ident, $($tail:tt)*) => {{ // let $v = $v; // go!(@parse $($tail)*) // }}; // (@parse $v:ident, $($tail:tt)*) => {{ // let $v = $v.clone(); // go!(@parse $($tail)*) // }}; // (@parse $body:expr) => { // ::std::thread::spawn(move || { // let res = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| { // $body // })); // if res.is_err() { // eprintln!("goroutine panicked: {:?}", res); // ::std::process::abort(); // } // }) // }; // (@parse $($tail:tt)*) => { // compile_error!("invalid `go!` syntax") // }; // ($($tail:tt)*) => {{ // go!(@parse $($tail)*) // }}; // } // // https://github.com/golang/go/blob/master/test/chan/doubleselect.go // mod doubleselect { // use super::*; // const ITERATIONS: i32 = 10_000; // fn sender(n: i32, c1: Chan, c2: Chan, c3: Chan, c4: Chan) { // defer! { c1.close() } // defer! { c2.close() } // defer! { c3.close() } // defer! { c4.close() } // for i in 0..n { // select! { // send(c1.tx(), i) -> _ => {} // send(c2.tx(), i) -> _ => {} // send(c3.tx(), i) -> _ => {} // send(c4.tx(), i) -> _ => {} // } // } // } // fn mux(out: Chan, inp: Chan, done: Chan) { // for v in inp { // out.send(v); // } // done.send(true); // } // fn recver(inp: Chan) { // let mut seen = HashMap::new(); // for v in &inp { // if seen.contains_key(&v) { // panic!("got duplicate value for {}", v); // } // seen.insert(v, true); // } // } // #[test] // fn main() { // let c1 = make::(0); // let c2 = make::(0); // let c3 = make::(0); // let c4 = make::(0); // let done = make::(0); // let cmux = make::(0); // go!(c1, c2, c3, c4, sender(ITERATIONS, c1, c2, c3, c4)); // go!(cmux, c1, done, mux(cmux, c1, done)); // go!(cmux, c2, done, mux(cmux, c2, done)); // go!(cmux, c3, done, mux(cmux, c3, done)); // go!(cmux, c4, done, mux(cmux, c4, done)); // go!(done, cmux, { // done.recv(); // done.recv(); // done.recv(); // done.recv(); // cmux.close(); // }); // recver(cmux); // } // } // // https://github.com/golang/go/blob/master/test/chan/fifo.go // mod fifo { // use super::*; // const N: i32 = 10; // #[test] // fn asynch_fifo() { // let ch = make::(N as usize); // for i in 0..N { // ch.send(i); // } // for i in 0..N { // if ch.recv() != Some(i) { // panic!("bad receive"); // } // } // } // fn chain(ch: Chan, val: i32, inp: Chan, out: Chan) { // inp.recv(); // if ch.recv() != Some(val) { // panic!(val); // } // out.send(1); // } // #[test] // fn synch_fifo() { // let ch = make::(0); // let mut inp = make::(0); // let start = inp.clone(); // for i in 0..N { // let out = make::(0); // go!(ch, i, inp, out, chain(ch, i, inp, out)); // inp = out; // } // start.send(0); // for i in 0..N { // ch.send(i); // } // inp.recv(); // } // } // // https://github.com/golang/go/blob/master/test/chan/goroutines.go // mod goroutines { // use super::*; // fn f(left: Chan, right: Chan) { // left.send(right.recv().unwrap()); // } // #[test] // fn main() { // let n = 100i32; // let leftmost = make::(0); // let mut right = leftmost.clone(); // let mut left = leftmost.clone(); // for _ in 0..n { // right = make::(0); // go!(left, right, f(left, right)); // left = right.clone(); // } // go!(right, right.send(1)); // leftmost.recv().unwrap(); // } // } // // https://github.com/golang/go/blob/master/test/chan/nonblock.go // mod nonblock { // use super::*; // fn i32receiver(c: Chan, strobe: Chan) { // if c.recv().unwrap() != 123 { // panic!("i32 value"); // } // strobe.send(true); // } // fn i32sender(c: Chan, strobe: Chan) { // c.send(234); // strobe.send(true); // } // fn i64receiver(c: Chan, strobe: Chan) { // if c.recv().unwrap() != 123456 { // panic!("i64 value"); // } // strobe.send(true); // } // fn i64sender(c: Chan, strobe: Chan) { // c.send(234567); // strobe.send(true); // } // fn breceiver(c: Chan, strobe: Chan) { // if !c.recv().unwrap() { // panic!("b value"); // } // strobe.send(true); // } // fn bsender(c: Chan, strobe: Chan) { // c.send(true); // strobe.send(true); // } // fn sreceiver(c: Chan, strobe: Chan) { // if c.recv().unwrap() != "hello" { // panic!("x value"); // } // strobe.send(true); // } // fn ssender(c: Chan, strobe: Chan) { // c.send("hello again".to_string()); // strobe.send(true); // } // const MAX_TRIES: usize = 10000; // Up to 100ms per test. // #[test] // fn main() { // let ticker = tick(Duration::new(0, 10_000)); // 10 us // let sleep = || { // ticker.recv().unwrap(); // ticker.recv().unwrap(); // thread::yield_now(); // thread::yield_now(); // thread::yield_now(); // }; // let sync = make::(0); // for buffer in 0..2 { // let c32 = make::(buffer); // let c64 = make::(buffer); // let cb = make::(buffer); // let cs = make::(buffer); // select! { // recv(c32.rx()) -> _ => panic!("blocked i32sender"), // default => {} // } // select! { // recv(c64.rx()) -> _ => panic!("blocked i64sender"), // default => {} // } // select! { // recv(cb.rx()) -> _ => panic!("blocked bsender"), // default => {} // } // select! { // recv(cs.rx()) -> _ => panic!("blocked ssender"), // default => {} // } // go!(c32, sync, i32receiver(c32, sync)); // let mut try = 0; // loop { // select! { // send(c32.tx(), 123) -> _ => break, // default => { // try += 1; // if try > MAX_TRIES { // println!("i32receiver buffer={}", buffer); // panic!("fail") // } // sleep(); // } // } // } // sync.recv(); // go!(c32, sync, i32sender(c32, sync)); // if buffer > 0 { // sync.recv(); // } // let mut try = 0; // loop { // select! { // recv(c32.rx()) -> v => { // if v != Ok(234) { // panic!("i32sender value"); // } // break; // } // default => { // try += 1; // if try > MAX_TRIES { // println!("i32sender buffer={}", buffer); // panic!("fail"); // } // sleep(); // } // } // } // if buffer == 0 { // sync.recv(); // } // go!(c64, sync, i64receiver(c64, sync)); // let mut try = 0; // loop { // select! { // send(c64.tx(), 123456) -> _ => break, // default => { // try += 1; // if try > MAX_TRIES { // println!("i64receiver buffer={}", buffer); // panic!("fail") // } // sleep(); // } // } // } // sync.recv(); // go!(c64, sync, i64sender(c64, sync)); // if buffer > 0 { // sync.recv(); // } // let mut try = 0; // loop { // select! { // recv(c64.rx()) -> v => { // if v != Ok(234567) { // panic!("i64sender value"); // } // break; // } // default => { // try += 1; // if try > MAX_TRIES { // println!("i64sender buffer={}", buffer); // panic!("fail"); // } // sleep(); // } // } // } // if buffer == 0 { // sync.recv(); // } // go!(cb, sync, breceiver(cb, sync)); // let mut try = 0; // loop { // select! { // send(cb.tx(), true) -> _ => break, // default => { // try += 1; // if try > MAX_TRIES { // println!("breceiver buffer={}", buffer); // panic!("fail") // } // sleep(); // } // } // } // sync.recv(); // go!(cb, sync, bsender(cb, sync)); // if buffer > 0 { // sync.recv(); // } // let mut try = 0; // loop { // select! { // recv(cb.rx()) -> v => { // if v != Ok(true) { // panic!("bsender value"); // } // break; // } // default => { // try += 1; // if try > MAX_TRIES { // println!("bsender buffer={}", buffer); // panic!("fail"); // } // sleep(); // } // } // } // if buffer == 0 { // sync.recv(); // } // go!(cs, sync, sreceiver(cs, sync)); // let mut try = 0; // loop { // select! { // send(cs.tx(), "hello".to_string()) -> _ => break, // default => { // try += 1; // if try > MAX_TRIES { // println!("sreceiver buffer={}", buffer); // panic!("fail") // } // sleep(); // } // } // } // sync.recv(); // go!(cs, sync, ssender(cs, sync)); // if buffer > 0 { // sync.recv(); // } // let mut try = 0; // loop { // select! { // recv(cs.rx()) -> v => { // if v != Ok("hello again".to_string()) { // panic!("ssender value"); // } // break; // } // default => { // try += 1; // if try > MAX_TRIES { // println!("ssender buffer={}", buffer); // panic!("fail"); // } // sleep(); // } // } // } // if buffer == 0 { // sync.recv(); // } // } // } // } // // https://github.com/golang/go/blob/master/test/chan/select.go // mod select { // use super::*; // #[test] // fn main() { // let shift = Cell::new(0); // let counter = Cell::new(0); // let get_value = || { // counter.set(counter.get() + 1); // 1 << shift.get() // }; // let send = |mut a: Option<&Chan>, mut b: Option<&Chan>| { // let mut i = 0; // let never = make::(0); // loop { // let nil1 = never.tx(); // let nil2 = never.tx(); // let v1 = get_value(); // let v2 = get_value(); // select! { // send(a.map(|c| c.tx()).unwrap_or(nil1), v1) -> _ => { // i += 1; // a = None; // } // send(b.map(|c| c.tx()).unwrap_or(nil2), v2) -> _ => { // i += 1; // b = None; // } // default => break, // } // shift.set(shift.get() + 1); // } // i // }; // let a = make::(1); // let b = make::(1); // assert_eq!(send(Some(&a), Some(&b)), 2); // let av = a.recv().unwrap(); // let bv = b.recv().unwrap(); // assert_eq!(av | bv, 3); // assert_eq!(send(Some(&a), None), 1); // assert_eq!(counter.get(), 10); // } // } // // https://github.com/golang/go/blob/master/test/chan/select2.go // mod select2 { // // TODO // } // // https://github.com/golang/go/blob/master/test/chan/select3.go // mod select3 { // // TODO // } // // https://github.com/golang/go/blob/master/test/chan/select4.go // mod select4 { // use super::*; // #[test] // fn main() { // let c = make::(1); // let c1 = make::(0); // c.send(42); // select! { // recv(c1.rx()) -> _ => panic!("BUG"), // recv(c.rx()) -> v => assert_eq!(v, Ok(42)), // } // } // } // // https://github.com/golang/go/blob/master/test/chan/select6.go // mod select6 { // use super::*; // #[test] // fn main() { // let c1 = make::(0); // let c2 = make::(0); // let c3 = make::(0); // go!(c1, c1.recv()); // go!(c1, c2, c3, { // select! { // recv(c1.rx()) -> _ => panic!("dummy"), // recv(c2.rx()) -> _ => c3.send(true), // } // c1.recv(); // }); // go!(c2, c2.send(true)); // c3.recv(); // c1.send(true); // c1.send(true); // } // } // // https://github.com/golang/go/blob/master/test/chan/select7.go // mod select7 { // use super::*; // fn recv1(c: Chan) { // c.recv().unwrap(); // } // fn recv2(c: Chan) { // select! { // recv(c.rx()) -> _ => () // } // } // fn recv3(c: Chan) { // let c2 = make::(1); // select! { // recv(c.rx()) -> _ => (), // recv(c2.rx()) -> _ => () // } // } // fn send1(recv: fn(Chan)) { // let c = make::(1); // go!(c, recv(c)); // thread::yield_now(); // c.send(1); // } // fn send2(recv: fn(Chan)) { // let c = make::(1); // go!(c, recv(c)); // thread::yield_now(); // select! { // send(c.tx(), 1) -> _ => () // } // } // fn send3(recv: fn(Chan)) { // let c = make::(1); // go!(c, recv(c)); // thread::yield_now(); // let c2 = make::(1); // select! { // send(c.tx(), 1) -> _ => (), // send(c2.tx(), 1) -> _ => () // } // } // #[test] // fn main() { // send1(recv1); // send2(recv1); // send3(recv1); // send1(recv2); // send2(recv2); // send3(recv2); // send1(recv3); // send2(recv3); // send3(recv3); // } // } // // https://github.com/golang/go/blob/master/test/chan/sieve1.go // mod sieve1 { // use super::*; // fn generate(ch: Chan) { // let mut i = 2; // loop { // ch.send(i); // i += 1; // } // } // fn filter(in_ch: Chan, out_ch: Chan, prime: i32) { // for i in in_ch { // if i % prime != 0 { // out_ch.send(i); // } // } // } // fn sieve(primes: Chan) { // let mut ch = make::(1); // go!(ch, generate(ch)); // loop { // let prime = ch.recv().unwrap(); // primes.send(prime); // let ch1 = make::(1); // go!(ch, ch1, prime, filter(ch, ch1, prime)); // ch = ch1; // } // } // #[test] // fn main() { // let primes = make::(1); // go!(primes, sieve(primes)); // let a = [ // 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, // 89, 97, // ]; // for item in a.iter() { // let x = primes.recv().unwrap(); // if x != *item { // println!("{} != {}", x, item); // panic!("fail"); // } // } // } // } // // https://github.com/golang/go/blob/master/test/chan/zerosize.go // mod zerosize { // use super::*; // #[test] // fn zero_size_struct() { // struct ZeroSize; // let _ = make::(0); // } // #[test] // fn zero_size_array() { // let _ = make::<[u8; 0]>(0); // } // } // // https://github.com/golang/go/blob/master/src/runtime/chan_test.go // mod chan_test { // use super::*; // #[test] // fn test_chan() { // const N: i32 = 200; // for cap in 0..N { // { // // Ensure that receive from empty chan blocks. // let c = make::(cap as usize); // let recv1 = Arc::new(Mutex::new(false)); // go!(c, recv1, { // c.recv(); // *recv1.lock().unwrap() = true; // }); // let recv2 = Arc::new(Mutex::new(false)); // go!(c, recv2, { // c.recv(); // *recv2.lock().unwrap() = true; // }); // thread::sleep(ms(1)); // if *recv1.lock().unwrap() || *recv2.lock().unwrap() { // panic!(); // } // // Ensure that non-blocking receive does not block. // select! { // recv(c.rx()) -> _ => panic!(), // default => {} // } // select! { // recv(c.rx()) -> _ => panic!(), // default => {} // } // c.send(0); // c.send(0); // } // { // // Ensure that send to full chan blocks. // let c = make::(cap as usize); // for i in 0..cap { // c.send(i); // } // let sent = Arc::new(Mutex::new(0)); // go!(sent, c, { // c.send(0); // *sent.lock().unwrap() = 1; // }); // thread::sleep(ms(1)); // if *sent.lock().unwrap() != 0 { // panic!(); // } // // Ensure that non-blocking send does not block. // select! { // send(c.tx(), 0) -> _ => panic!(), // default => {} // } // c.recv(); // } // { // // Ensure that we receive 0 from closed chan. // let c = make::(cap as usize); // for i in 0..cap { // c.send(i); // } // c.close(); // for i in 0..cap { // let v = c.recv(); // if v != Some(i) { // panic!(); // } // } // if c.recv() != None { // panic!(); // } // if c.try_recv() != None { // panic!(); // } // } // { // // Ensure that close unblocks receive. // let c = make::(cap as usize); // let done = make::(0); // go!(c, done, { // let v = c.try_recv(); // done.send(v.is_some()); // }); // thread::sleep(ms(1)); // c.close(); // if !done.recv().unwrap() { // // panic!(); // } // } // { // // Send 100 integers, // // ensure that we receive them non-corrupted in FIFO order. // let c = make::(cap as usize); // go!(c, { // for i in 0..100 { // c.send(i); // } // }); // for i in 0..100 { // if c.recv() != Some(i) { // panic!(); // } // } // // Same, but using recv2. // go!(c, { // for i in 0..100 { // c.send(i); // } // }); // for i in 0..100 { // if c.recv() != Some(i) { // panic!(); // } // } // } // } // } // #[test] // fn test_nonblock_recv_race() { // const N: usize = 1000; // for _ in 0..N { // let c = make::(1); // c.send(1); // let t = go!(c, { // select! { // recv(c.rx()) -> _ => {} // default => panic!("chan is not ready"), // } // }); // c.close(); // c.recv(); // t.join().unwrap(); // } // } // #[test] // fn test_nonblock_select_race() { // const N: usize = 1000; // let done = make::(1); // for _ in 0..N { // let c1 = make::(1); // let c2 = make::(1); // c1.send(1); // go!(c1, c2, done, { // select! { // recv(c1.rx()) -> _ => {} // recv(c2.rx()) -> _ => {} // default => { // done.send(false); // return; // } // } // done.send(true); // }); // c2.send(1); // select! { // recv(c1.rx()) -> _ => {} // default => {} // } // if !done.recv().unwrap() { // panic!("no chan is ready"); // } // } // } // #[test] // fn test_nonblock_select_race2() { // const N: usize = 1000; // let done = make::(1); // for _ in 0..N { // let c1 = make::(1); // let c2 = make::(0); // c1.send(1); // go!(c1, c2, done, { // select! { // recv(c1.rx()) -> _ => {} // recv(c2.rx()) -> _ => {} // default => { // done.send(false); // return; // } // } // done.send(true); // }); // c2.close(); // select! { // recv(c1.rx()) -> _ => {} // default => {} // } // if !done.recv().unwrap() { // panic!("no chan is ready"); // } // } // } // #[test] // fn test_self_select() { // // Ensure that send/recv on the same chan in select // // does not crash nor deadlock. // for &cap in &[0, 10] { // let wg = WaitGroup::new(); // wg.add(2); // let c = make::(cap); // for p in 0..2 { // let p = p; // go!(wg, p, c, { // defer! { wg.done() } // for i in 0..1000 { // if p == 0 || i % 2 == 0 { // select! { // send(c.tx(), p) -> _ => {} // recv(c.rx()) -> v => { // if cap == 0 && v.ok() == Some(p) { // panic!("self receive"); // } // } // } // } else { // select! { // recv(c.rx()) -> v => { // if cap == 0 && v.ok() == Some(p) { // panic!("self receive"); // } // } // send(c.tx(), p) -> _ => {} // } // } // } // }); // } // wg.wait(); // } // } // #[test] // fn test_select_stress() { // let c = vec![ // make::(0), // make::(0), // make::(2), // make::(3), // ]; // const N: usize = 10000; // // There are 4 goroutines that send N values on each of the chans, // // + 4 goroutines that receive N values on each of the chans, // // + 1 goroutine that sends N values on each of the chans in a single select, // // + 1 goroutine that receives N values on each of the chans in a single select. // // All these sends, receives and selects interact chaotically at runtime, // // but we are careful that this whole construct does not deadlock. // let wg = WaitGroup::new(); // wg.add(10); // for k in 0..4 { // go!(k, c, wg, { // for _ in 0..N { // c[k].send(0); // } // wg.done(); // }); // go!(k, c, wg, { // for _ in 0..N { // c[k].recv(); // } // wg.done(); // }); // } // go!(c, wg, { // let mut n = [0; 4]; // let mut c1 = c.iter().map(|c| Some(c.rx().clone())).collect::>(); // for _ in 0..4 * N { // let index = { // let mut sel = Select::new(); // let mut opers = [!0; 4]; // for &i in &[3, 2, 0, 1] { // if let Some(c) = &c1[i] { // opers[i] = sel.recv(c); // } // } // let oper = sel.select(); // let mut index = !0; // for i in 0..4 { // if opers[i] == oper.index() { // index = i; // let _ = oper.recv(c1[i].as_ref().unwrap()); // break; // } // } // index // }; // n[index] += 1; // if n[index] == N { // c1[index] = None; // } // } // wg.done(); // }); // go!(c, wg, { // let mut n = [0; 4]; // let mut c1 = c.iter().map(|c| Some(c.tx().clone())).collect::>(); // for _ in 0..4 * N { // let index = { // let mut sel = Select::new(); // let mut opers = [!0; 4]; // for &i in &[0, 1, 2, 3] { // if let Some(c) = &c1[i] { // opers[i] = sel.send(c); // } // } // let oper = sel.select(); // let mut index = !0; // for i in 0..4 { // if opers[i] == oper.index() { // index = i; // let _ = oper.send(c1[i].as_ref().unwrap(), 0); // break; // } // } // index // }; // n[index] += 1; // if n[index] == N { // c1[index] = None; // } // } // wg.done(); // }); // wg.wait(); // } // #[test] // fn test_select_fairness() { // const TRIALS: usize = 10000; // let c1 = make::(TRIALS + 1); // let c2 = make::(TRIALS + 1); // for _ in 0..TRIALS + 1 { // c1.send(1); // c2.send(2); // } // let c3 = make::(0); // let c4 = make::(0); // let out = make::(0); // let done = make::(0); // let wg = WaitGroup::new(); // wg.add(1); // go!(wg, c1, c2, c3, c4, out, done, { // defer! { wg.done() }; // loop { // let b; // select! { // recv(c3.rx()) -> m => b = m.unwrap(), // recv(c4.rx()) -> m => b = m.unwrap(), // recv(c1.rx()) -> m => b = m.unwrap(), // recv(c2.rx()) -> m => b = m.unwrap(), // } // select! { // send(out.tx(), b) -> _ => {} // recv(done.rx()) -> _ => return, // } // } // }); // let (mut cnt1, mut cnt2) = (0, 0); // for _ in 0..TRIALS { // match out.recv() { // Some(1) => cnt1 += 1, // Some(2) => cnt2 += 1, // b => panic!("unexpected value {:?} on channel", b), // } // } // // If the select in the goroutine is fair, // // cnt1 and cnt2 should be about the same value. // // With 10,000 trials, the expected margin of error at // // a confidence level of five nines is 4.4172 / (2 * Sqrt(10000)). // let r = cnt1 as f64 / TRIALS as f64; // let e = (r - 0.5).abs(); // if e > 4.4172 / (2.0 * (TRIALS as f64).sqrt()) { // panic!( // "unfair select: in {} trials, results were {}, {}", // TRIALS, cnt1, cnt2, // ); // } // done.close(); // wg.wait(); // } // #[test] // fn test_chan_send_interface() { // struct Mt; // let c = make::>(1); // c.send(Box::new(Mt)); // select! { // send(c.tx(), Box::new(Mt)) -> _ => {} // default => {} // } // select! { // send(c.tx(), Box::new(Mt)) -> _ => {} // send(c.tx(), Box::new(Mt)) -> _ => {} // default => {} // } // } // #[test] // fn test_pseudo_random_send() { // const N: usize = 100; // for cap in 0..N { // let c = make::(cap); // let l = Arc::new(Mutex::new(vec![0i32; N])); // let done = make::(0); // go!(c, done, l, { // let mut l = l.lock().unwrap(); // for i in 0..N { // thread::yield_now(); // l[i] = c.recv().unwrap(); // } // done.send(true); // }); // for _ in 0..N { // select! { // send(c.tx(), 1) -> _ => {} // send(c.tx(), 0) -> _ => {} // } // } // done.recv(); // let mut n0 = 0; // let mut n1 = 0; // for &i in l.lock().unwrap().iter() { // n0 += (i + 1) % 2; // n1 += i; // } // if n0 <= N as i32 / 10 || n1 <= N as i32 / 10 { // panic!( // "Want pseudorandom, got {} zeros and {} ones (chan cap {})", // n0, n1, cap, // ); // } // } // } // #[test] // fn test_multi_consumer() { // const NWORK: usize = 23; // const NITER: usize = 271828; // let pn = [2, 3, 7, 11, 13, 17, 19, 23, 27, 31]; // let q = make::(NWORK * 3); // let r = make::(NWORK * 3); // let wg = WaitGroup::new(); // for i in 0..NWORK { // wg.add(1); // let w = i; // go!(q, r, wg, pn, { // for v in &q { // if pn[w % pn.len()] == v { // thread::yield_now(); // } // r.send(v); // } // wg.done(); // }); // } // let expect = Arc::new(Mutex::new(0)); // go!(q, r, expect, wg, pn, { // for i in 0..NITER { // let v = pn[i % pn.len()]; // *expect.lock().unwrap() += v; // q.send(v); // } // q.close(); // wg.wait(); // r.close(); // }); // let mut n = 0; // let mut s = 0; // for v in &r { // n += 1; // s += v; // } // if n != NITER || s != *expect.lock().unwrap() { // panic!(); // } // } // #[test] // fn test_select_duplicate_channel() { // // This test makes sure we can queue a G on // // the same channel multiple times. // let c = make::(0); // let d = make::(0); // let e = make::(0); // go!(c, d, e, { // select! { // recv(c.rx()) -> _ => {} // recv(d.rx()) -> _ => {} // recv(e.rx()) -> _ => {} // } // e.send(9); // }); // thread::sleep(ms(1)); // go!(c, c.recv()); // thread::sleep(ms(1)); // d.send(7); // e.recv(); // c.send(8); // } // } // // https://github.com/golang/go/blob/master/test/closedchan.go // mod closedchan { // // TODO // } // // https://github.com/golang/go/blob/master/src/runtime/chanbarrier_test.go // mod chanbarrier_test { // // TODO // } // // https://github.com/golang/go/blob/master/src/runtime/race/testdata/chan_test.go // mod race_chan_test { // // TODO // } // // https://github.com/golang/go/blob/master/test/ken/chan.go // mod chan { // // TODO // } // // https://github.com/golang/go/blob/master/test/ken/chan1.go // mod chan1 { // // TODO // } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/tests/iter.rs000066400000000000000000000047231446715670500230160ustar00rootroot00000000000000//! 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::(); let (total_s, total_r) = unbounded::(); 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::(); 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::(); 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::(); 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); } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/tests/list.rs000066400000000000000000000270201446715670500230210ustar00rootroot00000000000000//! 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::(); 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::(); let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); 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::(); 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; let (s, r) = unbounded::(); 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::>>() .unwrap() .take() .unwrap() } }); }) .unwrap(); } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/tests/method_sharing.rs000066400000000000000000000030471446715670500250440ustar00rootroot00000000000000#[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()); } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/tests/mpsc.rs000066400000000000000000001533561446715670500230240ustar00rootroot00000000000000//! Tests copied from `std::sync::mpsc`. //! //! This is a copy of tests for the `std::sync::mpsc` channels from the standard library, but //! modified to work with `crossbeam-channel` instead. //! //! Minor tweaks were needed to make the tests compile: //! //! - Replace `box` syntax with `Box::new`. //! - Replace all uses of `Select` with `select!`. //! - Change the imports. //! - Join all spawned threads. //! - Removed assertion from oneshot_multi_thread_send_close_stress tests. //! //! Source: //! - https://github.com/rust-lang/rust/tree/master/src/libstd/sync/mpsc //! //! Copyright & License: //! - Copyright 2013-2014 The Rust Project Developers //! - Apache License, Version 2.0 or MIT license, at your option //! - https://github.com/rust-lang/rust/blob/master/COPYRIGHT //! - https://www.rust-lang.org/en-US/legal.html #[macro_use] extern crate crossbeam_channel as cc; use std::sync::mpsc::{RecvError, RecvTimeoutError, TryRecvError}; use std::sync::mpsc::{SendError, TrySendError}; use std::thread::JoinHandle; use std::time::Duration; pub struct Sender { pub inner: cc::Sender, } impl Sender { pub fn send(&self, t: T) -> Result<(), SendError> { self.inner.send(t).map_err(|cc::SendError(m)| SendError(m)) } } impl Clone for Sender { fn clone(&self) -> Sender { Sender { inner: self.inner.clone(), } } } pub struct SyncSender { pub inner: cc::Sender, } impl SyncSender { pub fn send(&self, t: T) -> Result<(), SendError> { self.inner.send(t).map_err(|cc::SendError(m)| SendError(m)) } pub fn try_send(&self, t: T) -> Result<(), TrySendError> { self.inner.try_send(t).map_err(|err| match err { cc::TrySendError::Full(m) => TrySendError::Full(m), cc::TrySendError::Disconnected(m) => TrySendError::Disconnected(m), }) } } impl Clone for SyncSender { fn clone(&self) -> SyncSender { SyncSender { inner: self.inner.clone(), } } } pub struct Receiver { pub inner: cc::Receiver, } impl Receiver { pub fn try_recv(&self) -> Result { self.inner.try_recv().map_err(|err| match err { cc::TryRecvError::Empty => TryRecvError::Empty, cc::TryRecvError::Disconnected => TryRecvError::Disconnected, }) } pub fn recv(&self) -> Result { self.inner.recv().map_err(|_| RecvError) } pub fn recv_timeout(&self, timeout: Duration) -> Result { self.inner.recv_timeout(timeout).map_err(|err| match err { cc::RecvTimeoutError::Timeout => RecvTimeoutError::Timeout, cc::RecvTimeoutError::Disconnected => RecvTimeoutError::Disconnected, }) } pub fn iter(&self) -> Iter { Iter { inner: self } } pub fn try_iter(&self) -> TryIter { TryIter { inner: self } } } impl<'a, T> IntoIterator for &'a Receiver { type Item = T; type IntoIter = Iter<'a, T>; fn into_iter(self) -> Iter<'a, T> { self.iter() } } impl IntoIterator for Receiver { type Item = T; type IntoIter = IntoIter; fn into_iter(self) -> IntoIter { IntoIter { inner: self } } } pub struct TryIter<'a, T: 'a> { inner: &'a Receiver, } impl<'a, T> Iterator for TryIter<'a, T> { type Item = T; fn next(&mut self) -> Option { self.inner.try_recv().ok() } } pub struct Iter<'a, T: 'a> { inner: &'a Receiver, } impl<'a, T> Iterator for Iter<'a, T> { type Item = T; fn next(&mut self) -> Option { self.inner.recv().ok() } } pub struct IntoIter { inner: Receiver, } impl Iterator for IntoIter { type Item = T; fn next(&mut self) -> Option { self.inner.recv().ok() } } pub fn channel() -> (Sender, Receiver) { let (s, r) = cc::unbounded(); let s = Sender { inner: s }; let r = Receiver { inner: r }; (s, r) } pub fn sync_channel(bound: usize) -> (SyncSender, Receiver) { let (s, r) = cc::bounded(bound); let s = SyncSender { inner: s }; let r = Receiver { inner: r }; (s, r) } macro_rules! select { ( $($name:pat = $rx:ident.$meth:ident() => $code:expr),+ ) => ({ crossbeam_channel_internal! { $( recv(($rx).inner) -> res => { let $name = res.map_err(|_| ::std::sync::mpsc::RecvError); $code } )+ } }) } // Source: https://github.com/rust-lang/rust/blob/master/src/libstd/sync/mpsc/mod.rs mod channel_tests { use super::*; use std::env; use std::thread; use std::time::{Duration, Instant}; pub fn stress_factor() -> usize { match env::var("RUST_TEST_STRESS") { Ok(val) => val.parse().unwrap(), Err(..) => 1, } } #[test] fn smoke() { let (tx, rx) = channel::(); tx.send(1).unwrap(); assert_eq!(rx.recv().unwrap(), 1); } #[test] fn drop_full() { let (tx, _rx) = channel::>(); tx.send(Box::new(1)).unwrap(); } #[test] fn drop_full_shared() { let (tx, _rx) = channel::>(); drop(tx.clone()); drop(tx.clone()); tx.send(Box::new(1)).unwrap(); } #[test] fn smoke_shared() { let (tx, rx) = channel::(); tx.send(1).unwrap(); assert_eq!(rx.recv().unwrap(), 1); let tx = tx.clone(); tx.send(1).unwrap(); assert_eq!(rx.recv().unwrap(), 1); } #[test] fn smoke_threads() { let (tx, rx) = channel::(); let t = thread::spawn(move || { tx.send(1).unwrap(); }); assert_eq!(rx.recv().unwrap(), 1); t.join().unwrap(); } #[test] fn smoke_port_gone() { let (tx, rx) = channel::(); drop(rx); assert!(tx.send(1).is_err()); } #[test] fn smoke_shared_port_gone() { let (tx, rx) = channel::(); drop(rx); assert!(tx.send(1).is_err()) } #[test] fn smoke_shared_port_gone2() { let (tx, rx) = channel::(); drop(rx); let tx2 = tx.clone(); drop(tx); assert!(tx2.send(1).is_err()); } #[test] fn port_gone_concurrent() { let (tx, rx) = channel::(); let t = thread::spawn(move || { rx.recv().unwrap(); }); while tx.send(1).is_ok() {} t.join().unwrap(); } #[test] fn port_gone_concurrent_shared() { let (tx, rx) = channel::(); let tx2 = tx.clone(); let t = thread::spawn(move || { rx.recv().unwrap(); }); while tx.send(1).is_ok() && tx2.send(1).is_ok() {} t.join().unwrap(); } #[test] fn smoke_chan_gone() { let (tx, rx) = channel::(); drop(tx); assert!(rx.recv().is_err()); } #[test] fn smoke_chan_gone_shared() { let (tx, rx) = channel::<()>(); let tx2 = tx.clone(); drop(tx); drop(tx2); assert!(rx.recv().is_err()); } #[test] fn chan_gone_concurrent() { let (tx, rx) = channel::(); let t = thread::spawn(move || { tx.send(1).unwrap(); tx.send(1).unwrap(); }); while rx.recv().is_ok() {} t.join().unwrap(); } #[test] fn stress() { let (tx, rx) = channel::(); let t = thread::spawn(move || { for _ in 0..10000 { tx.send(1).unwrap(); } }); for _ in 0..10000 { assert_eq!(rx.recv().unwrap(), 1); } t.join().ok().unwrap(); } #[test] fn stress_shared() { const AMT: u32 = 10000; const NTHREADS: u32 = 8; let (tx, rx) = channel::(); let t = thread::spawn(move || { for _ in 0..AMT * NTHREADS { assert_eq!(rx.recv().unwrap(), 1); } match rx.try_recv() { Ok(..) => panic!(), _ => {} } }); let mut ts = Vec::with_capacity(NTHREADS as usize); for _ in 0..NTHREADS { let tx = tx.clone(); let t = thread::spawn(move || { for _ in 0..AMT { tx.send(1).unwrap(); } }); ts.push(t); } drop(tx); t.join().ok().unwrap(); for t in ts { t.join().unwrap(); } } #[test] fn send_from_outside_runtime() { let (tx1, rx1) = channel::<()>(); let (tx2, rx2) = channel::(); let t1 = thread::spawn(move || { tx1.send(()).unwrap(); for _ in 0..40 { assert_eq!(rx2.recv().unwrap(), 1); } }); rx1.recv().unwrap(); let t2 = thread::spawn(move || { for _ in 0..40 { tx2.send(1).unwrap(); } }); t1.join().ok().unwrap(); t2.join().ok().unwrap(); } #[test] fn recv_from_outside_runtime() { let (tx, rx) = channel::(); let t = thread::spawn(move || { for _ in 0..40 { assert_eq!(rx.recv().unwrap(), 1); } }); for _ in 0..40 { tx.send(1).unwrap(); } t.join().ok().unwrap(); } #[test] fn no_runtime() { let (tx1, rx1) = channel::(); let (tx2, rx2) = channel::(); let t1 = thread::spawn(move || { assert_eq!(rx1.recv().unwrap(), 1); tx2.send(2).unwrap(); }); let t2 = thread::spawn(move || { tx1.send(1).unwrap(); assert_eq!(rx2.recv().unwrap(), 2); }); t1.join().ok().unwrap(); t2.join().ok().unwrap(); } #[test] fn oneshot_single_thread_close_port_first() { // Simple test of closing without sending let (_tx, rx) = channel::(); drop(rx); } #[test] fn oneshot_single_thread_close_chan_first() { // Simple test of closing without sending let (tx, _rx) = channel::(); drop(tx); } #[test] fn oneshot_single_thread_send_port_close() { // Testing that the sender cleans up the payload if receiver is closed let (tx, rx) = channel::>(); drop(rx); assert!(tx.send(Box::new(0)).is_err()); } #[test] fn oneshot_single_thread_recv_chan_close() { let (tx, rx) = channel::(); drop(tx); assert_eq!(rx.recv(), Err(RecvError)); } #[test] fn oneshot_single_thread_send_then_recv() { let (tx, rx) = channel::>(); tx.send(Box::new(10)).unwrap(); assert!(*rx.recv().unwrap() == 10); } #[test] fn oneshot_single_thread_try_send_open() { let (tx, rx) = channel::(); assert!(tx.send(10).is_ok()); assert!(rx.recv().unwrap() == 10); } #[test] fn oneshot_single_thread_try_send_closed() { let (tx, rx) = channel::(); drop(rx); assert!(tx.send(10).is_err()); } #[test] fn oneshot_single_thread_try_recv_open() { let (tx, rx) = channel::(); tx.send(10).unwrap(); assert!(rx.recv() == Ok(10)); } #[test] fn oneshot_single_thread_try_recv_closed() { let (tx, rx) = channel::(); drop(tx); assert!(rx.recv().is_err()); } #[test] fn oneshot_single_thread_peek_data() { let (tx, rx) = channel::(); assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); tx.send(10).unwrap(); assert_eq!(rx.try_recv(), Ok(10)); } #[test] fn oneshot_single_thread_peek_close() { let (tx, rx) = channel::(); drop(tx); assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); } #[test] fn oneshot_single_thread_peek_open() { let (_tx, rx) = channel::(); assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); } #[test] fn oneshot_multi_task_recv_then_send() { let (tx, rx) = channel::>(); let t = thread::spawn(move || { assert!(*rx.recv().unwrap() == 10); }); tx.send(Box::new(10)).unwrap(); t.join().unwrap(); } #[test] fn oneshot_multi_task_recv_then_close() { let (tx, rx) = channel::>(); let t = thread::spawn(move || { drop(tx); }); thread::spawn(move || { assert_eq!(rx.recv(), Err(RecvError)); }) .join() .unwrap(); t.join().unwrap(); } #[test] fn oneshot_multi_thread_close_stress() { let stress_factor = stress_factor(); let mut ts = Vec::with_capacity(stress_factor); for _ in 0..stress_factor { let (tx, rx) = channel::(); let t = thread::spawn(move || { drop(rx); }); ts.push(t); drop(tx); } for t in ts { t.join().unwrap(); } } #[test] fn oneshot_multi_thread_send_close_stress() { let stress_factor = stress_factor(); let mut ts = Vec::with_capacity(2 * stress_factor); for _ in 0..stress_factor { let (tx, rx) = channel::(); let t = thread::spawn(move || { drop(rx); }); ts.push(t); thread::spawn(move || { let _ = tx.send(1); }) .join() .unwrap(); } for t in ts { t.join().unwrap(); } } #[test] fn oneshot_multi_thread_recv_close_stress() { let stress_factor = stress_factor(); let mut ts = Vec::with_capacity(2 * stress_factor); for _ in 0..stress_factor { let (tx, rx) = channel::(); let t = thread::spawn(move || { thread::spawn(move || { assert_eq!(rx.recv(), Err(RecvError)); }) .join() .unwrap(); }); ts.push(t); let t2 = thread::spawn(move || { let t = thread::spawn(move || { drop(tx); }); t.join().unwrap(); }); ts.push(t2); } for t in ts { t.join().unwrap(); } } #[test] fn oneshot_multi_thread_send_recv_stress() { let stress_factor = stress_factor(); let mut ts = Vec::with_capacity(stress_factor); for _ in 0..stress_factor { let (tx, rx) = channel::>(); let t = thread::spawn(move || { tx.send(Box::new(10)).unwrap(); }); ts.push(t); assert!(*rx.recv().unwrap() == 10); } for t in ts { t.join().unwrap(); } } #[test] fn stream_send_recv_stress() { let stress_factor = stress_factor(); let mut ts = Vec::with_capacity(2 * stress_factor); for _ in 0..stress_factor { let (tx, rx) = channel(); if let Some(t) = send(tx, 0) { ts.push(t); } if let Some(t2) = recv(rx, 0) { ts.push(t2); } fn send(tx: Sender>, i: i32) -> Option> { if i == 10 { return None; } Some(thread::spawn(move || { tx.send(Box::new(i)).unwrap(); send(tx, i + 1); })) } fn recv(rx: Receiver>, i: i32) -> Option> { if i == 10 { return None; } Some(thread::spawn(move || { assert!(*rx.recv().unwrap() == i); recv(rx, i + 1); })) } } for t in ts { t.join().unwrap(); } } #[test] fn oneshot_single_thread_recv_timeout() { let (tx, rx) = channel(); tx.send(()).unwrap(); assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); assert_eq!( rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout) ); tx.send(()).unwrap(); assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); } #[test] fn stress_recv_timeout_two_threads() { let (tx, rx) = channel(); let stress = stress_factor() + 100; let timeout = Duration::from_millis(100); let t = thread::spawn(move || { for i in 0..stress { if i % 2 == 0 { thread::sleep(timeout * 2); } tx.send(1usize).unwrap(); } }); let mut recv_count = 0; loop { match rx.recv_timeout(timeout) { Ok(n) => { assert_eq!(n, 1usize); recv_count += 1; } Err(RecvTimeoutError::Timeout) => continue, Err(RecvTimeoutError::Disconnected) => break, } } assert_eq!(recv_count, stress); t.join().unwrap() } #[test] fn recv_timeout_upgrade() { let (tx, rx) = channel::<()>(); let timeout = Duration::from_millis(1); let _tx_clone = tx.clone(); let start = Instant::now(); assert_eq!(rx.recv_timeout(timeout), Err(RecvTimeoutError::Timeout)); assert!(Instant::now() >= start + timeout); } #[test] fn stress_recv_timeout_shared() { let (tx, rx) = channel(); let stress = stress_factor() + 100; let mut ts = Vec::with_capacity(stress); for i in 0..stress { let tx = tx.clone(); let t = thread::spawn(move || { thread::sleep(Duration::from_millis(i as u64 * 10)); tx.send(1usize).unwrap(); }); ts.push(t); } drop(tx); let mut recv_count = 0; loop { match rx.recv_timeout(Duration::from_millis(10)) { Ok(n) => { assert_eq!(n, 1usize); recv_count += 1; } Err(RecvTimeoutError::Timeout) => continue, Err(RecvTimeoutError::Disconnected) => break, } } assert_eq!(recv_count, stress); for t in ts { t.join().unwrap(); } } #[test] fn recv_a_lot() { // Regression test that we don't run out of stack in scheduler context let (tx, rx) = channel(); for _ in 0..10000 { tx.send(()).unwrap(); } for _ in 0..10000 { rx.recv().unwrap(); } } #[test] fn shared_recv_timeout() { let (tx, rx) = channel(); let total = 5; let mut ts = Vec::with_capacity(total); for _ in 0..total { let tx = tx.clone(); let t = thread::spawn(move || { tx.send(()).unwrap(); }); ts.push(t); } for _ in 0..total { rx.recv().unwrap(); } assert_eq!( rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout) ); tx.send(()).unwrap(); assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); for t in ts { t.join().unwrap(); } } #[test] fn shared_chan_stress() { let (tx, rx) = channel(); let total = stress_factor() + 100; let mut ts = Vec::with_capacity(total); for _ in 0..total { let tx = tx.clone(); let t = thread::spawn(move || { tx.send(()).unwrap(); }); ts.push(t); } for _ in 0..total { rx.recv().unwrap(); } for t in ts { t.join().unwrap(); } } #[test] fn test_nested_recv_iter() { let (tx, rx) = channel::(); let (total_tx, total_rx) = channel::(); let t = thread::spawn(move || { let mut acc = 0; for x in rx.iter() { acc += x; } total_tx.send(acc).unwrap(); }); tx.send(3).unwrap(); tx.send(1).unwrap(); tx.send(2).unwrap(); drop(tx); assert_eq!(total_rx.recv().unwrap(), 6); t.join().unwrap(); } #[test] fn test_recv_iter_break() { let (tx, rx) = channel::(); let (count_tx, count_rx) = channel(); let t = thread::spawn(move || { let mut count = 0; for x in rx.iter() { if count >= 3 { break; } else { count += x; } } count_tx.send(count).unwrap(); }); tx.send(2).unwrap(); tx.send(2).unwrap(); tx.send(2).unwrap(); let _ = tx.send(2); drop(tx); assert_eq!(count_rx.recv().unwrap(), 4); t.join().unwrap(); } #[test] fn test_recv_try_iter() { let (request_tx, request_rx) = channel(); let (response_tx, response_rx) = channel(); // Request `x`s until we have `6`. let t = thread::spawn(move || { let mut count = 0; loop { for x in response_rx.try_iter() { count += x; if count == 6 { return count; } } request_tx.send(()).unwrap(); } }); for _ in request_rx.iter() { if response_tx.send(2).is_err() { break; } } assert_eq!(t.join().unwrap(), 6); } #[test] fn test_recv_into_iter_owned() { let mut iter = { let (tx, rx) = channel::(); tx.send(1).unwrap(); tx.send(2).unwrap(); rx.into_iter() }; assert_eq!(iter.next().unwrap(), 1); assert_eq!(iter.next().unwrap(), 2); assert_eq!(iter.next().is_none(), true); } #[test] fn test_recv_into_iter_borrowed() { let (tx, rx) = channel::(); tx.send(1).unwrap(); tx.send(2).unwrap(); drop(tx); let mut iter = (&rx).into_iter(); assert_eq!(iter.next().unwrap(), 1); assert_eq!(iter.next().unwrap(), 2); assert_eq!(iter.next().is_none(), true); } #[test] fn try_recv_states() { let (tx1, rx1) = channel::(); let (tx2, rx2) = channel::<()>(); let (tx3, rx3) = channel::<()>(); let t = thread::spawn(move || { rx2.recv().unwrap(); tx1.send(1).unwrap(); tx3.send(()).unwrap(); rx2.recv().unwrap(); drop(tx1); tx3.send(()).unwrap(); }); assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); tx2.send(()).unwrap(); rx3.recv().unwrap(); assert_eq!(rx1.try_recv(), Ok(1)); assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); tx2.send(()).unwrap(); rx3.recv().unwrap(); assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); t.join().unwrap(); } // This bug used to end up in a livelock inside of the Receiver destructor // because the internal state of the Shared packet was corrupted #[test] fn destroy_upgraded_shared_port_when_sender_still_active() { let (tx, rx) = channel(); let (tx2, rx2) = channel(); let t = thread::spawn(move || { rx.recv().unwrap(); // wait on a oneshot drop(rx); // destroy a shared tx2.send(()).unwrap(); }); // make sure the other thread has gone to sleep for _ in 0..5000 { thread::yield_now(); } // upgrade to a shared chan and send a message let tx2 = tx.clone(); drop(tx); tx2.send(()).unwrap(); // wait for the child thread to exit before we exit rx2.recv().unwrap(); t.join().unwrap(); } #[test] fn issue_32114() { let (tx, _) = channel(); let _ = tx.send(123); assert_eq!(tx.send(123), Err(SendError(123))); } } // Source: https://github.com/rust-lang/rust/blob/master/src/libstd/sync/mpsc/mod.rs mod sync_channel_tests { use super::*; use std::env; use std::thread; use std::time::Duration; pub fn stress_factor() -> usize { match env::var("RUST_TEST_STRESS") { Ok(val) => val.parse().unwrap(), Err(..) => 1, } } #[test] fn smoke() { let (tx, rx) = sync_channel::(1); tx.send(1).unwrap(); assert_eq!(rx.recv().unwrap(), 1); } #[test] fn drop_full() { let (tx, _rx) = sync_channel::>(1); tx.send(Box::new(1)).unwrap(); } #[test] fn smoke_shared() { let (tx, rx) = sync_channel::(1); tx.send(1).unwrap(); assert_eq!(rx.recv().unwrap(), 1); let tx = tx.clone(); tx.send(1).unwrap(); assert_eq!(rx.recv().unwrap(), 1); } #[test] fn recv_timeout() { let (tx, rx) = sync_channel::(1); assert_eq!( rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout) ); tx.send(1).unwrap(); assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(1)); } #[test] fn smoke_threads() { let (tx, rx) = sync_channel::(0); let t = thread::spawn(move || { tx.send(1).unwrap(); }); assert_eq!(rx.recv().unwrap(), 1); t.join().unwrap(); } #[test] fn smoke_port_gone() { let (tx, rx) = sync_channel::(0); drop(rx); assert!(tx.send(1).is_err()); } #[test] fn smoke_shared_port_gone2() { let (tx, rx) = sync_channel::(0); drop(rx); let tx2 = tx.clone(); drop(tx); assert!(tx2.send(1).is_err()); } #[test] fn port_gone_concurrent() { let (tx, rx) = sync_channel::(0); let t = thread::spawn(move || { rx.recv().unwrap(); }); while tx.send(1).is_ok() {} t.join().unwrap(); } #[test] fn port_gone_concurrent_shared() { let (tx, rx) = sync_channel::(0); let tx2 = tx.clone(); let t = thread::spawn(move || { rx.recv().unwrap(); }); while tx.send(1).is_ok() && tx2.send(1).is_ok() {} t.join().unwrap(); } #[test] fn smoke_chan_gone() { let (tx, rx) = sync_channel::(0); drop(tx); assert!(rx.recv().is_err()); } #[test] fn smoke_chan_gone_shared() { let (tx, rx) = sync_channel::<()>(0); let tx2 = tx.clone(); drop(tx); drop(tx2); assert!(rx.recv().is_err()); } #[test] fn chan_gone_concurrent() { let (tx, rx) = sync_channel::(0); let t = thread::spawn(move || { tx.send(1).unwrap(); tx.send(1).unwrap(); }); while rx.recv().is_ok() {} t.join().unwrap(); } #[test] fn stress() { let (tx, rx) = sync_channel::(0); let t = thread::spawn(move || { for _ in 0..10000 { tx.send(1).unwrap(); } }); for _ in 0..10000 { assert_eq!(rx.recv().unwrap(), 1); } t.join().unwrap(); } #[test] fn stress_recv_timeout_two_threads() { let (tx, rx) = sync_channel::(0); let t = thread::spawn(move || { for _ in 0..10000 { tx.send(1).unwrap(); } }); let mut recv_count = 0; loop { match rx.recv_timeout(Duration::from_millis(1)) { Ok(v) => { assert_eq!(v, 1); recv_count += 1; } Err(RecvTimeoutError::Timeout) => continue, Err(RecvTimeoutError::Disconnected) => break, } } assert_eq!(recv_count, 10000); t.join().unwrap(); } #[test] fn stress_recv_timeout_shared() { const AMT: u32 = 1000; const NTHREADS: u32 = 8; let (tx, rx) = sync_channel::(0); let (dtx, drx) = sync_channel::<()>(0); let t = thread::spawn(move || { let mut recv_count = 0; loop { match rx.recv_timeout(Duration::from_millis(10)) { Ok(v) => { assert_eq!(v, 1); recv_count += 1; } Err(RecvTimeoutError::Timeout) => continue, Err(RecvTimeoutError::Disconnected) => break, } } assert_eq!(recv_count, AMT * NTHREADS); assert!(rx.try_recv().is_err()); dtx.send(()).unwrap(); }); let mut ts = Vec::with_capacity(NTHREADS as usize); for _ in 0..NTHREADS { let tx = tx.clone(); let t = thread::spawn(move || { for _ in 0..AMT { tx.send(1).unwrap(); } }); ts.push(t); } drop(tx); drx.recv().unwrap(); for t in ts { t.join().unwrap(); } t.join().unwrap(); } #[test] fn stress_shared() { const AMT: u32 = 1000; const NTHREADS: u32 = 8; let (tx, rx) = sync_channel::(0); let (dtx, drx) = sync_channel::<()>(0); let t = thread::spawn(move || { for _ in 0..AMT * NTHREADS { assert_eq!(rx.recv().unwrap(), 1); } match rx.try_recv() { Ok(..) => panic!(), _ => {} } dtx.send(()).unwrap(); }); let mut ts = Vec::with_capacity(NTHREADS as usize); for _ in 0..NTHREADS { let tx = tx.clone(); let t = thread::spawn(move || { for _ in 0..AMT { tx.send(1).unwrap(); } }); ts.push(t); } drop(tx); drx.recv().unwrap(); for t in ts { t.join().unwrap(); } t.join().unwrap(); } #[test] fn oneshot_single_thread_close_port_first() { // Simple test of closing without sending let (_tx, rx) = sync_channel::(0); drop(rx); } #[test] fn oneshot_single_thread_close_chan_first() { // Simple test of closing without sending let (tx, _rx) = sync_channel::(0); drop(tx); } #[test] fn oneshot_single_thread_send_port_close() { // Testing that the sender cleans up the payload if receiver is closed let (tx, rx) = sync_channel::>(0); drop(rx); assert!(tx.send(Box::new(0)).is_err()); } #[test] fn oneshot_single_thread_recv_chan_close() { let (tx, rx) = sync_channel::(0); drop(tx); assert_eq!(rx.recv(), Err(RecvError)); } #[test] fn oneshot_single_thread_send_then_recv() { let (tx, rx) = sync_channel::>(1); tx.send(Box::new(10)).unwrap(); assert!(*rx.recv().unwrap() == 10); } #[test] fn oneshot_single_thread_try_send_open() { let (tx, rx) = sync_channel::(1); assert_eq!(tx.try_send(10), Ok(())); assert!(rx.recv().unwrap() == 10); } #[test] fn oneshot_single_thread_try_send_closed() { let (tx, rx) = sync_channel::(0); drop(rx); assert_eq!(tx.try_send(10), Err(TrySendError::Disconnected(10))); } #[test] fn oneshot_single_thread_try_send_closed2() { let (tx, _rx) = sync_channel::(0); assert_eq!(tx.try_send(10), Err(TrySendError::Full(10))); } #[test] fn oneshot_single_thread_try_recv_open() { let (tx, rx) = sync_channel::(1); tx.send(10).unwrap(); assert!(rx.recv() == Ok(10)); } #[test] fn oneshot_single_thread_try_recv_closed() { let (tx, rx) = sync_channel::(0); drop(tx); assert!(rx.recv().is_err()); } #[test] fn oneshot_single_thread_try_recv_closed_with_data() { let (tx, rx) = sync_channel::(1); tx.send(10).unwrap(); drop(tx); assert_eq!(rx.try_recv(), Ok(10)); assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); } #[test] fn oneshot_single_thread_peek_data() { let (tx, rx) = sync_channel::(1); assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); tx.send(10).unwrap(); assert_eq!(rx.try_recv(), Ok(10)); } #[test] fn oneshot_single_thread_peek_close() { let (tx, rx) = sync_channel::(0); drop(tx); assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); } #[test] fn oneshot_single_thread_peek_open() { let (_tx, rx) = sync_channel::(0); assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); } #[test] fn oneshot_multi_task_recv_then_send() { let (tx, rx) = sync_channel::>(0); let t = thread::spawn(move || { assert!(*rx.recv().unwrap() == 10); }); tx.send(Box::new(10)).unwrap(); t.join().unwrap(); } #[test] fn oneshot_multi_task_recv_then_close() { let (tx, rx) = sync_channel::>(0); let t = thread::spawn(move || { drop(tx); }); thread::spawn(move || { assert_eq!(rx.recv(), Err(RecvError)); }) .join() .unwrap(); t.join().unwrap(); } #[test] fn oneshot_multi_thread_close_stress() { let stress_factor = stress_factor(); let mut ts = Vec::with_capacity(stress_factor); for _ in 0..stress_factor { let (tx, rx) = sync_channel::(0); let t = thread::spawn(move || { drop(rx); }); ts.push(t); drop(tx); } for t in ts { t.join().unwrap(); } } #[test] fn oneshot_multi_thread_send_close_stress() { let stress_factor = stress_factor(); let mut ts = Vec::with_capacity(stress_factor); for _ in 0..stress_factor { let (tx, rx) = sync_channel::(0); let t = thread::spawn(move || { drop(rx); }); ts.push(t); thread::spawn(move || { let _ = tx.send(1); }) .join() .unwrap(); } for t in ts { t.join().unwrap(); } } #[test] fn oneshot_multi_thread_recv_close_stress() { let stress_factor = stress_factor(); let mut ts = Vec::with_capacity(2 * stress_factor); for _ in 0..stress_factor { let (tx, rx) = sync_channel::(0); let t = thread::spawn(move || { thread::spawn(move || { assert_eq!(rx.recv(), Err(RecvError)); }) .join() .unwrap(); }); ts.push(t); let t2 = thread::spawn(move || { thread::spawn(move || { drop(tx); }); }); ts.push(t2); } for t in ts { t.join().unwrap(); } } #[test] fn oneshot_multi_thread_send_recv_stress() { let stress_factor = stress_factor(); let mut ts = Vec::with_capacity(stress_factor); for _ in 0..stress_factor { let (tx, rx) = sync_channel::>(0); let t = thread::spawn(move || { tx.send(Box::new(10)).unwrap(); }); ts.push(t); assert!(*rx.recv().unwrap() == 10); } for t in ts { t.join().unwrap(); } } #[test] fn stream_send_recv_stress() { let stress_factor = stress_factor(); let mut ts = Vec::with_capacity(2 * stress_factor); for _ in 0..stress_factor { let (tx, rx) = sync_channel::>(0); if let Some(t) = send(tx, 0) { ts.push(t); } if let Some(t) = recv(rx, 0) { ts.push(t); } fn send(tx: SyncSender>, i: i32) -> Option> { if i == 10 { return None; } Some(thread::spawn(move || { tx.send(Box::new(i)).unwrap(); send(tx, i + 1); })) } fn recv(rx: Receiver>, i: i32) -> Option> { if i == 10 { return None; } Some(thread::spawn(move || { assert!(*rx.recv().unwrap() == i); recv(rx, i + 1); })) } } for t in ts { t.join().unwrap(); } } #[test] fn recv_a_lot() { // Regression test that we don't run out of stack in scheduler context let (tx, rx) = sync_channel(10000); for _ in 0..10000 { tx.send(()).unwrap(); } for _ in 0..10000 { rx.recv().unwrap(); } } #[test] fn shared_chan_stress() { let (tx, rx) = sync_channel(0); let total = stress_factor() + 100; let mut ts = Vec::with_capacity(total); for _ in 0..total { let tx = tx.clone(); let t = thread::spawn(move || { tx.send(()).unwrap(); }); ts.push(t); } for _ in 0..total { rx.recv().unwrap(); } for t in ts { t.join().unwrap(); } } #[test] fn test_nested_recv_iter() { let (tx, rx) = sync_channel::(0); let (total_tx, total_rx) = sync_channel::(0); let t = thread::spawn(move || { let mut acc = 0; for x in rx.iter() { acc += x; } total_tx.send(acc).unwrap(); }); tx.send(3).unwrap(); tx.send(1).unwrap(); tx.send(2).unwrap(); drop(tx); assert_eq!(total_rx.recv().unwrap(), 6); t.join().unwrap(); } #[test] fn test_recv_iter_break() { let (tx, rx) = sync_channel::(0); let (count_tx, count_rx) = sync_channel(0); let t = thread::spawn(move || { let mut count = 0; for x in rx.iter() { if count >= 3 { break; } else { count += x; } } count_tx.send(count).unwrap(); }); tx.send(2).unwrap(); tx.send(2).unwrap(); tx.send(2).unwrap(); let _ = tx.try_send(2); drop(tx); assert_eq!(count_rx.recv().unwrap(), 4); t.join().unwrap(); } #[test] fn try_recv_states() { let (tx1, rx1) = sync_channel::(1); let (tx2, rx2) = sync_channel::<()>(1); let (tx3, rx3) = sync_channel::<()>(1); let t = thread::spawn(move || { rx2.recv().unwrap(); tx1.send(1).unwrap(); tx3.send(()).unwrap(); rx2.recv().unwrap(); drop(tx1); tx3.send(()).unwrap(); }); assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); tx2.send(()).unwrap(); rx3.recv().unwrap(); assert_eq!(rx1.try_recv(), Ok(1)); assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); tx2.send(()).unwrap(); rx3.recv().unwrap(); assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); t.join().unwrap(); } // This bug used to end up in a livelock inside of the Receiver destructor // because the internal state of the Shared packet was corrupted #[test] fn destroy_upgraded_shared_port_when_sender_still_active() { let (tx, rx) = sync_channel::<()>(0); let (tx2, rx2) = sync_channel::<()>(0); let t = thread::spawn(move || { rx.recv().unwrap(); // wait on a oneshot drop(rx); // destroy a shared tx2.send(()).unwrap(); }); // make sure the other thread has gone to sleep for _ in 0..5000 { thread::yield_now(); } // upgrade to a shared chan and send a message let tx2 = tx.clone(); drop(tx); tx2.send(()).unwrap(); // wait for the child thread to exit before we exit rx2.recv().unwrap(); t.join().unwrap(); } #[test] fn send1() { let (tx, rx) = sync_channel::(0); let t = thread::spawn(move || { rx.recv().unwrap(); }); assert_eq!(tx.send(1), Ok(())); t.join().unwrap(); } #[test] fn send2() { let (tx, rx) = sync_channel::(0); let t = thread::spawn(move || { drop(rx); }); assert!(tx.send(1).is_err()); t.join().unwrap(); } #[test] fn send3() { let (tx, rx) = sync_channel::(1); assert_eq!(tx.send(1), Ok(())); let t = thread::spawn(move || { drop(rx); }); assert!(tx.send(1).is_err()); t.join().unwrap(); } #[test] fn send4() { let (tx, rx) = sync_channel::(0); let tx2 = tx.clone(); let (done, donerx) = channel(); let done2 = done.clone(); let t = thread::spawn(move || { assert!(tx.send(1).is_err()); done.send(()).unwrap(); }); let t2 = thread::spawn(move || { assert!(tx2.send(2).is_err()); done2.send(()).unwrap(); }); drop(rx); donerx.recv().unwrap(); donerx.recv().unwrap(); t.join().unwrap(); t2.join().unwrap(); } #[test] fn try_send1() { let (tx, _rx) = sync_channel::(0); assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); } #[test] fn try_send2() { let (tx, _rx) = sync_channel::(1); assert_eq!(tx.try_send(1), Ok(())); assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); } #[test] fn try_send3() { let (tx, rx) = sync_channel::(1); assert_eq!(tx.try_send(1), Ok(())); drop(rx); assert_eq!(tx.try_send(1), Err(TrySendError::Disconnected(1))); } #[test] fn issue_15761() { fn repro() { let (tx1, rx1) = sync_channel::<()>(3); let (tx2, rx2) = sync_channel::<()>(3); let _t = thread::spawn(move || { rx1.recv().unwrap(); tx2.try_send(()).unwrap(); }); tx1.try_send(()).unwrap(); rx2.recv().unwrap(); } for _ in 0..100 { repro() } } } // Source: https://github.com/rust-lang/rust/blob/master/src/libstd/sync/mpsc/select.rs mod select_tests { use super::*; use std::thread; #[test] fn smoke() { let (tx1, rx1) = channel::(); let (tx2, rx2) = channel::(); tx1.send(1).unwrap(); select! { foo = rx1.recv() => { assert_eq!(foo.unwrap(), 1); }, _bar = rx2.recv() => { panic!() } } tx2.send(2).unwrap(); select! { _foo = rx1.recv() => { panic!() }, bar = rx2.recv() => { assert_eq!(bar.unwrap(), 2) } } drop(tx1); select! { foo = rx1.recv() => { assert!(foo.is_err()); }, _bar = rx2.recv() => { panic!() } } drop(tx2); select! { bar = rx2.recv() => { assert!(bar.is_err()); } } } #[test] fn smoke2() { let (_tx1, rx1) = channel::(); let (_tx2, rx2) = channel::(); let (_tx3, rx3) = channel::(); let (_tx4, rx4) = channel::(); let (tx5, rx5) = channel::(); tx5.send(4).unwrap(); select! { _foo = rx1.recv() => { panic!("1") }, _foo = rx2.recv() => { panic!("2") }, _foo = rx3.recv() => { panic!("3") }, _foo = rx4.recv() => { panic!("4") }, foo = rx5.recv() => { assert_eq!(foo.unwrap(), 4); } } } #[test] fn closed() { let (_tx1, rx1) = channel::(); let (tx2, rx2) = channel::(); drop(tx2); select! { _a1 = rx1.recv() => { panic!() }, a2 = rx2.recv() => { assert!(a2.is_err()); } } } #[test] fn unblocks() { let (tx1, rx1) = channel::(); let (_tx2, rx2) = channel::(); let (tx3, rx3) = channel::(); let t = thread::spawn(move || { for _ in 0..20 { thread::yield_now(); } tx1.send(1).unwrap(); rx3.recv().unwrap(); for _ in 0..20 { thread::yield_now(); } }); select! { a = rx1.recv() => { assert_eq!(a.unwrap(), 1); }, _b = rx2.recv() => { panic!() } } tx3.send(1).unwrap(); select! { a = rx1.recv() => { assert!(a.is_err()) }, _b = rx2.recv() => { panic!() } } t.join().unwrap(); } #[test] fn both_ready() { let (tx1, rx1) = channel::(); let (tx2, rx2) = channel::(); let (tx3, rx3) = channel::<()>(); let t = thread::spawn(move || { for _ in 0..20 { thread::yield_now(); } tx1.send(1).unwrap(); tx2.send(2).unwrap(); rx3.recv().unwrap(); }); select! { a = rx1.recv() => { assert_eq!(a.unwrap(), 1); }, a = rx2.recv() => { assert_eq!(a.unwrap(), 2); } } select! { a = rx1.recv() => { assert_eq!(a.unwrap(), 1); }, a = rx2.recv() => { assert_eq!(a.unwrap(), 2); } } assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); assert_eq!(rx2.try_recv(), Err(TryRecvError::Empty)); tx3.send(()).unwrap(); t.join().unwrap(); } #[test] fn stress() { const AMT: i32 = 10000; let (tx1, rx1) = channel::(); let (tx2, rx2) = channel::(); let (tx3, rx3) = channel::<()>(); let t = thread::spawn(move || { for i in 0..AMT { if i % 2 == 0 { tx1.send(i).unwrap(); } else { tx2.send(i).unwrap(); } rx3.recv().unwrap(); } }); for i in 0..AMT { select! { i1 = rx1.recv() => { assert!(i % 2 == 0 && i == i1.unwrap()); }, i2 = rx2.recv() => { assert!(i % 2 == 1 && i == i2.unwrap()); } } tx3.send(()).unwrap(); } t.join().unwrap(); } #[allow(unused_must_use)] #[test] fn cloning() { let (tx1, rx1) = channel::(); let (_tx2, rx2) = channel::(); let (tx3, rx3) = channel::<()>(); let t = thread::spawn(move || { rx3.recv().unwrap(); tx1.clone(); assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty)); tx1.send(2).unwrap(); rx3.recv().unwrap(); }); tx3.send(()).unwrap(); select! { _i1 = rx1.recv() => {}, _i2 = rx2.recv() => panic!() } tx3.send(()).unwrap(); t.join().unwrap(); } #[allow(unused_must_use)] #[test] fn cloning2() { let (tx1, rx1) = channel::(); let (_tx2, rx2) = channel::(); let (tx3, rx3) = channel::<()>(); let t = thread::spawn(move || { rx3.recv().unwrap(); tx1.clone(); assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty)); tx1.send(2).unwrap(); rx3.recv().unwrap(); }); tx3.send(()).unwrap(); select! { _i1 = rx1.recv() => {}, _i2 = rx2.recv() => panic!() } tx3.send(()).unwrap(); t.join().unwrap(); } #[test] fn cloning3() { let (tx1, rx1) = channel::<()>(); let (tx2, rx2) = channel::<()>(); let (tx3, rx3) = channel::<()>(); let t = thread::spawn(move || { select! { _ = rx1.recv() => panic!(), _ = rx2.recv() => {} } tx3.send(()).unwrap(); }); for _ in 0..1000 { thread::yield_now(); } drop(tx1.clone()); tx2.send(()).unwrap(); rx3.recv().unwrap(); t.join().unwrap(); } #[test] fn preflight1() { let (tx, rx) = channel(); tx.send(()).unwrap(); select! { _n = rx.recv() => {} } } #[test] fn preflight2() { let (tx, rx) = channel(); tx.send(()).unwrap(); tx.send(()).unwrap(); select! { _n = rx.recv() => {} } } #[test] fn preflight3() { let (tx, rx) = channel(); drop(tx.clone()); tx.send(()).unwrap(); select! { _n = rx.recv() => {} } } #[test] fn preflight4() { let (tx, rx) = channel(); tx.send(()).unwrap(); select! { _ = rx.recv() => {} } } #[test] fn preflight5() { let (tx, rx) = channel(); tx.send(()).unwrap(); tx.send(()).unwrap(); select! { _ = rx.recv() => {} } } #[test] fn preflight6() { let (tx, rx) = channel(); drop(tx.clone()); tx.send(()).unwrap(); select! { _ = rx.recv() => {} } } #[test] fn preflight7() { let (tx, rx) = channel::<()>(); drop(tx); select! { _ = rx.recv() => {} } } #[test] fn preflight8() { let (tx, rx) = channel(); tx.send(()).unwrap(); drop(tx); rx.recv().unwrap(); select! { _ = rx.recv() => {} } } #[test] fn preflight9() { let (tx, rx) = channel(); drop(tx.clone()); tx.send(()).unwrap(); drop(tx); rx.recv().unwrap(); select! { _ = rx.recv() => {} } } #[test] fn oneshot_data_waiting() { let (tx1, rx1) = channel(); let (tx2, rx2) = channel(); let t = thread::spawn(move || { select! { _n = rx1.recv() => {} } tx2.send(()).unwrap(); }); for _ in 0..100 { thread::yield_now() } tx1.send(()).unwrap(); rx2.recv().unwrap(); t.join().unwrap(); } #[test] fn stream_data_waiting() { let (tx1, rx1) = channel(); let (tx2, rx2) = channel(); tx1.send(()).unwrap(); tx1.send(()).unwrap(); rx1.recv().unwrap(); rx1.recv().unwrap(); let t = thread::spawn(move || { select! { _n = rx1.recv() => {} } tx2.send(()).unwrap(); }); for _ in 0..100 { thread::yield_now() } tx1.send(()).unwrap(); rx2.recv().unwrap(); t.join().unwrap(); } #[test] fn shared_data_waiting() { let (tx1, rx1) = channel(); let (tx2, rx2) = channel(); drop(tx1.clone()); tx1.send(()).unwrap(); rx1.recv().unwrap(); let t = thread::spawn(move || { select! { _n = rx1.recv() => {} } tx2.send(()).unwrap(); }); for _ in 0..100 { thread::yield_now() } tx1.send(()).unwrap(); rx2.recv().unwrap(); t.join().unwrap(); } #[test] fn sync1() { let (tx, rx) = sync_channel::(1); tx.send(1).unwrap(); select! { n = rx.recv() => { assert_eq!(n.unwrap(), 1); } } } #[test] fn sync2() { let (tx, rx) = sync_channel::(0); let t = thread::spawn(move || { for _ in 0..100 { thread::yield_now() } tx.send(1).unwrap(); }); select! { n = rx.recv() => { assert_eq!(n.unwrap(), 1); } } t.join().unwrap(); } #[test] fn sync3() { let (tx1, rx1) = sync_channel::(0); let (tx2, rx2): (Sender, Receiver) = channel(); let t = thread::spawn(move || { tx1.send(1).unwrap(); }); let t2 = thread::spawn(move || { tx2.send(2).unwrap(); }); select! { n = rx1.recv() => { let n = n.unwrap(); assert_eq!(n, 1); assert_eq!(rx2.recv().unwrap(), 2); }, n = rx2.recv() => { let n = n.unwrap(); assert_eq!(n, 2); assert_eq!(rx1.recv().unwrap(), 1); } } t.join().unwrap(); t2.join().unwrap(); } } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/tests/never.rs000066400000000000000000000040201446715670500231600ustar00rootroot00000000000000// //! 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::()) -> _ => panic!(), // default => {} // } // } // #[test] // fn optional() { // let (s, r) = unbounded::(); // 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::(); // assert_eq!(r.capacity(), Some(0)); // } // #[test] // fn len_empty_full() { // let r = never::(); // assert_eq!(r.len(), 0); // assert_eq!(r.is_empty(), true); // assert_eq!(r.is_full(), true); // } // #[test] // fn try_recv() { // let r = never::(); // 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::(); // 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)); // } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/tests/ready.rs000066400000000000000000000546571446715670500231720ustar00rootroot00000000000000// //! 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::(); // let (s2, r2) = unbounded::(); // 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::(); // let (_s2, r2) = unbounded::(); // let (_s3, r3) = unbounded::(); // let (_s4, r4) = unbounded::(); // let (s5, r5) = unbounded::(); // 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::(); // let (s2, r2) = unbounded::(); // 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::(); // let (s2, r2) = unbounded::(); // 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::(); // let (s2, r2) = unbounded::(); // 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::(); // 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::(); // 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::(); // 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::(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::(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::(0); // let (s2, r2) = bounded::(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::(); // let (_s2, r2) = unbounded::(); // 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::(); // 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::(); // 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::(0); // let mut sel = Select::new(); // sel.send(&s); // sel.recv(&r); // assert!(sel.ready_timeout(ms(100)).is_err()); // let (s, r) = unbounded::(); // 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; // for cap in 1..4 { // let (s, r) = bounded::(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::>>() // .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(); // } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/tests/same_channel.rs000066400000000000000000000052141446715670500244640ustar00rootroot00000000000000// 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::(1); // let s2 = s.clone(); // assert!(s.same_channel(&s2)); // let r2 = r.clone(); // assert!(r.same_channel(&r2)); // let (s3, r3) = bounded::(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::(); // let s2 = s.clone(); // assert!(s.same_channel(&s2)); // let r2 = r.clone(); // assert!(r.same_channel(&r2)); // let (s3, r3) = unbounded::(); // 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::(); // let r2 = r.clone(); // assert!(r.same_channel(&r2)); // // Never channel are always equal to one another. // let r3 = never::(); // 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::(0); // let s2 = s.clone(); // assert!(s.same_channel(&s2)); // let r2 = r.clone(); // assert!(r.same_channel(&r2)); // let (s3, r3) = bounded::(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::(0); // let (s2, r2) = unbounded::(); // assert!(!s1.same_channel(&s2)); // assert!(!r1.same_channel(&r2)); // } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/tests/select.rs000066400000000000000000001144571446715670500233400ustar00rootroot00000000000000// //! Tests for channel selection 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, Receiver, Select, TryRecvError}; // use crossbeam_utils::thread::scope; // fn ms(ms: u64) -> Duration { // Duration::from_millis(ms) // } // #[test] // fn smoke1() { // let (s1, r1) = unbounded::(); // let (s2, r2) = unbounded::(); // s1.send(1).unwrap(); // let mut sel = Select::new(); // let oper1 = sel.recv(&r1); // let oper2 = sel.recv(&r2); // let oper = sel.select(); // match oper.index() { // i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(1)), // i if i == oper2 => panic!(), // _ => unreachable!(), // } // s2.send(2).unwrap(); // let mut sel = Select::new(); // let oper1 = sel.recv(&r1); // let oper2 = sel.recv(&r2); // let oper = sel.select(); // match oper.index() { // i if i == oper1 => panic!(), // i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(2)), // _ => unreachable!(), // } // } // #[test] // fn smoke2() { // let (_s1, r1) = unbounded::(); // let (_s2, r2) = unbounded::(); // let (_s3, r3) = unbounded::(); // let (_s4, r4) = unbounded::(); // let (s5, r5) = unbounded::(); // s5.send(5).unwrap(); // let mut sel = Select::new(); // let oper1 = sel.recv(&r1); // let oper2 = sel.recv(&r2); // let oper3 = sel.recv(&r3); // let oper4 = sel.recv(&r4); // let oper5 = sel.recv(&r5); // let oper = sel.select(); // match oper.index() { // i if i == oper1 => panic!(), // i if i == oper2 => panic!(), // i if i == oper3 => panic!(), // i if i == oper4 => panic!(), // i if i == oper5 => assert_eq!(oper.recv(&r5), Ok(5)), // _ => unreachable!(), // } // } // #[test] // fn disconnected() { // let (s1, r1) = unbounded::(); // let (s2, r2) = unbounded::(); // scope(|scope| { // scope.spawn(|_| { // drop(s1); // thread::sleep(ms(500)); // s2.send(5).unwrap(); // }); // let mut sel = Select::new(); // let oper1 = sel.recv(&r1); // let oper2 = sel.recv(&r2); // let oper = sel.select_timeout(ms(1000)); // match oper { // Err(_) => panic!(), // Ok(oper) => match oper.index() { // i if i == oper1 => assert!(oper.recv(&r1).is_err()), // i if i == oper2 => panic!(), // _ => unreachable!(), // }, // } // r2.recv().unwrap(); // }) // .unwrap(); // let mut sel = Select::new(); // let oper1 = sel.recv(&r1); // let oper2 = sel.recv(&r2); // let oper = sel.select_timeout(ms(1000)); // match oper { // Err(_) => panic!(), // Ok(oper) => match oper.index() { // i if i == oper1 => assert!(oper.recv(&r1).is_err()), // i if i == oper2 => panic!(), // _ => unreachable!(), // }, // } // scope(|scope| { // scope.spawn(|_| { // thread::sleep(ms(500)); // drop(s2); // }); // let mut sel = Select::new(); // let oper1 = sel.recv(&r2); // let oper = sel.select_timeout(ms(1000)); // match oper { // Err(_) => panic!(), // Ok(oper) => match oper.index() { // i if i == oper1 => assert!(oper.recv(&r2).is_err()), // _ => unreachable!(), // }, // } // }) // .unwrap(); // } // #[test] // fn default() { // let (s1, r1) = unbounded::(); // let (s2, r2) = unbounded::(); // let mut sel = Select::new(); // let _oper1 = sel.recv(&r1); // let _oper2 = sel.recv(&r2); // let oper = sel.try_select(); // match oper { // Err(_) => {} // Ok(_) => panic!(), // } // drop(s1); // let mut sel = Select::new(); // let oper1 = sel.recv(&r1); // let oper2 = sel.recv(&r2); // let oper = sel.try_select(); // match oper { // Err(_) => panic!(), // Ok(oper) => match oper.index() { // i if i == oper1 => assert!(oper.recv(&r1).is_err()), // i if i == oper2 => panic!(), // _ => unreachable!(), // }, // } // s2.send(2).unwrap(); // let mut sel = Select::new(); // let oper1 = sel.recv(&r2); // let oper = sel.try_select(); // match oper { // Err(_) => panic!(), // Ok(oper) => match oper.index() { // i if i == oper1 => assert_eq!(oper.recv(&r2), Ok(2)), // _ => unreachable!(), // }, // } // let mut sel = Select::new(); // let _oper1 = sel.recv(&r2); // let oper = sel.try_select(); // match oper { // Err(_) => {} // Ok(_) => panic!(), // } // let mut sel = Select::new(); // let oper = sel.try_select(); // match oper { // Err(_) => {} // Ok(_) => panic!(), // } // } // #[test] // fn timeout() { // let (_s1, r1) = unbounded::(); // let (s2, r2) = unbounded::(); // scope(|scope| { // scope.spawn(|_| { // thread::sleep(ms(1500)); // s2.send(2).unwrap(); // }); // let mut sel = Select::new(); // let oper1 = sel.recv(&r1); // let oper2 = sel.recv(&r2); // let oper = sel.select_timeout(ms(1000)); // match oper { // Err(_) => {} // Ok(oper) => match oper.index() { // i if i == oper1 => panic!(), // i if i == oper2 => panic!(), // _ => unreachable!(), // }, // } // let mut sel = Select::new(); // let oper1 = sel.recv(&r1); // let oper2 = sel.recv(&r2); // let oper = sel.select_timeout(ms(1000)); // match oper { // Err(_) => panic!(), // Ok(oper) => match oper.index() { // i if i == oper1 => panic!(), // i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(2)), // _ => unreachable!(), // }, // } // }) // .unwrap(); // scope(|scope| { // let (s, r) = unbounded::(); // scope.spawn(move |_| { // thread::sleep(ms(500)); // drop(s); // }); // let mut sel = Select::new(); // let oper = sel.select_timeout(ms(1000)); // match oper { // Err(_) => { // let mut sel = Select::new(); // let oper1 = sel.recv(&r); // let oper = sel.try_select(); // match oper { // Err(_) => panic!(), // Ok(oper) => match oper.index() { // i if i == oper1 => assert!(oper.recv(&r).is_err()), // _ => unreachable!(), // }, // } // } // Ok(_) => unreachable!(), // } // }) // .unwrap(); // } // #[test] // fn default_when_disconnected() { // let (_, r) = unbounded::(); // let mut sel = Select::new(); // let oper1 = sel.recv(&r); // let oper = sel.try_select(); // match oper { // Err(_) => panic!(), // Ok(oper) => match oper.index() { // i if i == oper1 => assert!(oper.recv(&r).is_err()), // _ => unreachable!(), // }, // } // let (_, r) = unbounded::(); // let mut sel = Select::new(); // let oper1 = sel.recv(&r); // let oper = sel.select_timeout(ms(1000)); // match oper { // Err(_) => panic!(), // Ok(oper) => match oper.index() { // i if i == oper1 => assert!(oper.recv(&r).is_err()), // _ => unreachable!(), // }, // } // let (s, _) = bounded::(0); // let mut sel = Select::new(); // let oper1 = sel.send(&s); // let oper = sel.try_select(); // match oper { // Err(_) => panic!(), // Ok(oper) => match oper.index() { // i if i == oper1 => assert!(oper.send(&s, 0).is_err()), // _ => unreachable!(), // }, // } // let (s, _) = bounded::(0); // let mut sel = Select::new(); // let oper1 = sel.send(&s); // let oper = sel.select_timeout(ms(1000)); // match oper { // Err(_) => panic!(), // Ok(oper) => match oper.index() { // i if i == oper1 => assert!(oper.send(&s, 0).is_err()), // _ => unreachable!(), // }, // } // } // #[test] // fn default_only() { // let start = Instant::now(); // let mut sel = Select::new(); // let oper = sel.try_select(); // assert!(oper.is_err()); // let now = Instant::now(); // assert!(now - start <= ms(50)); // let start = Instant::now(); // let mut sel = Select::new(); // let oper = sel.select_timeout(ms(500)); // assert!(oper.is_err()); // let now = Instant::now(); // assert!(now - start >= ms(450)); // assert!(now - start <= ms(550)); // } // #[test] // fn unblocks() { // let (s1, r1) = bounded::(0); // let (s2, r2) = bounded::(0); // scope(|scope| { // scope.spawn(|_| { // thread::sleep(ms(500)); // s2.send(2).unwrap(); // }); // let mut sel = Select::new(); // let oper1 = sel.recv(&r1); // let oper2 = sel.recv(&r2); // let oper = sel.select_timeout(ms(1000)); // match oper { // Err(_) => panic!(), // Ok(oper) => match oper.index() { // i if i == oper1 => panic!(), // i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(2)), // _ => unreachable!(), // }, // } // }) // .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(); // let oper1 = sel.recv(&r1); // let oper2 = sel.send(&s2); // let oper = sel.select(); // match oper.index() { // i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(1)), // i if i == oper2 => oper.send(&s2, 2).unwrap(), // _ => unreachable!(), // } // } // }) // .unwrap(); // } // #[test] // fn loop_try() { // const RUNS: usize = 20; // for _ in 0..RUNS { // let (s1, r1) = bounded::(0); // let (s2, r2) = bounded::(0); // let (s_end, r_end) = bounded::<()>(0); // scope(|scope| { // scope.spawn(|_| loop { // let mut done = false; // let mut sel = Select::new(); // let oper1 = sel.send(&s1); // let oper = sel.try_select(); // match oper { // Err(_) => {} // Ok(oper) => match oper.index() { // i if i == oper1 => { // let _ = oper.send(&s1, 1); // done = true; // } // _ => unreachable!(), // }, // } // if done { // break; // } // let mut sel = Select::new(); // let oper1 = sel.recv(&r_end); // let oper = sel.try_select(); // match oper { // Err(_) => {} // Ok(oper) => match oper.index() { // i if i == oper1 => { // let _ = oper.recv(&r_end); // done = true; // } // _ => unreachable!(), // }, // } // if done { // break; // } // }); // scope.spawn(|_| loop { // if let Ok(x) = r2.try_recv() { // assert_eq!(x, 2); // break; // } // let mut done = false; // let mut sel = Select::new(); // let oper1 = sel.recv(&r_end); // let oper = sel.try_select(); // match oper { // Err(_) => {} // Ok(oper) => match oper.index() { // i if i == oper1 => { // let _ = oper.recv(&r_end); // done = true; // } // _ => unreachable!(), // }, // } // if done { // break; // } // }); // scope.spawn(|_| { // thread::sleep(ms(500)); // let mut sel = Select::new(); // let oper1 = sel.recv(&r1); // let oper2 = sel.send(&s2); // let oper = sel.select_timeout(ms(1000)); // match oper { // Err(_) => {} // Ok(oper) => match oper.index() { // i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(1)), // i if i == oper2 => assert!(oper.send(&s2, 2).is_ok()), // _ => unreachable!(), // }, // } // drop(s_end); // }); // }) // .unwrap(); // } // } // #[test] // fn cloning1() { // scope(|scope| { // let (s1, r1) = unbounded::(); // let (_s2, r2) = unbounded::(); // 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(); // let oper1 = sel.recv(&r1); // let oper2 = sel.recv(&r2); // let oper = sel.select(); // match oper.index() { // i if i == oper1 => drop(oper.recv(&r1)), // i if i == oper2 => drop(oper.recv(&r2)), // _ => unreachable!(), // } // 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(); // let oper1 = sel.recv(&r1); // let oper2 = sel.recv(&r2); // let oper = sel.select(); // match oper.index() { // i if i == oper1 => panic!(), // i if i == oper2 => drop(oper.recv(&r2)), // _ => unreachable!(), // } // }); // 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(); // let oper1 = sel.recv(&r); // let oper = sel.select(); // match oper.index() { // i if i == oper1 => drop(oper.recv(&r)), // _ => unreachable!(), // } // } // #[test] // fn preflight2() { // let (s, r) = unbounded(); // drop(s.clone()); // s.send(()).unwrap(); // drop(s); // let mut sel = Select::new(); // let oper1 = sel.recv(&r); // let oper = sel.select(); // match oper.index() { // i if i == oper1 => assert_eq!(oper.recv(&r), Ok(())), // _ => unreachable!(), // } // 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(); // let oper1 = sel.recv(&r); // let oper = sel.select(); // match oper.index() { // i if i == oper1 => assert!(oper.recv(&r).is_err()), // _ => unreachable!(), // } // } // #[test] // fn duplicate_operations() { // let (s, r) = unbounded::(); // let hit = vec![Cell::new(false); 4]; // while hit.iter().map(|h| h.get()).any(|hit| !hit) { // let mut sel = Select::new(); // let oper0 = sel.recv(&r); // let oper1 = sel.recv(&r); // let oper2 = sel.send(&s); // let oper3 = sel.send(&s); // let oper = sel.select(); // match oper.index() { // i if i == oper0 => { // assert!(oper.recv(&r).is_ok()); // hit[0].set(true); // } // i if i == oper1 => { // assert!(oper.recv(&r).is_ok()); // hit[1].set(true); // } // i if i == oper2 => { // assert!(oper.send(&s, 0).is_ok()); // hit[2].set(true); // } // i if i == oper3 => { // assert!(oper.send(&s, 0).is_ok()); // hit[3].set(true); // } // _ => unreachable!(), // } // } // } // #[test] // fn nesting() { // let (s, r) = unbounded::(); // let mut sel = Select::new(); // let oper1 = sel.send(&s); // let oper = sel.select(); // match oper.index() { // i if i == oper1 => { // assert!(oper.send(&s, 0).is_ok()); // let mut sel = Select::new(); // let oper1 = sel.recv(&r); // let oper = sel.select(); // match oper.index() { // i if i == oper1 => { // assert_eq!(oper.recv(&r), Ok(0)); // let mut sel = Select::new(); // let oper1 = sel.send(&s); // let oper = sel.select(); // match oper.index() { // i if i == oper1 => { // assert!(oper.send(&s, 1).is_ok()); // let mut sel = Select::new(); // let oper1 = sel.recv(&r); // let oper = sel.select(); // match oper.index() { // i if i == oper1 => { // assert_eq!(oper.recv(&r), Ok(1)); // } // _ => unreachable!(), // } // } // _ => unreachable!(), // } // } // _ => unreachable!(), // } // } // _ => unreachable!(), // } // } // #[test] // fn stress_recv() { // const COUNT: usize = 10_000; // let (s1, r1) = unbounded(); // let (s2, r2) = bounded(5); // let (s3, r3) = bounded(100); // 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(); // let oper1 = sel.recv(&r1); // let oper2 = sel.recv(&r2); // let oper = sel.select(); // match oper.index() { // ix if ix == oper1 => assert_eq!(oper.recv(&r1), Ok(i)), // ix if ix == oper2 => assert_eq!(oper.recv(&r2), Ok(i)), // _ => unreachable!(), // } // 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(); // let oper1 = sel.send(&s1); // let oper2 = sel.send(&s2); // let oper = sel.select(); // match oper.index() { // ix if ix == oper1 => assert!(oper.send(&s1, i).is_ok()), // ix if ix == oper2 => assert!(oper.send(&s2, i).is_ok()), // _ => unreachable!(), // } // } // 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(); // let oper1 = sel.recv(&r1); // let oper2 = sel.send(&s2); // let oper = sel.select(); // match oper.index() { // ix if ix == oper1 => assert_eq!(oper.recv(&r1), Ok(i)), // ix if ix == oper2 => assert!(oper.send(&s2, i).is_ok()), // _ => unreachable!(), // } // } // 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(); // let oper1 = sel.send(&s); // let oper = sel.select_timeout(ms(100)); // match oper { // Err(_) => {} // Ok(oper) => match oper.index() { // ix if ix == oper1 => { // assert!(oper.send(&s, i).is_ok()); // break; // } // _ => unreachable!(), // }, // } // } // } // }); // 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(); // let oper1 = sel.recv(&r); // let oper = sel.select_timeout(ms(100)); // match oper { // Err(_) => {} // Ok(oper) => match oper.index() { // ix if ix == oper1 => { // assert_eq!(oper.recv(&r), Ok(i)); // done = true; // } // _ => unreachable!(), // }, // } // } // } // }); // }) // .unwrap(); // } // #[test] // fn send_recv_same_channel() { // let (s, r) = bounded::(0); // let mut sel = Select::new(); // let oper1 = sel.send(&s); // let oper2 = sel.recv(&r); // let oper = sel.select_timeout(ms(100)); // match oper { // Err(_) => {} // Ok(oper) => match oper.index() { // ix if ix == oper1 => panic!(), // ix if ix == oper2 => panic!(), // _ => unreachable!(), // }, // } // let (s, r) = unbounded::(); // let mut sel = Select::new(); // let oper1 = sel.send(&s); // let oper2 = sel.recv(&r); // let oper = sel.select_timeout(ms(100)); // match oper { // Err(_) => panic!(), // Ok(oper) => match oper.index() { // ix if ix == oper1 => assert!(oper.send(&s, 0).is_ok()), // ix if ix == oper2 => panic!(), // _ => unreachable!(), // }, // } // } // #[test] // fn matching() { // const THREADS: usize = 44; // let (s, r) = &bounded::(0); // scope(|scope| { // for i in 0..THREADS { // scope.spawn(move |_| { // let mut sel = Select::new(); // let oper1 = sel.recv(&r); // let oper2 = sel.send(&s); // let oper = sel.select(); // match oper.index() { // ix if ix == oper1 => assert_ne!(oper.recv(&r), Ok(i)), // ix if ix == oper2 => assert!(oper.send(&s, i).is_ok()), // _ => unreachable!(), // } // }); // } // }) // .unwrap(); // assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); // } // #[test] // fn matching_with_leftover() { // const THREADS: usize = 55; // let (s, r) = &bounded::(0); // scope(|scope| { // for i in 0..THREADS { // scope.spawn(move |_| { // let mut sel = Select::new(); // let oper1 = sel.recv(&r); // let oper2 = sel.send(&s); // let oper = sel.select(); // match oper.index() { // ix if ix == oper1 => assert_ne!(oper.recv(&r), Ok(i)), // ix if ix == oper2 => assert!(oper.send(&s, i).is_ok()), // _ => unreachable!(), // } // }); // } // s.send(!0).unwrap(); // }) // .unwrap(); // assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); // } // #[test] // fn channel_through_channel() { // const COUNT: usize = 1000; // type T = Box; // for cap in 0..3 { // let (s, r) = bounded::(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(); // let oper1 = sel.send(&s); // let oper = sel.select(); // match oper.index() { // ix if ix == oper1 => assert!(oper.send(&s, new_r).is_ok()), // _ => unreachable!(), // } // } // s = new_s; // } // }); // scope.spawn(move |_| { // let mut r = r; // for _ in 0..COUNT { // let new = { // let mut sel = Select::new(); // let oper1 = sel.recv(&r); // let oper = sel.select(); // match oper.index() { // ix if ix == oper1 => oper // .recv(&r) // .unwrap() // .downcast_mut::>>() // .unwrap() // .take() // .unwrap(), // _ => unreachable!(), // } // }; // r = new; // } // }); // }) // .unwrap(); // } // } // #[test] // fn linearizable_try() { // const COUNT: usize = 100_000; // for step in 0..2 { // let (start_s, start_r) = bounded::<()>(0); // let (end_s, end_r) = bounded::<()>(0); // let ((s1, r1), (s2, r2)) = if step == 0 { // (bounded::(1), bounded::(1)) // } else { // (unbounded::(), unbounded::()) // }; // scope(|scope| { // scope.spawn(|_| { // for _ in 0..COUNT { // start_s.send(()).unwrap(); // s1.send(1).unwrap(); // let mut sel = Select::new(); // let oper1 = sel.recv(&r1); // let oper2 = sel.recv(&r2); // let oper = sel.try_select(); // match oper { // Err(_) => unreachable!(), // Ok(oper) => match oper.index() { // ix if ix == oper1 => assert!(oper.recv(&r1).is_ok()), // ix if ix == oper2 => assert!(oper.recv(&r2).is_ok()), // _ => unreachable!(), // }, // } // end_s.send(()).unwrap(); // let _ = r2.try_recv(); // } // }); // for _ in 0..COUNT { // start_r.recv().unwrap(); // s2.send(1).unwrap(); // let _ = r1.try_recv(); // end_r.recv().unwrap(); // } // }) // .unwrap(); // } // } // #[test] // fn linearizable_timeout() { // const COUNT: usize = 100_000; // for step in 0..2 { // let (start_s, start_r) = bounded::<()>(0); // let (end_s, end_r) = bounded::<()>(0); // let ((s1, r1), (s2, r2)) = if step == 0 { // (bounded::(1), bounded::(1)) // } else { // (unbounded::(), unbounded::()) // }; // scope(|scope| { // scope.spawn(|_| { // for _ in 0..COUNT { // start_s.send(()).unwrap(); // s1.send(1).unwrap(); // let mut sel = Select::new(); // let oper1 = sel.recv(&r1); // let oper2 = sel.recv(&r2); // let oper = sel.select_timeout(ms(0)); // match oper { // Err(_) => unreachable!(), // Ok(oper) => match oper.index() { // ix if ix == oper1 => assert!(oper.recv(&r1).is_ok()), // ix if ix == oper2 => assert!(oper.recv(&r2).is_ok()), // _ => unreachable!(), // }, // } // end_s.send(()).unwrap(); // let _ = r2.try_recv(); // } // }); // for _ in 0..COUNT { // start_r.recv().unwrap(); // s2.send(1).unwrap(); // let _ = r1.try_recv(); // end_r.recv().unwrap(); // } // }) // .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(); // let oper1 = sel.recv(&r1); // let oper2 = sel.recv(&r2); // let oper3 = sel.recv(&after); // let oper4 = sel.recv(&tick); // let oper = sel.select(); // match oper.index() { // i if i == oper1 => { // oper.recv(&r1).unwrap(); // hits[0].set(hits[0].get() + 1); // } // i if i == oper2 => { // oper.recv(&r2).unwrap(); // hits[1].set(hits[1].get() + 1); // } // i if i == oper3 => { // oper.recv(&after).unwrap(); // hits[2].set(hits[2].get() + 1); // } // i if i == oper4 => { // oper.recv(&tick).unwrap(); // hits[3].set(hits[3].get() + 1); // } // _ => unreachable!(), // } // } // 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(); // let oper1 = sel.recv(&r1); // let oper2 = sel.recv(&r2); // let oper3 = sel.recv(&r3); // let oper = sel.select(); // match oper.index() { // i if i == oper1 => { // oper.recv(&r1).unwrap(); // hits[0].set(hits[0].get() + 1); // } // i if i == oper2 => { // oper.recv(&r2).unwrap(); // hits[1].set(hits[1].get() + 1); // } // i if i == oper3 => { // oper.recv(&r3).unwrap(); // hits[2].set(hits[2].get() + 1); // } // _ => unreachable!(), // } // } // assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 50)); // }) // .unwrap(); // } // #[test] // fn sync_and_clone() { // const THREADS: usize = 20; // let (s, r) = &bounded::(0); // let mut sel = Select::new(); // let oper1 = sel.recv(&r); // let oper2 = sel.send(&s); // let sel = &sel; // scope(|scope| { // for i in 0..THREADS { // scope.spawn(move |_| { // let mut sel = sel.clone(); // let oper = sel.select(); // match oper.index() { // ix if ix == oper1 => assert_ne!(oper.recv(&r), Ok(i)), // ix if ix == oper2 => assert!(oper.send(&s, i).is_ok()), // _ => unreachable!(), // } // }); // } // }) // .unwrap(); // assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); // } // #[test] // fn send_and_clone() { // const THREADS: usize = 20; // let (s, r) = &bounded::(0); // let mut sel = Select::new(); // let oper1 = sel.recv(&r); // let oper2 = sel.send(&s); // scope(|scope| { // for i in 0..THREADS { // let mut sel = sel.clone(); // scope.spawn(move |_| { // let oper = sel.select(); // match oper.index() { // ix if ix == oper1 => assert_ne!(oper.recv(&r), Ok(i)), // ix if ix == oper2 => assert!(oper.send(&s, i).is_ok()), // _ => unreachable!(), // } // }); // } // }) // .unwrap(); // assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); // } // #[test] // fn reuse() { // 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(); // } // }); // let mut sel = Select::new(); // let oper1 = sel.recv(&r1); // let oper2 = sel.send(&s2); // for i in 0..COUNT { // for _ in 0..2 { // let oper = sel.select(); // match oper.index() { // ix if ix == oper1 => assert_eq!(oper.recv(&r1), Ok(i)), // ix if ix == oper2 => assert!(oper.send(&s2, i).is_ok()), // _ => unreachable!(), // } // } // s3.send(()).unwrap(); // } // }) // .unwrap(); // } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/tests/select_macro.rs000066400000000000000000001045111446715670500245070ustar00rootroot00000000000000// //! Tests for the `select!` macro. // #![deny(unsafe_code)] // #[macro_use] // extern crate crossbeam_channel; // extern crate crossbeam_utils; // use std::any::Any; // use std::cell::Cell; // use std::ops::Deref; // use std::thread; // use std::time::{Duration, Instant}; // use crossbeam_channel::{after, bounded, never, tick, unbounded}; // use crossbeam_channel::{Receiver, RecvError, SendError, Sender, TryRecvError}; // use crossbeam_utils::thread::scope; // fn ms(ms: u64) -> Duration { // Duration::from_millis(ms) // } // #[test] // fn smoke1() { // let (s1, r1) = unbounded::(); // let (s2, r2) = unbounded::(); // s1.send(1).unwrap(); // select! { // recv(r1) -> v => assert_eq!(v, Ok(1)), // recv(r2) -> _ => panic!(), // } // s2.send(2).unwrap(); // select! { // recv(r1) -> _ => panic!(), // recv(r2) -> v => assert_eq!(v, Ok(2)), // } // } // #[test] // fn smoke2() { // let (_s1, r1) = unbounded::(); // let (_s2, r2) = unbounded::(); // let (_s3, r3) = unbounded::(); // let (_s4, r4) = unbounded::(); // let (s5, r5) = unbounded::(); // s5.send(5).unwrap(); // select! { // recv(r1) -> _ => panic!(), // recv(r2) -> _ => panic!(), // recv(r3) -> _ => panic!(), // recv(r4) -> _ => panic!(), // recv(r5) -> v => assert_eq!(v, Ok(5)), // } // } // #[test] // fn disconnected() { // let (s1, r1) = unbounded::(); // let (s2, r2) = unbounded::(); // scope(|scope| { // scope.spawn(|_| { // drop(s1); // thread::sleep(ms(500)); // s2.send(5).unwrap(); // }); // select! { // recv(r1) -> v => assert!(v.is_err()), // recv(r2) -> _ => panic!(), // default(ms(1000)) => panic!(), // } // r2.recv().unwrap(); // }) // .unwrap(); // select! { // recv(r1) -> v => assert!(v.is_err()), // recv(r2) -> _ => panic!(), // default(ms(1000)) => panic!(), // } // scope(|scope| { // scope.spawn(|_| { // thread::sleep(ms(500)); // drop(s2); // }); // select! { // recv(r2) -> v => assert!(v.is_err()), // default(ms(1000)) => panic!(), // } // }) // .unwrap(); // } // #[test] // fn default() { // let (s1, r1) = unbounded::(); // let (s2, r2) = unbounded::(); // select! { // recv(r1) -> _ => panic!(), // recv(r2) -> _ => panic!(), // default => {} // } // drop(s1); // select! { // recv(r1) -> v => assert!(v.is_err()), // recv(r2) -> _ => panic!(), // default => panic!(), // } // s2.send(2).unwrap(); // select! { // recv(r2) -> v => assert_eq!(v, Ok(2)), // default => panic!(), // } // select! { // recv(r2) -> _ => panic!(), // default => {}, // } // select! { // default => {}, // } // } // #[test] // fn timeout() { // let (_s1, r1) = unbounded::(); // let (s2, r2) = unbounded::(); // scope(|scope| { // scope.spawn(|_| { // thread::sleep(ms(1500)); // s2.send(2).unwrap(); // }); // select! { // recv(r1) -> _ => panic!(), // recv(r2) -> _ => panic!(), // default(ms(1000)) => {}, // } // select! { // recv(r1) -> _ => panic!(), // recv(r2) -> v => assert_eq!(v, Ok(2)), // default(ms(1000)) => panic!(), // } // }) // .unwrap(); // scope(|scope| { // let (s, r) = unbounded::(); // scope.spawn(move |_| { // thread::sleep(ms(500)); // drop(s); // }); // select! { // default(ms(1000)) => { // select! { // recv(r) -> v => assert!(v.is_err()), // default => panic!(), // } // } // } // }) // .unwrap(); // } // #[test] // fn default_when_disconnected() { // let (_, r) = unbounded::(); // select! { // recv(r) -> res => assert!(res.is_err()), // default => panic!(), // } // let (_, r) = unbounded::(); // select! { // recv(r) -> res => assert!(res.is_err()), // default(ms(1000)) => panic!(), // } // let (s, _) = bounded::(0); // select! { // send(s, 0) -> res => assert!(res.is_err()), // default => panic!(), // } // let (s, _) = bounded::(0); // select! { // send(s, 0) -> res => assert!(res.is_err()), // default(ms(1000)) => panic!(), // } // } // #[test] // fn default_only() { // let start = Instant::now(); // select! { // default => {} // } // let now = Instant::now(); // assert!(now - start <= ms(50)); // let start = Instant::now(); // select! { // default(ms(500)) => {} // } // let now = Instant::now(); // assert!(now - start >= ms(450)); // assert!(now - start <= ms(550)); // } // #[test] // fn unblocks() { // let (s1, r1) = bounded::(0); // let (s2, r2) = bounded::(0); // scope(|scope| { // scope.spawn(|_| { // thread::sleep(ms(500)); // s2.send(2).unwrap(); // }); // select! { // recv(r1) -> _ => panic!(), // recv(r2) -> v => assert_eq!(v, Ok(2)), // default(ms(1000)) => panic!(), // } // }) // .unwrap(); // scope(|scope| { // scope.spawn(|_| { // thread::sleep(ms(500)); // assert_eq!(r1.recv().unwrap(), 1); // }); // select! { // send(s1, 1) -> _ => {}, // send(s2, 2) -> _ => panic!(), // default(ms(1000)) => panic!(), // } // }) // .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 { // select! { // recv(r1) -> v => assert_eq!(v, Ok(1)), // send(s2, 2) -> _ => {}, // } // } // }) // .unwrap(); // } // #[test] // fn loop_try() { // const RUNS: usize = 20; // for _ in 0..RUNS { // let (s1, r1) = bounded::(0); // let (s2, r2) = bounded::(0); // let (s_end, r_end) = bounded::<()>(0); // scope(|scope| { // scope.spawn(|_| loop { // select! { // send(s1, 1) -> _ => break, // default => {} // } // select! { // recv(r_end) -> _ => break, // default => {} // } // }); // scope.spawn(|_| loop { // if let Ok(x) = r2.try_recv() { // assert_eq!(x, 2); // break; // } // select! { // recv(r_end) -> _ => break, // default => {} // } // }); // scope.spawn(|_| { // thread::sleep(ms(500)); // select! { // recv(r1) -> v => assert_eq!(v, Ok(1)), // send(s2, 2) -> _ => {}, // default(ms(500)) => panic!(), // } // drop(s_end); // }); // }) // .unwrap(); // } // } // #[test] // fn cloning1() { // scope(|scope| { // let (s1, r1) = unbounded::(); // let (_s2, r2) = unbounded::(); // let (s3, r3) = unbounded::<()>(); // scope.spawn(move |_| { // r3.recv().unwrap(); // drop(s1.clone()); // assert_eq!(r3.try_recv(), Err(TryRecvError::Empty)); // s1.send(1).unwrap(); // r3.recv().unwrap(); // }); // s3.send(()).unwrap(); // select! { // recv(r1) -> _ => {}, // recv(r2) -> _ => {}, // } // s3.send(()).unwrap(); // }) // .unwrap(); // } // #[test] // fn cloning2() { // let (s1, r1) = unbounded::<()>(); // let (s2, r2) = unbounded::<()>(); // let (_s3, _r3) = unbounded::<()>(); // scope(|scope| { // scope.spawn(move |_| { // select! { // recv(r1) -> _ => panic!(), // recv(r2) -> _ => {}, // } // }); // thread::sleep(ms(500)); // drop(s1.clone()); // s2.send(()).unwrap(); // }) // .unwrap(); // } // #[test] // fn preflight1() { // let (s, r) = unbounded(); // s.send(()).unwrap(); // select! { // recv(r) -> _ => {} // } // } // #[test] // fn preflight2() { // let (s, r) = unbounded(); // drop(s.clone()); // s.send(()).unwrap(); // drop(s); // select! { // recv(r) -> v => assert!(v.is_ok()), // } // 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(); // select! { // recv(r) -> v => assert!(v.is_err()) // } // } // #[test] // fn duplicate_operations() { // let (s, r) = unbounded::(); // let mut hit = [false; 4]; // while hit.iter().any(|hit| !hit) { // select! { // recv(r) -> _ => hit[0] = true, // recv(r) -> _ => hit[1] = true, // send(s, 0) -> _ => hit[2] = true, // send(s, 0) -> _ => hit[3] = true, // } // } // } // #[test] // fn nesting() { // let (s, r) = unbounded::(); // select! { // send(s, 0) -> _ => { // select! { // recv(r) -> v => { // assert_eq!(v, Ok(0)); // select! { // send(s, 1) -> _ => { // select! { // recv(r) -> v => { // assert_eq!(v, Ok(1)); // } // } // } // } // } // } // } // } // } // #[test] // #[should_panic(expected = "send panicked")] // fn panic_sender() { // fn get() -> Sender { // panic!("send panicked") // } // #[allow(unreachable_code)] // { // select! { // send(get(), panic!()) -> _ => {} // } // } // } // #[test] // #[should_panic(expected = "recv panicked")] // fn panic_receiver() { // fn get() -> Receiver { // panic!("recv panicked") // } // select! { // recv(get()) -> _ => {} // } // } // #[test] // fn stress_recv() { // const COUNT: usize = 10_000; // let (s1, r1) = unbounded(); // let (s2, r2) = bounded(5); // let (s3, r3) = bounded(100); // 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 { // select! { // recv(r1) -> v => assert_eq!(v, Ok(i)), // recv(r2) -> v => assert_eq!(v, Ok(i)), // } // 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 { // select! { // send(s1, i) -> _ => {}, // send(s2, i) -> _ => {}, // } // } // 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 { // select! { // recv(r1) -> v => assert_eq!(v, Ok(i)), // send(s2, i) -> _ => {}, // } // } // 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)); // } // loop { // select! { // send(s, i) -> _ => break, // default(ms(100)) => {} // } // } // } // }); // scope.spawn(|_| { // for i in 0..COUNT { // if i % 2 == 0 { // thread::sleep(ms(500)); // } // loop { // select! { // recv(r) -> v => { // assert_eq!(v, Ok(i)); // break; // } // default(ms(100)) => {} // } // } // } // }); // }) // .unwrap(); // } // #[test] // fn send_recv_same_channel() { // let (s, r) = bounded::(0); // select! { // send(s, 0) -> _ => panic!(), // recv(r) -> _ => panic!(), // default(ms(500)) => {} // } // let (s, r) = unbounded::(); // select! { // send(s, 0) -> _ => {}, // recv(r) -> _ => panic!(), // default(ms(500)) => panic!(), // } // } // #[test] // fn matching() { // const THREADS: usize = 44; // let (s, r) = &bounded::(0); // scope(|scope| { // for i in 0..THREADS { // scope.spawn(move |_| { // select! { // recv(r) -> v => assert_ne!(v.unwrap(), i), // send(s, i) -> _ => {}, // } // }); // } // }) // .unwrap(); // assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); // } // #[test] // fn matching_with_leftover() { // const THREADS: usize = 55; // let (s, r) = &bounded::(0); // scope(|scope| { // for i in 0..THREADS { // scope.spawn(move |_| { // select! { // recv(r) -> v => assert_ne!(v.unwrap(), i), // send(s, i) -> _ => {}, // } // }); // } // s.send(!0).unwrap(); // }) // .unwrap(); // assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); // } // #[test] // fn channel_through_channel() { // const COUNT: usize = 1000; // type T = Box; // for cap in 0..3 { // let (s, r) = bounded::(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)); // select! { // send(s, new_r) -> _ => {} // } // s = new_s; // } // }); // scope.spawn(move |_| { // let mut r = r; // for _ in 0..COUNT { // r = select! { // recv(r) -> msg => { // msg.unwrap() // .downcast_mut::>>() // .unwrap() // .take() // .unwrap() // } // } // } // }); // }) // .unwrap(); // } // } // #[test] // fn linearizable_default() { // const COUNT: usize = 100_000; // for step in 0..2 { // let (start_s, start_r) = bounded::<()>(0); // let (end_s, end_r) = bounded::<()>(0); // let ((s1, r1), (s2, r2)) = if step == 0 { // (bounded::(1), bounded::(1)) // } else { // (unbounded::(), unbounded::()) // }; // scope(|scope| { // scope.spawn(|_| { // for _ in 0..COUNT { // start_s.send(()).unwrap(); // s1.send(1).unwrap(); // select! { // recv(r1) -> _ => {} // recv(r2) -> _ => {} // default => unreachable!() // } // end_s.send(()).unwrap(); // let _ = r2.try_recv(); // } // }); // for _ in 0..COUNT { // start_r.recv().unwrap(); // s2.send(1).unwrap(); // let _ = r1.try_recv(); // end_r.recv().unwrap(); // } // }) // .unwrap(); // } // } // #[test] // fn linearizable_timeout() { // const COUNT: usize = 100_000; // for step in 0..2 { // let (start_s, start_r) = bounded::<()>(0); // let (end_s, end_r) = bounded::<()>(0); // let ((s1, r1), (s2, r2)) = if step == 0 { // (bounded::(1), bounded::(1)) // } else { // (unbounded::(), unbounded::()) // }; // scope(|scope| { // scope.spawn(|_| { // for _ in 0..COUNT { // start_s.send(()).unwrap(); // s1.send(1).unwrap(); // select! { // recv(r1) -> _ => {} // recv(r2) -> _ => {} // default(ms(0)) => unreachable!() // } // end_s.send(()).unwrap(); // let _ = r2.try_recv(); // } // }); // for _ in 0..COUNT { // start_r.recv().unwrap(); // s2.send(1).unwrap(); // let _ = r1.try_recv(); // end_r.recv().unwrap(); // } // }) // .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 mut hits = [0usize; 4]; // for _ in 0..COUNT { // select! { // recv(r1) -> _ => hits[0] += 1, // recv(r2) -> _ => hits[1] += 1, // recv(after(ms(0))) -> _ => hits[2] += 1, // recv(tick(ms(0))) -> _ => hits[3] += 1, // } // } // assert!(hits.iter().all(|x| *x >= 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(|_| { // let (hole, _r) = bounded(0); // for _ in 0..COUNT { // let s1 = if s1.is_empty() { &s1 } else { &hole }; // let s2 = if s2.is_empty() { &s2 } else { &hole }; // select! { // send(s1, ()) -> res => assert!(res.is_ok()), // send(s2, ()) -> res => assert!(res.is_ok()), // send(s3, ()) -> res => assert!(res.is_ok()), // } // } // }); // let hits = vec![Cell::new(0usize); 3]; // for _ in 0..COUNT { // select! { // recv(r1) -> _ => hits[0].set(hits[0].get() + 1), // recv(r2) -> _ => hits[1].set(hits[1].get() + 1), // recv(r3) -> _ => hits[2].set(hits[2].get() + 1), // } // } // assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 50)); // }) // .unwrap(); // } // #[test] // fn fairness_recv() { // 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 mut hits = [0usize; 2]; // while hits[0] + hits[1] < COUNT { // select! { // recv(r1) -> _ => hits[0] += 1, // recv(r2) -> _ => hits[1] += 1, // } // } // assert!(hits.iter().all(|x| *x >= COUNT / 4)); // } // #[test] // fn fairness_send() { // const COUNT: usize = 10_000; // let (s1, _r1) = bounded::<()>(COUNT); // let (s2, _r2) = unbounded::<()>(); // 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 / 4)); // } // #[test] // fn references() { // let (s, r) = unbounded::(); // select! { // send(s, 0) -> _ => {} // recv(r) -> _ => {} // } // select! { // send(&&&&s, 0) -> _ => {} // recv(&&&&r) -> _ => {} // } // select! { // recv(Some(&r).unwrap_or(&never())) -> _ => {}, // default => {} // } // select! { // recv(Some(r).unwrap_or(never())) -> _ => {}, // default => {} // } // } // #[test] // fn case_blocks() { // let (s, r) = unbounded::(); // select! { // recv(r) -> _ => 3.0, // recv(r) -> _ => loop { // unreachable!() // }, // recv(r) -> _ => match 7 + 3 { // _ => unreachable!() // }, // default => 7. // }; // select! { // recv(r) -> msg => if msg.is_ok() { // unreachable!() // }, // default => () // } // drop(s); // } // #[test] // fn move_handles() { // let (s, r) = unbounded::(); // select! { // recv((move || r)()) -> _ => {} // send((move || s)(), 0) -> _ => {} // } // } // #[test] // fn infer_types() { // let (s, r) = unbounded(); // select! { // recv(r) -> _ => {} // default => {} // } // s.send(()).unwrap(); // let (s, r) = unbounded(); // select! { // send(s, ()) -> _ => {} // } // r.recv().unwrap(); // } // #[test] // fn default_syntax() { // let (s, r) = bounded::(0); // select! { // recv(r) -> _ => panic!(), // default => {} // } // select! { // send(s, 0) -> _ => panic!(), // default() => {} // } // select! { // default => {} // } // select! { // default() => {} // } // } // #[test] // fn same_variable_name() { // let (_, r) = unbounded::(); // select! { // recv(r) -> r => assert!(r.is_err()), // } // } // #[test] // fn handles_on_heap() { // let (s, r) = unbounded::(); // let (s, r) = (Box::new(s), Box::new(r)); // select! { // send(*s, 0) -> _ => {} // recv(*r) -> _ => {} // default => {} // } // drop(s); // drop(r); // } // #[test] // fn once_blocks() { // let (s, r) = unbounded::(); // let once = Box::new(()); // select! { // send(s, 0) -> _ => drop(once), // } // let once = Box::new(()); // select! { // recv(r) -> _ => drop(once), // } // let once1 = Box::new(()); // let once2 = Box::new(()); // select! { // send(s, 0) -> _ => drop(once1), // default => drop(once2), // } // let once1 = Box::new(()); // let once2 = Box::new(()); // select! { // recv(r) -> _ => drop(once1), // default => drop(once2), // } // let once1 = Box::new(()); // let once2 = Box::new(()); // select! { // recv(r) -> _ => drop(once1), // send(s, 0) -> _ => drop(once2), // } // } // #[test] // fn once_receiver() { // let (_, r) = unbounded::(); // let once = Box::new(()); // let get = move || { // drop(once); // r // }; // select! { // recv(get()) -> _ => {} // } // } // #[test] // fn once_sender() { // let (s, _) = unbounded::(); // let once = Box::new(()); // let get = move || { // drop(once); // s // }; // select! { // send(get(), 5) -> _ => {} // } // } // #[test] // fn parse_nesting() { // let (_, r) = unbounded::(); // select! { // recv(r) -> _ => {} // recv(r) -> _ => { // select! { // recv(r) -> _ => {} // recv(r) -> _ => { // select! { // recv(r) -> _ => {} // recv(r) -> _ => { // select! { // default => {} // } // } // } // } // } // } // } // } // #[test] // fn evaluate() { // let (s, r) = unbounded::(); // let v = select! { // recv(r) -> _ => "foo".into(), // send(s, 0) -> _ => "bar".to_owned(), // default => "baz".to_string(), // }; // assert_eq!(v, "bar"); // let v = select! { // recv(r) -> _ => "foo".into(), // default => "baz".to_string(), // }; // assert_eq!(v, "foo"); // let v = select! { // recv(r) -> _ => "foo".into(), // default => "baz".to_string(), // }; // assert_eq!(v, "baz"); // } // #[test] // fn deref() { // use crossbeam_channel as cc; // struct Sender(cc::Sender); // struct Receiver(cc::Receiver); // impl Deref for Receiver { // type Target = cc::Receiver; // fn deref(&self) -> &Self::Target { // &self.0 // } // } // impl Deref for Sender { // type Target = cc::Sender; // fn deref(&self) -> &Self::Target { // &self.0 // } // } // let (s, r) = bounded::(0); // let (s, r) = (Sender(s), Receiver(r)); // select! { // send(s, 0) -> _ => panic!(), // recv(r) -> _ => panic!(), // default => {} // } // } // #[test] // fn result_types() { // let (s, _) = bounded::(0); // let (_, r) = bounded::(0); // select! { // recv(r) -> res => drop::>(res), // } // select! { // recv(r) -> res => drop::>(res), // default => {} // } // select! { // recv(r) -> res => drop::>(res), // default(ms(0)) => {} // } // select! { // send(s, 0) -> res => drop::>>(res), // } // select! { // send(s, 0) -> res => drop::>>(res), // default => {} // } // select! { // send(s, 0) -> res => drop::>>(res), // default(ms(0)) => {} // } // select! { // send(s, 0) -> res => drop::>>(res), // recv(r) -> res => drop::>(res), // } // } // #[test] // fn try_recv() { // let (s, r) = bounded(0); // scope(|scope| { // scope.spawn(move |_| { // select! { // recv(r) -> _ => panic!(), // default => {} // } // thread::sleep(ms(1500)); // select! { // recv(r) -> v => assert_eq!(v, Ok(7)), // default => panic!(), // } // thread::sleep(ms(500)); // select! { // recv(r) -> v => assert_eq!(v, Err(RecvError)), // default => panic!(), // } // }); // scope.spawn(move |_| { // thread::sleep(ms(1000)); // select! { // send(s, 7) -> res => res.unwrap(), // } // }); // }) // .unwrap(); // } // #[test] // fn recv() { // let (s, r) = bounded(0); // scope(|scope| { // scope.spawn(move |_| { // select! { // recv(r) -> v => assert_eq!(v, Ok(7)), // } // thread::sleep(ms(1000)); // select! { // recv(r) -> v => assert_eq!(v, Ok(8)), // } // thread::sleep(ms(1000)); // select! { // recv(r) -> v => assert_eq!(v, Ok(9)), // } // select! { // recv(r) -> v => assert_eq!(v, Err(RecvError)), // } // }); // scope.spawn(move |_| { // thread::sleep(ms(1500)); // select! { // send(s, 7) -> res => res.unwrap(), // } // select! { // send(s, 8) -> res => res.unwrap(), // } // select! { // send(s, 9) -> res => res.unwrap(), // } // }); // }) // .unwrap(); // } // #[test] // fn recv_timeout() { // let (s, r) = bounded::(0); // scope(|scope| { // scope.spawn(move |_| { // select! { // recv(r) -> _ => panic!(), // default(ms(1000)) => {} // } // select! { // recv(r) -> v => assert_eq!(v, Ok(7)), // default(ms(1000)) => panic!(), // } // select! { // recv(r) -> v => assert_eq!(v, Err(RecvError)), // default(ms(1000)) => panic!(), // } // }); // scope.spawn(move |_| { // thread::sleep(ms(1500)); // select! { // send(s, 7) -> res => res.unwrap(), // } // }); // }) // .unwrap(); // } // #[test] // fn try_send() { // let (s, r) = bounded(0); // scope(|scope| { // scope.spawn(move |_| { // select! { // send(s, 7) -> _ => panic!(), // default => {} // } // thread::sleep(ms(1500)); // select! { // send(s, 8) -> res => res.unwrap(), // default => panic!(), // } // thread::sleep(ms(500)); // select! { // send(s, 8) -> res => assert_eq!(res, Err(SendError(8))), // default => panic!(), // } // }); // scope.spawn(move |_| { // thread::sleep(ms(1000)); // select! { // recv(r) -> v => assert_eq!(v, Ok(8)), // } // }); // }) // .unwrap(); // } // #[test] // fn send() { // let (s, r) = bounded(0); // scope(|scope| { // scope.spawn(move |_| { // select! { // send(s, 7) -> res => res.unwrap(), // } // thread::sleep(ms(1000)); // select! { // send(s, 8) -> res => res.unwrap(), // } // thread::sleep(ms(1000)); // select! { // send(s, 9) -> res => res.unwrap(), // } // }); // scope.spawn(move |_| { // thread::sleep(ms(1500)); // select! { // recv(r) -> v => assert_eq!(v, Ok(7)), // } // select! { // recv(r) -> v => assert_eq!(v, Ok(8)), // } // select! { // recv(r) -> v => assert_eq!(v, Ok(9)), // } // }); // }) // .unwrap(); // } // #[test] // fn send_timeout() { // let (s, r) = bounded(0); // scope(|scope| { // scope.spawn(move |_| { // select! { // send(s, 7) -> _ => panic!(), // default(ms(1000)) => {} // } // select! { // send(s, 8) -> res => res.unwrap(), // default(ms(1000)) => panic!(), // } // select! { // send(s, 9) -> res => assert_eq!(res, Err(SendError(9))), // default(ms(1000)) => panic!(), // } // }); // scope.spawn(move |_| { // thread::sleep(ms(1500)); // select! { // recv(r) -> v => assert_eq!(v, Ok(8)), // } // }); // }) // .unwrap(); // } // #[test] // fn disconnect_wakes_sender() { // let (s, r) = bounded(0); // scope(|scope| { // scope.spawn(move |_| { // select! { // send(s, ()) -> res => assert_eq!(res, 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 |_| { // select! { // recv(r) -> res => assert_eq!(res, Err(RecvError)), // } // }); // scope.spawn(move |_| { // thread::sleep(ms(1000)); // drop(s); // }); // }) // .unwrap(); // } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/tests/stream.rs000066400000000000000000000137631446715670500233520ustar00rootroot00000000000000#[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::(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::(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::(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::>(); 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, } impl ArcWake for CounterWaker { fn wake_by_ref(arc_self: &Arc) { 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 { 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(); } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/tests/thread_locals.rs000066400000000000000000000027421446715670500246560ustar00rootroot00000000000000// //! 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(); // } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/tests/tick.rs000066400000000000000000000222531446715670500230030ustar00rootroot00000000000000// //! 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)); // } // } flume-ee6fe6adb98856edbda47d1cc867cbc255ff0d88/tests/zero.rs000066400000000000000000000314051446715670500230270ustar00rootroot00000000000000//! 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::(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::(0); let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); 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::(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; let (s, r) = bounded::(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::>>() .unwrap() .take() .unwrap() } }); }) .unwrap(); }