├── .github ├── FUNDING.yml └── workflows │ └── rust.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benches └── basic.rs ├── examples ├── async.rs ├── perf.rs ├── select.rs └── simple.rs ├── misc └── benchmarks.png ├── src ├── async.rs ├── lib.rs ├── select.rs └── signal.rs └── tests ├── after.rs ├── array.rs ├── async.rs ├── basic.rs ├── check_same_channel.rs ├── golang.rs ├── iter.rs ├── list.rs ├── method_sharing.rs ├── mpsc.rs ├── never.rs ├── ready.rs ├── same_channel.rs ├── select.rs ├── select_macro.rs ├── stream.rs ├── thread_locals.rs ├── tick.rs └── zero.rs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [zesterer] 2 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ${{ matrix.os }} 12 | env: 13 | RUST_BACKTRACE: 1 14 | strategy: 15 | matrix: 16 | build: [linux64, macos, win32, win64, wasm32] 17 | include: 18 | - build: linux64 19 | os: ubuntu-latest 20 | channel: stable 21 | toolchain: x86_64-unknown-linux-gnu 22 | target: x86_64-unknown-linux-gnu 23 | #- build: linux32 24 | # os: ubuntu-latest 25 | # channel: stable 26 | # toolchain: i686-unknown-linux-gnu 27 | # target: i686-unknown-linux-gnu 28 | - build: macos 29 | os: macos-latest 30 | channel: stable 31 | toolchain: x86_64-apple-darwin 32 | target: x86_64-apple-darwin 33 | - build: win32 34 | os: windows-latest 35 | channel: stable 36 | toolchain: i686-pc-windows-msvc 37 | target: i686-pc-windows-msvc 38 | - build: win64 39 | os: windows-latest 40 | channel: stable 41 | toolchain: x86_64-pc-windows-msvc 42 | target: x86_64-pc-windows-msvc 43 | - build: wasm32 44 | os: ubuntu-latest 45 | channel: stable 46 | toolchain: x86_64-unknown-linux-gnu 47 | target: wasm32-unknown-unknown 48 | steps: 49 | - uses: actions/checkout@v4 50 | - run: | 51 | TOOLCHAIN=${{ matrix.channel }}-${{ matrix.toolchain }} 52 | rustup toolchain install --no-self-update $TOOLCHAIN 53 | rustup default $TOOLCHAIN 54 | rustup target add ${{ matrix.target }} 55 | shell: bash 56 | - name: Rust version 57 | run: | 58 | set -ex 59 | rustc -Vv 60 | cargo -V 61 | rustup show 62 | shell: bash 63 | # Check build to fail fast 64 | - run: cargo check --target ${{ matrix.target }} 65 | - run: cargo build --target ${{ matrix.target }} 66 | - run: cargo test --target ${{ matrix.target }} 67 | if: ${{ matrix.target != 'wasm32-unknown-unknown' }} 68 | # FIXME(#41): Some timeout/deadline tests make more sense to run in release mode. 69 | #- run: cargo test --release --target ${{ matrix.target }} 70 | - run: cargo build --all-targets --target ${{ matrix.target }} 71 | - run: cargo build --all-targets --no-default-features --target ${{ matrix.target }} 72 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | # Unreleased 9 | 10 | ### Added 11 | 12 | ### Removed 13 | 14 | ### Changed 15 | 16 | ### Fixed 17 | 18 | # [0.11.1] - 2024-10-19 19 | 20 | ### Added 21 | 22 | - `SendSink::sender` 23 | - `SendFut`, `SendSink`, `RecvFut`, `RecvStream`, `WeakSender`, `Iter`, `TryIter`, and `IntoIter` now implement `Debug` 24 | - Docs now show required features 25 | 26 | ### Removed 27 | 28 | ### Changed 29 | 30 | - `WeakSender` is now `Clone` 31 | - `spin` feature no longer uses `std::thread::sleep` for locking except on Unix-like operating systems and Windows 32 | - Flume is now in [casual maintenance mode](https://casuallymaintained.tech/). 33 | 34 | ### Fixed 35 | 36 | # [0.11.0] - 2023-08-16 37 | 38 | ### Added 39 | 40 | - `WeakSender`, a sender that doesn't keep the channel open 41 | - `Sender/Receiver::sender_count/receiver_count`, a way to query the number of senders and receivers attached to a channel 42 | - `Sender/Receiver::same_channel`, a way to determine whether senders and receivers are attached to the same channel 43 | 44 | ### Changed 45 | 46 | - Relaxed some API features 47 | - Make all remaining spinlocks opt-in 48 | 49 | ### Fixed 50 | 51 | - Fixed a rare race condition in the async implementation 52 | 53 | # [0.10.14] - 2022-07-21 54 | 55 | ### Fixed 56 | 57 | - Fixed unbounded memory usage in `RecvFut::poll_inner` 58 | 59 | # [0.10.13] - 2022-06-10 60 | 61 | ### Added 62 | 63 | - `SendSink::sender`, to get the sender of a `SendSink` 64 | 65 | # [0.10.12] - 2022-03-10 66 | 67 | ### Changed 68 | 69 | - Updated `nanorand` to 0.7 70 | 71 | # [0.10.11] - 2022-02-14 72 | 73 | ### Fixed 74 | 75 | - Out-of-order bug when using channels asynchronously 76 | 77 | # [0.10.10] - 2022-01-11 78 | 79 | ### Added 80 | 81 | - `From` and `From` impls for other error types 82 | - Marked futures as `#[must_use]` 83 | 84 | ### Changes 85 | 86 | - Switched to scheduler-driven locking by default, with a `spin` feature to reenable the old behaviour 87 | - Minor doc improvements 88 | 89 | # [0.10.9] - 2021-08-25 90 | 91 | ### Changed 92 | 93 | - Switched from `spinning_top` to `spin` 94 | 95 | # [0.10.8] - 2021-08-06 96 | 97 | ### Changed 98 | 99 | - Updated `nanorand` to `0.6` 100 | 101 | # [0.10.7] - 2021-06-10 102 | 103 | ### Fixed 104 | 105 | - Removed accidental nightly-only syntax 106 | 107 | # [0.10.6] - 2021-06-10 108 | 109 | ### Added 110 | 111 | - `fn into_inner(self) -> T` for send errors, allowing for easy access to the unsent message 112 | 113 | # [0.10.5] - 2021-04-26 114 | 115 | ### Added 116 | 117 | - `is_disconnected`, `is_empty`, `is_full`, `len`, and `capacity` on future types 118 | 119 | # [0.10.4] - 2021-04-12 120 | 121 | ### Fixed 122 | 123 | - Shutdown-related race condition with async recv that caused spurious errors 124 | 125 | # [0.10.3] - 2021-04-09 126 | 127 | ### Fixed 128 | 129 | - Compilation error when enabling `select` without `eventual_fairness` 130 | 131 | # [0.10.2] - 2021-02-07 132 | 133 | ### Fixed 134 | 135 | - Incorrect pointer comparison in `Selector` causing missing receives 136 | 137 | # [0.10.1] - 2020-12-30 138 | 139 | ### Removed 140 | 141 | - Removed `T: Unpin` requirement from async traits using `pin_project` 142 | 143 | # [0.10.0] - 2020-12-09 144 | 145 | ### Changed 146 | 147 | - Renamed `SendFuture` to `SendFut` to be consistent with `RecvFut` 148 | - Improved async-related documentation 149 | 150 | ### Fixed 151 | 152 | - Updated `nanorand` to address security advisory 153 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "flume" 3 | version = "0.11.1" 4 | authors = ["Joshua Barretto "] 5 | edition = "2018" 6 | description = "A blazingly fast multi-producer channel" 7 | repository = "https://github.com/zesterer/flume" 8 | documentation = "https://docs.rs/flume" 9 | keywords = ["mpsc", "fifo", "channel", "thread", "mpmc"] 10 | categories = ["concurrency", "data-structures"] 11 | license = "Apache-2.0/MIT" 12 | readme = "README.md" 13 | exclude = [ 14 | "/.github", 15 | "/misc", 16 | ] 17 | 18 | [package.metadata.docs.rs] 19 | all-features = true 20 | rustdoc-args = ["--cfg", "docsrs"] 21 | 22 | [features] 23 | # Use a spinlock internally (may be faster on some platforms) 24 | spin = [] 25 | select = [] 26 | async = ["futures-sink", "futures-core"] 27 | eventual-fairness = ["select", "fastrand"] 28 | default = ["async", "select", "eventual-fairness"] 29 | 30 | [dependencies] 31 | spin1 = { package = "spin", version = "0.9.8", features = ["mutex"] } 32 | futures-sink = { version = "0.3", default_features = false, optional = true } 33 | futures-core = { version = "0.3", default_features = false, optional = true } 34 | fastrand = { version = "2.3", features = ["std", "js"], optional = true } 35 | 36 | [dev-dependencies] 37 | #flume-test = { path = "../flume-test" } 38 | crossbeam-channel = "0.5.5" 39 | crossbeam-utils = "0.8.10" 40 | criterion = { version = "0.5.1", default-features = false } 41 | rand = "0.8.3" 42 | async-std = { version = "1.13.0", features = ["attributes", "unstable"] } 43 | futures = { version = "^0.3", features = ["std"] } 44 | waker-fn = "1.1.0" 45 | tokio = { version = "^1.16.1", features = ["rt", "macros"] } 46 | getrandom = { version = "0.2.15", features = ["js"] } 47 | 48 | [[bench]] 49 | name = "basic" 50 | harness = false 51 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flume 2 | 3 | A blazingly fast multi-producer, multi-consumer channel. 4 | 5 | [![Cargo](https://img.shields.io/crates/v/flume.svg)]( 6 | https://crates.io/crates/flume) 7 | [![Documentation](https://docs.rs/flume/badge.svg)]( 8 | https://docs.rs/flume) 9 | [![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)]( 10 | https://github.com/zesterer/flume) 11 | ![actions-badge](https://github.com/zesterer/flume/workflows/Rust/badge.svg?branch=master) 12 | [![Casual Maintenance Intended](https://casuallymaintained.tech/badge.svg)](https://casuallymaintained.tech/) 13 | 14 | ```rust 15 | use std::thread; 16 | 17 | fn main() { 18 | println!("Hello, world!"); 19 | 20 | let (tx, rx) = flume::unbounded(); 21 | 22 | thread::spawn(move || { 23 | (0..10).for_each(|i| { 24 | tx.send(i).unwrap(); 25 | }) 26 | }); 27 | 28 | let received: u32 = rx.iter().sum(); 29 | 30 | assert_eq!((0..10).sum::(), received); 31 | } 32 | ``` 33 | 34 | ## Why Flume? 35 | 36 | - **Featureful**: Unbounded, bounded and rendezvous queues 37 | - **Fast**: Always faster than `std::sync::mpsc` and sometimes `crossbeam-channel` 38 | - **Safe**: No `unsafe` code anywhere in the codebase! 39 | - **Flexible**: `Sender` and `Receiver` both implement `Send + Sync + Clone` 40 | - **Familiar**: Drop-in replacement for `std::sync::mpsc` 41 | - **Capable**: Additional features like MPMC support and send timeouts/deadlines 42 | - **Simple**: Few dependencies, minimal codebase, fast to compile 43 | - **Asynchronous**: `async` support, including mix 'n match with sync code 44 | - **Ergonomic**: Powerful `select`-like interface 45 | 46 | ## Usage 47 | 48 | To use Flume, place the following line under the `[dependencies]` section in your `Cargo.toml`: 49 | 50 | ```toml 51 | flume = "x.y" 52 | ``` 53 | 54 | ## Cargo Features 55 | 56 | Flume comes with several optional features: 57 | 58 | - `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) 59 | 60 | - `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 61 | 62 | - `async`: Adds support for the [async API](https://docs.rs/flume/latest/flume/async/index.html), including on otherwise synchronous channels 63 | 64 | - `eventual-fairness`: Use randomness in the implementation of `Selector` to avoid biasing/saturating certain events over others 65 | 66 | You can enable these features by changing the dependency in your `Cargo.toml` like so: 67 | 68 | ```toml 69 | flume = { version = "x.y", default-features = false, features = ["async", "select"] } 70 | ``` 71 | 72 | ## [Benchmarks](https://what-if.xkcd.com/147/) 73 | 74 | Although Flume has its own extensive benchmarks, don't take it from here that Flume is quick. 75 | The following graph is from the `crossbeam-channel` benchmark suite. 76 | 77 | Tests were performed on an AMD Ryzen 7 3700x with 8/16 cores running Linux kernel 5.11.2 with the bfq scheduler. 78 | 79 | # Flume benchmarks (crossbeam benchmark suite) 80 | 81 | ## Status 82 | 83 | Flume is in [casual maintenance mode](https://casuallymaintained.tech/). This means that the crate will continue to 84 | receive critical security and bug fixes, but heavy feature development has stopped. If you're looking for a new 85 | feature, you're welcome to open a PR and I'll try to find the time to review it. 86 | 87 | Flume has been great fun to work on, and I'm happy that it's being used successfully by so many people. I consider the 88 | crate to be largely feature-complete at this point (bar small details here and there). 89 | 90 | ## License 91 | 92 | Flume is licensed under either of: 93 | 94 | - Apache License 2.0, (http://www.apache.org/licenses/LICENSE-2.0) 95 | 96 | - MIT license (http://opensource.org/licenses/MIT) 97 | -------------------------------------------------------------------------------- /benches/basic.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate criterion; 3 | 4 | use std::{ 5 | sync::mpsc, 6 | thread, 7 | fmt::Debug, 8 | }; 9 | use criterion::{Criterion, Bencher, black_box}; 10 | use std::time::Instant; 11 | 12 | trait Sender: Clone + Send + Sized + 'static { 13 | type Item: Debug + Default; 14 | type BoundedSender: Sender; 15 | type Receiver: Receiver; 16 | 17 | fn unbounded() -> (Self, Self::Receiver); 18 | fn bounded(n: usize) -> (Self::BoundedSender, Self::Receiver); 19 | fn send(&self, msg: Self::Item); 20 | } 21 | 22 | trait Receiver: Send + Sized + 'static { 23 | type Item: Default; 24 | fn recv(&self) -> Self::Item; 25 | fn iter(&self) -> Box + '_>; 26 | } 27 | 28 | impl Sender for flume::Sender { 29 | type Item = T; 30 | type BoundedSender = Self; 31 | type Receiver = flume::Receiver; 32 | 33 | fn unbounded() -> (Self, Self::Receiver) { 34 | flume::unbounded() 35 | } 36 | 37 | fn bounded(n: usize) -> (Self::BoundedSender, Self::Receiver) { 38 | flume::bounded(n) 39 | } 40 | 41 | fn send(&self, msg: T) { 42 | flume::Sender::send(self, msg).unwrap(); 43 | } 44 | } 45 | 46 | impl Receiver for flume::Receiver { 47 | type Item = T; 48 | 49 | fn recv(&self) -> Self::Item { 50 | flume::Receiver::recv(self).unwrap() 51 | } 52 | 53 | fn iter(&self) -> Box + '_> { 54 | Box::new(std::iter::from_fn(move || flume::Receiver::recv(self).ok())) 55 | } 56 | } 57 | 58 | impl Sender for crossbeam_channel::Sender { 59 | type Item = T; 60 | type BoundedSender = Self; 61 | type Receiver = crossbeam_channel::Receiver; 62 | 63 | fn unbounded() -> (Self, Self::Receiver) { 64 | crossbeam_channel::unbounded() 65 | } 66 | 67 | fn bounded(n: usize) -> (Self::BoundedSender, Self::Receiver) { 68 | crossbeam_channel::bounded(n) 69 | } 70 | 71 | fn send(&self, msg: T) { 72 | crossbeam_channel::Sender::send(self, msg).unwrap(); 73 | } 74 | } 75 | 76 | impl Receiver for crossbeam_channel::Receiver { 77 | type Item = T; 78 | 79 | fn recv(&self) -> Self::Item { 80 | crossbeam_channel::Receiver::recv(self).unwrap() 81 | } 82 | 83 | fn iter(&self) -> Box + '_> { 84 | Box::new(crossbeam_channel::Receiver::iter(self)) 85 | } 86 | } 87 | 88 | impl Sender for mpsc::Sender { 89 | type Item = T; 90 | type BoundedSender = mpsc::SyncSender; 91 | type Receiver = mpsc::Receiver; 92 | 93 | fn unbounded() -> (Self, Self::Receiver) { 94 | mpsc::channel() 95 | } 96 | 97 | fn bounded(n: usize) -> (Self::BoundedSender, Self::Receiver) { 98 | mpsc::sync_channel(n) 99 | } 100 | 101 | fn send(&self, msg: T) { 102 | mpsc::Sender::send(self, msg).unwrap(); 103 | } 104 | } 105 | 106 | impl Sender for mpsc::SyncSender { 107 | type Item = T; 108 | type BoundedSender = Self; 109 | type Receiver = mpsc::Receiver; 110 | 111 | fn unbounded() -> (Self, Self::Receiver) { unimplemented!() } 112 | fn bounded(_: usize) -> (Self::BoundedSender, Self::Receiver) { unimplemented!() } 113 | 114 | fn send(&self, msg: T) { 115 | mpsc::SyncSender::send(self, msg).unwrap(); 116 | } 117 | } 118 | 119 | impl Receiver for mpsc::Receiver { 120 | type Item = T; 121 | 122 | fn recv(&self) -> Self::Item { 123 | mpsc::Receiver::recv(self).unwrap() 124 | } 125 | 126 | fn iter(&self) -> Box + '_> { 127 | Box::new(mpsc::Receiver::iter(self)) 128 | } 129 | } 130 | 131 | fn test_create(b: &mut Bencher) { 132 | b.iter(|| S::unbounded()); 133 | } 134 | 135 | fn test_oneshot(b: &mut Bencher) { 136 | b.iter(|| { 137 | let (tx, rx) = S::unbounded(); 138 | tx.send(Default::default()); 139 | black_box(rx.recv()); 140 | }); 141 | } 142 | 143 | fn test_inout(b: &mut Bencher) { 144 | let (tx, rx) = S::unbounded(); 145 | b.iter(|| { 146 | tx.send(Default::default()); 147 | black_box(rx.recv()); 148 | }); 149 | } 150 | 151 | fn test_hydra(b: &mut Bencher, thread_num: usize, msg_num: usize) { 152 | let (main_tx, main_rx) = S::unbounded(); 153 | 154 | let mut txs = Vec::new(); 155 | for _ in 0..thread_num { 156 | let main_tx = main_tx.clone(); 157 | let (tx, rx) = S::unbounded(); 158 | txs.push(tx); 159 | 160 | thread::spawn(move || { 161 | for msg in rx.iter() { 162 | main_tx.send(msg); 163 | } 164 | }); 165 | } 166 | 167 | drop(main_tx); 168 | 169 | b.iter(|| { 170 | for tx in &txs { 171 | for _ in 0..msg_num { 172 | tx.send(Default::default()); 173 | } 174 | } 175 | 176 | for _ in 0..thread_num { 177 | for _ in 0..msg_num { 178 | black_box(main_rx.recv()); 179 | } 180 | } 181 | }); 182 | } 183 | 184 | fn test_kitsune(b: &mut Bencher, thread_num: usize, msg_num: usize) 185 | where S::Receiver: Clone 186 | { 187 | let (out_tx, out_rx) = S::unbounded(); 188 | let (in_tx, in_rx) = S::unbounded(); 189 | 190 | for _ in 0..thread_num { 191 | let in_tx = in_tx.clone(); 192 | let out_rx = out_rx.clone(); 193 | 194 | thread::spawn(move || { 195 | for msg in out_rx.iter() { 196 | in_tx.send(msg); 197 | } 198 | }); 199 | } 200 | 201 | b.iter(|| { 202 | for _ in 0..thread_num { 203 | for _ in 0..msg_num { 204 | out_tx.send(Default::default()); 205 | } 206 | } 207 | 208 | for _ in 0..thread_num { 209 | for _ in 0..msg_num { 210 | black_box(in_rx.recv()); 211 | } 212 | } 213 | }); 214 | } 215 | 216 | fn test_robin_u(b: &mut Bencher, thread_num: usize, msg_num: usize) { 217 | let (mut main_tx, main_rx) = S::unbounded(); 218 | 219 | for _ in 0..thread_num { 220 | let (mut tx, rx) = S::unbounded(); 221 | std::mem::swap(&mut tx, &mut main_tx); 222 | 223 | thread::spawn(move || { 224 | for msg in rx.iter() { 225 | tx.send(msg); 226 | } 227 | }); 228 | } 229 | 230 | b.iter(|| { 231 | for _ in 0..msg_num { 232 | main_tx.send(Default::default()); 233 | } 234 | 235 | for _ in 0..msg_num { 236 | black_box(main_rx.recv()); 237 | } 238 | }); 239 | } 240 | 241 | fn test_robin_b(b: &mut Bencher, thread_num: usize, msg_num: usize) { 242 | let (mut main_tx, main_rx) = S::bounded(1); 243 | 244 | for _ in 0..thread_num { 245 | let (mut tx, rx) = S::bounded(1); 246 | std::mem::swap(&mut tx, &mut main_tx); 247 | 248 | thread::spawn(move || { 249 | for msg in rx.iter() { 250 | tx.send(msg); 251 | } 252 | }); 253 | } 254 | 255 | b.iter(|| { 256 | let main_tx = main_tx.clone(); 257 | thread::spawn(move || { 258 | for _ in 0..msg_num { 259 | main_tx.send(Default::default()); 260 | } 261 | }); 262 | 263 | for _ in 0..msg_num { 264 | black_box(main_rx.recv()); 265 | } 266 | }); 267 | } 268 | 269 | fn test_mpsc_bounded_no_wait(b: &mut Bencher, thread_num: u64) { 270 | b.iter_custom(|iters| { 271 | let iters = iters * 1000; 272 | let (tx, rx) = S::bounded(iters as usize); 273 | let start = Instant::now(); 274 | 275 | crossbeam_utils::thread::scope(|scope| { 276 | for _ in 0..thread_num { 277 | let tx = tx.clone(); 278 | scope.spawn(move |_| { 279 | for _ in 0..iters / thread_num { 280 | tx.send(Default::default()); 281 | } 282 | }); 283 | } 284 | 285 | for _ in 0..iters - ((iters / thread_num) * thread_num) { 286 | tx.send(Default::default()); 287 | } 288 | 289 | for _ in 0..iters { 290 | black_box(rx.recv()); 291 | } 292 | }) 293 | .unwrap(); 294 | 295 | start.elapsed() 296 | }) 297 | } 298 | 299 | fn test_mpsc_bounded(b: &mut Bencher, bound: usize, thread_num: usize) { 300 | b.iter_custom(|iters| { 301 | let (tx, rx) = S::bounded(bound); 302 | let start = Instant::now(); 303 | 304 | crossbeam_utils::thread::scope(|scope| { 305 | let msgs = iters as usize * bound.max(1); 306 | 307 | for _ in 0..thread_num { 308 | let tx = tx.clone(); 309 | scope.spawn(move |_| { 310 | for _ in 0..msgs / thread_num as usize { 311 | tx.send(Default::default()); 312 | } 313 | }); 314 | } 315 | 316 | scope.spawn(move |_| { 317 | // Remainder 318 | for _ in 0..msgs - (msgs / thread_num as usize * thread_num) { 319 | tx.send(Default::default()); 320 | } 321 | }); 322 | 323 | for _ in 0..msgs { 324 | black_box(rx.recv()); 325 | } 326 | }) 327 | .unwrap(); 328 | 329 | start.elapsed() 330 | }) 331 | } 332 | 333 | fn create(b: &mut Criterion) { 334 | b.bench_function("create-flume", |b| test_create::>(b)); 335 | b.bench_function("create-crossbeam", |b| test_create::>(b)); 336 | b.bench_function("create-std", |b| test_create::>(b)); 337 | } 338 | 339 | fn oneshot(b: &mut Criterion) { 340 | b.bench_function("oneshot-flume", |b| test_oneshot::>(b)); 341 | b.bench_function("oneshot-crossbeam", |b| test_oneshot::>(b)); 342 | b.bench_function("oneshot-std", |b| test_oneshot::>(b)); 343 | } 344 | 345 | fn inout(b: &mut Criterion) { 346 | b.bench_function("inout-flume", |b| test_inout::>(b)); 347 | b.bench_function("inout-crossbeam", |b| test_inout::>(b)); 348 | b.bench_function("inout-std", |b| test_inout::>(b)); 349 | } 350 | 351 | fn hydra_32t_1m(b: &mut Criterion) { 352 | b.bench_function("hydra-32t-1m-flume", |b| test_hydra::>(b, 32, 1)); 353 | b.bench_function("hydra-32t-1m-crossbeam", |b| test_hydra::>(b, 32, 1)); 354 | b.bench_function("hydra-32t-1m-std", |b| test_hydra::>(b, 32, 1)); 355 | } 356 | 357 | fn hydra_32t_1000m(b: &mut Criterion) { 358 | b.bench_function("hydra-32t-1000m-flume", |b| test_hydra::>(b, 32, 1000)); 359 | b.bench_function("hydra-32t-1000m-crossbeam", |b| test_hydra::>(b, 32, 1000)); 360 | b.bench_function("hydra-32t-1000m-std", |b| test_hydra::>(b, 32, 1000)); 361 | } 362 | 363 | fn hydra_256t_1m(b: &mut Criterion) { 364 | b.bench_function("hydra-256t-1m-flume", |b| test_hydra::>(b, 256, 1)); 365 | b.bench_function("hydra-256t-1m-crossbeam", |b| test_hydra::>(b, 256, 1)); 366 | b.bench_function("hydra-256t-1m-std", |b| test_hydra::>(b, 256, 1)); 367 | } 368 | 369 | fn hydra_1t_1000m(b: &mut Criterion) { 370 | b.bench_function("hydra-1t-1000m-flume", |b| test_hydra::>(b, 1, 1000)); 371 | b.bench_function("hydra-1t-1000m-crossbeam", |b| test_hydra::>(b, 1, 1000)); 372 | b.bench_function("hydra-1t-1000m-std", |b| test_hydra::>(b, 1, 1000)); 373 | } 374 | 375 | fn hydra_4t_10000m(b: &mut Criterion) { 376 | b.bench_function("hydra-4t-10000m-flume", |b| test_hydra::>(b, 4, 10000)); 377 | b.bench_function("hydra-4t-10000m-crossbeam", |b| test_hydra::>(b, 4, 10000)); 378 | b.bench_function("hydra-4t-10000m-std", |b| test_hydra::>(b, 4, 10000)); 379 | } 380 | 381 | fn kitsune_32t_1m(b: &mut Criterion) { 382 | b.bench_function("kitsune-32t-1m-flume", |b| test_kitsune::>(b, 32, 1)); 383 | b.bench_function("kitsune-32t-1m-crossbeam", |b| test_kitsune::>(b, 32, 1)); 384 | //b.bench_function("kitsune-32t-1m-std", |b| test_kitsune::>(b, 32, 1)); 385 | } 386 | 387 | fn kitsune_32t_1000m(b: &mut Criterion) { 388 | b.bench_function("kitsune-32t-1000m-flume", |b| test_kitsune::>(b, 32, 1000)); 389 | b.bench_function("kitsune-32t-1000m-crossbeam", |b| test_kitsune::>(b, 32, 1000)); 390 | //b.bench_function("kitsune-32t-1000m-std", |b| test_kitsune::>(b, 32, 1000)); 391 | } 392 | 393 | fn kitsune_256t_1m(b: &mut Criterion) { 394 | b.bench_function("kitsune-256t-1m-flume", |b| test_kitsune::>(b, 256, 1)); 395 | b.bench_function("kitsune-256t-1m-crossbeam", |b| test_kitsune::>(b, 256, 1)); 396 | //b.bench_function("kitsune-256t-1m-std", |b| test_kitsune::>(b, 256, 1)); 397 | } 398 | 399 | fn kitsune_1t_1000m(b: &mut Criterion) { 400 | b.bench_function("kitsune-1t-1000m-flume", |b| test_kitsune::>(b, 1, 1000)); 401 | b.bench_function("kitsune-1t-1000m-crossbeam", |b| test_kitsune::>(b, 1, 1000)); 402 | //b.bench_function("kitsune-1t-1000m-std", |b| test_kitsune::>(b, 1, 1000)); 403 | } 404 | 405 | fn kitsune_4t_10000m(b: &mut Criterion) { 406 | b.bench_function("kitsune-4t-10000m-flume", |b| test_kitsune::>(b, 4, 10000)); 407 | b.bench_function("kitsune-4t-10000m-crossbeam", |b| test_kitsune::>(b, 4, 10000)); 408 | //b.bench_function("kitsune-4t-10000m-std", |b| test_kitsune::>(b, 4, 10000)); 409 | } 410 | 411 | fn robin_u_32t_1m(b: &mut Criterion) { 412 | b.bench_function("robin-u-32t-1m-flume", |b| test_robin_u::>(b, 32, 1)); 413 | b.bench_function("robin-u-32t-1m-crossbeam", |b| test_robin_u::>(b, 32, 1)); 414 | b.bench_function("robin-u-32t-1m-std", |b| test_robin_u::>(b, 32, 1)); 415 | } 416 | 417 | fn robin_u_4t_1000m(b: &mut Criterion) { 418 | b.bench_function("robin-u-4t-1000m-flume", |b| test_robin_u::>(b, 4, 1000)); 419 | b.bench_function("robin-u-4t-1000m-crossbeam", |b| test_robin_u::>(b, 4, 1000)); 420 | b.bench_function("robin-u-4t-1000m-std", |b| test_robin_u::>(b, 4, 1000)); 421 | } 422 | 423 | fn robin_b_32t_16m(b: &mut Criterion) { 424 | b.bench_function("robin-b-32t-16m-flume", |b| test_robin_b::>(b, 32, 16)); 425 | b.bench_function("robin-b-32t-16m-crossbeam", |b| test_robin_b::>(b, 32, 16)); 426 | b.bench_function("robin-b-32t-16m-std", |b| test_robin_b::>(b, 32, 16)); 427 | } 428 | 429 | fn robin_b_4t_1000m(b: &mut Criterion) { 430 | b.bench_function("robin-b-4t-1000m-flume", |b| test_robin_b::>(b, 4, 1000)); 431 | b.bench_function("robin-b-4t-1000m-crossbeam", |b| test_robin_b::>(b, 4, 1000)); 432 | b.bench_function("robin-b-4t-1000m-std", |b| test_robin_b::>(b, 4, 1000)); 433 | } 434 | 435 | fn mpsc_bounded_no_wait_4t(b: &mut Criterion) { 436 | b.bench_function("mpsc-bounded-no-wait-4t-flume", |b| test_mpsc_bounded_no_wait::>(b, 4)); 437 | b.bench_function("mpsc-bounded-no-wait-4t-crossbeam", |b| test_mpsc_bounded_no_wait::>(b, 4)); 438 | b.bench_function("mpsc-bounded-no-wait-4t-std", |b| test_mpsc_bounded_no_wait::>(b, 4)); 439 | } 440 | 441 | fn mpsc_bounded_4t(b: &mut Criterion) { 442 | for bound in &[0, 1, 10, 50, 10_000] { 443 | let text = format!("mpsc-bounded-small-4t-{}m-", bound); 444 | let bound = *bound; 445 | 446 | b.bench_function(&format!("{}{}", text, "flume"), |b| test_mpsc_bounded::>(b, bound, 4)); 447 | b.bench_function(&format!("{}{}", text, "crossbeam"), |b| test_mpsc_bounded::>(b, bound, 4)); 448 | b.bench_function(&format!("{}{}", text, "std"), |b| test_mpsc_bounded::>(b, bound, 4)); 449 | } 450 | } 451 | 452 | criterion_group!( 453 | compare, 454 | create, 455 | oneshot, 456 | inout, 457 | hydra_32t_1m, 458 | hydra_32t_1000m, 459 | hydra_256t_1m, 460 | hydra_1t_1000m, 461 | hydra_4t_10000m, 462 | robin_b_32t_16m, 463 | robin_b_4t_1000m, 464 | robin_u_32t_1m, 465 | robin_u_4t_1000m, 466 | mpsc_bounded_no_wait_4t, 467 | mpsc_bounded_4t, 468 | kitsune_32t_1m, 469 | kitsune_32t_1000m, 470 | kitsune_256t_1m, 471 | kitsune_1t_1000m, 472 | kitsune_4t_10000m, 473 | ); 474 | criterion_main!(compare); 475 | -------------------------------------------------------------------------------- /examples/async.rs: -------------------------------------------------------------------------------- 1 | #[cfg(all(feature = "async", not(target_os = "unknown")))] 2 | #[async_std::main] 3 | async fn main() { 4 | let (tx, rx) = flume::bounded(1); 5 | 6 | let t = async_std::task::spawn(async move { 7 | while let Ok(msg) = rx.recv_async().await { 8 | println!("Received: {}", msg); 9 | } 10 | }); 11 | 12 | tx.send_async("Hello, world!").await.unwrap(); 13 | tx.send_async("How are you today?").await.unwrap(); 14 | 15 | drop(tx); 16 | 17 | t.await; 18 | } 19 | 20 | #[cfg(any(not(feature = "async"), target_os = "unknown"))] 21 | fn main() {} 22 | -------------------------------------------------------------------------------- /examples/perf.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let thread_num = 32; 3 | let msg_num = 16; 4 | 5 | let (mut main_tx, main_rx) = flume::bounded::<()>(1); 6 | 7 | for _ in 0..thread_num { 8 | let (mut tx, rx) = flume::bounded(1); 9 | std::mem::swap(&mut tx, &mut main_tx); 10 | 11 | std::thread::spawn(move || { 12 | for msg in rx.iter() { 13 | tx.send(msg).unwrap(); 14 | } 15 | }); 16 | } 17 | 18 | for _ in 0..1000 { 19 | let main_tx = main_tx.clone(); 20 | std::thread::spawn(move || { 21 | for _ in 0..msg_num { 22 | main_tx.send(Default::default()).unwrap(); 23 | } 24 | }); 25 | 26 | for _ in 0..msg_num { 27 | main_rx.recv().unwrap(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /examples/select.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "select")] 2 | use flume::Selector; 3 | 4 | #[cfg(feature = "select")] 5 | fn main() { 6 | // Create two channels 7 | let (red_tx, red_rx) = flume::unbounded(); 8 | let (blue_tx, blue_rx) = flume::unbounded(); 9 | 10 | // Spawn two threads that each send a message into their respective channel 11 | std::thread::spawn(move || { let _ = red_tx.send("Red"); }); 12 | std::thread::spawn(move || { let _ = blue_tx.send("Blue"); }); 13 | 14 | // Race them to see which one sends their message first 15 | let winner = Selector::new() 16 | .recv(&red_rx, |msg| msg) 17 | .recv(&blue_rx, |msg| msg) 18 | .wait() 19 | .unwrap(); 20 | 21 | println!("{} won!", winner); 22 | } 23 | 24 | #[cfg(not(feature = "select"))] 25 | fn main() {} 26 | -------------------------------------------------------------------------------- /examples/simple.rs: -------------------------------------------------------------------------------- 1 | use std::thread; 2 | 3 | fn main() { 4 | let (tx, rx) = flume::unbounded(); 5 | 6 | let t = thread::spawn(move || { 7 | for msg in rx.iter() { 8 | println!("Received: {}", msg); 9 | } 10 | }); 11 | 12 | tx.send("Hello, world!").unwrap(); 13 | tx.send("How are you today?").unwrap(); 14 | 15 | drop(tx); 16 | 17 | t.join().unwrap(); 18 | } 19 | -------------------------------------------------------------------------------- /misc/benchmarks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zesterer/flume/02eda72e14d6805beb3b27559b8e066f8464f490/misc/benchmarks.png -------------------------------------------------------------------------------- /src/async.rs: -------------------------------------------------------------------------------- 1 | //! Futures and other types that allow asynchronous interaction with channels. 2 | 3 | use std::{ 4 | future::Future, 5 | pin::Pin, 6 | task::{Context, Poll, Waker}, 7 | any::Any, 8 | ops::Deref, 9 | }; 10 | use std::fmt::{Debug, Formatter}; 11 | use crate::*; 12 | use futures_core::{stream::{Stream, FusedStream}, future::FusedFuture}; 13 | use futures_sink::Sink; 14 | use spin1::Mutex as Spinlock; 15 | 16 | struct AsyncSignal { 17 | waker: Spinlock, 18 | woken: AtomicBool, 19 | stream: bool, 20 | } 21 | 22 | impl AsyncSignal { 23 | fn new(cx: &Context, stream: bool) -> Self { 24 | AsyncSignal { 25 | waker: Spinlock::new(cx.waker().clone()), 26 | woken: AtomicBool::new(false), 27 | stream, 28 | } 29 | } 30 | } 31 | 32 | impl Signal for AsyncSignal { 33 | fn fire(&self) -> bool { 34 | self.woken.store(true, Ordering::SeqCst); 35 | self.waker.lock().wake_by_ref(); 36 | self.stream 37 | } 38 | 39 | fn as_any(&self) -> &(dyn Any + 'static) { self } 40 | fn as_ptr(&self) -> *const () { self as *const _ as *const () } 41 | } 42 | 43 | impl Hook { 44 | // Update the hook to point to the given Waker. 45 | // Returns whether the hook has been previously awakened 46 | fn update_waker(&self, cx_waker: &Waker) -> bool { 47 | let mut waker = self.1.waker.lock(); 48 | let woken = self.1.woken.load(Ordering::SeqCst); 49 | if !waker.will_wake(cx_waker) { 50 | *waker = cx_waker.clone(); 51 | 52 | // Avoid the edge case where the waker was woken just before the wakers were 53 | // swapped. 54 | if woken { 55 | cx_waker.wake_by_ref(); 56 | } 57 | } 58 | woken 59 | } 60 | } 61 | 62 | #[derive(Clone)] 63 | enum OwnedOrRef<'a, T> { 64 | Owned(T), 65 | Ref(&'a T), 66 | } 67 | 68 | impl<'a, T> Deref for OwnedOrRef<'a, T> { 69 | type Target = T; 70 | 71 | fn deref(&self) -> &T { 72 | match self { 73 | OwnedOrRef::Owned(arc) => &arc, 74 | OwnedOrRef::Ref(r) => r, 75 | } 76 | } 77 | } 78 | 79 | impl Sender { 80 | /// Asynchronously send a value into the channel, returning an error if all receivers have been 81 | /// dropped. If the channel is bounded and is full, the returned future will yield to the async 82 | /// runtime. 83 | /// 84 | /// In the current implementation, the returned future will not yield to the async runtime if the 85 | /// channel is unbounded. This may change in later versions. 86 | pub fn send_async(&self, item: T) -> SendFut { 87 | SendFut { 88 | sender: OwnedOrRef::Ref(&self), 89 | hook: Some(SendState::NotYetSent(item)), 90 | } 91 | } 92 | 93 | /// Convert this sender into a future that asynchronously sends a single message into the channel, 94 | /// returning an error if all receivers have been dropped. If the channel is bounded and is full, 95 | /// this future will yield to the async runtime. 96 | /// 97 | /// In the current implementation, the returned future will not yield to the async runtime if the 98 | /// channel is unbounded. This may change in later versions. 99 | pub fn into_send_async<'a>(self, item: T) -> SendFut<'a, T> { 100 | SendFut { 101 | sender: OwnedOrRef::Owned(self), 102 | hook: Some(SendState::NotYetSent(item)), 103 | } 104 | } 105 | 106 | /// Create an asynchronous sink that uses this sender to asynchronously send messages into the 107 | /// channel. The sender will continue to be usable after the sink has been dropped. 108 | /// 109 | /// In the current implementation, the returned sink will not yield to the async runtime if the 110 | /// channel is unbounded. This may change in later versions. 111 | pub fn sink(&self) -> SendSink<'_, T> { 112 | SendSink(SendFut { 113 | sender: OwnedOrRef::Ref(&self), 114 | hook: None, 115 | }) 116 | } 117 | 118 | /// Convert this sender into a sink that allows asynchronously sending messages into the channel. 119 | /// 120 | /// In the current implementation, the returned sink will not yield to the async runtime if the 121 | /// channel is unbounded. This may change in later versions. 122 | pub fn into_sink<'a>(self) -> SendSink<'a, T> { 123 | SendSink(SendFut { 124 | sender: OwnedOrRef::Owned(self), 125 | hook: None, 126 | }) 127 | } 128 | } 129 | 130 | enum SendState { 131 | NotYetSent(T), 132 | QueuedItem(Arc>), 133 | } 134 | 135 | /// A future that sends a value into a channel. 136 | /// 137 | /// Can be created via [`Sender::send_async`] or [`Sender::into_send_async`]. 138 | #[must_use = "futures/streams/sinks do nothing unless you `.await` or poll them"] 139 | pub struct SendFut<'a, T> { 140 | sender: OwnedOrRef<'a, Sender>, 141 | // Only none after dropping 142 | hook: Option>, 143 | } 144 | 145 | impl<'a, T> Debug for SendFut<'a, T> { 146 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 147 | f.debug_struct("SendFut").finish() 148 | } 149 | } 150 | 151 | impl std::marker::Unpin for SendFut<'_, T> {} 152 | 153 | impl<'a, T> SendFut<'a, T> { 154 | /// Reset the hook, clearing it and removing it from the waiting sender's queue. This is called 155 | /// on drop and just before `start_send` in the `Sink` implementation. 156 | fn reset_hook(&mut self) { 157 | if let Some(SendState::QueuedItem(hook)) = self.hook.take() { 158 | let hook: Arc> = hook; 159 | wait_lock(&self.sender.shared.chan).sending 160 | .as_mut() 161 | .unwrap().1 162 | .retain(|s| s.signal().as_ptr() != hook.signal().as_ptr()); 163 | } 164 | } 165 | 166 | /// See [`Sender::is_disconnected`]. 167 | pub fn is_disconnected(&self) -> bool { 168 | self.sender.is_disconnected() 169 | } 170 | 171 | /// See [`Sender::is_empty`]. 172 | pub fn is_empty(&self) -> bool { 173 | self.sender.is_empty() 174 | } 175 | 176 | /// See [`Sender::is_full`]. 177 | pub fn is_full(&self) -> bool { 178 | self.sender.is_full() 179 | } 180 | 181 | /// See [`Sender::len`]. 182 | pub fn len(&self) -> usize { 183 | self.sender.len() 184 | } 185 | 186 | /// See [`Sender::capacity`]. 187 | pub fn capacity(&self) -> Option { 188 | self.sender.capacity() 189 | } 190 | } 191 | 192 | impl<'a, T> Drop for SendFut<'a, T> { 193 | fn drop(&mut self) { 194 | self.reset_hook() 195 | } 196 | } 197 | 198 | 199 | impl<'a, T> Future for SendFut<'a, T> { 200 | type Output = Result<(), SendError>; 201 | 202 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 203 | if let Some(SendState::QueuedItem(hook)) = self.hook.as_ref() { 204 | if hook.is_empty() { 205 | Poll::Ready(Ok(())) 206 | } else if self.sender.shared.is_disconnected() { 207 | let item = hook.try_take(); 208 | self.hook = None; 209 | match item { 210 | Some(item) => Poll::Ready(Err(SendError(item))), 211 | None => Poll::Ready(Ok(())), 212 | } 213 | } else { 214 | hook.update_waker(cx.waker()); 215 | Poll::Pending 216 | } 217 | } else if let Some(SendState::NotYetSent(item)) = self.hook.take() { 218 | let this = self.get_mut(); 219 | let (shared, this_hook) = (&this.sender.shared, &mut this.hook); 220 | 221 | shared.send( 222 | // item 223 | item, 224 | // should_block 225 | true, 226 | // make_signal 227 | |msg| Hook::slot(Some(msg), AsyncSignal::new(cx, false)), 228 | // do_block 229 | |hook| { 230 | *this_hook = Some(SendState::QueuedItem(hook)); 231 | Poll::Pending 232 | }, 233 | ) 234 | .map(|r| r.map_err(|err| match err { 235 | TrySendTimeoutError::Disconnected(msg) => SendError(msg), 236 | _ => unreachable!(), 237 | })) 238 | } else { // Nothing to do 239 | Poll::Ready(Ok(())) 240 | } 241 | } 242 | } 243 | 244 | impl<'a, T> FusedFuture for SendFut<'a, T> { 245 | fn is_terminated(&self) -> bool { 246 | self.sender.shared.is_disconnected() 247 | } 248 | } 249 | 250 | /// A sink that allows sending values into a channel. 251 | /// 252 | /// Can be created via [`Sender::sink`] or [`Sender::into_sink`]. 253 | pub struct SendSink<'a, T>(SendFut<'a, T>); 254 | 255 | impl<'a, T> SendSink<'a, T> { 256 | /// Returns a clone of a sending half of the channel of this sink. 257 | pub fn sender(&self) -> &Sender { 258 | &self.0.sender 259 | } 260 | 261 | /// See [`Sender::is_disconnected`]. 262 | pub fn is_disconnected(&self) -> bool { 263 | self.0.is_disconnected() 264 | } 265 | 266 | /// See [`Sender::is_empty`]. 267 | pub fn is_empty(&self) -> bool { 268 | self.0.is_empty() 269 | } 270 | 271 | /// See [`Sender::is_full`]. 272 | pub fn is_full(&self) -> bool { 273 | self.0.is_full() 274 | } 275 | 276 | /// See [`Sender::len`]. 277 | pub fn len(&self) -> usize { 278 | self.0.len() 279 | } 280 | 281 | /// See [`Sender::capacity`]. 282 | pub fn capacity(&self) -> Option { 283 | self.0.capacity() 284 | } 285 | 286 | /// Returns whether the SendSinks are belong to the same channel. 287 | pub fn same_channel(&self, other: &Self) -> bool { 288 | self.sender().same_channel(other.sender()) 289 | } 290 | } 291 | 292 | impl<'a, T> Debug for SendSink<'a, T> { 293 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 294 | f.debug_struct("SendSink").finish() 295 | } 296 | } 297 | 298 | impl<'a, T> Sink for SendSink<'a, T> { 299 | type Error = SendError; 300 | 301 | fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { 302 | Pin::new(&mut self.0).poll(cx) 303 | } 304 | 305 | fn start_send(mut self: Pin<&mut Self>, item: T) -> Result<(), Self::Error> { 306 | self.0.reset_hook(); 307 | self.0.hook = Some(SendState::NotYetSent(item)); 308 | 309 | Ok(()) 310 | } 311 | 312 | fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { 313 | Pin::new(&mut self.0).poll(cx) // TODO: A different strategy here? 314 | } 315 | 316 | fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { 317 | Pin::new(&mut self.0).poll(cx) // TODO: A different strategy here? 318 | } 319 | } 320 | 321 | impl<'a, T> Clone for SendSink<'a, T> { 322 | fn clone(&self) -> SendSink<'a, T> { 323 | SendSink(SendFut { 324 | sender: self.0.sender.clone(), 325 | hook: None, 326 | }) 327 | } 328 | } 329 | 330 | impl Receiver { 331 | /// Asynchronously receive a value from the channel, returning an error if all senders have been 332 | /// dropped. If the channel is empty, the returned future will yield to the async runtime. 333 | pub fn recv_async(&self) -> RecvFut<'_, T> { 334 | RecvFut::new(OwnedOrRef::Ref(self)) 335 | } 336 | 337 | /// Convert this receiver into a future that asynchronously receives a single message from the 338 | /// channel, returning an error if all senders have been dropped. If the channel is empty, this 339 | /// future will yield to the async runtime. 340 | pub fn into_recv_async<'a>(self) -> RecvFut<'a, T> { 341 | RecvFut::new(OwnedOrRef::Owned(self)) 342 | } 343 | 344 | /// Create an asynchronous stream that uses this receiver to asynchronously receive messages 345 | /// from the channel. The receiver will continue to be usable after the stream has been dropped. 346 | pub fn stream(&self) -> RecvStream<'_, T> { 347 | RecvStream(RecvFut::new(OwnedOrRef::Ref(self))) 348 | } 349 | 350 | /// Convert this receiver into a stream that allows asynchronously receiving messages from the channel. 351 | pub fn into_stream<'a>(self) -> RecvStream<'a, T> { 352 | RecvStream(RecvFut::new(OwnedOrRef::Owned(self))) 353 | } 354 | } 355 | 356 | /// A future which allows asynchronously receiving a message. 357 | /// 358 | /// Can be created via [`Receiver::recv_async`] or [`Receiver::into_recv_async`]. 359 | #[must_use = "futures/streams/sinks do nothing unless you `.await` or poll them"] 360 | pub struct RecvFut<'a, T> { 361 | receiver: OwnedOrRef<'a, Receiver>, 362 | hook: Option>>, 363 | } 364 | 365 | impl<'a, T> RecvFut<'a, T> { 366 | fn new(receiver: OwnedOrRef<'a, Receiver>) -> Self { 367 | Self { 368 | receiver, 369 | hook: None, 370 | } 371 | } 372 | 373 | /// Reset the hook, clearing it and removing it from the waiting receivers queue and waking 374 | /// another receiver if this receiver has been woken, so as not to cause any missed wakeups. 375 | /// This is called on drop and after a new item is received in `Stream::poll_next`. 376 | fn reset_hook(&mut self) { 377 | if let Some(hook) = self.hook.take() { 378 | let hook: Arc> = hook; 379 | let mut chan = wait_lock(&self.receiver.shared.chan); 380 | // We'd like to use `Arc::ptr_eq` here but it doesn't seem to work consistently with wide pointers? 381 | chan.waiting.retain(|s| s.signal().as_ptr() != hook.signal().as_ptr()); 382 | if hook.signal().as_any().downcast_ref::().unwrap().woken.load(Ordering::SeqCst) { 383 | // If this signal has been fired, but we're being dropped (and so not listening to it), 384 | // pass the signal on to another receiver 385 | chan.try_wake_receiver_if_pending(); 386 | } 387 | } 388 | } 389 | 390 | fn poll_inner( 391 | self: Pin<&mut Self>, 392 | cx: &mut Context, 393 | stream: bool, 394 | ) -> Poll> { 395 | if self.hook.is_some() { 396 | match self.receiver.shared.recv_sync(None) { 397 | Ok(msg) => return Poll::Ready(Ok(msg)), 398 | Err(TryRecvTimeoutError::Disconnected) => { 399 | return Poll::Ready(Err(RecvError::Disconnected)) 400 | } 401 | _ => (), 402 | } 403 | 404 | let hook = self.hook.as_ref().map(Arc::clone).unwrap(); 405 | if hook.update_waker(cx.waker()) { 406 | // If the previous hook was awakened, we need to insert it back to the 407 | // queue, otherwise, it remains valid. 408 | wait_lock(&self.receiver.shared.chan) 409 | .waiting 410 | .push_back(hook); 411 | } 412 | // To avoid a missed wakeup, re-check disconnect status here because the channel might have 413 | // gotten shut down before we had a chance to push our hook 414 | if self.receiver.shared.is_disconnected() { 415 | // And now, to avoid a race condition between the first recv attempt and the disconnect check we 416 | // just performed, attempt to recv again just in case we missed something. 417 | Poll::Ready( 418 | self.receiver 419 | .shared 420 | .recv_sync(None) 421 | .map(Ok) 422 | .unwrap_or(Err(RecvError::Disconnected)), 423 | ) 424 | } else { 425 | Poll::Pending 426 | } 427 | } else { 428 | let mut_self = self.get_mut(); 429 | let (shared, this_hook) = (&mut_self.receiver.shared, &mut mut_self.hook); 430 | 431 | shared.recv( 432 | // should_block 433 | true, 434 | // make_signal 435 | || Hook::trigger(AsyncSignal::new(cx, stream)), 436 | // do_block 437 | |hook| { 438 | *this_hook = Some(hook); 439 | Poll::Pending 440 | }, 441 | ) 442 | .map(|r| r.map_err(|err| match err { 443 | TryRecvTimeoutError::Disconnected => RecvError::Disconnected, 444 | _ => unreachable!(), 445 | })) 446 | } 447 | } 448 | 449 | /// See [`Receiver::is_disconnected`]. 450 | pub fn is_disconnected(&self) -> bool { 451 | self.receiver.is_disconnected() 452 | } 453 | 454 | /// See [`Receiver::is_empty`]. 455 | pub fn is_empty(&self) -> bool { 456 | self.receiver.is_empty() 457 | } 458 | 459 | /// See [`Receiver::is_full`]. 460 | pub fn is_full(&self) -> bool { 461 | self.receiver.is_full() 462 | } 463 | 464 | /// See [`Receiver::len`]. 465 | pub fn len(&self) -> usize { 466 | self.receiver.len() 467 | } 468 | 469 | /// See [`Receiver::capacity`]. 470 | pub fn capacity(&self) -> Option { 471 | self.receiver.capacity() 472 | } 473 | } 474 | 475 | impl<'a, T> Debug for RecvFut<'a, T> { 476 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 477 | f.debug_struct("RecvFut").finish() 478 | } 479 | } 480 | 481 | impl<'a, T> Drop for RecvFut<'a, T> { 482 | fn drop(&mut self) { 483 | self.reset_hook(); 484 | } 485 | } 486 | 487 | impl<'a, T> Future for RecvFut<'a, T> { 488 | type Output = Result; 489 | 490 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 491 | self.poll_inner(cx, false) // stream = false 492 | } 493 | } 494 | 495 | impl<'a, T> FusedFuture for RecvFut<'a, T> { 496 | fn is_terminated(&self) -> bool { 497 | self.receiver.shared.is_disconnected() && self.receiver.shared.is_empty() 498 | } 499 | } 500 | 501 | /// A stream which allows asynchronously receiving messages. 502 | /// 503 | /// Can be created via [`Receiver::stream`] or [`Receiver::into_stream`]. 504 | pub struct RecvStream<'a, T>(RecvFut<'a, T>); 505 | 506 | impl<'a, T> RecvStream<'a, T> { 507 | /// See [`Receiver::is_disconnected`]. 508 | pub fn is_disconnected(&self) -> bool { 509 | self.0.is_disconnected() 510 | } 511 | 512 | /// See [`Receiver::is_empty`]. 513 | pub fn is_empty(&self) -> bool { 514 | self.0.is_empty() 515 | } 516 | 517 | /// See [`Receiver::is_full`]. 518 | pub fn is_full(&self) -> bool { 519 | self.0.is_full() 520 | } 521 | 522 | /// See [`Receiver::len`]. 523 | pub fn len(&self) -> usize { 524 | self.0.len() 525 | } 526 | 527 | /// See [`Receiver::capacity`]. 528 | pub fn capacity(&self) -> Option { 529 | self.0.capacity() 530 | } 531 | 532 | /// Returns whether the SendSinks are belong to the same channel. 533 | pub fn same_channel(&self, other: &Self) -> bool { 534 | self.0.receiver.same_channel(&*other.0.receiver) 535 | } 536 | } 537 | 538 | impl<'a, T> Debug for RecvStream<'a, T> { 539 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 540 | f.debug_struct("RecvStream").finish() 541 | } 542 | } 543 | 544 | impl<'a, T> Clone for RecvStream<'a, T> { 545 | fn clone(&self) -> RecvStream<'a, T> { 546 | RecvStream(RecvFut::new(self.0.receiver.clone())) 547 | } 548 | } 549 | 550 | impl<'a, T> Stream for RecvStream<'a, T> { 551 | type Item = T; 552 | 553 | fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 554 | match Pin::new(&mut self.0).poll_inner(cx, true) { // stream = true 555 | Poll::Pending => Poll::Pending, 556 | Poll::Ready(item) => { 557 | self.0.reset_hook(); 558 | Poll::Ready(item.ok()) 559 | } 560 | } 561 | } 562 | } 563 | 564 | impl<'a, T> FusedStream for RecvStream<'a, T> { 565 | fn is_terminated(&self) -> bool { 566 | self.0.is_terminated() 567 | } 568 | } 569 | -------------------------------------------------------------------------------- /src/select.rs: -------------------------------------------------------------------------------- 1 | //! Types that permit waiting upon multiple blocking operations using the [`Selector`] interface. 2 | 3 | use crate::*; 4 | use spin1::Mutex as Spinlock; 5 | use std::{any::Any, marker::PhantomData}; 6 | 7 | // A unique token corresponding to an event in a selector 8 | type Token = usize; 9 | 10 | struct SelectSignal( 11 | thread::Thread, 12 | Token, 13 | AtomicBool, 14 | Arc>>, 15 | ); 16 | 17 | impl Signal for SelectSignal { 18 | fn fire(&self) -> bool { 19 | self.2.store(true, Ordering::SeqCst); 20 | self.3.lock().push_back(self.1); 21 | self.0.unpark(); 22 | false 23 | } 24 | 25 | fn as_any(&self) -> &(dyn Any + 'static) { 26 | self 27 | } 28 | fn as_ptr(&self) -> *const () { 29 | self as *const _ as *const () 30 | } 31 | } 32 | 33 | trait Selection<'a, T> { 34 | fn init(&mut self) -> Option; 35 | fn poll(&mut self) -> Option; 36 | fn deinit(&mut self); 37 | } 38 | 39 | /// An error that may be emitted when attempting to wait for a value on a receiver. 40 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 41 | pub enum SelectError { 42 | /// A timeout occurred when waiting on a `Selector`. 43 | Timeout, 44 | } 45 | 46 | impl fmt::Display for SelectError { 47 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 48 | match self { 49 | SelectError::Timeout => "timeout occurred".fmt(f), 50 | } 51 | } 52 | } 53 | 54 | impl std::error::Error for SelectError {} 55 | 56 | /// A type used to wait upon multiple blocking operations at once. 57 | /// 58 | /// A [`Selector`] implements [`select`](https://en.wikipedia.org/wiki/Select_(Unix))-like behaviour, 59 | /// allowing a thread to wait upon the result of more than one operation at once. 60 | /// 61 | /// # Examples 62 | /// ``` 63 | /// let (tx0, rx0) = flume::unbounded(); 64 | /// let (tx1, rx1) = flume::unbounded(); 65 | /// 66 | /// std::thread::spawn(move || { 67 | /// tx0.send(true).unwrap(); 68 | /// tx1.send(42).unwrap(); 69 | /// }); 70 | /// 71 | /// flume::Selector::new() 72 | /// .recv(&rx0, |b| println!("Received {:?}", b)) 73 | /// .recv(&rx1, |n| println!("Received {:?}", n)) 74 | /// .wait(); 75 | /// ``` 76 | pub struct Selector<'a, T: 'a> { 77 | selections: Vec + 'a>>, 78 | next_poll: usize, 79 | signalled: Arc>>, 80 | #[cfg(feature = "eventual-fairness")] 81 | rng: fastrand::Rng, 82 | phantom: PhantomData<*const ()>, 83 | } 84 | 85 | impl<'a, T: 'a> Default for Selector<'a, T> { 86 | fn default() -> Self { 87 | Self::new() 88 | } 89 | } 90 | 91 | impl<'a, T: 'a> fmt::Debug for Selector<'a, T> { 92 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 93 | f.debug_struct("Selector").finish() 94 | } 95 | } 96 | 97 | impl<'a, T> Selector<'a, T> { 98 | /// Create a new selector. 99 | pub fn new() -> Self { 100 | Self { 101 | selections: Vec::new(), 102 | next_poll: 0, 103 | signalled: Arc::default(), 104 | phantom: PhantomData::default(), 105 | #[cfg(feature = "eventual-fairness")] 106 | rng: fastrand::Rng::new(), 107 | } 108 | } 109 | 110 | /// Add a send operation to the selector that sends the provided value. 111 | /// 112 | /// Once added, the selector can be used to run the provided handler function on completion of this operation. 113 | pub fn send>) -> T + 'a>( 114 | mut self, 115 | sender: &'a Sender, 116 | msg: U, 117 | mapper: F, 118 | ) -> Self { 119 | struct SendSelection<'a, T, F, U> { 120 | sender: &'a Sender, 121 | msg: Option, 122 | token: Token, 123 | signalled: Arc>>, 124 | hook: Option>>, 125 | mapper: F, 126 | phantom: PhantomData, 127 | } 128 | 129 | impl<'a, T, F, U> Selection<'a, T> for SendSelection<'a, T, F, U> 130 | where 131 | F: FnMut(Result<(), SendError>) -> T, 132 | { 133 | fn init(&mut self) -> Option { 134 | let token = self.token; 135 | let signalled = self.signalled.clone(); 136 | let r = self.sender.shared.send( 137 | self.msg.take().unwrap(), 138 | true, 139 | |msg| { 140 | Hook::slot( 141 | Some(msg), 142 | SelectSignal( 143 | thread::current(), 144 | token, 145 | AtomicBool::new(false), 146 | signalled, 147 | ), 148 | ) 149 | }, 150 | // Always runs 151 | |h| { 152 | self.hook = Some(h); 153 | Ok(()) 154 | }, 155 | ); 156 | 157 | if self.hook.is_none() { 158 | Some((self.mapper)(match r { 159 | Ok(()) => Ok(()), 160 | Err(TrySendTimeoutError::Disconnected(msg)) => Err(SendError(msg)), 161 | _ => unreachable!(), 162 | })) 163 | } else { 164 | None 165 | } 166 | } 167 | 168 | fn poll(&mut self) -> Option { 169 | let res = if self.sender.shared.is_disconnected() { 170 | // Check the hook one last time 171 | if let Some(msg) = self.hook.as_ref()?.try_take() { 172 | Err(SendError(msg)) 173 | } else { 174 | Ok(()) 175 | } 176 | } else if self.hook.as_ref().unwrap().is_empty() { 177 | // The message was sent 178 | Ok(()) 179 | } else { 180 | return None; 181 | }; 182 | 183 | Some((&mut self.mapper)(res)) 184 | } 185 | 186 | fn deinit(&mut self) { 187 | if let Some(hook) = self.hook.take() { 188 | // Remove hook 189 | let hook: Arc> = hook; 190 | wait_lock(&self.sender.shared.chan) 191 | .sending 192 | .as_mut() 193 | .unwrap() 194 | .1 195 | .retain(|s| s.signal().as_ptr() != hook.signal().as_ptr()); 196 | } 197 | } 198 | } 199 | 200 | let token = self.selections.len(); 201 | self.selections.push(Box::new(SendSelection { 202 | sender, 203 | msg: Some(msg), 204 | token, 205 | signalled: self.signalled.clone(), 206 | hook: None, 207 | mapper, 208 | phantom: Default::default(), 209 | })); 210 | 211 | self 212 | } 213 | 214 | /// Add a receive operation to the selector. 215 | /// 216 | /// Once added, the selector can be used to run the provided handler function on completion of this operation. 217 | pub fn recv) -> T + 'a>( 218 | mut self, 219 | receiver: &'a Receiver, 220 | mapper: F, 221 | ) -> Self { 222 | struct RecvSelection<'a, T, F, U> { 223 | receiver: &'a Receiver, 224 | token: Token, 225 | signalled: Arc>>, 226 | hook: Option>>, 227 | mapper: F, 228 | received: bool, 229 | phantom: PhantomData, 230 | } 231 | 232 | impl<'a, T, F, U> Selection<'a, T> for RecvSelection<'a, T, F, U> 233 | where 234 | F: FnMut(Result) -> T, 235 | { 236 | fn init(&mut self) -> Option { 237 | let token = self.token; 238 | let signalled = self.signalled.clone(); 239 | let r = self.receiver.shared.recv( 240 | true, 241 | || { 242 | Hook::trigger(SelectSignal( 243 | thread::current(), 244 | token, 245 | AtomicBool::new(false), 246 | signalled, 247 | )) 248 | }, 249 | // Always runs 250 | |h| { 251 | self.hook = Some(h); 252 | Err(TryRecvTimeoutError::Timeout) 253 | }, 254 | ); 255 | 256 | if self.hook.is_none() { 257 | Some((self.mapper)(match r { 258 | Ok(msg) => Ok(msg), 259 | Err(TryRecvTimeoutError::Disconnected) => Err(RecvError::Disconnected), 260 | _ => unreachable!(), 261 | })) 262 | } else { 263 | None 264 | } 265 | } 266 | 267 | fn poll(&mut self) -> Option { 268 | let res = if let Ok(msg) = self.receiver.try_recv() { 269 | self.received = true; 270 | Ok(msg) 271 | } else if self.receiver.shared.is_disconnected() { 272 | Err(RecvError::Disconnected) 273 | } else { 274 | return None; 275 | }; 276 | 277 | Some((&mut self.mapper)(res)) 278 | } 279 | 280 | fn deinit(&mut self) { 281 | if let Some(hook) = self.hook.take() { 282 | // Remove hook 283 | let hook: Arc> = hook; 284 | wait_lock(&self.receiver.shared.chan) 285 | .waiting 286 | .retain(|s| s.signal().as_ptr() != hook.signal().as_ptr()); 287 | // If we were woken, but never polled, wake up another 288 | if !self.received 289 | && hook 290 | .signal() 291 | .as_any() 292 | .downcast_ref::() 293 | .unwrap() 294 | .2 295 | .load(Ordering::SeqCst) 296 | { 297 | wait_lock(&self.receiver.shared.chan).try_wake_receiver_if_pending(); 298 | } 299 | } 300 | } 301 | } 302 | 303 | let token = self.selections.len(); 304 | self.selections.push(Box::new(RecvSelection { 305 | receiver, 306 | token, 307 | signalled: self.signalled.clone(), 308 | hook: None, 309 | mapper, 310 | received: false, 311 | phantom: Default::default(), 312 | })); 313 | 314 | self 315 | } 316 | 317 | fn wait_inner(mut self, deadline: Option) -> Option { 318 | #[cfg(feature = "eventual-fairness")] 319 | { 320 | self.next_poll = self.rng.usize(0..self.selections.len()); 321 | } 322 | 323 | let res = 'outer: loop { 324 | // Init signals 325 | for _ in 0..self.selections.len() { 326 | if let Some(val) = self.selections[self.next_poll].init() { 327 | break 'outer Some(val); 328 | } 329 | self.next_poll = (self.next_poll + 1) % self.selections.len(); 330 | } 331 | 332 | // Speculatively poll 333 | if let Some(msg) = self.poll() { 334 | break 'outer Some(msg); 335 | } 336 | 337 | loop { 338 | if let Some(deadline) = deadline { 339 | if let Some(dur) = deadline.checked_duration_since(Instant::now()) { 340 | thread::park_timeout(dur); 341 | } 342 | } else { 343 | thread::park(); 344 | } 345 | 346 | if deadline.map(|d| Instant::now() >= d).unwrap_or(false) { 347 | break 'outer self.poll(); 348 | } 349 | 350 | let token = if let Some(token) = self.signalled.lock().pop_front() { 351 | token 352 | } else { 353 | // Spurious wakeup, park again 354 | continue; 355 | }; 356 | 357 | // Attempt to receive a message 358 | if let Some(msg) = self.selections[token].poll() { 359 | break 'outer Some(msg); 360 | } 361 | } 362 | }; 363 | 364 | // Deinit signals 365 | for s in &mut self.selections { 366 | s.deinit(); 367 | } 368 | 369 | res 370 | } 371 | 372 | fn poll(&mut self) -> Option { 373 | for _ in 0..self.selections.len() { 374 | if let Some(val) = self.selections[self.next_poll].poll() { 375 | return Some(val); 376 | } 377 | self.next_poll = (self.next_poll + 1) % self.selections.len(); 378 | } 379 | None 380 | } 381 | 382 | /// Wait until one of the events associated with this [`Selector`] has completed. If the `eventual-fairness` 383 | /// feature flag is enabled, this method is fair and will handle a random event of those that are ready. 384 | pub fn wait(self) -> T { 385 | self.wait_inner(None).unwrap() 386 | } 387 | 388 | /// Wait until one of the events associated with this [`Selector`] has completed or the timeout has expired. If the 389 | /// `eventual-fairness` feature flag is enabled, this method is fair and will handle a random event of those that 390 | /// are ready. 391 | pub fn wait_timeout(self, dur: Duration) -> Result { 392 | self.wait_inner(Some(Instant::now() + dur)) 393 | .ok_or(SelectError::Timeout) 394 | } 395 | 396 | /// Wait until one of the events associated with this [`Selector`] has completed or the deadline has been reached. 397 | /// If the `eventual-fairness` feature flag is enabled, this method is fair and will handle a random event of those 398 | /// that are ready. 399 | pub fn wait_deadline(self, deadline: Instant) -> Result { 400 | self.wait_inner(Some(deadline)).ok_or(SelectError::Timeout) 401 | } 402 | } 403 | -------------------------------------------------------------------------------- /src/signal.rs: -------------------------------------------------------------------------------- 1 | use std::{thread::{self, Thread}, time::Duration, any::Any}; 2 | 3 | pub trait Signal: Send + Sync + 'static { 4 | /// Fire the signal, returning whether it is a stream signal. This is because streams do not 5 | /// acquire a message when woken, so signals must be fired until one that does acquire a message 6 | /// is fired, otherwise a wakeup could be missed, leading to a lost message until one is eagerly 7 | /// grabbed by a receiver. 8 | fn fire(&self) -> bool; 9 | fn as_any(&self) -> &(dyn Any + 'static); 10 | fn as_ptr(&self) -> *const (); 11 | } 12 | 13 | pub struct SyncSignal(Thread); 14 | 15 | impl Default for SyncSignal { 16 | fn default() -> Self { 17 | Self(thread::current()) 18 | } 19 | } 20 | 21 | impl Signal for SyncSignal { 22 | fn fire(&self) -> bool { 23 | self.0.unpark(); 24 | false 25 | } 26 | fn as_any(&self) -> &(dyn Any + 'static) { self } 27 | fn as_ptr(&self) -> *const () { self as *const _ as *const () } 28 | } 29 | 30 | impl SyncSignal { 31 | pub fn wait(&self) { thread::park(); } 32 | pub fn wait_timeout(&self, dur: Duration) { thread::park_timeout(dur); } 33 | } 34 | -------------------------------------------------------------------------------- /tests/after.rs: -------------------------------------------------------------------------------- 1 | // //! Tests for the after channel flavor. 2 | 3 | // #[macro_use] 4 | // extern crate crossbeam_channel; 5 | // extern crate crossbeam_utils; 6 | // extern crate rand; 7 | 8 | // use std::sync::atomic::AtomicUsize; 9 | // use std::sync::atomic::Ordering; 10 | // use std::thread; 11 | // use std::time::{Duration, Instant}; 12 | 13 | // use crossbeam_channel::{after, Select, TryRecvError}; 14 | // use crossbeam_utils::thread::scope; 15 | 16 | // fn ms(ms: u64) -> Duration { 17 | // Duration::from_millis(ms) 18 | // } 19 | 20 | // #[test] 21 | // fn fire() { 22 | // let start = Instant::now(); 23 | // let r = after(ms(50)); 24 | 25 | // assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); 26 | // thread::sleep(ms(100)); 27 | 28 | // let fired = r.try_recv().unwrap(); 29 | // assert!(start < fired); 30 | // assert!(fired - start >= ms(50)); 31 | 32 | // let now = Instant::now(); 33 | // assert!(fired < now); 34 | // assert!(now - fired >= ms(50)); 35 | 36 | // assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); 37 | 38 | // select! { 39 | // recv(r) -> _ => panic!(), 40 | // default => {} 41 | // } 42 | 43 | // select! { 44 | // recv(r) -> _ => panic!(), 45 | // recv(after(ms(200))) -> _ => {} 46 | // } 47 | // } 48 | 49 | // #[test] 50 | // fn capacity() { 51 | // const COUNT: usize = 10; 52 | 53 | // for i in 0..COUNT { 54 | // let r = after(ms(i as u64)); 55 | // assert_eq!(r.capacity(), Some(1)); 56 | // } 57 | // } 58 | 59 | // #[test] 60 | // fn len_empty_full() { 61 | // let r = after(ms(50)); 62 | 63 | // assert_eq!(r.len(), 0); 64 | // assert_eq!(r.is_empty(), true); 65 | // assert_eq!(r.is_full(), false); 66 | 67 | // thread::sleep(ms(100)); 68 | 69 | // assert_eq!(r.len(), 1); 70 | // assert_eq!(r.is_empty(), false); 71 | // assert_eq!(r.is_full(), true); 72 | 73 | // r.try_recv().unwrap(); 74 | 75 | // assert_eq!(r.len(), 0); 76 | // assert_eq!(r.is_empty(), true); 77 | // assert_eq!(r.is_full(), false); 78 | // } 79 | 80 | // #[test] 81 | // fn try_recv() { 82 | // let r = after(ms(200)); 83 | // assert!(r.try_recv().is_err()); 84 | 85 | // thread::sleep(ms(100)); 86 | // assert!(r.try_recv().is_err()); 87 | 88 | // thread::sleep(ms(200)); 89 | // assert!(r.try_recv().is_ok()); 90 | // assert!(r.try_recv().is_err()); 91 | 92 | // thread::sleep(ms(200)); 93 | // assert!(r.try_recv().is_err()); 94 | // } 95 | 96 | // #[test] 97 | // fn recv() { 98 | // let start = Instant::now(); 99 | // let r = after(ms(50)); 100 | 101 | // let fired = r.recv().unwrap(); 102 | // assert!(start < fired); 103 | // assert!(fired - start >= ms(50)); 104 | 105 | // let now = Instant::now(); 106 | // assert!(fired < now); 107 | // assert!(now - fired < fired - start); 108 | 109 | // assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); 110 | // } 111 | 112 | // #[test] 113 | // fn recv_timeout() { 114 | // let start = Instant::now(); 115 | // let r = after(ms(200)); 116 | 117 | // assert!(r.recv_timeout(ms(100)).is_err()); 118 | // let now = Instant::now(); 119 | // assert!(now - start >= ms(100)); 120 | // assert!(now - start <= ms(150)); 121 | 122 | // let fired = r.recv_timeout(ms(200)).unwrap(); 123 | // assert!(fired - start >= ms(200)); 124 | // assert!(fired - start <= ms(250)); 125 | 126 | // assert!(r.recv_timeout(ms(200)).is_err()); 127 | // let now = Instant::now(); 128 | // assert!(now - start >= ms(400)); 129 | // assert!(now - start <= ms(450)); 130 | 131 | // assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); 132 | // } 133 | 134 | // #[test] 135 | // fn recv_two() { 136 | // let r1 = after(ms(50)); 137 | // let r2 = after(ms(50)); 138 | 139 | // scope(|scope| { 140 | // scope.spawn(|_| { 141 | // select! { 142 | // recv(r1) -> _ => {} 143 | // recv(r2) -> _ => {} 144 | // } 145 | // }); 146 | // scope.spawn(|_| { 147 | // select! { 148 | // recv(r1) -> _ => {} 149 | // recv(r2) -> _ => {} 150 | // } 151 | // }); 152 | // }) 153 | // .unwrap(); 154 | // } 155 | 156 | // #[test] 157 | // fn recv_race() { 158 | // select! { 159 | // recv(after(ms(50))) -> _ => {} 160 | // recv(after(ms(100))) -> _ => panic!(), 161 | // } 162 | 163 | // select! { 164 | // recv(after(ms(100))) -> _ => panic!(), 165 | // recv(after(ms(50))) -> _ => {} 166 | // } 167 | // } 168 | 169 | // #[test] 170 | // fn stress_default() { 171 | // const COUNT: usize = 10; 172 | 173 | // for _ in 0..COUNT { 174 | // select! { 175 | // recv(after(ms(0))) -> _ => {} 176 | // default => panic!(), 177 | // } 178 | // } 179 | 180 | // for _ in 0..COUNT { 181 | // select! { 182 | // recv(after(ms(100))) -> _ => panic!(), 183 | // default => {} 184 | // } 185 | // } 186 | // } 187 | 188 | // #[test] 189 | // fn select() { 190 | // const THREADS: usize = 4; 191 | // const COUNT: usize = 1000; 192 | // const TIMEOUT_MS: u64 = 100; 193 | 194 | // let v = (0..COUNT) 195 | // .map(|i| after(ms(i as u64 / TIMEOUT_MS / 2))) 196 | // .collect::>(); 197 | // let hits = AtomicUsize::new(0); 198 | 199 | // scope(|scope| { 200 | // for _ in 0..THREADS { 201 | // scope.spawn(|_| { 202 | // let v: Vec<&_> = v.iter().collect(); 203 | 204 | // loop { 205 | // let timeout = after(ms(TIMEOUT_MS)); 206 | // let mut sel = Select::new(); 207 | // for r in &v { 208 | // sel.recv(r); 209 | // } 210 | // let oper_timeout = sel.recv(&timeout); 211 | 212 | // let oper = sel.select(); 213 | // match oper.index() { 214 | // i if i == oper_timeout => { 215 | // oper.recv(&timeout).unwrap(); 216 | // break; 217 | // } 218 | // i => { 219 | // oper.recv(&v[i]).unwrap(); 220 | // hits.fetch_add(1, Ordering::SeqCst); 221 | // } 222 | // } 223 | // } 224 | // }); 225 | // } 226 | // }) 227 | // .unwrap(); 228 | 229 | // assert_eq!(hits.load(Ordering::SeqCst), COUNT); 230 | // } 231 | 232 | // #[test] 233 | // fn ready() { 234 | // const THREADS: usize = 4; 235 | // const COUNT: usize = 1000; 236 | // const TIMEOUT_MS: u64 = 100; 237 | 238 | // let v = (0..COUNT) 239 | // .map(|i| after(ms(i as u64 / TIMEOUT_MS / 2))) 240 | // .collect::>(); 241 | // let hits = AtomicUsize::new(0); 242 | 243 | // scope(|scope| { 244 | // for _ in 0..THREADS { 245 | // scope.spawn(|_| { 246 | // let v: Vec<&_> = v.iter().collect(); 247 | 248 | // loop { 249 | // let timeout = after(ms(TIMEOUT_MS)); 250 | // let mut sel = Select::new(); 251 | // for r in &v { 252 | // sel.recv(r); 253 | // } 254 | // let oper_timeout = sel.recv(&timeout); 255 | 256 | // loop { 257 | // let i = sel.ready(); 258 | // if i == oper_timeout { 259 | // timeout.try_recv().unwrap(); 260 | // return; 261 | // } else if v[i].try_recv().is_ok() { 262 | // hits.fetch_add(1, Ordering::SeqCst); 263 | // break; 264 | // } 265 | // } 266 | // } 267 | // }); 268 | // } 269 | // }) 270 | // .unwrap(); 271 | 272 | // assert_eq!(hits.load(Ordering::SeqCst), COUNT); 273 | // } 274 | 275 | // #[test] 276 | // fn stress_clone() { 277 | // const RUNS: usize = 1000; 278 | // const THREADS: usize = 10; 279 | // const COUNT: usize = 50; 280 | 281 | // for i in 0..RUNS { 282 | // let r = after(ms(i as u64)); 283 | 284 | // scope(|scope| { 285 | // for _ in 0..THREADS { 286 | // scope.spawn(|_| { 287 | // let r = r.clone(); 288 | // let _ = r.try_recv(); 289 | 290 | // for _ in 0..COUNT { 291 | // drop(r.clone()); 292 | // thread::yield_now(); 293 | // } 294 | // }); 295 | // } 296 | // }) 297 | // .unwrap(); 298 | // } 299 | // } 300 | 301 | // #[test] 302 | // fn fairness() { 303 | // const COUNT: usize = 1000; 304 | 305 | // for &dur in &[0, 1] { 306 | // let mut hits = [0usize; 2]; 307 | 308 | // for _ in 0..COUNT { 309 | // select! { 310 | // recv(after(ms(dur))) -> _ => hits[0] += 1, 311 | // recv(after(ms(dur))) -> _ => hits[1] += 1, 312 | // } 313 | // } 314 | 315 | // assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); 316 | // } 317 | // } 318 | 319 | // #[test] 320 | // fn fairness_duplicates() { 321 | // const COUNT: usize = 1000; 322 | 323 | // for &dur in &[0, 1] { 324 | // let mut hits = [0usize; 5]; 325 | 326 | // for _ in 0..COUNT { 327 | // let r = after(ms(dur)); 328 | // select! { 329 | // recv(r) -> _ => hits[0] += 1, 330 | // recv(r) -> _ => hits[1] += 1, 331 | // recv(r) -> _ => hits[2] += 1, 332 | // recv(r) -> _ => hits[3] += 1, 333 | // recv(r) -> _ => hits[4] += 1, 334 | // } 335 | // } 336 | 337 | // assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); 338 | // } 339 | // } 340 | -------------------------------------------------------------------------------- /tests/array.rs: -------------------------------------------------------------------------------- 1 | //! Tests for the array channel flavor. 2 | 3 | extern crate crossbeam_utils; 4 | extern crate rand; 5 | 6 | use std::any::Any; 7 | use std::sync::atomic::AtomicUsize; 8 | use std::sync::atomic::Ordering; 9 | use std::thread; 10 | use std::time::Duration; 11 | 12 | use flume::{bounded, Receiver}; 13 | use flume::{RecvError, RecvTimeoutError, TryRecvError}; 14 | use flume::{SendError, SendTimeoutError, TrySendError}; 15 | use crossbeam_utils::thread::scope; 16 | use rand::{thread_rng, Rng}; 17 | 18 | fn ms(ms: u64) -> Duration { 19 | Duration::from_millis(ms) 20 | } 21 | 22 | #[test] 23 | fn smoke() { 24 | let (s, r) = bounded(1); 25 | s.send(7).unwrap(); 26 | assert_eq!(r.try_recv(), Ok(7)); 27 | 28 | s.send(8).unwrap(); 29 | assert_eq!(r.recv(), Ok(8)); 30 | 31 | assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); 32 | assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout)); 33 | } 34 | 35 | #[test] 36 | fn capacity() { 37 | for i in 1..10 { 38 | let (s, r) = bounded::<()>(i); 39 | assert_eq!(s.capacity(), Some(i)); 40 | assert_eq!(r.capacity(), Some(i)); 41 | } 42 | } 43 | 44 | #[test] 45 | fn len_empty_full() { 46 | let (s, r) = bounded(2); 47 | 48 | assert_eq!(s.len(), 0); 49 | assert_eq!(s.is_empty(), true); 50 | assert_eq!(s.is_full(), false); 51 | assert_eq!(r.len(), 0); 52 | assert_eq!(r.is_empty(), true); 53 | assert_eq!(r.is_full(), false); 54 | 55 | s.send(()).unwrap(); 56 | 57 | assert_eq!(s.len(), 1); 58 | assert_eq!(s.is_empty(), false); 59 | assert_eq!(s.is_full(), false); 60 | assert_eq!(r.len(), 1); 61 | assert_eq!(r.is_empty(), false); 62 | assert_eq!(r.is_full(), false); 63 | 64 | s.send(()).unwrap(); 65 | 66 | assert_eq!(s.len(), 2); 67 | assert_eq!(s.is_empty(), false); 68 | assert_eq!(s.is_full(), true); 69 | assert_eq!(r.len(), 2); 70 | assert_eq!(r.is_empty(), false); 71 | assert_eq!(r.is_full(), true); 72 | 73 | r.recv().unwrap(); 74 | 75 | assert_eq!(s.len(), 1); 76 | assert_eq!(s.is_empty(), false); 77 | assert_eq!(s.is_full(), false); 78 | assert_eq!(r.len(), 1); 79 | assert_eq!(r.is_empty(), false); 80 | assert_eq!(r.is_full(), false); 81 | } 82 | 83 | #[test] 84 | fn try_recv() { 85 | let (s, r) = bounded(100); 86 | 87 | scope(|scope| { 88 | scope.spawn(move |_| { 89 | assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); 90 | thread::sleep(ms(1500)); 91 | assert_eq!(r.try_recv(), Ok(7)); 92 | thread::sleep(ms(500)); 93 | assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); 94 | }); 95 | scope.spawn(move |_| { 96 | thread::sleep(ms(1000)); 97 | s.send(7).unwrap(); 98 | }); 99 | }) 100 | .unwrap(); 101 | } 102 | 103 | #[test] 104 | fn recv() { 105 | let (s, r) = bounded(100); 106 | 107 | scope(|scope| { 108 | scope.spawn(move |_| { 109 | assert_eq!(r.recv(), Ok(7)); 110 | thread::sleep(ms(1000)); 111 | assert_eq!(r.recv(), Ok(8)); 112 | thread::sleep(ms(1000)); 113 | assert_eq!(r.recv(), Ok(9)); 114 | assert!(r.recv().is_err()); 115 | }); 116 | scope.spawn(move |_| { 117 | thread::sleep(ms(1500)); 118 | s.send(7).unwrap(); 119 | s.send(8).unwrap(); 120 | s.send(9).unwrap(); 121 | }); 122 | }) 123 | .unwrap(); 124 | } 125 | 126 | #[test] 127 | fn recv_timeout() { 128 | let (s, r) = bounded::(100); 129 | 130 | scope(|scope| { 131 | scope.spawn(move |_| { 132 | assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout)); 133 | assert_eq!(r.recv_timeout(ms(1000)), Ok(7)); 134 | assert_eq!( 135 | r.recv_timeout(ms(1000)), 136 | Err(RecvTimeoutError::Disconnected) 137 | ); 138 | }); 139 | scope.spawn(move |_| { 140 | thread::sleep(ms(1500)); 141 | s.send(7).unwrap(); 142 | }); 143 | }) 144 | .unwrap(); 145 | } 146 | 147 | #[test] 148 | fn try_send() { 149 | let (s, r) = bounded(1); 150 | 151 | scope(|scope| { 152 | scope.spawn(move |_| { 153 | assert_eq!(s.try_send(1), Ok(())); 154 | assert_eq!(s.try_send(2), Err(TrySendError::Full(2))); 155 | thread::sleep(ms(1500)); 156 | assert_eq!(s.try_send(3), Ok(())); 157 | thread::sleep(ms(500)); 158 | assert_eq!(s.try_send(4), Err(TrySendError::Disconnected(4))); 159 | }); 160 | scope.spawn(move |_| { 161 | thread::sleep(ms(1000)); 162 | assert_eq!(r.try_recv(), Ok(1)); 163 | assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); 164 | assert_eq!(r.recv(), Ok(3)); 165 | }); 166 | }) 167 | .unwrap(); 168 | } 169 | 170 | #[test] 171 | fn send() { 172 | let (s, r) = bounded(1); 173 | 174 | scope(|scope| { 175 | scope.spawn(|_| { 176 | s.send(7).unwrap(); 177 | thread::sleep(ms(1000)); 178 | s.send(8).unwrap(); 179 | thread::sleep(ms(1000)); 180 | s.send(9).unwrap(); 181 | thread::sleep(ms(1000)); 182 | s.send(10).unwrap(); 183 | }); 184 | scope.spawn(|_| { 185 | thread::sleep(ms(1500)); 186 | assert_eq!(r.recv(), Ok(7)); 187 | assert_eq!(r.recv(), Ok(8)); 188 | assert_eq!(r.recv(), Ok(9)); 189 | }); 190 | }) 191 | .unwrap(); 192 | } 193 | 194 | #[test] 195 | fn send_timeout() { 196 | let (s, r) = bounded(2); 197 | 198 | scope(|scope| { 199 | scope.spawn(move |_| { 200 | assert_eq!(s.send_timeout(1, ms(1000)), Ok(())); 201 | assert_eq!(s.send_timeout(2, ms(1000)), Ok(())); 202 | assert_eq!( 203 | s.send_timeout(3, ms(500)), 204 | Err(SendTimeoutError::Timeout(3)) 205 | ); 206 | thread::sleep(ms(1000)); 207 | assert_eq!(s.send_timeout(4, ms(1000)), Ok(())); 208 | thread::sleep(ms(1000)); 209 | assert_eq!(s.send(5), Err(SendError(5))); 210 | }); 211 | scope.spawn(move |_| { 212 | thread::sleep(ms(1000)); 213 | assert_eq!(r.recv(), Ok(1)); 214 | thread::sleep(ms(1000)); 215 | assert_eq!(r.recv(), Ok(2)); 216 | assert_eq!(r.recv(), Ok(4)); 217 | }); 218 | }) 219 | .unwrap(); 220 | } 221 | 222 | #[test] 223 | fn send_after_disconnect() { 224 | let (s, r) = bounded(100); 225 | 226 | s.send(1).unwrap(); 227 | s.send(2).unwrap(); 228 | s.send(3).unwrap(); 229 | 230 | drop(r); 231 | 232 | assert_eq!(s.send(4), Err(SendError(4))); 233 | assert_eq!(s.try_send(5), Err(TrySendError::Disconnected(5))); 234 | assert_eq!( 235 | s.send_timeout(6, ms(500)), 236 | Err(SendTimeoutError::Disconnected(6)) 237 | ); 238 | } 239 | 240 | #[test] 241 | fn recv_after_disconnect() { 242 | let (s, r) = bounded(100); 243 | 244 | s.send(1).unwrap(); 245 | s.send(2).unwrap(); 246 | s.send(3).unwrap(); 247 | 248 | drop(s); 249 | 250 | assert_eq!(r.recv(), Ok(1)); 251 | assert_eq!(r.recv(), Ok(2)); 252 | assert_eq!(r.recv(), Ok(3)); 253 | assert!(r.recv().is_err()); 254 | } 255 | 256 | #[test] 257 | fn len() { 258 | const COUNT: usize = 25_000; 259 | const CAP: usize = 1000; 260 | 261 | let (s, r) = bounded(CAP); 262 | 263 | assert_eq!(s.len(), 0); 264 | assert_eq!(r.len(), 0); 265 | 266 | for _ in 0..CAP / 10 { 267 | for i in 0..50 { 268 | s.send(i).unwrap(); 269 | assert_eq!(s.len(), i + 1); 270 | } 271 | 272 | for i in 0..50 { 273 | r.recv().unwrap(); 274 | assert_eq!(r.len(), 50 - i - 1); 275 | } 276 | } 277 | 278 | assert_eq!(s.len(), 0); 279 | assert_eq!(r.len(), 0); 280 | 281 | for i in 0..CAP { 282 | s.send(i).unwrap(); 283 | assert_eq!(s.len(), i + 1); 284 | } 285 | 286 | for _ in 0..CAP { 287 | r.recv().unwrap(); 288 | } 289 | 290 | assert_eq!(s.len(), 0); 291 | assert_eq!(r.len(), 0); 292 | 293 | scope(|scope| { 294 | scope.spawn(|_| { 295 | for i in 0..COUNT { 296 | assert_eq!(r.recv(), Ok(i)); 297 | let len = r.len(); 298 | assert!(len <= CAP); 299 | } 300 | }); 301 | 302 | scope.spawn(|_| { 303 | for i in 0..COUNT { 304 | s.send(i).unwrap(); 305 | let len = s.len(); 306 | assert!(len <= CAP); 307 | } 308 | }); 309 | }) 310 | .unwrap(); 311 | 312 | assert_eq!(s.len(), 0); 313 | assert_eq!(r.len(), 0); 314 | } 315 | 316 | #[test] 317 | fn disconnect_wakes_sender() { 318 | let (s, r) = bounded(1); 319 | 320 | scope(|scope| { 321 | scope.spawn(move |_| { 322 | assert_eq!(s.send(()), Ok(())); 323 | assert_eq!(s.send(()), Err(SendError(()))); 324 | }); 325 | scope.spawn(move |_| { 326 | thread::sleep(ms(1000)); 327 | drop(r); 328 | }); 329 | }) 330 | .unwrap(); 331 | } 332 | 333 | #[test] 334 | fn disconnect_wakes_receiver() { 335 | let (s, r) = bounded::<()>(1); 336 | 337 | scope(|scope| { 338 | scope.spawn(move |_| { 339 | assert!(r.recv().is_err()); 340 | }); 341 | scope.spawn(move |_| { 342 | thread::sleep(ms(1000)); 343 | drop(s); 344 | }); 345 | }) 346 | .unwrap(); 347 | } 348 | 349 | #[test] 350 | fn spsc() { 351 | const COUNT: usize = 100_000; 352 | 353 | let (s, r) = bounded(3); 354 | 355 | scope(|scope| { 356 | scope.spawn(move |_| { 357 | for i in 0..COUNT { 358 | assert_eq!(r.recv(), Ok(i)); 359 | } 360 | assert!(r.recv().is_err()); 361 | }); 362 | scope.spawn(move |_| { 363 | for i in 0..COUNT { 364 | s.send(i).unwrap(); 365 | } 366 | }); 367 | }) 368 | .unwrap(); 369 | } 370 | 371 | #[test] 372 | fn mpmc() { 373 | const COUNT: usize = 25_000; 374 | const THREADS: usize = 4; 375 | 376 | let (s, r) = bounded::(3); 377 | let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); 378 | 379 | scope(|scope| { 380 | for _ in 0..THREADS { 381 | scope.spawn(|_| { 382 | for _ in 0..COUNT { 383 | let n = r.recv().unwrap(); 384 | v[n].fetch_add(1, Ordering::SeqCst); 385 | } 386 | }); 387 | } 388 | for _ in 0..THREADS { 389 | scope.spawn(|_| { 390 | for i in 0..COUNT { 391 | s.send(i).unwrap(); 392 | } 393 | }); 394 | } 395 | }) 396 | .unwrap(); 397 | 398 | for c in v { 399 | assert_eq!(c.load(Ordering::SeqCst), THREADS); 400 | } 401 | } 402 | 403 | #[test] 404 | fn stress_oneshot() { 405 | const COUNT: usize = 10_000; 406 | 407 | for _ in 0..COUNT { 408 | let (s, r) = bounded(1); 409 | 410 | scope(|scope| { 411 | scope.spawn(|_| r.recv().unwrap()); 412 | scope.spawn(|_| s.send(0).unwrap()); 413 | }) 414 | .unwrap(); 415 | } 416 | } 417 | 418 | #[test] 419 | fn stress_iter() { 420 | const COUNT: usize = 100_000; 421 | 422 | let (request_s, request_r) = bounded(1); 423 | let (response_s, response_r) = bounded(1); 424 | 425 | scope(|scope| { 426 | scope.spawn(move |_| { 427 | let mut count = 0; 428 | loop { 429 | for x in response_r.try_iter() { 430 | count += x; 431 | if count == COUNT { 432 | return; 433 | } 434 | } 435 | request_s.send(()).unwrap(); 436 | } 437 | }); 438 | 439 | for _ in request_r.iter() { 440 | if response_s.send(1).is_err() { 441 | break; 442 | } 443 | } 444 | }) 445 | .unwrap(); 446 | } 447 | 448 | #[test] 449 | fn stress_timeout_two_threads() { 450 | const COUNT: usize = 100; 451 | 452 | let (s, r) = bounded(2); 453 | 454 | scope(|scope| { 455 | scope.spawn(|_| { 456 | for i in 0..COUNT { 457 | if i % 2 == 0 { 458 | thread::sleep(ms(50)); 459 | } 460 | loop { 461 | if let Ok(()) = s.send_timeout(i, ms(10)) { 462 | break; 463 | } 464 | } 465 | } 466 | }); 467 | 468 | scope.spawn(|_| { 469 | for i in 0..COUNT { 470 | if i % 2 == 0 { 471 | thread::sleep(ms(50)); 472 | } 473 | loop { 474 | if let Ok(x) = r.recv_timeout(ms(10)) { 475 | assert_eq!(x, i); 476 | break; 477 | } 478 | } 479 | } 480 | }); 481 | }) 482 | .unwrap(); 483 | } 484 | 485 | #[test] 486 | fn drops() { 487 | const RUNS: usize = 100; 488 | 489 | static DROPS: AtomicUsize = AtomicUsize::new(0); 490 | 491 | #[derive(Debug, PartialEq)] 492 | struct DropCounter; 493 | 494 | impl Drop for DropCounter { 495 | fn drop(&mut self) { 496 | DROPS.fetch_add(1, Ordering::SeqCst); 497 | } 498 | } 499 | 500 | let mut rng = thread_rng(); 501 | 502 | for _ in 0..RUNS { 503 | let steps = rng.gen_range(0..10_000); 504 | let additional = rng.gen_range(0..50); 505 | 506 | DROPS.store(0, Ordering::SeqCst); 507 | let (s, r) = bounded::(50); 508 | 509 | scope(|scope| { 510 | scope.spawn(|_| { 511 | for _ in 0..steps { 512 | r.recv().unwrap(); 513 | } 514 | }); 515 | 516 | scope.spawn(|_| { 517 | for _ in 0..steps { 518 | s.send(DropCounter).unwrap(); 519 | } 520 | }); 521 | }) 522 | .unwrap(); 523 | 524 | for _ in 0..additional { 525 | s.send(DropCounter).unwrap(); 526 | } 527 | 528 | assert_eq!(DROPS.load(Ordering::SeqCst), steps); 529 | drop(s); 530 | drop(r); 531 | assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional); 532 | } 533 | } 534 | 535 | #[test] 536 | fn linearizable() { 537 | const COUNT: usize = 25_000; 538 | const THREADS: usize = 4; 539 | 540 | let (s, r) = bounded(THREADS); 541 | 542 | scope(|scope| { 543 | for _ in 0..THREADS { 544 | scope.spawn(|_| { 545 | for _ in 0..COUNT { 546 | s.send(0).unwrap(); 547 | r.try_recv().unwrap(); 548 | } 549 | }); 550 | } 551 | }) 552 | .unwrap(); 553 | } 554 | 555 | // #[test] 556 | // fn fairness() { 557 | // const COUNT: usize = 10_000; 558 | 559 | // let (s1, r1) = bounded::<()>(COUNT); 560 | // let (s2, r2) = bounded::<()>(COUNT); 561 | 562 | // for _ in 0..COUNT { 563 | // s1.send(()).unwrap(); 564 | // s2.send(()).unwrap(); 565 | // } 566 | 567 | // let mut hits = [0usize; 2]; 568 | // for _ in 0..COUNT { 569 | // select! { 570 | // recv(r1) -> _ => hits[0] += 1, 571 | // recv(r2) -> _ => hits[1] += 1, 572 | // } 573 | // } 574 | // assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); 575 | // } 576 | 577 | // #[test] 578 | // fn fairness_duplicates() { 579 | // const COUNT: usize = 10_000; 580 | 581 | // let (s, r) = bounded::<()>(COUNT); 582 | 583 | // for _ in 0..COUNT { 584 | // s.send(()).unwrap(); 585 | // } 586 | 587 | // let mut hits = [0usize; 5]; 588 | // for _ in 0..COUNT { 589 | // select! { 590 | // recv(r) -> _ => hits[0] += 1, 591 | // recv(r) -> _ => hits[1] += 1, 592 | // recv(r) -> _ => hits[2] += 1, 593 | // recv(r) -> _ => hits[3] += 1, 594 | // recv(r) -> _ => hits[4] += 1, 595 | // } 596 | // } 597 | // assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); 598 | // } 599 | 600 | // #[test] 601 | // fn recv_in_send() { 602 | // let (s, _r) = bounded(1); 603 | // s.send(()).unwrap(); 604 | 605 | // #[allow(unreachable_code)] 606 | // { 607 | // select! { 608 | // send(s, panic!()) -> _ => panic!(), 609 | // default => {} 610 | // } 611 | // } 612 | 613 | // let (s, r) = bounded(2); 614 | // s.send(()).unwrap(); 615 | 616 | // select! { 617 | // send(s, assert_eq!(r.recv(), Ok(()))) -> _ => {} 618 | // } 619 | // } 620 | 621 | #[test] 622 | fn channel_through_channel() { 623 | const COUNT: usize = 1000; 624 | 625 | type T = Box; 626 | 627 | let (s, r) = bounded::(1); 628 | 629 | scope(|scope| { 630 | scope.spawn(move |_| { 631 | let mut s = s; 632 | 633 | for _ in 0..COUNT { 634 | let (new_s, new_r) = bounded(1); 635 | let new_r: T = Box::new(Some(new_r)); 636 | 637 | s.send(new_r).unwrap(); 638 | s = new_s; 639 | } 640 | }); 641 | 642 | scope.spawn(move |_| { 643 | let mut r = r; 644 | 645 | for _ in 0..COUNT { 646 | r = r 647 | .recv() 648 | .unwrap() 649 | .downcast_mut::>>() 650 | .unwrap() 651 | .take() 652 | .unwrap() 653 | } 654 | }); 655 | }) 656 | .unwrap(); 657 | } 658 | -------------------------------------------------------------------------------- /tests/async.rs: -------------------------------------------------------------------------------- 1 | #[cfg(all(feature = "async", not(target_os = "unknown")))] 2 | use { 3 | flume::*, 4 | futures::{stream::FuturesUnordered, StreamExt, TryFutureExt, Future}, 5 | futures::task::{Context, Waker, Poll}, 6 | async_std::prelude::FutureExt, 7 | std::{time::Duration, sync::{atomic::{AtomicUsize, Ordering}, Arc}}, 8 | }; 9 | 10 | #[cfg(all(feature = "async", not(target_os = "unknown")))] 11 | #[test] 12 | fn r#async_recv() { 13 | let (tx, rx) = unbounded(); 14 | 15 | let t = std::thread::spawn(move || { 16 | std::thread::sleep(std::time::Duration::from_millis(250)); 17 | tx.send(42u32).unwrap(); 18 | }); 19 | 20 | async_std::task::block_on(async { 21 | assert_eq!(rx.recv_async().await.unwrap(), 42); 22 | }); 23 | 24 | t.join().unwrap(); 25 | } 26 | 27 | #[cfg(all(feature = "async", not(target_os = "unknown")))] 28 | #[test] 29 | fn r#async_send() { 30 | let (tx, rx) = bounded(1); 31 | 32 | let t = std::thread::spawn(move || { 33 | std::thread::sleep(std::time::Duration::from_millis(250)); 34 | assert_eq!(rx.recv(), Ok(42)); 35 | }); 36 | 37 | async_std::task::block_on(async { 38 | tx.send_async(42u32).await.unwrap(); 39 | }); 40 | 41 | t.join().unwrap(); 42 | } 43 | 44 | #[cfg(all(feature = "async", not(target_os = "unknown")))] 45 | #[test] 46 | fn r#async_recv_disconnect() { 47 | let (tx, rx) = bounded::(0); 48 | 49 | let t = std::thread::spawn(move || { 50 | std::thread::sleep(std::time::Duration::from_millis(250)); 51 | drop(tx) 52 | }); 53 | 54 | async_std::task::block_on(async { 55 | assert_eq!(rx.recv_async().await, Err(RecvError::Disconnected)); 56 | }); 57 | 58 | t.join().unwrap(); 59 | } 60 | 61 | #[cfg(all(feature = "async", not(target_os = "unknown")))] 62 | #[test] 63 | fn r#async_send_disconnect() { 64 | let (tx, rx) = bounded(0); 65 | 66 | let t = std::thread::spawn(move || { 67 | std::thread::sleep(std::time::Duration::from_millis(250)); 68 | drop(rx) 69 | }); 70 | 71 | async_std::task::block_on(async { 72 | assert_eq!(tx.send_async(42u32).await, Err(SendError(42))); 73 | }); 74 | 75 | t.join().unwrap(); 76 | } 77 | 78 | #[cfg(all(feature = "async", not(target_os = "unknown")))] 79 | #[test] 80 | fn r#async_recv_drop_recv() { 81 | let (tx, rx) = bounded::(10); 82 | 83 | let recv_fut = rx.recv_async(); 84 | 85 | async_std::task::block_on(async { 86 | let res = async_std::future::timeout(std::time::Duration::from_millis(500), rx.recv_async()).await; 87 | assert!(res.is_err()); 88 | }); 89 | 90 | let rx2 = rx.clone(); 91 | let t = std::thread::spawn(move || { 92 | async_std::task::block_on(async { 93 | rx2.recv_async().await 94 | }) 95 | }); 96 | 97 | std::thread::sleep(std::time::Duration::from_millis(500)); 98 | 99 | tx.send(42).unwrap(); 100 | 101 | drop(recv_fut); 102 | 103 | assert_eq!(t.join().unwrap(), Ok(42)) 104 | } 105 | 106 | #[cfg(all(feature = "async", not(target_os = "unknown")))] 107 | #[async_std::test] 108 | async fn r#async_send_1_million_no_drop_or_reorder() { 109 | #[derive(Debug)] 110 | enum Message { 111 | Increment { 112 | old: u64, 113 | }, 114 | ReturnCount, 115 | } 116 | 117 | let (tx, rx) = unbounded(); 118 | 119 | let t = async_std::task::spawn(async move { 120 | let mut count = 0u64; 121 | 122 | while let Ok(Message::Increment { old }) = rx.recv_async().await { 123 | assert_eq!(old, count); 124 | count += 1; 125 | } 126 | 127 | count 128 | }); 129 | 130 | for next in 0..1_000_000 { 131 | tx.send(Message::Increment { old: next }).unwrap(); 132 | } 133 | 134 | tx.send(Message::ReturnCount).unwrap(); 135 | 136 | let count = t.await; 137 | assert_eq!(count, 1_000_000) 138 | } 139 | 140 | #[cfg(all(feature = "async", not(target_os = "unknown")))] 141 | #[async_std::test] 142 | async fn parallel_async_receivers() { 143 | let (tx, rx) = flume::unbounded(); 144 | let send_fut = async move { 145 | let n_sends: usize = 100000; 146 | for _ in 0..n_sends { 147 | tx.send_async(()).await.unwrap(); 148 | } 149 | }; 150 | 151 | async_std::task::spawn( 152 | send_fut 153 | .timeout(Duration::from_secs(5)) 154 | .map_err(|_| panic!("Send timed out!")) 155 | ); 156 | 157 | let mut futures_unordered = (0..250) 158 | .map(|_| async { 159 | while let Ok(()) = rx.recv_async().await 160 | /* rx.recv() is OK */ 161 | {} 162 | }) 163 | .collect::>(); 164 | 165 | let recv_fut = async { 166 | while futures_unordered.next().await.is_some() {} 167 | }; 168 | 169 | recv_fut 170 | .timeout(Duration::from_secs(5)) 171 | .map_err(|_| panic!("Receive timed out!")) 172 | .await 173 | .unwrap(); 174 | 175 | println!("recv end"); 176 | } 177 | 178 | #[cfg(all(feature = "async", not(target_os = "unknown")))] 179 | #[test] 180 | fn change_waker() { 181 | let (tx, rx) = flume::bounded(1); 182 | tx.send(()).unwrap(); 183 | 184 | struct DebugWaker(Arc, Waker); 185 | 186 | impl DebugWaker { 187 | fn new() -> Self { 188 | let woken = Arc::new(AtomicUsize::new(0)); 189 | let woken_cloned = woken.clone(); 190 | let waker = waker_fn::waker_fn(move || { 191 | woken.fetch_add(1, Ordering::SeqCst); 192 | }); 193 | DebugWaker(woken_cloned, waker) 194 | } 195 | 196 | fn woken(&self) -> usize { 197 | self.0.load(Ordering::SeqCst) 198 | } 199 | 200 | fn ctx(&self) -> Context { 201 | Context::from_waker(&self.1) 202 | } 203 | } 204 | 205 | // Check that the waker is correctly updated when sending tasks change their wakers 206 | { 207 | let send_fut = tx.send_async(()); 208 | futures::pin_mut!(send_fut); 209 | 210 | let (waker1, waker2) = (DebugWaker::new(), DebugWaker::new()); 211 | 212 | // Set the waker to waker1 213 | assert_eq!(send_fut.as_mut().poll(&mut waker1.ctx()), Poll::Pending); 214 | 215 | // Change the waker to waker2 216 | assert_eq!(send_fut.poll(&mut waker2.ctx()), Poll::Pending); 217 | 218 | // Wake the future 219 | rx.recv().unwrap(); 220 | 221 | // Check that waker2 was woken and waker1 was not 222 | assert_eq!(waker1.woken(), 0); 223 | assert_eq!(waker2.woken(), 1); 224 | } 225 | 226 | // Check that the waker is correctly updated when receiving tasks change their wakers 227 | { 228 | rx.recv().unwrap(); 229 | let recv_fut = rx.recv_async(); 230 | futures::pin_mut!(recv_fut); 231 | 232 | let (waker1, waker2) = (DebugWaker::new(), DebugWaker::new()); 233 | 234 | // Set the waker to waker1 235 | assert_eq!(recv_fut.as_mut().poll(&mut waker1.ctx()), Poll::Pending); 236 | 237 | // Change the waker to waker2 238 | assert_eq!(recv_fut.poll(&mut waker2.ctx()), Poll::Pending); 239 | 240 | // Wake the future 241 | tx.send(()).unwrap(); 242 | 243 | // Check that waker2 was woken and waker1 was not 244 | assert_eq!(waker1.woken(), 0); 245 | assert_eq!(waker2.woken(), 1); 246 | } 247 | } 248 | 249 | #[cfg(all(feature = "async", not(target_os = "unknown")))] 250 | #[test] 251 | fn spsc_single_threaded_value_ordering() { 252 | async fn test() { 253 | let (tx, rx) = flume::bounded(4); 254 | tokio::select! { 255 | _ = producer(tx) => {}, 256 | _ = consumer(rx) => {}, 257 | } 258 | } 259 | 260 | async fn producer(tx: flume::Sender) { 261 | for i in 0..100 { 262 | tx.send_async(i).await.unwrap(); 263 | } 264 | } 265 | 266 | async fn consumer(rx: flume::Receiver) { 267 | let mut expected = 0; 268 | while let Ok(value) = rx.recv_async().await { 269 | assert_eq!(value, expected); 270 | expected += 1; 271 | } 272 | } 273 | 274 | let rt = tokio::runtime::Builder::new_current_thread().build().unwrap(); 275 | rt.block_on(test()); 276 | } 277 | -------------------------------------------------------------------------------- /tests/basic.rs: -------------------------------------------------------------------------------- 1 | use std::time::{Instant, Duration}; 2 | use flume::*; 3 | 4 | #[test] 5 | fn send_recv() { 6 | let (tx, rx) = unbounded(); 7 | for i in 0..1000 { tx.send(i).unwrap(); } 8 | for i in 0..1000 { assert_eq!(rx.try_recv().unwrap(), i); } 9 | assert!(rx.try_recv().is_err()); 10 | } 11 | 12 | #[test] 13 | fn iter() { 14 | let (tx, rx) = unbounded(); 15 | for i in 0..1000 { tx.send(i).unwrap(); } 16 | drop(tx); 17 | assert_eq!(rx.iter().sum::(), (0..1000).sum()); 18 | } 19 | 20 | #[test] 21 | fn try_iter() { 22 | let (tx, rx) = unbounded(); 23 | for i in 0..1000 { tx.send(i).unwrap(); } 24 | assert_eq!(rx.try_iter().sum::(), (0..1000).sum()); 25 | } 26 | 27 | #[test] 28 | fn iter_threaded() { 29 | let (tx, rx) = unbounded(); 30 | for i in 0..1000 { 31 | let tx = tx.clone(); 32 | std::thread::spawn(move || tx.send(i).unwrap()); 33 | } 34 | drop(tx); 35 | assert_eq!(rx.iter().sum::(), (0..1000).sum()); 36 | } 37 | 38 | #[cfg_attr(any(target_os = "macos", windows), ignore)] // FIXME #41 39 | #[test] 40 | fn send_timeout() { 41 | let dur = Duration::from_millis(350); 42 | let max_error = Duration::from_millis(5); 43 | let dur_min = dur.checked_sub(max_error).unwrap(); 44 | let dur_max = dur.checked_add(max_error).unwrap(); 45 | 46 | let (tx, rx) = bounded(1); 47 | 48 | assert!(tx.send_timeout(42, dur).is_ok()); 49 | 50 | let then = Instant::now(); 51 | assert!(tx.send_timeout(43, dur).is_err()); 52 | let now = Instant::now(); 53 | 54 | let this = now.duration_since(then); 55 | if !(dur_min < this && this < dur_max) { 56 | panic!("timeout exceeded: {:?}", this); 57 | } 58 | 59 | assert_eq!(rx.drain().count(), 1); 60 | 61 | drop(rx); 62 | 63 | assert!(tx.send_timeout(42, Duration::from_millis(350)).is_err()); 64 | } 65 | 66 | #[cfg_attr(any(target_os = "macos", windows), ignore)] // FIXME #41 67 | #[test] 68 | fn recv_timeout() { 69 | let dur = Duration::from_millis(350); 70 | let max_error = Duration::from_millis(5); 71 | let dur_min = dur.checked_sub(max_error).unwrap(); 72 | let dur_max = dur.checked_add(max_error).unwrap(); 73 | 74 | let (tx, rx) = unbounded(); 75 | let then = Instant::now(); 76 | assert!(rx.recv_timeout(dur).is_err()); 77 | let now = Instant::now(); 78 | 79 | let this = now.duration_since(then); 80 | if !(dur_min < this && this < dur_max) { 81 | panic!("timeout exceeded: {:?}", this); 82 | } 83 | 84 | tx.send(42).unwrap(); 85 | assert_eq!(rx.recv_timeout(dur), Ok(42)); 86 | assert!(Instant::now().duration_since(now) < max_error); 87 | } 88 | 89 | #[cfg_attr(any(target_os = "macos", windows), ignore)] // FIXME #41 90 | #[test] 91 | fn recv_deadline() { 92 | let dur = Duration::from_millis(350); 93 | let max_error = Duration::from_millis(5); 94 | let dur_min = dur.checked_sub(max_error).unwrap(); 95 | let dur_max = dur.checked_add(max_error).unwrap(); 96 | 97 | let (tx, rx) = unbounded(); 98 | let then = Instant::now(); 99 | assert!(rx.recv_deadline(then.checked_add(dur).unwrap()).is_err()); 100 | let now = Instant::now(); 101 | 102 | let this = now.duration_since(then); 103 | if !(dur_min < this && this < dur_max) { 104 | panic!("timeout exceeded: {:?}", this); 105 | } 106 | 107 | tx.send(42).unwrap(); 108 | assert_eq!(rx.recv_deadline(now.checked_add(dur).unwrap()), Ok(42)); 109 | assert!(Instant::now().duration_since(now) < max_error); 110 | } 111 | 112 | #[test] 113 | fn recv_timeout_missed_send() { 114 | let (tx, rx) = bounded(10); 115 | 116 | assert!(rx.recv_timeout(Duration::from_millis(100)).is_err()); 117 | 118 | tx.send(42).unwrap(); 119 | 120 | assert_eq!(rx.recv(), Ok(42)); 121 | } 122 | 123 | #[test] 124 | fn disconnect_tx() { 125 | let (tx, rx) = unbounded::<()>(); 126 | drop(tx); 127 | assert!(rx.recv().is_err()); 128 | } 129 | 130 | #[test] 131 | fn disconnect_rx() { 132 | let (tx, rx) = unbounded(); 133 | drop(rx); 134 | assert!(tx.send(0).is_err()); 135 | } 136 | 137 | #[test] 138 | fn drain() { 139 | let (tx, rx) = unbounded(); 140 | 141 | for i in 0..100 { 142 | tx.send(i).unwrap(); 143 | } 144 | 145 | assert_eq!(rx.drain().sum::(), (0..100).sum()); 146 | 147 | for i in 0..100 { 148 | tx.send(i).unwrap(); 149 | } 150 | 151 | for i in 0..100 { 152 | tx.send(i).unwrap(); 153 | } 154 | 155 | rx.recv().unwrap(); 156 | 157 | (1u32..100).chain(0..100).zip(rx).for_each(|(l, r)| assert_eq!(l, r)); 158 | } 159 | 160 | #[test] 161 | fn try_send() { 162 | let (tx, rx) = bounded(5); 163 | 164 | for i in 0..5 { 165 | tx.try_send(i).unwrap(); 166 | } 167 | 168 | assert!(tx.try_send(42).is_err()); 169 | 170 | assert_eq!(rx.recv(), Ok(0)); 171 | 172 | assert_eq!(tx.try_send(42), Ok(())); 173 | 174 | assert_eq!(rx.recv(), Ok(1)); 175 | drop(rx); 176 | 177 | assert!(tx.try_send(42).is_err()); 178 | } 179 | 180 | #[test] 181 | fn send_bounded() { 182 | let (tx, rx) = bounded(5); 183 | 184 | for _ in 0..5 { 185 | tx.send(42).unwrap(); 186 | } 187 | 188 | let _ = rx.recv().unwrap(); 189 | 190 | tx.send(42).unwrap(); 191 | 192 | assert!(tx.try_send(42).is_err()); 193 | 194 | rx.drain(); 195 | 196 | let mut ts = Vec::new(); 197 | for _ in 0..100 { 198 | let tx = tx.clone(); 199 | ts.push(std::thread::spawn(move || { 200 | for i in 0..10000 { 201 | tx.send(i).unwrap(); 202 | } 203 | })); 204 | } 205 | 206 | drop(tx); 207 | 208 | assert_eq!(rx.iter().sum::(), (0..10000).sum::() * 100); 209 | 210 | for t in ts { 211 | t.join().unwrap(); 212 | } 213 | 214 | assert!(rx.recv().is_err()); 215 | } 216 | 217 | #[test] 218 | fn rendezvous() { 219 | let (tx, rx) = bounded(0); 220 | 221 | for i in 0..5 { 222 | let tx = tx.clone(); 223 | let t = std::thread::spawn(move || { 224 | assert!(tx.try_send(()).is_err()); 225 | 226 | let then = Instant::now(); 227 | tx.send(()).unwrap(); 228 | let now = Instant::now(); 229 | 230 | assert!(now.duration_since(then) > Duration::from_millis(100), "iter = {}", i); 231 | }); 232 | 233 | std::thread::sleep(Duration::from_millis(1000)); 234 | rx.recv().unwrap(); 235 | 236 | t.join().unwrap(); 237 | } 238 | } 239 | 240 | #[test] 241 | fn hydra() { 242 | let thread_num = 32; 243 | let msg_num = 1000; 244 | 245 | let (main_tx, main_rx) = unbounded::<()>(); 246 | 247 | let mut txs = Vec::new(); 248 | for _ in 0..thread_num { 249 | let main_tx = main_tx.clone(); 250 | let (tx, rx) = unbounded(); 251 | txs.push(tx); 252 | 253 | std::thread::spawn(move || { 254 | for msg in rx.iter() { 255 | main_tx.send(msg).unwrap(); 256 | } 257 | }); 258 | } 259 | 260 | drop(main_tx); 261 | 262 | for _ in 0..10 { 263 | for tx in &txs { 264 | for _ in 0..msg_num { 265 | tx.send(Default::default()).unwrap(); 266 | } 267 | } 268 | 269 | for _ in 0..thread_num { 270 | for _ in 0..msg_num { 271 | main_rx.recv().unwrap(); 272 | } 273 | } 274 | } 275 | 276 | drop(txs); 277 | assert!(main_rx.recv().is_err()); 278 | } 279 | 280 | #[test] 281 | fn robin() { 282 | let thread_num = 32; 283 | let msg_num = 10; 284 | 285 | let (mut main_tx, main_rx) = bounded::<()>(1); 286 | 287 | for _ in 0..thread_num { 288 | let (mut tx, rx) = bounded(100); 289 | std::mem::swap(&mut tx, &mut main_tx); 290 | 291 | std::thread::spawn(move || { 292 | for msg in rx.iter() { 293 | tx.send(msg).unwrap(); 294 | } 295 | }); 296 | } 297 | 298 | for _ in 0..10 { 299 | let main_tx = main_tx.clone(); 300 | std::thread::spawn(move || { 301 | for _ in 0..msg_num { 302 | main_tx.send(Default::default()).unwrap(); 303 | } 304 | }); 305 | 306 | for _ in 0..msg_num { 307 | main_rx.recv().unwrap(); 308 | } 309 | } 310 | } 311 | 312 | #[cfg(feature = "select")] 313 | #[test] 314 | fn select_general() { 315 | #[derive(Debug, PartialEq)] 316 | struct Foo(usize); 317 | 318 | let (tx0, rx0) = bounded(1); 319 | let (tx1, rx1) = unbounded(); 320 | 321 | for (i, t) in vec![tx0.clone(), tx1].into_iter().enumerate() { 322 | std::thread::spawn(move || { 323 | std::thread::sleep(std::time::Duration::from_millis(250)); 324 | let _ = t.send(Foo(i)); 325 | }); 326 | } 327 | 328 | let x = Selector::new() 329 | .recv(&rx0, |x| x) 330 | .recv(&rx1, |x| x) 331 | .wait() 332 | .unwrap(); 333 | 334 | if x == Foo(0) { 335 | assert!(rx1.recv().unwrap() == Foo(1)); 336 | } else { 337 | assert!(rx0.recv().unwrap() == Foo(0)); 338 | } 339 | 340 | tx0.send(Foo(42)).unwrap(); 341 | 342 | let t = std::thread::spawn(move || { 343 | std::thread::sleep(std::time::Duration::from_millis(100)); 344 | assert_eq!(rx0.recv().unwrap(), Foo(42)); 345 | assert_eq!(rx0.recv().unwrap(), Foo(43)); 346 | 347 | }); 348 | 349 | Selector::new() 350 | .send(&tx0, Foo(43), |x| x) 351 | .wait() 352 | .unwrap(); 353 | 354 | t.join().unwrap(); 355 | } 356 | 357 | struct MessageWithoutDebug(u32); 358 | 359 | #[test] 360 | // This is a 'does it build' test, to make sure that the error types can turn 361 | // into a std::error::Error without requiring the payload (which is not used 362 | // there) to impl Debug. 363 | fn std_error_without_debug() { 364 | let (tx, rx) = unbounded::(); 365 | 366 | match tx.send(MessageWithoutDebug(1)) { 367 | Ok(_) => {} 368 | Err(e) => { 369 | let _std_err: &dyn std::error::Error = &e; 370 | } 371 | } 372 | 373 | match rx.recv() { 374 | Ok(_) => {} 375 | Err(e) => { 376 | let _std_err: &dyn std::error::Error = &e; 377 | } 378 | } 379 | 380 | match tx.try_send(MessageWithoutDebug(2)) { 381 | Ok(_) => {} 382 | Err(e) => { 383 | let _std_err: &dyn std::error::Error = &e; 384 | } 385 | } 386 | 387 | match rx.try_recv() { 388 | Ok(_) => {} 389 | Err(e) => { 390 | let _std_err: &dyn std::error::Error = &e; 391 | } 392 | } 393 | 394 | match tx.send_timeout(MessageWithoutDebug(3), Duration::from_secs(1000000)) { 395 | Ok(_) => {} 396 | Err(e) => { 397 | let _std_err: &dyn std::error::Error = &e; 398 | } 399 | } 400 | 401 | match rx.recv_timeout(Duration::from_secs(10000000)) { 402 | Ok(_) => {} 403 | Err(e) => { 404 | let _std_err: &dyn std::error::Error = &e; 405 | } 406 | } 407 | } 408 | 409 | #[test] 410 | fn weak_close() { 411 | let (tx, rx) = unbounded::<()>(); 412 | let weak = tx.downgrade(); 413 | drop(tx); 414 | assert!(weak.upgrade().is_none()); 415 | assert!(rx.is_disconnected()); 416 | assert!(rx.try_recv().is_err()); 417 | } 418 | 419 | #[test] 420 | fn weak_upgrade() { 421 | let (tx, rx) = unbounded(); 422 | let weak = tx.downgrade(); 423 | let tx2 = weak.upgrade().unwrap(); 424 | drop(tx); 425 | assert!(!rx.is_disconnected()); 426 | tx2.send(()).unwrap(); 427 | assert!(rx.try_recv().is_ok()); 428 | } 429 | -------------------------------------------------------------------------------- /tests/check_same_channel.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn same_sender() { 3 | let (tx1, _rx) = flume::unbounded::<()>(); 4 | let tx2 = tx1.clone(); 5 | 6 | assert!(tx1.same_channel(&tx2)); 7 | 8 | let (tx3, _rx) = flume::unbounded::<()>(); 9 | 10 | assert!(!tx1.same_channel(&tx3)); 11 | assert!(!tx2.same_channel(&tx3)); 12 | } 13 | 14 | #[test] 15 | fn same_receiver() { 16 | let (_tx, rx1) = flume::unbounded::<()>(); 17 | let rx2 = rx1.clone(); 18 | 19 | assert!(rx1.same_channel(&rx2)); 20 | 21 | let (_tx, rx3) = flume::unbounded::<()>(); 22 | 23 | assert!(!rx1.same_channel(&rx3)); 24 | assert!(!rx2.same_channel(&rx3)); 25 | } 26 | 27 | #[cfg(feature = "async")] 28 | #[test] 29 | fn same_send_sink() { 30 | let (tx1, _rx) = flume::unbounded::<()>(); 31 | let tx1 = tx1.into_sink(); 32 | let tx2 = tx1.clone(); 33 | 34 | assert!(tx1.same_channel(&tx2)); 35 | 36 | let (tx3, _rx) = flume::unbounded::<()>(); 37 | let tx3 = tx3.into_sink(); 38 | 39 | assert!(!tx1.same_channel(&tx3)); 40 | assert!(!tx2.same_channel(&tx3)); 41 | } 42 | 43 | #[cfg(feature = "async")] 44 | #[test] 45 | fn same_recv_stream() { 46 | let (_tx, rx1) = flume::unbounded::<()>(); 47 | let rx1 = rx1.into_stream(); 48 | let rx2 = rx1.clone(); 49 | 50 | assert!(rx1.same_channel(&rx2)); 51 | 52 | let (_tx, rx3) = flume::unbounded::<()>(); 53 | let rx3 = rx3.into_stream(); 54 | 55 | assert!(!rx1.same_channel(&rx3)); 56 | assert!(!rx2.same_channel(&rx3)); 57 | } 58 | -------------------------------------------------------------------------------- /tests/iter.rs: -------------------------------------------------------------------------------- 1 | //! Tests for iteration over receivers. 2 | 3 | extern crate crossbeam_utils; 4 | 5 | use flume::unbounded; 6 | use crossbeam_utils::thread::scope; 7 | 8 | #[test] 9 | fn nested_recv_iter() { 10 | let (s, r) = unbounded::(); 11 | let (total_s, total_r) = unbounded::(); 12 | 13 | scope(|scope| { 14 | scope.spawn(move |_| { 15 | let mut acc = 0; 16 | for x in r.iter() { 17 | acc += x; 18 | } 19 | total_s.send(acc).unwrap(); 20 | }); 21 | 22 | s.send(3).unwrap(); 23 | s.send(1).unwrap(); 24 | s.send(2).unwrap(); 25 | drop(s); 26 | assert_eq!(total_r.recv().unwrap(), 6); 27 | }) 28 | .unwrap(); 29 | } 30 | 31 | #[test] 32 | fn recv_iter_break() { 33 | let (s, r) = unbounded::(); 34 | let (count_s, count_r) = unbounded(); 35 | 36 | scope(|scope| { 37 | scope.spawn(move |_| { 38 | let mut count = 0; 39 | for x in r.iter() { 40 | if count >= 3 { 41 | break; 42 | } else { 43 | count += x; 44 | } 45 | } 46 | count_s.send(count).unwrap(); 47 | }); 48 | 49 | s.send(2).unwrap(); 50 | s.send(2).unwrap(); 51 | s.send(2).unwrap(); 52 | let _ = s.send(2); 53 | drop(s); 54 | assert_eq!(count_r.recv().unwrap(), 4); 55 | }) 56 | .unwrap(); 57 | } 58 | 59 | #[test] 60 | fn recv_try_iter() { 61 | let (request_s, request_r) = unbounded(); 62 | let (response_s, response_r) = unbounded(); 63 | 64 | scope(|scope| { 65 | scope.spawn(move |_| { 66 | let mut count = 0; 67 | loop { 68 | for x in response_r.try_iter() { 69 | count += x; 70 | if count == 6 { 71 | return; 72 | } 73 | } 74 | request_s.send(()).unwrap(); 75 | } 76 | }); 77 | 78 | for _ in request_r.iter() { 79 | if response_s.send(2).is_err() { 80 | break; 81 | } 82 | } 83 | }) 84 | .unwrap(); 85 | } 86 | 87 | #[test] 88 | fn recv_into_iter_owned() { 89 | let mut iter = { 90 | let (s, r) = unbounded::(); 91 | s.send(1).unwrap(); 92 | s.send(2).unwrap(); 93 | r.into_iter() 94 | }; 95 | 96 | assert_eq!(iter.next().unwrap(), 1); 97 | assert_eq!(iter.next().unwrap(), 2); 98 | assert_eq!(iter.next().is_none(), true); 99 | } 100 | 101 | #[test] 102 | fn recv_into_iter_borrowed() { 103 | let (s, r) = unbounded::(); 104 | s.send(1).unwrap(); 105 | s.send(2).unwrap(); 106 | drop(s); 107 | 108 | let mut iter = (&r).into_iter(); 109 | assert_eq!(iter.next().unwrap(), 1); 110 | assert_eq!(iter.next().unwrap(), 2); 111 | assert_eq!(iter.next().is_none(), true); 112 | } 113 | -------------------------------------------------------------------------------- /tests/list.rs: -------------------------------------------------------------------------------- 1 | //! Tests for the list channel flavor. 2 | 3 | extern crate crossbeam_utils; 4 | extern crate rand; 5 | 6 | use std::any::Any; 7 | use std::sync::atomic::AtomicUsize; 8 | use std::sync::atomic::Ordering; 9 | use std::thread; 10 | use std::time::Duration; 11 | 12 | use flume::{unbounded, Receiver}; 13 | use flume::{RecvError, RecvTimeoutError, TryRecvError}; 14 | use flume::{SendError, SendTimeoutError, TrySendError}; 15 | use crossbeam_utils::thread::scope; 16 | use rand::{thread_rng, Rng}; 17 | 18 | fn ms(ms: u64) -> Duration { 19 | Duration::from_millis(ms) 20 | } 21 | 22 | #[test] 23 | fn smoke() { 24 | let (s, r) = unbounded(); 25 | s.try_send(7).unwrap(); 26 | assert_eq!(r.try_recv(), Ok(7)); 27 | 28 | s.send(8).unwrap(); 29 | assert_eq!(r.recv(), Ok(8)); 30 | 31 | assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); 32 | assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout)); 33 | } 34 | 35 | #[test] 36 | fn capacity() { 37 | let (s, r) = unbounded::<()>(); 38 | assert_eq!(s.capacity(), None); 39 | assert_eq!(r.capacity(), None); 40 | } 41 | 42 | #[test] 43 | fn len_empty_full() { 44 | let (s, r) = unbounded(); 45 | 46 | assert_eq!(s.len(), 0); 47 | assert_eq!(s.is_empty(), true); 48 | assert_eq!(s.is_full(), false); 49 | assert_eq!(r.len(), 0); 50 | assert_eq!(r.is_empty(), true); 51 | assert_eq!(r.is_full(), false); 52 | 53 | s.send(()).unwrap(); 54 | 55 | assert_eq!(s.len(), 1); 56 | assert_eq!(s.is_empty(), false); 57 | assert_eq!(s.is_full(), false); 58 | assert_eq!(r.len(), 1); 59 | assert_eq!(r.is_empty(), false); 60 | assert_eq!(r.is_full(), false); 61 | 62 | r.recv().unwrap(); 63 | 64 | assert_eq!(s.len(), 0); 65 | assert_eq!(s.is_empty(), true); 66 | assert_eq!(s.is_full(), false); 67 | assert_eq!(r.len(), 0); 68 | assert_eq!(r.is_empty(), true); 69 | assert_eq!(r.is_full(), false); 70 | } 71 | 72 | #[test] 73 | fn try_recv() { 74 | let (s, r) = unbounded(); 75 | 76 | scope(|scope| { 77 | scope.spawn(move |_| { 78 | assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); 79 | thread::sleep(ms(1500)); 80 | assert_eq!(r.try_recv(), Ok(7)); 81 | thread::sleep(ms(500)); 82 | assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); 83 | }); 84 | scope.spawn(move |_| { 85 | thread::sleep(ms(1000)); 86 | s.send(7).unwrap(); 87 | }); 88 | }) 89 | .unwrap(); 90 | } 91 | 92 | #[test] 93 | fn recv() { 94 | let (s, r) = unbounded(); 95 | 96 | scope(|scope| { 97 | scope.spawn(move |_| { 98 | assert_eq!(r.recv(), Ok(7)); 99 | thread::sleep(ms(1000)); 100 | assert_eq!(r.recv(), Ok(8)); 101 | thread::sleep(ms(1000)); 102 | assert_eq!(r.recv(), Ok(9)); 103 | assert!(r.recv().is_err()); 104 | }); 105 | scope.spawn(move |_| { 106 | thread::sleep(ms(1500)); 107 | s.send(7).unwrap(); 108 | s.send(8).unwrap(); 109 | s.send(9).unwrap(); 110 | }); 111 | }) 112 | .unwrap(); 113 | } 114 | 115 | #[test] 116 | fn recv_timeout() { 117 | let (s, r) = unbounded::(); 118 | 119 | scope(|scope| { 120 | scope.spawn(move |_| { 121 | assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout)); 122 | assert_eq!(r.recv_timeout(ms(1000)), Ok(7)); 123 | assert_eq!( 124 | r.recv_timeout(ms(1000)), 125 | Err(RecvTimeoutError::Disconnected) 126 | ); 127 | }); 128 | scope.spawn(move |_| { 129 | thread::sleep(ms(1500)); 130 | s.send(7).unwrap(); 131 | }); 132 | }) 133 | .unwrap(); 134 | } 135 | 136 | #[test] 137 | fn try_send() { 138 | let (s, r) = unbounded(); 139 | for i in 0..1000 { 140 | assert_eq!(s.try_send(i), Ok(())); 141 | } 142 | 143 | drop(r); 144 | assert_eq!(s.try_send(777), Err(TrySendError::Disconnected(777))); 145 | } 146 | 147 | #[test] 148 | fn send() { 149 | let (s, r) = unbounded(); 150 | for i in 0..1000 { 151 | assert_eq!(s.send(i), Ok(())); 152 | } 153 | 154 | drop(r); 155 | assert_eq!(s.send(777), Err(SendError(777))); 156 | } 157 | 158 | #[test] 159 | fn send_timeout() { 160 | let (s, r) = unbounded(); 161 | for i in 0..1000 { 162 | assert_eq!(s.send_timeout(i, ms(i as u64)), Ok(())); 163 | } 164 | 165 | drop(r); 166 | assert_eq!( 167 | s.send_timeout(777, ms(0)), 168 | Err(SendTimeoutError::Disconnected(777)) 169 | ); 170 | } 171 | 172 | #[test] 173 | fn send_after_disconnect() { 174 | let (s, r) = unbounded(); 175 | 176 | s.send(1).unwrap(); 177 | s.send(2).unwrap(); 178 | s.send(3).unwrap(); 179 | 180 | drop(r); 181 | 182 | assert_eq!(s.send(4), Err(SendError(4))); 183 | assert_eq!(s.try_send(5), Err(TrySendError::Disconnected(5))); 184 | assert_eq!( 185 | s.send_timeout(6, ms(0)), 186 | Err(SendTimeoutError::Disconnected(6)) 187 | ); 188 | } 189 | 190 | #[test] 191 | fn recv_after_disconnect() { 192 | let (s, r) = unbounded(); 193 | 194 | s.send(1).unwrap(); 195 | s.send(2).unwrap(); 196 | s.send(3).unwrap(); 197 | 198 | drop(s); 199 | 200 | assert_eq!(r.recv(), Ok(1)); 201 | assert_eq!(r.recv(), Ok(2)); 202 | assert_eq!(r.recv(), Ok(3)); 203 | assert!(r.recv().is_err()); 204 | } 205 | 206 | #[test] 207 | fn len() { 208 | let (s, r) = unbounded(); 209 | 210 | assert_eq!(s.len(), 0); 211 | assert_eq!(r.len(), 0); 212 | 213 | for i in 0..50 { 214 | s.send(i).unwrap(); 215 | assert_eq!(s.len(), i + 1); 216 | } 217 | 218 | for i in 0..50 { 219 | r.recv().unwrap(); 220 | assert_eq!(r.len(), 50 - i - 1); 221 | } 222 | 223 | assert_eq!(s.len(), 0); 224 | assert_eq!(r.len(), 0); 225 | } 226 | 227 | #[test] 228 | fn disconnect_wakes_receiver() { 229 | let (s, r) = unbounded::<()>(); 230 | 231 | scope(|scope| { 232 | scope.spawn(move |_| { 233 | assert!(r.recv().is_err()); 234 | }); 235 | scope.spawn(move |_| { 236 | thread::sleep(ms(1000)); 237 | drop(s); 238 | }); 239 | }) 240 | .unwrap(); 241 | } 242 | 243 | #[test] 244 | fn spsc() { 245 | const COUNT: usize = 100_000; 246 | 247 | let (s, r) = unbounded(); 248 | 249 | scope(|scope| { 250 | scope.spawn(move |_| { 251 | for i in 0..COUNT { 252 | assert_eq!(r.recv(), Ok(i)); 253 | } 254 | assert!(r.recv().is_err()); 255 | }); 256 | scope.spawn(move |_| { 257 | for i in 0..COUNT { 258 | s.send(i).unwrap(); 259 | } 260 | }); 261 | }) 262 | .unwrap(); 263 | } 264 | 265 | #[test] 266 | fn mpmc() { 267 | const COUNT: usize = 25_000; 268 | const THREADS: usize = 4; 269 | 270 | let (s, r) = unbounded::(); 271 | let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); 272 | 273 | scope(|scope| { 274 | for _ in 0..THREADS { 275 | scope.spawn(|_| { 276 | for _ in 0..COUNT { 277 | let n = r.recv().unwrap(); 278 | v[n].fetch_add(1, Ordering::SeqCst); 279 | } 280 | }); 281 | } 282 | for _ in 0..THREADS { 283 | scope.spawn(|_| { 284 | for i in 0..COUNT { 285 | s.send(i).unwrap(); 286 | } 287 | }); 288 | } 289 | }) 290 | .unwrap(); 291 | 292 | assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); 293 | 294 | for c in v { 295 | assert_eq!(c.load(Ordering::SeqCst), THREADS); 296 | } 297 | } 298 | 299 | #[test] 300 | fn stress_oneshot() { 301 | const COUNT: usize = 10_000; 302 | 303 | for _ in 0..COUNT { 304 | let (s, r) = unbounded(); 305 | 306 | scope(|scope| { 307 | scope.spawn(|_| r.recv().unwrap()); 308 | scope.spawn(|_| s.send(0).unwrap()); 309 | }) 310 | .unwrap(); 311 | } 312 | } 313 | 314 | #[test] 315 | fn stress_iter() { 316 | const COUNT: usize = 100_000; 317 | 318 | let (request_s, request_r) = unbounded(); 319 | let (response_s, response_r) = unbounded(); 320 | 321 | scope(|scope| { 322 | scope.spawn(move |_| { 323 | let mut count = 0; 324 | loop { 325 | for x in response_r.try_iter() { 326 | count += x; 327 | if count == COUNT { 328 | return; 329 | } 330 | } 331 | request_s.send(()).unwrap(); 332 | } 333 | }); 334 | 335 | for _ in request_r.iter() { 336 | if response_s.send(1).is_err() { 337 | break; 338 | } 339 | } 340 | }) 341 | .unwrap(); 342 | } 343 | 344 | #[test] 345 | fn stress_timeout_two_threads() { 346 | const COUNT: usize = 100; 347 | 348 | let (s, r) = unbounded(); 349 | 350 | scope(|scope| { 351 | scope.spawn(|_| { 352 | for i in 0..COUNT { 353 | if i % 2 == 0 { 354 | thread::sleep(ms(50)); 355 | } 356 | s.send(i).unwrap(); 357 | } 358 | }); 359 | 360 | scope.spawn(|_| { 361 | for i in 0..COUNT { 362 | if i % 2 == 0 { 363 | thread::sleep(ms(50)); 364 | } 365 | loop { 366 | if let Ok(x) = r.recv_timeout(ms(10)) { 367 | assert_eq!(x, i); 368 | break; 369 | } 370 | } 371 | } 372 | }); 373 | }) 374 | .unwrap(); 375 | } 376 | 377 | #[test] 378 | fn drops() { 379 | static DROPS: AtomicUsize = AtomicUsize::new(0); 380 | 381 | #[derive(Debug, PartialEq)] 382 | struct DropCounter; 383 | 384 | impl Drop for DropCounter { 385 | fn drop(&mut self) { 386 | DROPS.fetch_add(1, Ordering::SeqCst); 387 | } 388 | } 389 | 390 | let mut rng = thread_rng(); 391 | 392 | for _ in 0..100 { 393 | let steps = rng.gen_range(0..10_000); 394 | let additional = rng.gen_range(0..1000); 395 | 396 | DROPS.store(0, Ordering::SeqCst); 397 | let (s, r) = unbounded::(); 398 | 399 | scope(|scope| { 400 | scope.spawn(|_| { 401 | for _ in 0..steps { 402 | r.recv().unwrap(); 403 | } 404 | }); 405 | 406 | scope.spawn(|_| { 407 | for _ in 0..steps { 408 | s.send(DropCounter).unwrap(); 409 | } 410 | }); 411 | }) 412 | .unwrap(); 413 | 414 | for _ in 0..additional { 415 | s.try_send(DropCounter).unwrap(); 416 | } 417 | 418 | assert_eq!(DROPS.load(Ordering::SeqCst), steps); 419 | drop(s); 420 | drop(r); 421 | assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional); 422 | } 423 | } 424 | 425 | #[test] 426 | fn linearizable() { 427 | const COUNT: usize = 25_000; 428 | const THREADS: usize = 4; 429 | 430 | let (s, r) = unbounded(); 431 | 432 | scope(|scope| { 433 | for _ in 0..THREADS { 434 | scope.spawn(|_| { 435 | for _ in 0..COUNT { 436 | s.send(0).unwrap(); 437 | r.try_recv().unwrap(); 438 | } 439 | }); 440 | } 441 | }) 442 | .unwrap(); 443 | } 444 | 445 | // #[test] 446 | // fn fairness() { 447 | // const COUNT: usize = 10_000; 448 | 449 | // let (s1, r1) = unbounded::<()>(); 450 | // let (s2, r2) = unbounded::<()>(); 451 | 452 | // for _ in 0..COUNT { 453 | // s1.send(()).unwrap(); 454 | // s2.send(()).unwrap(); 455 | // } 456 | 457 | // let mut hits = [0usize; 2]; 458 | // for _ in 0..COUNT { 459 | // select! { 460 | // recv(r1) -> _ => hits[0] += 1, 461 | // recv(r2) -> _ => hits[1] += 1, 462 | // } 463 | // } 464 | // assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); 465 | // } 466 | 467 | // #[test] 468 | // fn fairness_duplicates() { 469 | // const COUNT: usize = 10_000; 470 | 471 | // let (s, r) = unbounded(); 472 | 473 | // for _ in 0..COUNT { 474 | // s.send(()).unwrap(); 475 | // } 476 | 477 | // let mut hits = [0usize; 5]; 478 | // for _ in 0..COUNT { 479 | // select! { 480 | // recv(r) -> _ => hits[0] += 1, 481 | // recv(r) -> _ => hits[1] += 1, 482 | // recv(r) -> _ => hits[2] += 1, 483 | // recv(r) -> _ => hits[3] += 1, 484 | // recv(r) -> _ => hits[4] += 1, 485 | // } 486 | // } 487 | // assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); 488 | // } 489 | 490 | // #[test] 491 | // fn recv_in_send() { 492 | // let (s, r) = unbounded(); 493 | // s.send(()).unwrap(); 494 | 495 | // select! { 496 | // send(s, assert_eq!(r.recv(), Ok(()))) -> _ => {} 497 | // } 498 | // } 499 | 500 | #[test] 501 | fn channel_through_channel() { 502 | const COUNT: usize = 1000; 503 | 504 | type T = Box; 505 | 506 | let (s, r) = unbounded::(); 507 | 508 | scope(|scope| { 509 | scope.spawn(move |_| { 510 | let mut s = s; 511 | 512 | for _ in 0..COUNT { 513 | let (new_s, new_r) = unbounded(); 514 | let new_r: T = Box::new(Some(new_r)); 515 | 516 | s.send(new_r).unwrap(); 517 | s = new_s; 518 | } 519 | }); 520 | 521 | scope.spawn(move |_| { 522 | let mut r = r; 523 | 524 | for _ in 0..COUNT { 525 | r = r 526 | .recv() 527 | .unwrap() 528 | .downcast_mut::>>() 529 | .unwrap() 530 | .take() 531 | .unwrap() 532 | } 533 | }); 534 | }) 535 | .unwrap(); 536 | } 537 | -------------------------------------------------------------------------------- /tests/method_sharing.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "async")] 2 | use flume::*; 3 | 4 | #[cfg(feature = "async")] 5 | #[async_std::test] 6 | async fn sender() { 7 | let (sender, receiver) = bounded(1); 8 | 9 | let sender_fut = sender.send_async(()); 10 | assert_eq!(sender.is_disconnected(), sender_fut.is_disconnected()); 11 | assert_eq!(sender.is_empty(), sender_fut.is_empty()); 12 | assert_eq!(sender.is_full(), sender_fut.is_full()); 13 | assert_eq!(sender.len(), sender_fut.len()); 14 | assert_eq!(sender.capacity(), sender_fut.capacity()); 15 | 16 | let sender_sink = sender.sink(); 17 | assert_eq!(sender.is_disconnected(), sender_sink.is_disconnected()); 18 | assert_eq!(sender.is_empty(), sender_sink.is_empty()); 19 | assert_eq!(sender.is_full(), sender_sink.is_full()); 20 | assert_eq!(sender.len(), sender_sink.len()); 21 | assert_eq!(sender.capacity(), sender_sink.capacity()); 22 | 23 | let receiver_fut = receiver.recv_async(); 24 | assert_eq!(receiver.is_disconnected(), receiver_fut.is_disconnected()); 25 | assert_eq!(receiver.is_empty(), receiver_fut.is_empty()); 26 | assert_eq!(receiver.is_full(), receiver_fut.is_full()); 27 | assert_eq!(receiver.len(), receiver_fut.len()); 28 | assert_eq!(receiver.capacity(), receiver_fut.capacity()); 29 | 30 | let receiver_stream = receiver.stream(); 31 | assert_eq!( 32 | receiver.is_disconnected(), 33 | receiver_stream.is_disconnected() 34 | ); 35 | assert_eq!(receiver.is_empty(), receiver_stream.is_empty()); 36 | assert_eq!(receiver.is_full(), receiver_stream.is_full()); 37 | assert_eq!(receiver.len(), receiver_stream.len()); 38 | assert_eq!(receiver.capacity(), receiver_stream.capacity()); 39 | } 40 | -------------------------------------------------------------------------------- /tests/never.rs: -------------------------------------------------------------------------------- 1 | // //! Tests for the never channel flavor. 2 | 3 | // #[macro_use] 4 | // extern crate crossbeam_channel; 5 | // extern crate rand; 6 | 7 | // use std::thread; 8 | // use std::time::{Duration, Instant}; 9 | 10 | // use crossbeam_channel::{never, tick, unbounded}; 11 | 12 | // fn ms(ms: u64) -> Duration { 13 | // Duration::from_millis(ms) 14 | // } 15 | 16 | // #[test] 17 | // fn smoke() { 18 | // select! { 19 | // recv(never::()) -> _ => panic!(), 20 | // default => {} 21 | // } 22 | // } 23 | 24 | // #[test] 25 | // fn optional() { 26 | // let (s, r) = unbounded::(); 27 | // s.send(1).unwrap(); 28 | // s.send(2).unwrap(); 29 | 30 | // let mut r = Some(&r); 31 | // select! { 32 | // recv(r.unwrap_or(&never())) -> _ => {} 33 | // default => panic!(), 34 | // } 35 | 36 | // r = None; 37 | // select! { 38 | // recv(r.unwrap_or(&never())) -> _ => panic!(), 39 | // default => {} 40 | // } 41 | // } 42 | 43 | // #[test] 44 | // fn tick_n() { 45 | // let mut r = tick(ms(100)); 46 | // let mut step = 0; 47 | 48 | // loop { 49 | // select! { 50 | // recv(r) -> _ => step += 1, 51 | // default(ms(500)) => break, 52 | // } 53 | 54 | // if step == 10 { 55 | // r = never(); 56 | // } 57 | // } 58 | 59 | // assert_eq!(step, 10); 60 | // } 61 | 62 | // #[test] 63 | // fn capacity() { 64 | // let r = never::(); 65 | // assert_eq!(r.capacity(), Some(0)); 66 | // } 67 | 68 | // #[test] 69 | // fn len_empty_full() { 70 | // let r = never::(); 71 | // assert_eq!(r.len(), 0); 72 | // assert_eq!(r.is_empty(), true); 73 | // assert_eq!(r.is_full(), true); 74 | // } 75 | 76 | // #[test] 77 | // fn try_recv() { 78 | // let r = never::(); 79 | // assert!(r.try_recv().is_err()); 80 | 81 | // thread::sleep(ms(100)); 82 | // assert!(r.try_recv().is_err()); 83 | // } 84 | 85 | // #[test] 86 | // fn recv_timeout() { 87 | // let start = Instant::now(); 88 | // let r = never::(); 89 | 90 | // assert!(r.recv_timeout(ms(100)).is_err()); 91 | // let now = Instant::now(); 92 | // assert!(now - start >= ms(100)); 93 | // assert!(now - start <= ms(150)); 94 | 95 | // assert!(r.recv_timeout(ms(100)).is_err()); 96 | // let now = Instant::now(); 97 | // assert!(now - start >= ms(200)); 98 | // assert!(now - start <= ms(250)); 99 | // } 100 | -------------------------------------------------------------------------------- /tests/ready.rs: -------------------------------------------------------------------------------- 1 | // //! Tests for channel readiness using the `Select` struct. 2 | 3 | // extern crate crossbeam_channel; 4 | // extern crate crossbeam_utils; 5 | 6 | // use std::any::Any; 7 | // use std::cell::Cell; 8 | // use std::thread; 9 | // use std::time::{Duration, Instant}; 10 | 11 | // use crossbeam_channel::{after, bounded, tick, unbounded}; 12 | // use crossbeam_channel::{Receiver, Select, TryRecvError, TrySendError}; 13 | // use crossbeam_utils::thread::scope; 14 | 15 | // fn ms(ms: u64) -> Duration { 16 | // Duration::from_millis(ms) 17 | // } 18 | 19 | // #[test] 20 | // fn smoke1() { 21 | // let (s1, r1) = unbounded::(); 22 | // let (s2, r2) = unbounded::(); 23 | 24 | // s1.send(1).unwrap(); 25 | 26 | // let mut sel = Select::new(); 27 | // sel.recv(&r1); 28 | // sel.recv(&r2); 29 | // assert_eq!(sel.ready(), 0); 30 | // assert_eq!(r1.try_recv(), Ok(1)); 31 | 32 | // s2.send(2).unwrap(); 33 | 34 | // let mut sel = Select::new(); 35 | // sel.recv(&r1); 36 | // sel.recv(&r2); 37 | // assert_eq!(sel.ready(), 1); 38 | // assert_eq!(r2.try_recv(), Ok(2)); 39 | // } 40 | 41 | // #[test] 42 | // fn smoke2() { 43 | // let (_s1, r1) = unbounded::(); 44 | // let (_s2, r2) = unbounded::(); 45 | // let (_s3, r3) = unbounded::(); 46 | // let (_s4, r4) = unbounded::(); 47 | // let (s5, r5) = unbounded::(); 48 | 49 | // s5.send(5).unwrap(); 50 | 51 | // let mut sel = Select::new(); 52 | // sel.recv(&r1); 53 | // sel.recv(&r2); 54 | // sel.recv(&r3); 55 | // sel.recv(&r4); 56 | // sel.recv(&r5); 57 | // assert_eq!(sel.ready(), 4); 58 | // assert_eq!(r5.try_recv(), Ok(5)); 59 | // } 60 | 61 | // #[test] 62 | // fn disconnected() { 63 | // let (s1, r1) = unbounded::(); 64 | // let (s2, r2) = unbounded::(); 65 | 66 | // scope(|scope| { 67 | // scope.spawn(|_| { 68 | // drop(s1); 69 | // thread::sleep(ms(500)); 70 | // s2.send(5).unwrap(); 71 | // }); 72 | 73 | // let mut sel = Select::new(); 74 | // sel.recv(&r1); 75 | // sel.recv(&r2); 76 | // match sel.ready_timeout(ms(1000)) { 77 | // Ok(0) => assert_eq!(r1.try_recv(), Err(TryRecvError::Disconnected)), 78 | // _ => panic!(), 79 | // } 80 | 81 | // r2.recv().unwrap(); 82 | // }) 83 | // .unwrap(); 84 | 85 | // let mut sel = Select::new(); 86 | // sel.recv(&r1); 87 | // sel.recv(&r2); 88 | // match sel.ready_timeout(ms(1000)) { 89 | // Ok(0) => assert_eq!(r1.try_recv(), Err(TryRecvError::Disconnected)), 90 | // _ => panic!(), 91 | // } 92 | 93 | // scope(|scope| { 94 | // scope.spawn(|_| { 95 | // thread::sleep(ms(500)); 96 | // drop(s2); 97 | // }); 98 | 99 | // let mut sel = Select::new(); 100 | // sel.recv(&r2); 101 | // match sel.ready_timeout(ms(1000)) { 102 | // Ok(0) => assert_eq!(r2.try_recv(), Err(TryRecvError::Disconnected)), 103 | // _ => panic!(), 104 | // } 105 | // }) 106 | // .unwrap(); 107 | // } 108 | 109 | // #[test] 110 | // fn default() { 111 | // let (s1, r1) = unbounded::(); 112 | // let (s2, r2) = unbounded::(); 113 | 114 | // let mut sel = Select::new(); 115 | // sel.recv(&r1); 116 | // sel.recv(&r2); 117 | // assert!(sel.try_ready().is_err()); 118 | 119 | // drop(s1); 120 | 121 | // let mut sel = Select::new(); 122 | // sel.recv(&r1); 123 | // sel.recv(&r2); 124 | // match sel.try_ready() { 125 | // Ok(0) => assert!(r1.try_recv().is_err()), 126 | // _ => panic!(), 127 | // } 128 | 129 | // s2.send(2).unwrap(); 130 | 131 | // let mut sel = Select::new(); 132 | // sel.recv(&r2); 133 | // match sel.try_ready() { 134 | // Ok(0) => assert_eq!(r2.try_recv(), Ok(2)), 135 | // _ => panic!(), 136 | // } 137 | 138 | // let mut sel = Select::new(); 139 | // sel.recv(&r2); 140 | // assert!(sel.try_ready().is_err()); 141 | 142 | // let mut sel = Select::new(); 143 | // assert!(sel.try_ready().is_err()); 144 | // } 145 | 146 | // #[test] 147 | // fn timeout() { 148 | // let (_s1, r1) = unbounded::(); 149 | // let (s2, r2) = unbounded::(); 150 | 151 | // scope(|scope| { 152 | // scope.spawn(|_| { 153 | // thread::sleep(ms(1500)); 154 | // s2.send(2).unwrap(); 155 | // }); 156 | 157 | // let mut sel = Select::new(); 158 | // sel.recv(&r1); 159 | // sel.recv(&r2); 160 | // assert!(sel.ready_timeout(ms(1000)).is_err()); 161 | 162 | // let mut sel = Select::new(); 163 | // sel.recv(&r1); 164 | // sel.recv(&r2); 165 | // match sel.ready_timeout(ms(1000)) { 166 | // Ok(1) => assert_eq!(r2.try_recv(), Ok(2)), 167 | // _ => panic!(), 168 | // } 169 | // }) 170 | // .unwrap(); 171 | 172 | // scope(|scope| { 173 | // let (s, r) = unbounded::(); 174 | 175 | // scope.spawn(move |_| { 176 | // thread::sleep(ms(500)); 177 | // drop(s); 178 | // }); 179 | 180 | // let mut sel = Select::new(); 181 | // assert!(sel.ready_timeout(ms(1000)).is_err()); 182 | 183 | // let mut sel = Select::new(); 184 | // sel.recv(&r); 185 | // match sel.try_ready() { 186 | // Ok(0) => assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)), 187 | // _ => panic!(), 188 | // } 189 | // }) 190 | // .unwrap(); 191 | // } 192 | 193 | // #[test] 194 | // fn default_when_disconnected() { 195 | // let (_, r) = unbounded::(); 196 | 197 | // let mut sel = Select::new(); 198 | // sel.recv(&r); 199 | // match sel.try_ready() { 200 | // Ok(0) => assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)), 201 | // _ => panic!(), 202 | // } 203 | 204 | // let (_, r) = unbounded::(); 205 | 206 | // let mut sel = Select::new(); 207 | // sel.recv(&r); 208 | // match sel.ready_timeout(ms(1000)) { 209 | // Ok(0) => assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)), 210 | // _ => panic!(), 211 | // } 212 | 213 | // let (s, _) = bounded::(0); 214 | 215 | // let mut sel = Select::new(); 216 | // sel.send(&s); 217 | // match sel.try_ready() { 218 | // Ok(0) => assert_eq!(s.try_send(0), Err(TrySendError::Disconnected(0))), 219 | // _ => panic!(), 220 | // } 221 | 222 | // let (s, _) = bounded::(0); 223 | 224 | // let mut sel = Select::new(); 225 | // sel.send(&s); 226 | // match sel.ready_timeout(ms(1000)) { 227 | // Ok(0) => assert_eq!(s.try_send(0), Err(TrySendError::Disconnected(0))), 228 | // _ => panic!(), 229 | // } 230 | // } 231 | 232 | // #[test] 233 | // fn default_only() { 234 | // let start = Instant::now(); 235 | 236 | // let mut sel = Select::new(); 237 | // assert!(sel.try_ready().is_err()); 238 | // let now = Instant::now(); 239 | // assert!(now - start <= ms(50)); 240 | 241 | // let start = Instant::now(); 242 | // let mut sel = Select::new(); 243 | // assert!(sel.ready_timeout(ms(500)).is_err()); 244 | // let now = Instant::now(); 245 | // assert!(now - start >= ms(450)); 246 | // assert!(now - start <= ms(550)); 247 | // } 248 | 249 | // #[test] 250 | // fn unblocks() { 251 | // let (s1, r1) = bounded::(0); 252 | // let (s2, r2) = bounded::(0); 253 | 254 | // scope(|scope| { 255 | // scope.spawn(|_| { 256 | // thread::sleep(ms(500)); 257 | // s2.send(2).unwrap(); 258 | // }); 259 | 260 | // let mut sel = Select::new(); 261 | // sel.recv(&r1); 262 | // sel.recv(&r2); 263 | // match sel.ready_timeout(ms(1000)) { 264 | // Ok(1) => assert_eq!(r2.try_recv(), Ok(2)), 265 | // _ => panic!(), 266 | // } 267 | // }) 268 | // .unwrap(); 269 | 270 | // scope(|scope| { 271 | // scope.spawn(|_| { 272 | // thread::sleep(ms(500)); 273 | // assert_eq!(r1.recv().unwrap(), 1); 274 | // }); 275 | 276 | // let mut sel = Select::new(); 277 | // let oper1 = sel.send(&s1); 278 | // let oper2 = sel.send(&s2); 279 | // let oper = sel.select_timeout(ms(1000)); 280 | // match oper { 281 | // Err(_) => panic!(), 282 | // Ok(oper) => match oper.index() { 283 | // i if i == oper1 => oper.send(&s1, 1).unwrap(), 284 | // i if i == oper2 => panic!(), 285 | // _ => unreachable!(), 286 | // }, 287 | // } 288 | // }) 289 | // .unwrap(); 290 | // } 291 | 292 | // #[test] 293 | // fn both_ready() { 294 | // let (s1, r1) = bounded(0); 295 | // let (s2, r2) = bounded(0); 296 | 297 | // scope(|scope| { 298 | // scope.spawn(|_| { 299 | // thread::sleep(ms(500)); 300 | // s1.send(1).unwrap(); 301 | // assert_eq!(r2.recv().unwrap(), 2); 302 | // }); 303 | 304 | // for _ in 0..2 { 305 | // let mut sel = Select::new(); 306 | // sel.recv(&r1); 307 | // sel.send(&s2); 308 | // match sel.ready() { 309 | // 0 => assert_eq!(r1.try_recv(), Ok(1)), 310 | // 1 => s2.try_send(2).unwrap(), 311 | // _ => panic!(), 312 | // } 313 | // } 314 | // }) 315 | // .unwrap(); 316 | // } 317 | 318 | // #[test] 319 | // fn cloning1() { 320 | // scope(|scope| { 321 | // let (s1, r1) = unbounded::(); 322 | // let (_s2, r2) = unbounded::(); 323 | // let (s3, r3) = unbounded::<()>(); 324 | 325 | // scope.spawn(move |_| { 326 | // r3.recv().unwrap(); 327 | // drop(s1.clone()); 328 | // assert!(r3.try_recv().is_err()); 329 | // s1.send(1).unwrap(); 330 | // r3.recv().unwrap(); 331 | // }); 332 | 333 | // s3.send(()).unwrap(); 334 | 335 | // let mut sel = Select::new(); 336 | // sel.recv(&r1); 337 | // sel.recv(&r2); 338 | // match sel.ready() { 339 | // 0 => drop(r1.try_recv()), 340 | // 1 => drop(r2.try_recv()), 341 | // _ => panic!(), 342 | // } 343 | 344 | // s3.send(()).unwrap(); 345 | // }) 346 | // .unwrap(); 347 | // } 348 | 349 | // #[test] 350 | // fn cloning2() { 351 | // let (s1, r1) = unbounded::<()>(); 352 | // let (s2, r2) = unbounded::<()>(); 353 | // let (_s3, _r3) = unbounded::<()>(); 354 | 355 | // scope(|scope| { 356 | // scope.spawn(move |_| { 357 | // let mut sel = Select::new(); 358 | // sel.recv(&r1); 359 | // sel.recv(&r2); 360 | // match sel.ready() { 361 | // 0 => panic!(), 362 | // 1 => drop(r2.try_recv()), 363 | // _ => panic!(), 364 | // } 365 | // }); 366 | 367 | // thread::sleep(ms(500)); 368 | // drop(s1.clone()); 369 | // s2.send(()).unwrap(); 370 | // }) 371 | // .unwrap(); 372 | // } 373 | 374 | // #[test] 375 | // fn preflight1() { 376 | // let (s, r) = unbounded(); 377 | // s.send(()).unwrap(); 378 | 379 | // let mut sel = Select::new(); 380 | // sel.recv(&r); 381 | // match sel.ready() { 382 | // 0 => drop(r.try_recv()), 383 | // _ => panic!(), 384 | // } 385 | // } 386 | 387 | // #[test] 388 | // fn preflight2() { 389 | // let (s, r) = unbounded(); 390 | // drop(s.clone()); 391 | // s.send(()).unwrap(); 392 | // drop(s); 393 | 394 | // let mut sel = Select::new(); 395 | // sel.recv(&r); 396 | // match sel.ready() { 397 | // 0 => assert_eq!(r.try_recv(), Ok(())), 398 | // _ => panic!(), 399 | // } 400 | 401 | // assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); 402 | // } 403 | 404 | // #[test] 405 | // fn preflight3() { 406 | // let (s, r) = unbounded(); 407 | // drop(s.clone()); 408 | // s.send(()).unwrap(); 409 | // drop(s); 410 | // r.recv().unwrap(); 411 | 412 | // let mut sel = Select::new(); 413 | // sel.recv(&r); 414 | // match sel.ready() { 415 | // 0 => assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)), 416 | // _ => panic!(), 417 | // } 418 | // } 419 | 420 | // #[test] 421 | // fn duplicate_operations() { 422 | // let (s, r) = unbounded::(); 423 | // let hit = vec![Cell::new(false); 4]; 424 | 425 | // while hit.iter().map(|h| h.get()).any(|hit| !hit) { 426 | // let mut sel = Select::new(); 427 | // sel.recv(&r); 428 | // sel.recv(&r); 429 | // sel.send(&s); 430 | // sel.send(&s); 431 | // match sel.ready() { 432 | // 0 => { 433 | // assert!(r.try_recv().is_ok()); 434 | // hit[0].set(true); 435 | // } 436 | // 1 => { 437 | // assert!(r.try_recv().is_ok()); 438 | // hit[1].set(true); 439 | // } 440 | // 2 => { 441 | // assert!(s.try_send(0).is_ok()); 442 | // hit[2].set(true); 443 | // } 444 | // 3 => { 445 | // assert!(s.try_send(0).is_ok()); 446 | // hit[3].set(true); 447 | // } 448 | // _ => panic!(), 449 | // } 450 | // } 451 | // } 452 | 453 | // #[test] 454 | // fn nesting() { 455 | // let (s, r) = unbounded::(); 456 | 457 | // let mut sel = Select::new(); 458 | // sel.send(&s); 459 | // match sel.ready() { 460 | // 0 => { 461 | // assert!(s.try_send(0).is_ok()); 462 | 463 | // let mut sel = Select::new(); 464 | // sel.recv(&r); 465 | // match sel.ready() { 466 | // 0 => { 467 | // assert_eq!(r.try_recv(), Ok(0)); 468 | 469 | // let mut sel = Select::new(); 470 | // sel.send(&s); 471 | // match sel.ready() { 472 | // 0 => { 473 | // assert!(s.try_send(1).is_ok()); 474 | 475 | // let mut sel = Select::new(); 476 | // sel.recv(&r); 477 | // match sel.ready() { 478 | // 0 => { 479 | // assert_eq!(r.try_recv(), Ok(1)); 480 | // } 481 | // _ => panic!(), 482 | // } 483 | // } 484 | // _ => panic!(), 485 | // } 486 | // } 487 | // _ => panic!(), 488 | // } 489 | // } 490 | // _ => panic!(), 491 | // } 492 | // } 493 | 494 | // #[test] 495 | // fn stress_recv() { 496 | // const COUNT: usize = 10_000; 497 | 498 | // let (s1, r1) = unbounded(); 499 | // let (s2, r2) = bounded(5); 500 | // let (s3, r3) = bounded(0); 501 | 502 | // scope(|scope| { 503 | // scope.spawn(|_| { 504 | // for i in 0..COUNT { 505 | // s1.send(i).unwrap(); 506 | // r3.recv().unwrap(); 507 | 508 | // s2.send(i).unwrap(); 509 | // r3.recv().unwrap(); 510 | // } 511 | // }); 512 | 513 | // for i in 0..COUNT { 514 | // for _ in 0..2 { 515 | // let mut sel = Select::new(); 516 | // sel.recv(&r1); 517 | // sel.recv(&r2); 518 | // match sel.ready() { 519 | // 0 => assert_eq!(r1.try_recv(), Ok(i)), 520 | // 1 => assert_eq!(r2.try_recv(), Ok(i)), 521 | // _ => panic!(), 522 | // } 523 | 524 | // s3.send(()).unwrap(); 525 | // } 526 | // } 527 | // }) 528 | // .unwrap(); 529 | // } 530 | 531 | // #[test] 532 | // fn stress_send() { 533 | // const COUNT: usize = 10_000; 534 | 535 | // let (s1, r1) = bounded(0); 536 | // let (s2, r2) = bounded(0); 537 | // let (s3, r3) = bounded(100); 538 | 539 | // scope(|scope| { 540 | // scope.spawn(|_| { 541 | // for i in 0..COUNT { 542 | // assert_eq!(r1.recv().unwrap(), i); 543 | // assert_eq!(r2.recv().unwrap(), i); 544 | // r3.recv().unwrap(); 545 | // } 546 | // }); 547 | 548 | // for i in 0..COUNT { 549 | // for _ in 0..2 { 550 | // let mut sel = Select::new(); 551 | // sel.send(&s1); 552 | // sel.send(&s2); 553 | // match sel.ready() { 554 | // 0 => assert!(s1.try_send(i).is_ok()), 555 | // 1 => assert!(s2.try_send(i).is_ok()), 556 | // _ => panic!(), 557 | // } 558 | // } 559 | // s3.send(()).unwrap(); 560 | // } 561 | // }) 562 | // .unwrap(); 563 | // } 564 | 565 | // #[test] 566 | // fn stress_mixed() { 567 | // const COUNT: usize = 10_000; 568 | 569 | // let (s1, r1) = bounded(0); 570 | // let (s2, r2) = bounded(0); 571 | // let (s3, r3) = bounded(100); 572 | 573 | // scope(|scope| { 574 | // scope.spawn(|_| { 575 | // for i in 0..COUNT { 576 | // s1.send(i).unwrap(); 577 | // assert_eq!(r2.recv().unwrap(), i); 578 | // r3.recv().unwrap(); 579 | // } 580 | // }); 581 | 582 | // for i in 0..COUNT { 583 | // for _ in 0..2 { 584 | // let mut sel = Select::new(); 585 | // sel.recv(&r1); 586 | // sel.send(&s2); 587 | // match sel.ready() { 588 | // 0 => assert_eq!(r1.try_recv(), Ok(i)), 589 | // 1 => assert!(s2.try_send(i).is_ok()), 590 | // _ => panic!(), 591 | // } 592 | // } 593 | // s3.send(()).unwrap(); 594 | // } 595 | // }) 596 | // .unwrap(); 597 | // } 598 | 599 | // #[test] 600 | // fn stress_timeout_two_threads() { 601 | // const COUNT: usize = 20; 602 | 603 | // let (s, r) = bounded(2); 604 | 605 | // scope(|scope| { 606 | // scope.spawn(|_| { 607 | // for i in 0..COUNT { 608 | // if i % 2 == 0 { 609 | // thread::sleep(ms(500)); 610 | // } 611 | 612 | // let done = false; 613 | // while !done { 614 | // let mut sel = Select::new(); 615 | // sel.send(&s); 616 | // match sel.ready_timeout(ms(100)) { 617 | // Err(_) => {} 618 | // Ok(0) => { 619 | // assert!(s.try_send(i).is_ok()); 620 | // break; 621 | // } 622 | // Ok(_) => panic!(), 623 | // } 624 | // } 625 | // } 626 | // }); 627 | 628 | // scope.spawn(|_| { 629 | // for i in 0..COUNT { 630 | // if i % 2 == 0 { 631 | // thread::sleep(ms(500)); 632 | // } 633 | 634 | // let mut done = false; 635 | // while !done { 636 | // let mut sel = Select::new(); 637 | // sel.recv(&r); 638 | // match sel.ready_timeout(ms(100)) { 639 | // Err(_) => {} 640 | // Ok(0) => { 641 | // assert_eq!(r.try_recv(), Ok(i)); 642 | // done = true; 643 | // } 644 | // Ok(_) => panic!(), 645 | // } 646 | // } 647 | // } 648 | // }); 649 | // }) 650 | // .unwrap(); 651 | // } 652 | 653 | // #[test] 654 | // fn send_recv_same_channel() { 655 | // let (s, r) = bounded::(0); 656 | // let mut sel = Select::new(); 657 | // sel.send(&s); 658 | // sel.recv(&r); 659 | // assert!(sel.ready_timeout(ms(100)).is_err()); 660 | 661 | // let (s, r) = unbounded::(); 662 | // let mut sel = Select::new(); 663 | // sel.send(&s); 664 | // sel.recv(&r); 665 | // match sel.ready_timeout(ms(100)) { 666 | // Err(_) => panic!(), 667 | // Ok(0) => assert!(s.try_send(0).is_ok()), 668 | // Ok(_) => panic!(), 669 | // } 670 | // } 671 | 672 | // #[test] 673 | // fn channel_through_channel() { 674 | // const COUNT: usize = 1000; 675 | 676 | // type T = Box; 677 | 678 | // for cap in 1..4 { 679 | // let (s, r) = bounded::(cap); 680 | 681 | // scope(|scope| { 682 | // scope.spawn(move |_| { 683 | // let mut s = s; 684 | 685 | // for _ in 0..COUNT { 686 | // let (new_s, new_r) = bounded(cap); 687 | // let new_r: T = Box::new(Some(new_r)); 688 | 689 | // { 690 | // let mut sel = Select::new(); 691 | // sel.send(&s); 692 | // match sel.ready() { 693 | // 0 => assert!(s.try_send(new_r).is_ok()), 694 | // _ => panic!(), 695 | // } 696 | // } 697 | 698 | // s = new_s; 699 | // } 700 | // }); 701 | 702 | // scope.spawn(move |_| { 703 | // let mut r = r; 704 | 705 | // for _ in 0..COUNT { 706 | // let new = { 707 | // let mut sel = Select::new(); 708 | // sel.recv(&r); 709 | // match sel.ready() { 710 | // 0 => r 711 | // .try_recv() 712 | // .unwrap() 713 | // .downcast_mut::>>() 714 | // .unwrap() 715 | // .take() 716 | // .unwrap(), 717 | // _ => panic!(), 718 | // } 719 | // }; 720 | // r = new; 721 | // } 722 | // }); 723 | // }) 724 | // .unwrap(); 725 | // } 726 | // } 727 | 728 | // #[test] 729 | // fn fairness1() { 730 | // const COUNT: usize = 10_000; 731 | 732 | // let (s1, r1) = bounded::<()>(COUNT); 733 | // let (s2, r2) = unbounded::<()>(); 734 | 735 | // for _ in 0..COUNT { 736 | // s1.send(()).unwrap(); 737 | // s2.send(()).unwrap(); 738 | // } 739 | 740 | // let hits = vec![Cell::new(0usize); 4]; 741 | // for _ in 0..COUNT { 742 | // let after = after(ms(0)); 743 | // let tick = tick(ms(0)); 744 | 745 | // let mut sel = Select::new(); 746 | // sel.recv(&r1); 747 | // sel.recv(&r2); 748 | // sel.recv(&after); 749 | // sel.recv(&tick); 750 | // match sel.ready() { 751 | // 0 => { 752 | // r1.try_recv().unwrap(); 753 | // hits[0].set(hits[0].get() + 1); 754 | // } 755 | // 1 => { 756 | // r2.try_recv().unwrap(); 757 | // hits[1].set(hits[1].get() + 1); 758 | // } 759 | // 2 => { 760 | // after.try_recv().unwrap(); 761 | // hits[2].set(hits[2].get() + 1); 762 | // } 763 | // 3 => { 764 | // tick.try_recv().unwrap(); 765 | // hits[3].set(hits[3].get() + 1); 766 | // } 767 | // _ => panic!(), 768 | // } 769 | // } 770 | // assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 2)); 771 | // } 772 | 773 | // #[test] 774 | // fn fairness2() { 775 | // const COUNT: usize = 10_000; 776 | 777 | // let (s1, r1) = unbounded::<()>(); 778 | // let (s2, r2) = bounded::<()>(1); 779 | // let (s3, r3) = bounded::<()>(0); 780 | 781 | // scope(|scope| { 782 | // scope.spawn(|_| { 783 | // for _ in 0..COUNT { 784 | // let mut sel = Select::new(); 785 | // let mut oper1 = None; 786 | // let mut oper2 = None; 787 | // if s1.is_empty() { 788 | // oper1 = Some(sel.send(&s1)); 789 | // } 790 | // if s2.is_empty() { 791 | // oper2 = Some(sel.send(&s2)); 792 | // } 793 | // let oper3 = sel.send(&s3); 794 | // let oper = sel.select(); 795 | // match oper.index() { 796 | // i if Some(i) == oper1 => assert!(oper.send(&s1, ()).is_ok()), 797 | // i if Some(i) == oper2 => assert!(oper.send(&s2, ()).is_ok()), 798 | // i if i == oper3 => assert!(oper.send(&s3, ()).is_ok()), 799 | // _ => unreachable!(), 800 | // } 801 | // } 802 | // }); 803 | 804 | // let hits = vec![Cell::new(0usize); 3]; 805 | // for _ in 0..COUNT { 806 | // let mut sel = Select::new(); 807 | // sel.recv(&r1); 808 | // sel.recv(&r2); 809 | // sel.recv(&r3); 810 | // loop { 811 | // match sel.ready() { 812 | // 0 => { 813 | // if r1.try_recv().is_ok() { 814 | // hits[0].set(hits[0].get() + 1); 815 | // break; 816 | // } 817 | // } 818 | // 1 => { 819 | // if r2.try_recv().is_ok() { 820 | // hits[1].set(hits[1].get() + 1); 821 | // break; 822 | // } 823 | // } 824 | // 2 => { 825 | // if r3.try_recv().is_ok() { 826 | // hits[2].set(hits[2].get() + 1); 827 | // break; 828 | // } 829 | // } 830 | // _ => unreachable!(), 831 | // } 832 | // } 833 | // } 834 | // assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 10)); 835 | // }) 836 | // .unwrap(); 837 | // } 838 | -------------------------------------------------------------------------------- /tests/same_channel.rs: -------------------------------------------------------------------------------- 1 | // extern crate crossbeam_channel; 2 | 3 | // use std::time::Duration; 4 | 5 | // use crossbeam_channel::{after, bounded, never, tick, unbounded}; 6 | 7 | // fn ms(ms: u64) -> Duration { 8 | // Duration::from_millis(ms) 9 | // } 10 | 11 | // #[test] 12 | // fn after_same_channel() { 13 | // let r = after(ms(50)); 14 | 15 | // let r2 = r.clone(); 16 | // assert!(r.same_channel(&r2)); 17 | 18 | // let r3 = after(ms(50)); 19 | // assert!(!r.same_channel(&r3)); 20 | // assert!(!r2.same_channel(&r3)); 21 | 22 | // let r4 = after(ms(100)); 23 | // assert!(!r.same_channel(&r4)); 24 | // assert!(!r2.same_channel(&r4)); 25 | // } 26 | 27 | // #[test] 28 | // fn array_same_channel() { 29 | // let (s, r) = bounded::(1); 30 | 31 | // let s2 = s.clone(); 32 | // assert!(s.same_channel(&s2)); 33 | 34 | // let r2 = r.clone(); 35 | // assert!(r.same_channel(&r2)); 36 | 37 | // let (s3, r3) = bounded::(1); 38 | // assert!(!s.same_channel(&s3)); 39 | // assert!(!s2.same_channel(&s3)); 40 | // assert!(!r.same_channel(&r3)); 41 | // assert!(!r2.same_channel(&r3)); 42 | // } 43 | 44 | // #[test] 45 | // fn list_same_channel() { 46 | // let (s, r) = unbounded::(); 47 | 48 | // let s2 = s.clone(); 49 | // assert!(s.same_channel(&s2)); 50 | 51 | // let r2 = r.clone(); 52 | // assert!(r.same_channel(&r2)); 53 | 54 | // let (s3, r3) = unbounded::(); 55 | // assert!(!s.same_channel(&s3)); 56 | // assert!(!s2.same_channel(&s3)); 57 | // assert!(!r.same_channel(&r3)); 58 | // assert!(!r2.same_channel(&r3)); 59 | // } 60 | 61 | // #[test] 62 | // fn never_same_channel() { 63 | // let r = never::(); 64 | 65 | // let r2 = r.clone(); 66 | // assert!(r.same_channel(&r2)); 67 | 68 | // // Never channel are always equal to one another. 69 | // let r3 = never::(); 70 | // assert!(r.same_channel(&r3)); 71 | // assert!(r2.same_channel(&r3)); 72 | // } 73 | 74 | // #[test] 75 | // fn tick_same_channel() { 76 | // let r = tick(ms(50)); 77 | 78 | // let r2 = r.clone(); 79 | // assert!(r.same_channel(&r2)); 80 | 81 | // let r3 = tick(ms(50)); 82 | // assert!(!r.same_channel(&r3)); 83 | // assert!(!r2.same_channel(&r3)); 84 | 85 | // let r4 = tick(ms(100)); 86 | // assert!(!r.same_channel(&r4)); 87 | // assert!(!r2.same_channel(&r4)); 88 | // } 89 | 90 | // #[test] 91 | // fn zero_same_channel() { 92 | // let (s, r) = bounded::(0); 93 | 94 | // let s2 = s.clone(); 95 | // assert!(s.same_channel(&s2)); 96 | 97 | // let r2 = r.clone(); 98 | // assert!(r.same_channel(&r2)); 99 | 100 | // let (s3, r3) = bounded::(0); 101 | // assert!(!s.same_channel(&s3)); 102 | // assert!(!s2.same_channel(&s3)); 103 | // assert!(!r.same_channel(&r3)); 104 | // assert!(!r2.same_channel(&r3)); 105 | // } 106 | 107 | // #[test] 108 | // fn different_flavors_same_channel() { 109 | // let (s1, r1) = bounded::(0); 110 | // let (s2, r2) = unbounded::(); 111 | 112 | // assert!(!s1.same_channel(&s2)); 113 | // assert!(!r1.same_channel(&r2)); 114 | // } 115 | -------------------------------------------------------------------------------- /tests/stream.rs: -------------------------------------------------------------------------------- 1 | #[cfg(all(feature = "async", not(target_os = "unknown")))] 2 | use { 3 | flume::*, 4 | futures::{stream::FuturesUnordered, StreamExt, TryFutureExt}, 5 | async_std::prelude::FutureExt, 6 | std::time::Duration, 7 | }; 8 | use futures::{stream, Stream}; 9 | 10 | #[cfg(all(feature = "async", not(target_os = "unknown")))] 11 | #[test] 12 | fn stream_recv() { 13 | let (tx, rx) = unbounded(); 14 | 15 | let t = std::thread::spawn(move || { 16 | std::thread::sleep(std::time::Duration::from_millis(250)); 17 | tx.send(42u32).unwrap(); 18 | println!("sent"); 19 | }); 20 | 21 | async_std::task::block_on(async { 22 | println!("receiving..."); 23 | let x = rx.stream().next().await; 24 | println!("received"); 25 | assert_eq!(x, Some(42)); 26 | }); 27 | 28 | t.join().unwrap(); 29 | } 30 | 31 | #[cfg(all(feature = "async", not(target_os = "unknown")))] 32 | #[test] 33 | fn stream_recv_disconnect() { 34 | let (tx, rx) = bounded::(0); 35 | 36 | let t = std::thread::spawn(move || { 37 | tx.send(42); 38 | std::thread::sleep(std::time::Duration::from_millis(250)); 39 | drop(tx) 40 | }); 41 | 42 | async_std::task::block_on(async { 43 | let mut stream = rx.into_stream(); 44 | assert_eq!(stream.next().await, Some(42)); 45 | assert_eq!(stream.next().await, None); 46 | }); 47 | 48 | t.join().unwrap(); 49 | } 50 | 51 | #[cfg(all(feature = "async", not(target_os = "unknown")))] 52 | #[test] 53 | fn stream_recv_drop_recv() { 54 | let (tx, rx) = bounded::(10); 55 | 56 | let rx2 = rx.clone(); 57 | let mut stream = rx.into_stream(); 58 | 59 | async_std::task::block_on(async { 60 | let res = async_std::future::timeout( 61 | std::time::Duration::from_millis(500), 62 | stream.next() 63 | ).await; 64 | 65 | assert!(res.is_err()); 66 | }); 67 | 68 | let t = std::thread::spawn(move || { 69 | async_std::task::block_on(async { 70 | rx2.stream().next().await 71 | }) 72 | }); 73 | 74 | std::thread::sleep(std::time::Duration::from_millis(500)); 75 | 76 | tx.send(42).unwrap(); 77 | 78 | drop(stream); 79 | 80 | assert_eq!(t.join().unwrap(), Some(42)) 81 | } 82 | 83 | #[cfg(all(feature = "async", not(target_os = "unknown")))] 84 | #[test] 85 | fn r#stream_drop_send_disconnect() { 86 | let (tx, rx) = bounded::(1); 87 | 88 | let t = std::thread::spawn(move || { 89 | std::thread::sleep(std::time::Duration::from_millis(250)); 90 | drop(tx); 91 | }); 92 | 93 | async_std::task::block_on(async { 94 | let mut stream = rx.into_stream(); 95 | assert_eq!(stream.next().await, None); 96 | }); 97 | 98 | t.join().unwrap(); 99 | } 100 | 101 | #[cfg(all(feature = "async", not(target_os = "unknown")))] 102 | #[async_std::test] 103 | async fn stream_send_1_million_no_drop_or_reorder() { 104 | #[derive(Debug)] 105 | enum Message { 106 | Increment { 107 | old: u64, 108 | }, 109 | ReturnCount, 110 | } 111 | 112 | let (tx, rx) = unbounded(); 113 | 114 | let t = async_std::task::spawn(async move { 115 | let mut count = 0u64; 116 | let mut stream = rx.into_stream(); 117 | 118 | while let Some(Message::Increment { old }) = stream.next().await { 119 | assert_eq!(old, count); 120 | count += 1; 121 | } 122 | 123 | count 124 | }); 125 | 126 | for next in 0..1_000_000 { 127 | tx.send(Message::Increment { old: next }).unwrap(); 128 | } 129 | 130 | tx.send(Message::ReturnCount).unwrap(); 131 | 132 | let count = t.await; 133 | assert_eq!(count, 1_000_000) 134 | } 135 | 136 | #[cfg(all(feature = "async", not(target_os = "unknown")))] 137 | #[async_std::test] 138 | async fn parallel_streams_and_async_recv() { 139 | let (tx, rx) = flume::unbounded(); 140 | let rx = ℞ 141 | let send_fut = async move { 142 | let n_sends: usize = 100000; 143 | for _ in 0..n_sends { 144 | tx.send_async(()).await.unwrap(); 145 | } 146 | }; 147 | 148 | async_std::task::spawn( 149 | send_fut 150 | .timeout(Duration::from_secs(5)) 151 | .map_err(|_| panic!("Send timed out!")) 152 | ); 153 | 154 | let mut futures_unordered = (0..250) 155 | .map(|n| async move { 156 | if n % 2 == 0 { 157 | let mut stream = rx.stream(); 158 | while let Some(()) = stream.next().await {} 159 | } else { 160 | while let Ok(()) = rx.recv_async().await {} 161 | } 162 | 163 | }) 164 | .collect::>(); 165 | 166 | let recv_fut = async { 167 | while futures_unordered.next().await.is_some() {} 168 | }; 169 | 170 | recv_fut 171 | .timeout(Duration::from_secs(5)) 172 | .map_err(|_| panic!("Receive timed out!")) 173 | .await 174 | .unwrap(); 175 | } 176 | 177 | #[cfg(all(feature = "async", not(target_os = "unknown")))] 178 | #[test] 179 | fn stream_no_double_wake() { 180 | use std::sync::atomic::{AtomicUsize, Ordering}; 181 | use std::sync::Arc; 182 | use std::pin::Pin; 183 | use std::task::Context; 184 | use futures::task::{waker, ArcWake}; 185 | use futures::Stream; 186 | 187 | let count = Arc::new(AtomicUsize::new(0)); 188 | 189 | // all this waker does is count how many times it is called 190 | struct CounterWaker { 191 | count: Arc, 192 | } 193 | 194 | impl ArcWake for CounterWaker { 195 | fn wake_by_ref(arc_self: &Arc) { 196 | arc_self.count.fetch_add(1, Ordering::SeqCst); 197 | } 198 | } 199 | 200 | // create waker and context 201 | let w = CounterWaker { 202 | count: count.clone(), 203 | }; 204 | let w = waker(Arc::new(w)); 205 | let cx = &mut Context::from_waker(&w); 206 | 207 | // create unbounded channel 208 | let (tx, rx) = unbounded::<()>(); 209 | let mut stream = rx.stream(); 210 | 211 | // register waker with stream 212 | let _ = Pin::new(&mut stream).poll_next(cx); 213 | 214 | // send multiple items 215 | tx.send(()).unwrap(); 216 | tx.send(()).unwrap(); 217 | tx.send(()).unwrap(); 218 | 219 | // verify that stream is only woken up once. 220 | assert_eq!(count.load(Ordering::SeqCst), 1); 221 | } 222 | 223 | #[cfg(all(feature = "async", not(target_os = "unknown")))] 224 | #[async_std::test] 225 | async fn stream_forward_issue_55() { // https://github.com/zesterer/flume/issues/55 226 | fn dummy_stream() -> impl Stream { 227 | stream::unfold(0, |count| async move { 228 | if count < 1000 { 229 | Some((count, count + 1)) 230 | } else { 231 | None 232 | } 233 | }) 234 | } 235 | 236 | let (send_task, recv_task) = { 237 | use futures::SinkExt; 238 | let (tx, rx) = flume::bounded(100); 239 | 240 | let send_task = dummy_stream() 241 | .map(|i| Ok(i)) 242 | .forward(tx.into_sink().sink_map_err(|e| { 243 | panic!("send error:{:#?}", e) 244 | })); 245 | 246 | let recv_task = rx 247 | .into_stream() 248 | .for_each(|item| async move {}); 249 | (send_task, recv_task) 250 | }; 251 | 252 | let jh = async_std::task::spawn(send_task); 253 | async_std::task::block_on(recv_task); 254 | jh.await.unwrap(); 255 | } 256 | -------------------------------------------------------------------------------- /tests/thread_locals.rs: -------------------------------------------------------------------------------- 1 | // //! Tests that make sure accessing thread-locals while exiting the thread doesn't cause panics. 2 | 3 | // extern crate crossbeam_utils; 4 | 5 | // use std::thread; 6 | // use std::time::Duration; 7 | 8 | // use flume::unbounded; 9 | // use crossbeam_utils::thread::scope; 10 | 11 | // fn ms(ms: u64) -> Duration { 12 | // Duration::from_millis(ms) 13 | // } 14 | 15 | // #[test] 16 | // #[cfg_attr(target_os = "macos", ignore = "TLS is destroyed too early on macOS")] 17 | // fn use_while_exiting() { 18 | // struct Foo; 19 | 20 | // impl Drop for Foo { 21 | // fn drop(&mut self) { 22 | // // A blocking operation after the thread-locals have been dropped. This will attempt to 23 | // // use the thread-locals and must not panic. 24 | // let (_s, r) = unbounded::<()>(); 25 | // select! { 26 | // recv(r) -> _ => {} 27 | // default(ms(100)) => {} 28 | // } 29 | // } 30 | // } 31 | 32 | // thread_local! { 33 | // static FOO: Foo = Foo; 34 | // } 35 | 36 | // let (s, r) = unbounded::<()>(); 37 | 38 | // scope(|scope| { 39 | // scope.spawn(|_| { 40 | // // First initialize `FOO`, then the thread-locals related to crossbeam-channel. 41 | // FOO.with(|_| ()); 42 | // r.recv().unwrap(); 43 | // // At thread exit, thread-locals related to crossbeam-channel get dropped first and 44 | // // `FOO` is dropped last. 45 | // }); 46 | 47 | // scope.spawn(|_| { 48 | // thread::sleep(ms(100)); 49 | // s.send(()).unwrap(); 50 | // }); 51 | // }) 52 | // .unwrap(); 53 | // } 54 | -------------------------------------------------------------------------------- /tests/tick.rs: -------------------------------------------------------------------------------- 1 | // //! Tests for the tick channel flavor. 2 | 3 | // #[macro_use] 4 | // extern crate crossbeam_channel; 5 | // extern crate crossbeam_utils; 6 | // extern crate rand; 7 | 8 | // use std::sync::atomic::AtomicUsize; 9 | // use std::sync::atomic::Ordering; 10 | // use std::thread; 11 | // use std::time::{Duration, Instant}; 12 | 13 | // use crossbeam_channel::{after, tick, Select, TryRecvError}; 14 | // use crossbeam_utils::thread::scope; 15 | 16 | // fn ms(ms: u64) -> Duration { 17 | // Duration::from_millis(ms) 18 | // } 19 | 20 | // #[test] 21 | // fn fire() { 22 | // let start = Instant::now(); 23 | // let r = tick(ms(50)); 24 | 25 | // assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); 26 | // thread::sleep(ms(100)); 27 | 28 | // let fired = r.try_recv().unwrap(); 29 | // assert!(start < fired); 30 | // assert!(fired - start >= ms(50)); 31 | 32 | // let now = Instant::now(); 33 | // assert!(fired < now); 34 | // assert!(now - fired >= ms(50)); 35 | 36 | // assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); 37 | 38 | // select! { 39 | // recv(r) -> _ => panic!(), 40 | // default => {} 41 | // } 42 | 43 | // select! { 44 | // recv(r) -> _ => {} 45 | // recv(tick(ms(200))) -> _ => panic!(), 46 | // } 47 | // } 48 | 49 | // #[test] 50 | // fn intervals() { 51 | // let start = Instant::now(); 52 | // let r = tick(ms(50)); 53 | 54 | // let t1 = r.recv().unwrap(); 55 | // assert!(start + ms(50) <= t1); 56 | // assert!(start + ms(100) > t1); 57 | 58 | // thread::sleep(ms(300)); 59 | // let t2 = r.try_recv().unwrap(); 60 | // assert!(start + ms(100) <= t2); 61 | // assert!(start + ms(150) > t2); 62 | 63 | // assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); 64 | // let t3 = r.recv().unwrap(); 65 | // assert!(start + ms(400) <= t3); 66 | // assert!(start + ms(450) > t3); 67 | 68 | // assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); 69 | // } 70 | 71 | // #[test] 72 | // fn capacity() { 73 | // const COUNT: usize = 10; 74 | 75 | // for i in 0..COUNT { 76 | // let r = tick(ms(i as u64)); 77 | // assert_eq!(r.capacity(), Some(1)); 78 | // } 79 | // } 80 | 81 | // #[test] 82 | // fn len_empty_full() { 83 | // let r = tick(ms(50)); 84 | 85 | // assert_eq!(r.len(), 0); 86 | // assert_eq!(r.is_empty(), true); 87 | // assert_eq!(r.is_full(), false); 88 | 89 | // thread::sleep(ms(100)); 90 | 91 | // assert_eq!(r.len(), 1); 92 | // assert_eq!(r.is_empty(), false); 93 | // assert_eq!(r.is_full(), true); 94 | 95 | // r.try_recv().unwrap(); 96 | 97 | // assert_eq!(r.len(), 0); 98 | // assert_eq!(r.is_empty(), true); 99 | // assert_eq!(r.is_full(), false); 100 | // } 101 | 102 | // #[test] 103 | // fn try_recv() { 104 | // let r = tick(ms(200)); 105 | // assert!(r.try_recv().is_err()); 106 | 107 | // thread::sleep(ms(100)); 108 | // assert!(r.try_recv().is_err()); 109 | 110 | // thread::sleep(ms(200)); 111 | // assert!(r.try_recv().is_ok()); 112 | // assert!(r.try_recv().is_err()); 113 | 114 | // thread::sleep(ms(200)); 115 | // assert!(r.try_recv().is_ok()); 116 | // assert!(r.try_recv().is_err()); 117 | // } 118 | 119 | // #[test] 120 | // fn recv() { 121 | // let start = Instant::now(); 122 | // let r = tick(ms(50)); 123 | 124 | // let fired = r.recv().unwrap(); 125 | // assert!(start < fired); 126 | // assert!(fired - start >= ms(50)); 127 | 128 | // let now = Instant::now(); 129 | // assert!(fired < now); 130 | // assert!(now - fired < fired - start); 131 | 132 | // assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); 133 | // } 134 | 135 | // #[test] 136 | // fn recv_timeout() { 137 | // let start = Instant::now(); 138 | // let r = tick(ms(200)); 139 | 140 | // assert!(r.recv_timeout(ms(100)).is_err()); 141 | // let now = Instant::now(); 142 | // assert!(now - start >= ms(100)); 143 | // assert!(now - start <= ms(150)); 144 | 145 | // let fired = r.recv_timeout(ms(200)).unwrap(); 146 | // assert!(fired - start >= ms(200)); 147 | // assert!(fired - start <= ms(250)); 148 | 149 | // assert!(r.recv_timeout(ms(100)).is_err()); 150 | // let now = Instant::now(); 151 | // assert!(now - start >= ms(300)); 152 | // assert!(now - start <= ms(350)); 153 | 154 | // let fired = r.recv_timeout(ms(200)).unwrap(); 155 | // assert!(fired - start >= ms(400)); 156 | // assert!(fired - start <= ms(450)); 157 | // } 158 | 159 | // #[test] 160 | // fn recv_two() { 161 | // let r1 = tick(ms(50)); 162 | // let r2 = tick(ms(50)); 163 | 164 | // scope(|scope| { 165 | // scope.spawn(|_| { 166 | // for _ in 0..10 { 167 | // select! { 168 | // recv(r1) -> _ => {} 169 | // recv(r2) -> _ => {} 170 | // } 171 | // } 172 | // }); 173 | // scope.spawn(|_| { 174 | // for _ in 0..10 { 175 | // select! { 176 | // recv(r1) -> _ => {} 177 | // recv(r2) -> _ => {} 178 | // } 179 | // } 180 | // }); 181 | // }) 182 | // .unwrap(); 183 | // } 184 | 185 | // #[test] 186 | // fn recv_race() { 187 | // select! { 188 | // recv(tick(ms(50))) -> _ => {} 189 | // recv(tick(ms(100))) -> _ => panic!(), 190 | // } 191 | 192 | // select! { 193 | // recv(tick(ms(100))) -> _ => panic!(), 194 | // recv(tick(ms(50))) -> _ => {} 195 | // } 196 | // } 197 | 198 | // #[test] 199 | // fn stress_default() { 200 | // const COUNT: usize = 10; 201 | 202 | // for _ in 0..COUNT { 203 | // select! { 204 | // recv(tick(ms(0))) -> _ => {} 205 | // default => panic!(), 206 | // } 207 | // } 208 | 209 | // for _ in 0..COUNT { 210 | // select! { 211 | // recv(tick(ms(100))) -> _ => panic!(), 212 | // default => {} 213 | // } 214 | // } 215 | // } 216 | 217 | // #[test] 218 | // fn select() { 219 | // const THREADS: usize = 4; 220 | 221 | // let hits = AtomicUsize::new(0); 222 | // let r1 = tick(ms(200)); 223 | // let r2 = tick(ms(300)); 224 | 225 | // scope(|scope| { 226 | // for _ in 0..THREADS { 227 | // scope.spawn(|_| { 228 | // let timeout = after(ms(1100)); 229 | // loop { 230 | // let mut sel = Select::new(); 231 | // let oper1 = sel.recv(&r1); 232 | // let oper2 = sel.recv(&r2); 233 | // let oper3 = sel.recv(&timeout); 234 | // let oper = sel.select(); 235 | // match oper.index() { 236 | // i if i == oper1 => { 237 | // oper.recv(&r1).unwrap(); 238 | // hits.fetch_add(1, Ordering::SeqCst); 239 | // } 240 | // i if i == oper2 => { 241 | // oper.recv(&r2).unwrap(); 242 | // hits.fetch_add(1, Ordering::SeqCst); 243 | // } 244 | // i if i == oper3 => { 245 | // oper.recv(&timeout).unwrap(); 246 | // break; 247 | // } 248 | // _ => unreachable!(), 249 | // } 250 | // } 251 | // }); 252 | // } 253 | // }) 254 | // .unwrap(); 255 | 256 | // assert_eq!(hits.load(Ordering::SeqCst), 8); 257 | // } 258 | 259 | // #[test] 260 | // fn ready() { 261 | // const THREADS: usize = 4; 262 | 263 | // let hits = AtomicUsize::new(0); 264 | // let r1 = tick(ms(200)); 265 | // let r2 = tick(ms(300)); 266 | 267 | // scope(|scope| { 268 | // for _ in 0..THREADS { 269 | // scope.spawn(|_| { 270 | // let timeout = after(ms(1100)); 271 | // 'outer: loop { 272 | // let mut sel = Select::new(); 273 | // sel.recv(&r1); 274 | // sel.recv(&r2); 275 | // sel.recv(&timeout); 276 | // loop { 277 | // match sel.ready() { 278 | // 0 => { 279 | // if r1.try_recv().is_ok() { 280 | // hits.fetch_add(1, Ordering::SeqCst); 281 | // break; 282 | // } 283 | // } 284 | // 1 => { 285 | // if r2.try_recv().is_ok() { 286 | // hits.fetch_add(1, Ordering::SeqCst); 287 | // break; 288 | // } 289 | // } 290 | // 2 => { 291 | // if timeout.try_recv().is_ok() { 292 | // break 'outer; 293 | // } 294 | // } 295 | // _ => unreachable!(), 296 | // } 297 | // } 298 | // } 299 | // }); 300 | // } 301 | // }) 302 | // .unwrap(); 303 | 304 | // assert_eq!(hits.load(Ordering::SeqCst), 8); 305 | // } 306 | 307 | // #[test] 308 | // fn fairness() { 309 | // const COUNT: usize = 30; 310 | 311 | // for &dur in &[0, 1] { 312 | // let mut hits = [0usize; 2]; 313 | 314 | // for _ in 0..COUNT { 315 | // let r1 = tick(ms(dur)); 316 | // let r2 = tick(ms(dur)); 317 | 318 | // for _ in 0..COUNT { 319 | // select! { 320 | // recv(r1) -> _ => hits[0] += 1, 321 | // recv(r2) -> _ => hits[1] += 1, 322 | // } 323 | // } 324 | // } 325 | 326 | // assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); 327 | // } 328 | // } 329 | 330 | // #[test] 331 | // fn fairness_duplicates() { 332 | // const COUNT: usize = 30; 333 | 334 | // for &dur in &[0, 1] { 335 | // let mut hits = [0usize; 5]; 336 | 337 | // for _ in 0..COUNT { 338 | // let r = tick(ms(dur)); 339 | 340 | // for _ in 0..COUNT { 341 | // select! { 342 | // recv(r) -> _ => hits[0] += 1, 343 | // recv(r) -> _ => hits[1] += 1, 344 | // recv(r) -> _ => hits[2] += 1, 345 | // recv(r) -> _ => hits[3] += 1, 346 | // recv(r) -> _ => hits[4] += 1, 347 | // } 348 | // } 349 | // } 350 | 351 | // assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); 352 | // } 353 | // } 354 | -------------------------------------------------------------------------------- /tests/zero.rs: -------------------------------------------------------------------------------- 1 | //! Tests for the zero channel flavor. 2 | 3 | extern crate crossbeam_utils; 4 | extern crate rand; 5 | 6 | use std::any::Any; 7 | use std::sync::atomic::AtomicUsize; 8 | use std::sync::atomic::Ordering; 9 | use std::thread; 10 | use std::time::Duration; 11 | 12 | use flume::{bounded, Receiver}; 13 | use flume::{RecvError, RecvTimeoutError, TryRecvError}; 14 | use flume::{SendError, SendTimeoutError, TrySendError}; 15 | use crossbeam_utils::thread::scope; 16 | use rand::{thread_rng, Rng}; 17 | 18 | fn ms(ms: u64) -> Duration { 19 | Duration::from_millis(ms) 20 | } 21 | 22 | #[test] 23 | fn smoke() { 24 | let (s, r) = bounded(0); 25 | assert_eq!(s.try_send(7), Err(TrySendError::Full(7))); 26 | assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); 27 | } 28 | 29 | #[test] 30 | fn capacity() { 31 | let (s, r) = bounded::<()>(0); 32 | assert_eq!(s.capacity(), Some(0)); 33 | assert_eq!(r.capacity(), Some(0)); 34 | } 35 | 36 | #[test] 37 | fn len_empty_full() { 38 | let (s, r) = bounded(0); 39 | 40 | assert_eq!(s.len(), 0); 41 | assert_eq!(s.is_empty(), true); 42 | assert_eq!(s.is_full(), true); 43 | assert_eq!(r.len(), 0); 44 | assert_eq!(r.is_empty(), true); 45 | assert_eq!(r.is_full(), true); 46 | 47 | scope(|scope| { 48 | scope.spawn(|_| s.send(0).unwrap()); 49 | scope.spawn(|_| r.recv().unwrap()); 50 | }) 51 | .unwrap(); 52 | 53 | assert_eq!(s.len(), 0); 54 | assert_eq!(s.is_empty(), true); 55 | assert_eq!(s.is_full(), true); 56 | assert_eq!(r.len(), 0); 57 | assert_eq!(r.is_empty(), true); 58 | assert_eq!(r.is_full(), true); 59 | } 60 | 61 | #[test] 62 | fn try_recv() { 63 | let (s, r) = bounded(0); 64 | 65 | scope(|scope| { 66 | scope.spawn(move |_| { 67 | assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); 68 | thread::sleep(ms(1500)); 69 | assert_eq!(r.try_recv(), Ok(7)); 70 | thread::sleep(ms(500)); 71 | assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); 72 | }); 73 | scope.spawn(move |_| { 74 | thread::sleep(ms(1000)); 75 | s.send(7).unwrap(); 76 | }); 77 | }) 78 | .unwrap(); 79 | } 80 | 81 | #[test] 82 | fn recv() { 83 | let (s, r) = bounded(0); 84 | 85 | scope(|scope| { 86 | scope.spawn(move |_| { 87 | assert_eq!(r.recv(), Ok(7)); 88 | thread::sleep(ms(1000)); 89 | assert_eq!(r.recv(), Ok(8)); 90 | thread::sleep(ms(1000)); 91 | assert_eq!(r.recv(), Ok(9)); 92 | assert!(r.recv().is_err()); 93 | }); 94 | scope.spawn(move |_| { 95 | thread::sleep(ms(1500)); 96 | s.send(7).unwrap(); 97 | s.send(8).unwrap(); 98 | s.send(9).unwrap(); 99 | }); 100 | }) 101 | .unwrap(); 102 | } 103 | 104 | #[test] 105 | fn recv_timeout() { 106 | let (s, r) = bounded::(0); 107 | 108 | scope(|scope| { 109 | scope.spawn(move |_| { 110 | assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout)); 111 | assert_eq!(r.recv_timeout(ms(1000)), Ok(7)); 112 | assert_eq!( 113 | r.recv_timeout(ms(1000)), 114 | Err(RecvTimeoutError::Disconnected) 115 | ); 116 | }); 117 | scope.spawn(move |_| { 118 | thread::sleep(ms(1500)); 119 | s.send(7).unwrap(); 120 | }); 121 | }) 122 | .unwrap(); 123 | } 124 | 125 | #[test] 126 | fn try_send() { 127 | let (s, r) = bounded(0); 128 | 129 | scope(|scope| { 130 | scope.spawn(move |_| { 131 | assert_eq!(s.try_send(7), Err(TrySendError::Full(7))); 132 | thread::sleep(ms(1500)); 133 | assert_eq!(s.try_send(8), Ok(())); 134 | thread::sleep(ms(500)); 135 | assert_eq!(s.try_send(9), Err(TrySendError::Disconnected(9))); 136 | }); 137 | scope.spawn(move |_| { 138 | thread::sleep(ms(1000)); 139 | assert_eq!(r.recv(), Ok(8)); 140 | }); 141 | }) 142 | .unwrap(); 143 | } 144 | 145 | #[test] 146 | fn send() { 147 | let (s, r) = bounded(0); 148 | 149 | scope(|scope| { 150 | scope.spawn(move |_| { 151 | s.send(7).unwrap(); 152 | thread::sleep(ms(1000)); 153 | s.send(8).unwrap(); 154 | thread::sleep(ms(1000)); 155 | s.send(9).unwrap(); 156 | }); 157 | scope.spawn(move |_| { 158 | thread::sleep(ms(1500)); 159 | assert_eq!(r.recv(), Ok(7)); 160 | assert_eq!(r.recv(), Ok(8)); 161 | assert_eq!(r.recv(), Ok(9)); 162 | }); 163 | }) 164 | .unwrap(); 165 | } 166 | 167 | #[test] 168 | fn send_timeout() { 169 | let (s, r) = bounded(0); 170 | 171 | scope(|scope| { 172 | scope.spawn(move |_| { 173 | assert_eq!( 174 | s.send_timeout(7, ms(1000)), 175 | Err(SendTimeoutError::Timeout(7)) 176 | ); 177 | assert_eq!(s.send_timeout(8, ms(1000)), Ok(())); 178 | assert_eq!( 179 | s.send_timeout(9, ms(1000)), 180 | Err(SendTimeoutError::Disconnected(9)) 181 | ); 182 | }); 183 | scope.spawn(move |_| { 184 | thread::sleep(ms(1500)); 185 | assert_eq!(r.recv(), Ok(8)); 186 | }); 187 | }) 188 | .unwrap(); 189 | } 190 | 191 | #[test] 192 | fn len() { 193 | const COUNT: usize = 25_000; 194 | 195 | let (s, r) = bounded(0); 196 | 197 | assert_eq!(s.len(), 0); 198 | assert_eq!(r.len(), 0); 199 | 200 | scope(|scope| { 201 | scope.spawn(|_| { 202 | for i in 0..COUNT { 203 | assert_eq!(r.recv(), Ok(i)); 204 | assert_eq!(r.len(), 0); 205 | } 206 | }); 207 | 208 | scope.spawn(|_| { 209 | for i in 0..COUNT { 210 | s.send(i).unwrap(); 211 | assert_eq!(s.len(), 0); 212 | } 213 | }); 214 | }) 215 | .unwrap(); 216 | 217 | assert_eq!(s.len(), 0); 218 | assert_eq!(r.len(), 0); 219 | } 220 | 221 | #[test] 222 | fn disconnect_wakes_sender() { 223 | let (s, r) = bounded(0); 224 | 225 | scope(|scope| { 226 | scope.spawn(move |_| { 227 | assert_eq!(s.send(()), Err(SendError(()))); 228 | }); 229 | scope.spawn(move |_| { 230 | thread::sleep(ms(1000)); 231 | drop(r); 232 | }); 233 | }) 234 | .unwrap(); 235 | } 236 | 237 | #[test] 238 | fn disconnect_wakes_receiver() { 239 | let (s, r) = bounded::<()>(0); 240 | 241 | scope(|scope| { 242 | scope.spawn(move |_| { 243 | assert!(r.recv().is_err()); 244 | }); 245 | scope.spawn(move |_| { 246 | thread::sleep(ms(1000)); 247 | drop(s); 248 | }); 249 | }) 250 | .unwrap(); 251 | } 252 | 253 | #[test] 254 | fn spsc() { 255 | const COUNT: usize = 100_000; 256 | 257 | let (s, r) = bounded(0); 258 | 259 | scope(|scope| { 260 | scope.spawn(move |_| { 261 | for i in 0..COUNT { 262 | assert_eq!(r.recv(), Ok(i)); 263 | } 264 | assert!(r.recv().is_err()); 265 | }); 266 | scope.spawn(move |_| { 267 | for i in 0..COUNT { 268 | s.send(i).unwrap(); 269 | } 270 | }); 271 | }) 272 | .unwrap(); 273 | } 274 | 275 | #[test] 276 | fn mpmc() { 277 | const COUNT: usize = 25_000; 278 | const THREADS: usize = 4; 279 | 280 | let (s, r) = bounded::(0); 281 | let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); 282 | 283 | scope(|scope| { 284 | for _ in 0..THREADS { 285 | scope.spawn(|_| { 286 | for _ in 0..COUNT { 287 | let n = r.recv().unwrap(); 288 | v[n].fetch_add(1, Ordering::SeqCst); 289 | } 290 | }); 291 | } 292 | for _ in 0..THREADS { 293 | scope.spawn(|_| { 294 | for i in 0..COUNT { 295 | s.send(i).unwrap(); 296 | } 297 | }); 298 | } 299 | }) 300 | .unwrap(); 301 | 302 | for c in v { 303 | assert_eq!(c.load(Ordering::SeqCst), THREADS); 304 | } 305 | } 306 | 307 | #[test] 308 | fn stress_oneshot() { 309 | const COUNT: usize = 10_000; 310 | 311 | for _ in 0..COUNT { 312 | let (s, r) = bounded(1); 313 | 314 | scope(|scope| { 315 | scope.spawn(|_| r.recv().unwrap()); 316 | scope.spawn(|_| s.send(0).unwrap()); 317 | }) 318 | .unwrap(); 319 | } 320 | } 321 | 322 | #[test] 323 | fn stress_iter() { 324 | const COUNT: usize = 1000; 325 | 326 | let (request_s, request_r) = bounded(0); 327 | let (response_s, response_r) = bounded(0); 328 | 329 | scope(|scope| { 330 | scope.spawn(move |_| { 331 | let mut count = 0; 332 | loop { 333 | for x in response_r.try_iter() { 334 | count += x; 335 | if count == COUNT { 336 | return; 337 | } 338 | } 339 | let _ = request_s.try_send(()); 340 | } 341 | }); 342 | 343 | for _ in request_r.iter() { 344 | if response_s.send(1).is_err() { 345 | break; 346 | } 347 | } 348 | }) 349 | .unwrap(); 350 | } 351 | 352 | #[test] 353 | fn stress_timeout_two_threads() { 354 | const COUNT: usize = 100; 355 | 356 | let (s, r) = bounded(0); 357 | 358 | scope(|scope| { 359 | scope.spawn(|_| { 360 | for i in 0..COUNT { 361 | if i % 2 == 0 { 362 | thread::sleep(ms(50)); 363 | } 364 | loop { 365 | if let Ok(()) = s.send_timeout(i, ms(10)) { 366 | break; 367 | } 368 | } 369 | } 370 | }); 371 | 372 | scope.spawn(|_| { 373 | for i in 0..COUNT { 374 | if i % 2 == 0 { 375 | thread::sleep(ms(50)); 376 | } 377 | loop { 378 | if let Ok(x) = r.recv_timeout(ms(10)) { 379 | assert_eq!(x, i); 380 | break; 381 | } 382 | } 383 | } 384 | }); 385 | }) 386 | .unwrap(); 387 | } 388 | 389 | #[test] 390 | fn drops() { 391 | static DROPS: AtomicUsize = AtomicUsize::new(0); 392 | 393 | #[derive(Debug, PartialEq)] 394 | struct DropCounter; 395 | 396 | impl Drop for DropCounter { 397 | fn drop(&mut self) { 398 | DROPS.fetch_add(1, Ordering::SeqCst); 399 | } 400 | } 401 | 402 | let mut rng = thread_rng(); 403 | 404 | for _ in 0..100 { 405 | let steps = rng.gen_range(0..3_000); 406 | 407 | DROPS.store(0, Ordering::SeqCst); 408 | let (s, r) = bounded::(0); 409 | 410 | scope(|scope| { 411 | scope.spawn(|_| { 412 | for _ in 0..steps { 413 | r.recv().unwrap(); 414 | } 415 | }); 416 | 417 | scope.spawn(|_| { 418 | for _ in 0..steps { 419 | s.send(DropCounter).unwrap(); 420 | } 421 | }); 422 | }) 423 | .unwrap(); 424 | 425 | assert_eq!(DROPS.load(Ordering::SeqCst), steps); 426 | drop(s); 427 | drop(r); 428 | assert_eq!(DROPS.load(Ordering::SeqCst), steps); 429 | } 430 | } 431 | 432 | // #[test] 433 | // fn fairness() { 434 | // const COUNT: usize = 10_000; 435 | 436 | // let (s1, r1) = bounded::<()>(0); 437 | // let (s2, r2) = bounded::<()>(0); 438 | 439 | // scope(|scope| { 440 | // scope.spawn(|_| { 441 | // let mut hits = [0usize; 2]; 442 | // for _ in 0..COUNT { 443 | // select! { 444 | // recv(r1) -> _ => hits[0] += 1, 445 | // recv(r2) -> _ => hits[1] += 1, 446 | // } 447 | // } 448 | // assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); 449 | // }); 450 | 451 | // let mut hits = [0usize; 2]; 452 | // for _ in 0..COUNT { 453 | // select! { 454 | // send(s1, ()) -> _ => hits[0] += 1, 455 | // send(s2, ()) -> _ => hits[1] += 1, 456 | // } 457 | // } 458 | // assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); 459 | // }) 460 | // .unwrap(); 461 | // } 462 | 463 | // #[test] 464 | // fn fairness_duplicates() { 465 | // const COUNT: usize = 10_000; 466 | 467 | // let (s, r) = bounded::<()>(0); 468 | 469 | // scope(|scope| { 470 | // scope.spawn(|_| { 471 | // let mut hits = [0usize; 5]; 472 | // for _ in 0..COUNT { 473 | // select! { 474 | // recv(r) -> _ => hits[0] += 1, 475 | // recv(r) -> _ => hits[1] += 1, 476 | // recv(r) -> _ => hits[2] += 1, 477 | // recv(r) -> _ => hits[3] += 1, 478 | // recv(r) -> _ => hits[4] += 1, 479 | // } 480 | // } 481 | // assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); 482 | // }); 483 | 484 | // let mut hits = [0usize; 5]; 485 | // for _ in 0..COUNT { 486 | // select! { 487 | // send(s, ()) -> _ => hits[0] += 1, 488 | // send(s, ()) -> _ => hits[1] += 1, 489 | // send(s, ()) -> _ => hits[2] += 1, 490 | // send(s, ()) -> _ => hits[3] += 1, 491 | // send(s, ()) -> _ => hits[4] += 1, 492 | // } 493 | // } 494 | // assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); 495 | // }) 496 | // .unwrap(); 497 | // } 498 | 499 | // #[test] 500 | // fn recv_in_send() { 501 | // let (s, r) = bounded(0); 502 | 503 | // scope(|scope| { 504 | // scope.spawn(|_| { 505 | // thread::sleep(ms(100)); 506 | // r.recv() 507 | // }); 508 | 509 | // scope.spawn(|_| { 510 | // thread::sleep(ms(500)); 511 | // s.send(()).unwrap(); 512 | // }); 513 | 514 | // select! { 515 | // send(s, r.recv().unwrap()) -> _ => {} 516 | // } 517 | // }) 518 | // .unwrap(); 519 | // } 520 | 521 | #[test] 522 | fn channel_through_channel() { 523 | const COUNT: usize = 1000; 524 | 525 | type T = Box; 526 | 527 | let (s, r) = bounded::(0); 528 | 529 | scope(|scope| { 530 | scope.spawn(move |_| { 531 | let mut s = s; 532 | 533 | for _ in 0..COUNT { 534 | let (new_s, new_r) = bounded(0); 535 | let new_r: T = Box::new(Some(new_r)); 536 | 537 | s.send(new_r).unwrap(); 538 | s = new_s; 539 | } 540 | }); 541 | 542 | scope.spawn(move |_| { 543 | let mut r = r; 544 | 545 | for _ in 0..COUNT { 546 | r = r 547 | .recv() 548 | .unwrap() 549 | .downcast_mut::>>() 550 | .unwrap() 551 | .take() 552 | .unwrap() 553 | } 554 | }); 555 | }) 556 | .unwrap(); 557 | } 558 | --------------------------------------------------------------------------------