Vendor dependencies for 0.3.0 release

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

View File

@@ -0,0 +1 @@
{"files":{"Cargo.toml":"6b8d190d4242002abcb14a1db311a30124bdad0fc34014ec546db85289ce0f44","LICENSE-APACHE":"275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427","LICENSE-MIT":"6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd","README.md":"faccd17503a06e7df67feb53da22dba6a8ea80ee88736ed37fae038d0d0906dd","benches/sync_mpsc.rs":"1019dd027f104f58883f396ff70efc3dd69b3a7d62df17af090e07b2b05eaf66","src/lib.rs":"7f226e1dfef15df3706ecb66b75555de258d25518f692658952de54b2b17bd55","src/lock.rs":"38655a797456ea4f67d132c42055cf74f18195e875c3b337fc81a12901f79292","src/mpsc/mod.rs":"742e362fb924caf4f04054c59ec0f9983f8de44712a67d30a35a19a0f357b6c4","src/mpsc/queue.rs":"22034085dc22050b708a37854e215fc7cbb16d65edc60370cb5d8f4b7faca18e","src/mpsc/sink_impl.rs":"c9977b530187e82c912fcd46e08316e48ed246e77bb2419d53020e69e403d086","src/oneshot.rs":"1e4e33c75d72b5d11cc23710e2a08099e04b72bf2368b68e7c1eb0beb6fc03fa","tests/channel.rs":"88f4a41d82b5c1b01e153d071a2bf48e0697355908c55ca42342ed45e63fdec8","tests/mpsc-close.rs":"ea423e82f0dc2593b20b7d06c0fc17b7740bafdec9c63556593fbb84b536a252","tests/mpsc-size_hint.rs":"50fba3495bdf4e91a84ad105b148b6cd72f73f64a85703414eeb2d07732c66b9","tests/mpsc.rs":"ff02a212f85f92da4c1fdfad79045ff1979a28187549506ad6b73523979b2c16","tests/oneshot.rs":"0f97d28852a1fd1327211772f43322c93916a639be3f2581e49ad37c9f8a2f88"},"package":"2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"}

96
vendor/futures-channel/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,96 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
rust-version = "1.56"
name = "futures-channel"
version = "0.3.31"
build = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = """
Channels for asynchronous communication using futures-rs.
"""
homepage = "https://rust-lang.github.io/futures-rs"
readme = "README.md"
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/futures-rs"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = [
"--cfg",
"docsrs",
]
[lib]
name = "futures_channel"
path = "src/lib.rs"
[[test]]
name = "channel"
path = "tests/channel.rs"
[[test]]
name = "mpsc"
path = "tests/mpsc.rs"
[[test]]
name = "mpsc-close"
path = "tests/mpsc-close.rs"
[[test]]
name = "mpsc-size_hint"
path = "tests/mpsc-size_hint.rs"
[[test]]
name = "oneshot"
path = "tests/oneshot.rs"
[[bench]]
name = "sync_mpsc"
path = "benches/sync_mpsc.rs"
[dependencies.futures-core]
version = "0.3.31"
default-features = false
[dependencies.futures-sink]
version = "0.3.31"
optional = true
default-features = false
[dev-dependencies]
[features]
alloc = ["futures-core/alloc"]
cfg-target-has-atomic = []
default = ["std"]
sink = ["futures-sink"]
std = [
"alloc",
"futures-core/std",
]
unstable = []
[lints.rust]
missing_debug_implementations = "warn"
rust_2018_idioms = "warn"
single_use_lifetimes = "warn"
unreachable_pub = "warn"
[lints.rust.unexpected_cfgs]
level = "warn"
priority = 0
check-cfg = ["cfg(futures_sanitizer)"]

202
vendor/futures-channel/LICENSE-APACHE vendored Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright (c) 2016 Alex Crichton
Copyright (c) 2017 The Tokio Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

26
vendor/futures-channel/LICENSE-MIT vendored Normal file
View File

@@ -0,0 +1,26 @@
Copyright (c) 2016 Alex Crichton
Copyright (c) 2017 The Tokio Authors
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

23
vendor/futures-channel/README.md vendored Normal file
View File

@@ -0,0 +1,23 @@
# futures-channel
Channels for asynchronous communication using futures-rs.
## Usage
Add this to your `Cargo.toml`:
```toml
[dependencies]
futures-channel = "0.3"
```
The current `futures-channel` requires Rust 1.56 or later.
## License
Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or
[MIT license](LICENSE-MIT) at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall
be dual licensed as above, without any additional terms or conditions.

View File

@@ -0,0 +1,135 @@
#![feature(test)]
extern crate test;
use crate::test::Bencher;
use {
futures::{
channel::mpsc::{self, Sender, UnboundedSender},
ready,
sink::Sink,
stream::{Stream, StreamExt},
task::{Context, Poll},
},
futures_test::task::noop_context,
std::pin::Pin,
};
/// Single producer, single consumer
#[bench]
fn unbounded_1_tx(b: &mut Bencher) {
let mut cx = noop_context();
b.iter(|| {
let (tx, mut rx) = mpsc::unbounded();
// 1000 iterations to avoid measuring overhead of initialization
// Result should be divided by 1000
for i in 0..1000 {
// Poll, not ready, park
assert_eq!(Poll::Pending, rx.poll_next_unpin(&mut cx));
UnboundedSender::unbounded_send(&tx, i).unwrap();
// Now poll ready
assert_eq!(Poll::Ready(Some(i)), rx.poll_next_unpin(&mut cx));
}
})
}
/// 100 producers, single consumer
#[bench]
fn unbounded_100_tx(b: &mut Bencher) {
let mut cx = noop_context();
b.iter(|| {
let (tx, mut rx) = mpsc::unbounded();
let tx: Vec<_> = (0..100).map(|_| tx.clone()).collect();
// 1000 send/recv operations total, result should be divided by 1000
for _ in 0..10 {
for (i, x) in tx.iter().enumerate() {
assert_eq!(Poll::Pending, rx.poll_next_unpin(&mut cx));
UnboundedSender::unbounded_send(x, i).unwrap();
assert_eq!(Poll::Ready(Some(i)), rx.poll_next_unpin(&mut cx));
}
}
})
}
#[bench]
fn unbounded_uncontended(b: &mut Bencher) {
let mut cx = noop_context();
b.iter(|| {
let (tx, mut rx) = mpsc::unbounded();
for i in 0..1000 {
UnboundedSender::unbounded_send(&tx, i).expect("send");
// No need to create a task, because poll is not going to park.
assert_eq!(Poll::Ready(Some(i)), rx.poll_next_unpin(&mut cx));
}
})
}
/// A Stream that continuously sends incrementing number of the queue
struct TestSender {
tx: Sender<u32>,
last: u32, // Last number sent
}
// Could be a Future, it doesn't matter
impl Stream for TestSender {
type Item = u32;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let this = &mut *self;
let mut tx = Pin::new(&mut this.tx);
ready!(tx.as_mut().poll_ready(cx)).unwrap();
tx.as_mut().start_send(this.last + 1).unwrap();
this.last += 1;
assert_eq!(Poll::Pending, tx.as_mut().poll_flush(cx));
Poll::Ready(Some(this.last))
}
}
/// Single producers, single consumer
#[bench]
fn bounded_1_tx(b: &mut Bencher) {
let mut cx = noop_context();
b.iter(|| {
let (tx, mut rx) = mpsc::channel(0);
let mut tx = TestSender { tx, last: 0 };
for i in 0..1000 {
assert_eq!(Poll::Ready(Some(i + 1)), tx.poll_next_unpin(&mut cx));
assert_eq!(Poll::Pending, tx.poll_next_unpin(&mut cx));
assert_eq!(Poll::Ready(Some(i + 1)), rx.poll_next_unpin(&mut cx));
}
})
}
/// 100 producers, single consumer
#[bench]
fn bounded_100_tx(b: &mut Bencher) {
let mut cx = noop_context();
b.iter(|| {
// Each sender can send one item after specified capacity
let (tx, mut rx) = mpsc::channel(0);
let mut tx: Vec<_> = (0..100).map(|_| TestSender { tx: tx.clone(), last: 0 }).collect();
for i in 0..10 {
for x in &mut tx {
// Send an item
assert_eq!(Poll::Ready(Some(i + 1)), x.poll_next_unpin(&mut cx));
// Then block
assert_eq!(Poll::Pending, x.poll_next_unpin(&mut cx));
// Recv the item
assert_eq!(Poll::Ready(Some(i + 1)), rx.poll_next_unpin(&mut cx));
}
}
})
}

38
vendor/futures-channel/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,38 @@
//! Asynchronous channels.
//!
//! Like threads, concurrent tasks sometimes need to communicate with each
//! other. This module contains two basic abstractions for doing so:
//!
//! - [oneshot], a way of sending a single value from one task to another.
//! - [mpsc], a multi-producer, single-consumer channel for sending values
//! between tasks, analogous to the similarly-named structure in the standard
//! library.
//!
//! All items are only available when the `std` or `alloc` feature of this
//! library is activated, and it is activated by default.
#![no_std]
#![doc(test(
no_crate_inject,
attr(
deny(warnings, rust_2018_idioms, single_use_lifetimes),
allow(dead_code, unused_assignments, unused_variables)
)
))]
#![warn(missing_docs, unsafe_op_in_unsafe_fn)]
#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))]
#[cfg(feature = "alloc")]
mod lock;
#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))]
#[cfg(feature = "std")]
pub mod mpsc;
#[cfg_attr(target_os = "none", cfg(target_has_atomic = "ptr"))]
#[cfg(feature = "alloc")]
pub mod oneshot;

102
vendor/futures-channel/src/lock.rs vendored Normal file
View File

@@ -0,0 +1,102 @@
//! A "mutex" which only supports `try_lock`
//!
//! As a futures library the eventual call to an event loop should be the only
//! thing that ever blocks, so this is assisted with a fast user-space
//! implementation of a lock that can only have a `try_lock` operation.
use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};
use core::sync::atomic::AtomicBool;
use core::sync::atomic::Ordering::SeqCst;
/// A "mutex" around a value, similar to `std::sync::Mutex<T>`.
///
/// This lock only supports the `try_lock` operation, however, and does not
/// implement poisoning.
#[derive(Debug)]
pub(crate) struct Lock<T> {
locked: AtomicBool,
data: UnsafeCell<T>,
}
/// Sentinel representing an acquired lock through which the data can be
/// accessed.
pub(crate) struct TryLock<'a, T> {
__ptr: &'a Lock<T>,
}
// The `Lock` structure is basically just a `Mutex<T>`, and these two impls are
// intended to mirror the standard library's corresponding impls for `Mutex<T>`.
//
// If a `T` is sendable across threads, so is the lock, and `T` must be sendable
// across threads to be `Sync` because it allows mutable access from multiple
// threads.
unsafe impl<T: Send> Send for Lock<T> {}
unsafe impl<T: Send> Sync for Lock<T> {}
impl<T> Lock<T> {
/// Creates a new lock around the given value.
pub(crate) fn new(t: T) -> Self {
Self { locked: AtomicBool::new(false), data: UnsafeCell::new(t) }
}
/// Attempts to acquire this lock, returning whether the lock was acquired or
/// not.
///
/// If `Some` is returned then the data this lock protects can be accessed
/// through the sentinel. This sentinel allows both mutable and immutable
/// access.
///
/// If `None` is returned then the lock is already locked, either elsewhere
/// on this thread or on another thread.
pub(crate) fn try_lock(&self) -> Option<TryLock<'_, T>> {
if !self.locked.swap(true, SeqCst) {
Some(TryLock { __ptr: self })
} else {
None
}
}
}
impl<T> Deref for TryLock<'_, T> {
type Target = T;
fn deref(&self) -> &T {
// The existence of `TryLock` represents that we own the lock, so we
// can safely access the data here.
unsafe { &*self.__ptr.data.get() }
}
}
impl<T> DerefMut for TryLock<'_, T> {
fn deref_mut(&mut self) -> &mut T {
// The existence of `TryLock` represents that we own the lock, so we
// can safely access the data here.
//
// Additionally, we're the *only* `TryLock` in existence so mutable
// access should be ok.
unsafe { &mut *self.__ptr.data.get() }
}
}
impl<T> Drop for TryLock<'_, T> {
fn drop(&mut self) {
self.__ptr.locked.store(false, SeqCst);
}
}
#[cfg(test)]
mod tests {
use super::Lock;
#[test]
fn smoke() {
let a = Lock::new(1);
let mut a1 = a.try_lock().unwrap();
assert!(a.try_lock().is_none());
assert_eq!(*a1, 1);
*a1 = 2;
drop(a1);
assert_eq!(*a.try_lock().unwrap(), 2);
assert_eq!(*a.try_lock().unwrap(), 2);
}
}

1373
vendor/futures-channel/src/mpsc/mod.rs vendored Normal file

File diff suppressed because it is too large Load Diff

177
vendor/futures-channel/src/mpsc/queue.rs vendored Normal file
View File

@@ -0,0 +1,177 @@
/* Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of Dmitry Vyukov.
*/
//! A mostly lock-free multi-producer, single consumer queue for sending
//! messages between asynchronous tasks.
//!
//! The queue implementation is essentially the same one used for mpsc channels
//! in the standard library.
//!
//! Note that the current implementation of this queue has a caveat of the `pop`
//! method, and see the method for more information about it. Due to this
//! caveat, this queue may not be appropriate for all use-cases.
// http://www.1024cores.net/home/lock-free-algorithms
// /queues/non-intrusive-mpsc-node-based-queue
// NOTE: this implementation is lifted from the standard library and only
// slightly modified
pub(super) use self::PopResult::*;
use std::boxed::Box;
use std::cell::UnsafeCell;
use std::ptr;
use std::sync::atomic::{AtomicPtr, Ordering};
use std::thread;
/// A result of the `pop` function.
pub(super) enum PopResult<T> {
/// Some data has been popped
Data(T),
/// The queue is empty
Empty,
/// The queue is in an inconsistent state. Popping data should succeed, but
/// some pushers have yet to make enough progress in order allow a pop to
/// succeed. It is recommended that a pop() occur "in the near future" in
/// order to see if the sender has made progress or not
Inconsistent,
}
struct Node<T> {
next: AtomicPtr<Self>,
value: Option<T>,
}
/// The multi-producer single-consumer structure. This is not cloneable, but it
/// may be safely shared so long as it is guaranteed that there is only one
/// popper at a time (many pushers are allowed).
pub(super) struct Queue<T> {
head: AtomicPtr<Node<T>>,
tail: UnsafeCell<*mut Node<T>>,
}
unsafe impl<T: Send> Send for Queue<T> {}
unsafe impl<T: Send> Sync for Queue<T> {}
impl<T> Node<T> {
unsafe fn new(v: Option<T>) -> *mut Self {
Box::into_raw(Box::new(Self { next: AtomicPtr::new(ptr::null_mut()), value: v }))
}
}
impl<T> Queue<T> {
/// Creates a new queue that is safe to share among multiple producers and
/// one consumer.
pub(super) fn new() -> Self {
let stub = unsafe { Node::new(None) };
Self { head: AtomicPtr::new(stub), tail: UnsafeCell::new(stub) }
}
/// Pushes a new value onto this queue.
pub(super) fn push(&self, t: T) {
unsafe {
let n = Node::new(Some(t));
let prev = self.head.swap(n, Ordering::AcqRel);
(*prev).next.store(n, Ordering::Release);
}
}
/// Pops some data from this queue.
///
/// Note that the current implementation means that this function cannot
/// return `Option<T>`. It is possible for this queue to be in an
/// inconsistent state where many pushes have succeeded and completely
/// finished, but pops cannot return `Some(t)`. This inconsistent state
/// happens when a pusher is preempted at an inopportune moment.
///
/// This inconsistent state means that this queue does indeed have data, but
/// it does not currently have access to it at this time.
///
/// This function is unsafe because only one thread can call it at a time.
pub(super) unsafe fn pop(&self) -> PopResult<T> {
unsafe {
let tail = *self.tail.get();
let next = (*tail).next.load(Ordering::Acquire);
if !next.is_null() {
*self.tail.get() = next;
assert!((*tail).value.is_none());
assert!((*next).value.is_some());
let ret = (*next).value.take().unwrap();
drop(Box::from_raw(tail));
return Data(ret);
}
if self.head.load(Ordering::Acquire) == tail {
Empty
} else {
Inconsistent
}
}
}
/// Pop an element similarly to `pop` function, but spin-wait on inconsistent
/// queue state instead of returning `Inconsistent`.
///
/// This function is unsafe because only one thread can call it at a time.
pub(super) unsafe fn pop_spin(&self) -> Option<T> {
loop {
match unsafe { self.pop() } {
Empty => return None,
Data(t) => return Some(t),
// Inconsistent means that there will be a message to pop
// in a short time. This branch can only be reached if
// values are being produced from another thread, so there
// are a few ways that we can deal with this:
//
// 1) Spin
// 2) thread::yield_now()
// 3) task::current().unwrap() & return Pending
//
// For now, thread::yield_now() is used, but it would
// probably be better to spin a few times then yield.
Inconsistent => {
thread::yield_now();
}
}
}
}
}
impl<T> Drop for Queue<T> {
fn drop(&mut self) {
unsafe {
let mut cur = *self.tail.get();
while !cur.is_null() {
let next = (*cur).next.load(Ordering::Relaxed);
drop(Box::from_raw(cur));
cur = next;
}
}
}
}

View File

@@ -0,0 +1,73 @@
use super::{SendError, Sender, TrySendError, UnboundedSender};
use futures_core::task::{Context, Poll};
use futures_sink::Sink;
use std::pin::Pin;
impl<T> Sink<T> for Sender<T> {
type Error = SendError;
fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
(*self).poll_ready(cx)
}
fn start_send(mut self: Pin<&mut Self>, msg: T) -> Result<(), Self::Error> {
(*self).start_send(msg)
}
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
match (*self).poll_ready(cx) {
Poll::Ready(Err(ref e)) if e.is_disconnected() => {
// If the receiver disconnected, we consider the sink to be flushed.
Poll::Ready(Ok(()))
}
x => x,
}
}
fn poll_close(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.disconnect();
Poll::Ready(Ok(()))
}
}
impl<T> Sink<T> for UnboundedSender<T> {
type Error = SendError;
fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Self::poll_ready(&*self, cx)
}
fn start_send(mut self: Pin<&mut Self>, msg: T) -> Result<(), Self::Error> {
Self::start_send(&mut *self, msg)
}
fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn poll_close(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.disconnect();
Poll::Ready(Ok(()))
}
}
impl<T> Sink<T> for &UnboundedSender<T> {
type Error = SendError;
fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
UnboundedSender::poll_ready(*self, cx)
}
fn start_send(self: Pin<&mut Self>, msg: T) -> Result<(), Self::Error> {
self.unbounded_send(msg).map_err(TrySendError::into_send_error)
}
fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.close_channel();
Poll::Ready(Ok(()))
}
}

488
vendor/futures-channel/src/oneshot.rs vendored Normal file
View File

@@ -0,0 +1,488 @@
//! A channel for sending a single message between asynchronous tasks.
//!
//! This is a single-producer, single-consumer channel.
use alloc::sync::Arc;
use core::fmt;
use core::pin::Pin;
use core::sync::atomic::AtomicBool;
use core::sync::atomic::Ordering::SeqCst;
use futures_core::future::{FusedFuture, Future};
use futures_core::task::{Context, Poll, Waker};
use crate::lock::Lock;
/// A future for a value that will be provided by another asynchronous task.
///
/// This is created by the [`channel`] function.
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Receiver<T> {
inner: Arc<Inner<T>>,
}
/// A means of transmitting a single value to another task.
///
/// This is created by the [`channel`] function.
pub struct Sender<T> {
inner: Arc<Inner<T>>,
}
// The channels do not ever project Pin to the inner T
impl<T> Unpin for Receiver<T> {}
impl<T> Unpin for Sender<T> {}
/// Internal state of the `Receiver`/`Sender` pair above. This is all used as
/// the internal synchronization between the two for send/recv operations.
struct Inner<T> {
/// Indicates whether this oneshot is complete yet. This is filled in both
/// by `Sender::drop` and by `Receiver::drop`, and both sides interpret it
/// appropriately.
///
/// For `Receiver`, if this is `true`, then it's guaranteed that `data` is
/// unlocked and ready to be inspected.
///
/// For `Sender` if this is `true` then the oneshot has gone away and it
/// can return ready from `poll_canceled`.
complete: AtomicBool,
/// The actual data being transferred as part of this `Receiver`. This is
/// filled in by `Sender::complete` and read by `Receiver::poll`.
///
/// Note that this is protected by `Lock`, but it is in theory safe to
/// replace with an `UnsafeCell` as it's actually protected by `complete`
/// above. I wouldn't recommend doing this, however, unless someone is
/// supremely confident in the various atomic orderings here and there.
data: Lock<Option<T>>,
/// Field to store the task which is blocked in `Receiver::poll`.
///
/// This is filled in when a oneshot is polled but not ready yet. Note that
/// the `Lock` here, unlike in `data` above, is important to resolve races.
/// Both the `Receiver` and the `Sender` halves understand that if they
/// can't acquire the lock then some important interference is happening.
rx_task: Lock<Option<Waker>>,
/// Like `rx_task` above, except for the task blocked in
/// `Sender::poll_canceled`. Additionally, `Lock` cannot be `UnsafeCell`.
tx_task: Lock<Option<Waker>>,
}
/// Creates a new one-shot channel for sending a single value across asynchronous tasks.
///
/// The channel works for a spsc (single-producer, single-consumer) scheme.
///
/// This function is similar to Rust's channel constructor found in the standard
/// library. Two halves are returned, the first of which is a `Sender` handle,
/// used to signal the end of a computation and provide its value. The second
/// half is a `Receiver` which implements the `Future` trait, resolving to the
/// value that was given to the `Sender` handle.
///
/// Each half can be separately owned and sent across tasks.
///
/// # Examples
///
/// ```
/// use futures::channel::oneshot;
/// use std::{thread, time::Duration};
///
/// let (sender, receiver) = oneshot::channel::<i32>();
///
/// thread::spawn(|| {
/// println!("THREAD: sleeping zzz...");
/// thread::sleep(Duration::from_millis(1000));
/// println!("THREAD: i'm awake! sending.");
/// sender.send(3).unwrap();
/// });
///
/// println!("MAIN: doing some useful stuff");
///
/// futures::executor::block_on(async {
/// println!("MAIN: waiting for msg...");
/// println!("MAIN: got: {:?}", receiver.await)
/// });
/// ```
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
let inner = Arc::new(Inner::new());
let receiver = Receiver { inner: inner.clone() };
let sender = Sender { inner };
(sender, receiver)
}
impl<T> Inner<T> {
fn new() -> Self {
Self {
complete: AtomicBool::new(false),
data: Lock::new(None),
rx_task: Lock::new(None),
tx_task: Lock::new(None),
}
}
fn send(&self, t: T) -> Result<(), T> {
if self.complete.load(SeqCst) {
return Err(t);
}
// Note that this lock acquisition may fail if the receiver
// is closed and sets the `complete` flag to `true`, whereupon
// the receiver may call `poll()`.
if let Some(mut slot) = self.data.try_lock() {
assert!(slot.is_none());
*slot = Some(t);
drop(slot);
// If the receiver called `close()` between the check at the
// start of the function, and the lock being released, then
// the receiver may not be around to receive it, so try to
// pull it back out.
if self.complete.load(SeqCst) {
// If lock acquisition fails, then receiver is actually
// receiving it, so we're good.
if let Some(mut slot) = self.data.try_lock() {
if let Some(t) = slot.take() {
return Err(t);
}
}
}
Ok(())
} else {
// Must have been closed
Err(t)
}
}
fn poll_canceled(&self, cx: &mut Context<'_>) -> Poll<()> {
// Fast path up first, just read the flag and see if our other half is
// gone. This flag is set both in our destructor and the oneshot
// destructor, but our destructor hasn't run yet so if it's set then the
// oneshot is gone.
if self.complete.load(SeqCst) {
return Poll::Ready(());
}
// If our other half is not gone then we need to park our current task
// and move it into the `tx_task` slot to get notified when it's
// actually gone.
//
// If `try_lock` fails, then the `Receiver` is in the process of using
// it, so we can deduce that it's now in the process of going away and
// hence we're canceled. If it succeeds then we just store our handle.
//
// Crucially we then check `complete` *again* before we return.
// While we were storing our handle inside `tx_task` the
// `Receiver` may have been dropped. The first thing it does is set the
// flag, and if it fails to acquire the lock it assumes that we'll see
// the flag later on. So... we then try to see the flag later on!
let handle = cx.waker().clone();
match self.tx_task.try_lock() {
Some(mut p) => *p = Some(handle),
None => return Poll::Ready(()),
}
if self.complete.load(SeqCst) {
Poll::Ready(())
} else {
Poll::Pending
}
}
fn is_canceled(&self) -> bool {
self.complete.load(SeqCst)
}
fn drop_tx(&self) {
// Flag that we're a completed `Sender` and try to wake up a receiver.
// Whether or not we actually stored any data will get picked up and
// translated to either an item or cancellation.
//
// Note that if we fail to acquire the `rx_task` lock then that means
// we're in one of two situations:
//
// 1. The receiver is trying to block in `poll`
// 2. The receiver is being dropped
//
// In the first case it'll check the `complete` flag after it's done
// blocking to see if it succeeded. In the latter case we don't need to
// wake up anyone anyway. So in both cases it's ok to ignore the `None`
// case of `try_lock` and bail out.
//
// The first case crucially depends on `Lock` using `SeqCst` ordering
// under the hood. If it instead used `Release` / `Acquire` ordering,
// then it would not necessarily synchronize with `inner.complete`
// and deadlock might be possible, as was observed in
// https://github.com/rust-lang/futures-rs/pull/219.
self.complete.store(true, SeqCst);
if let Some(mut slot) = self.rx_task.try_lock() {
if let Some(task) = slot.take() {
drop(slot);
task.wake();
}
}
// If we registered a task for cancel notification drop it to reduce
// spurious wakeups
if let Some(mut slot) = self.tx_task.try_lock() {
drop(slot.take());
}
}
fn close_rx(&self) {
// Flag our completion and then attempt to wake up the sender if it's
// blocked. See comments in `drop` below for more info
self.complete.store(true, SeqCst);
if let Some(mut handle) = self.tx_task.try_lock() {
if let Some(task) = handle.take() {
drop(handle);
task.wake()
}
}
}
fn try_recv(&self) -> Result<Option<T>, Canceled> {
// If we're complete, either `::close_rx` or `::drop_tx` was called.
// We can assume a successful send if data is present.
if self.complete.load(SeqCst) {
if let Some(mut slot) = self.data.try_lock() {
if let Some(data) = slot.take() {
return Ok(Some(data));
}
}
Err(Canceled)
} else {
Ok(None)
}
}
fn recv(&self, cx: &mut Context<'_>) -> Poll<Result<T, Canceled>> {
// Check to see if some data has arrived. If it hasn't then we need to
// block our task.
//
// Note that the acquisition of the `rx_task` lock might fail below, but
// the only situation where this can happen is during `Sender::drop`
// when we are indeed completed already. If that's happening then we
// know we're completed so keep going.
let done = if self.complete.load(SeqCst) {
true
} else {
let task = cx.waker().clone();
match self.rx_task.try_lock() {
Some(mut slot) => {
*slot = Some(task);
false
}
None => true,
}
};
// If we're `done` via one of the paths above, then look at the data and
// figure out what the answer is. If, however, we stored `rx_task`
// successfully above we need to check again if we're completed in case
// a message was sent while `rx_task` was locked and couldn't notify us
// otherwise.
//
// If we're not done, and we're not complete, though, then we've
// successfully blocked our task and we return `Pending`.
if done || self.complete.load(SeqCst) {
// If taking the lock fails, the sender will realise that the we're
// `done` when it checks the `complete` flag on the way out, and
// will treat the send as a failure.
if let Some(mut slot) = self.data.try_lock() {
if let Some(data) = slot.take() {
return Poll::Ready(Ok(data));
}
}
Poll::Ready(Err(Canceled))
} else {
Poll::Pending
}
}
fn drop_rx(&self) {
// Indicate to the `Sender` that we're done, so any future calls to
// `poll_canceled` are weeded out.
self.complete.store(true, SeqCst);
// If we've blocked a task then there's no need for it to stick around,
// so we need to drop it. If this lock acquisition fails, though, then
// it's just because our `Sender` is trying to take the task, so we
// let them take care of that.
if let Some(mut slot) = self.rx_task.try_lock() {
let task = slot.take();
drop(slot);
drop(task);
}
// Finally, if our `Sender` wants to get notified of us going away, it
// would have stored something in `tx_task`. Here we try to peel that
// out and unpark it.
//
// Note that the `try_lock` here may fail, but only if the `Sender` is
// in the process of filling in the task. If that happens then we
// already flagged `complete` and they'll pick that up above.
if let Some(mut handle) = self.tx_task.try_lock() {
if let Some(task) = handle.take() {
drop(handle);
task.wake()
}
}
}
}
impl<T> Sender<T> {
/// Completes this oneshot with a successful result.
///
/// This function will consume `self` and indicate to the other end, the
/// [`Receiver`], that the value provided is the result of the computation
/// this represents.
///
/// If the value is successfully enqueued for the remote end to receive,
/// then `Ok(())` is returned. If the receiving end was dropped before
/// this function was called, however, then `Err(t)` is returned.
pub fn send(self, t: T) -> Result<(), T> {
self.inner.send(t)
}
/// Polls this `Sender` half to detect whether its associated
/// [`Receiver`] has been dropped.
///
/// # Return values
///
/// If `Ready(())` is returned then the associated `Receiver` has been
/// dropped, which means any work required for sending should be canceled.
///
/// If `Pending` is returned then the associated `Receiver` is still
/// alive and may be able to receive a message if sent. The current task,
/// however, is scheduled to receive a notification if the corresponding
/// `Receiver` goes away.
pub fn poll_canceled(&mut self, cx: &mut Context<'_>) -> Poll<()> {
self.inner.poll_canceled(cx)
}
/// Creates a future that resolves when this `Sender`'s corresponding
/// [`Receiver`] half has hung up.
///
/// This is a utility wrapping [`poll_canceled`](Sender::poll_canceled)
/// to expose a [`Future`].
pub fn cancellation(&mut self) -> Cancellation<'_, T> {
Cancellation { inner: self }
}
/// Tests to see whether this `Sender`'s corresponding `Receiver`
/// has been dropped.
///
/// Unlike [`poll_canceled`](Sender::poll_canceled), this function does not
/// enqueue a task for wakeup upon cancellation, but merely reports the
/// current state, which may be subject to concurrent modification.
pub fn is_canceled(&self) -> bool {
self.inner.is_canceled()
}
/// Tests to see whether this `Sender` is connected to the given `Receiver`. That is, whether
/// they were created by the same call to `channel`.
pub fn is_connected_to(&self, receiver: &Receiver<T>) -> bool {
Arc::ptr_eq(&self.inner, &receiver.inner)
}
}
impl<T> Drop for Sender<T> {
fn drop(&mut self) {
self.inner.drop_tx()
}
}
impl<T> fmt::Debug for Sender<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Sender").field("complete", &self.inner.complete).finish()
}
}
/// A future that resolves when the receiving end of a channel has hung up.
///
/// This is an `.await`-friendly interface around [`poll_canceled`](Sender::poll_canceled).
#[must_use = "futures do nothing unless you `.await` or poll them"]
#[derive(Debug)]
pub struct Cancellation<'a, T> {
inner: &'a mut Sender<T>,
}
impl<T> Future for Cancellation<'_, T> {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
self.inner.poll_canceled(cx)
}
}
/// Error returned from a [`Receiver`] when the corresponding [`Sender`] is
/// dropped.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Canceled;
impl fmt::Display for Canceled {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "oneshot canceled")
}
}
#[cfg(feature = "std")]
impl std::error::Error for Canceled {}
impl<T> Receiver<T> {
/// Gracefully close this receiver, preventing any subsequent attempts to
/// send to it.
///
/// Any `send` operation which happens after this method returns is
/// guaranteed to fail. After calling this method, you can use
/// [`Receiver::poll`](core::future::Future::poll) to determine whether a
/// message had previously been sent.
pub fn close(&mut self) {
self.inner.close_rx()
}
/// Attempts to receive a message outside of the context of a task.
///
/// Does not schedule a task wakeup or have any other side effects.
///
/// A return value of `None` must be considered immediately stale (out of
/// date) unless [`close`](Receiver::close) has been called first.
///
/// Returns an error if the sender was dropped.
pub fn try_recv(&mut self) -> Result<Option<T>, Canceled> {
self.inner.try_recv()
}
}
impl<T> Future for Receiver<T> {
type Output = Result<T, Canceled>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<T, Canceled>> {
self.inner.recv(cx)
}
}
impl<T> FusedFuture for Receiver<T> {
fn is_terminated(&self) -> bool {
if self.inner.complete.load(SeqCst) {
if let Some(slot) = self.inner.data.try_lock() {
if slot.is_some() {
return false;
}
}
true
} else {
false
}
}
}
impl<T> Drop for Receiver<T> {
fn drop(&mut self) {
self.inner.drop_rx()
}
}
impl<T> fmt::Debug for Receiver<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Receiver").field("complete", &self.inner.complete).finish()
}
}

66
vendor/futures-channel/tests/channel.rs vendored Normal file
View File

@@ -0,0 +1,66 @@
use futures::channel::mpsc;
use futures::executor::block_on;
use futures::future::poll_fn;
use futures::sink::SinkExt;
use futures::stream::StreamExt;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
#[test]
fn sequence() {
let (tx, rx) = mpsc::channel(1);
let amt = 20;
let t = thread::spawn(move || block_on(send_sequence(amt, tx)));
let list: Vec<_> = block_on(rx.collect());
let mut list = list.into_iter();
for i in (1..=amt).rev() {
assert_eq!(list.next(), Some(i));
}
assert_eq!(list.next(), None);
t.join().unwrap();
}
async fn send_sequence(n: u32, mut sender: mpsc::Sender<u32>) {
for x in 0..n {
sender.send(n - x).await.unwrap();
}
}
#[test]
fn drop_sender() {
let (tx, mut rx) = mpsc::channel::<u32>(1);
drop(tx);
let f = poll_fn(|cx| rx.poll_next_unpin(cx));
assert_eq!(block_on(f), None)
}
#[test]
fn drop_rx() {
let (mut tx, rx) = mpsc::channel::<u32>(1);
block_on(tx.send(1)).unwrap();
drop(rx);
assert!(block_on(tx.send(1)).is_err());
}
#[test]
fn drop_order() {
static DROPS: AtomicUsize = AtomicUsize::new(0);
let (mut tx, rx) = mpsc::channel(1);
struct A;
impl Drop for A {
fn drop(&mut self) {
DROPS.fetch_add(1, Ordering::SeqCst);
}
}
block_on(tx.send(A)).unwrap();
assert_eq!(DROPS.load(Ordering::SeqCst), 0);
drop(rx);
assert_eq!(DROPS.load(Ordering::SeqCst), 1);
assert!(block_on(tx.send(A)).is_err());
assert_eq!(DROPS.load(Ordering::SeqCst), 2);
}

View File

@@ -0,0 +1,299 @@
use futures::channel::mpsc;
use futures::executor::block_on;
use futures::future::Future;
use futures::sink::SinkExt;
use futures::stream::StreamExt;
use futures::task::{Context, Poll};
use std::pin::Pin;
use std::sync::{Arc, Weak};
use std::thread;
use std::time::{Duration, Instant};
#[test]
fn smoke() {
let (mut sender, receiver) = mpsc::channel(1);
let t = thread::spawn(move || while let Ok(()) = block_on(sender.send(42)) {});
// `receiver` needs to be dropped for `sender` to stop sending and therefore before the join.
block_on(receiver.take(3).for_each(|_| futures::future::ready(())));
t.join().unwrap()
}
#[test]
fn multiple_senders_disconnect() {
{
let (mut tx1, mut rx) = mpsc::channel(1);
let (tx2, mut tx3, mut tx4) = (tx1.clone(), tx1.clone(), tx1.clone());
// disconnect, dropping and Sink::poll_close should all close this sender but leave the
// channel open for other senders
tx1.disconnect();
drop(tx2);
block_on(tx3.close()).unwrap();
assert!(tx1.is_closed());
assert!(tx3.is_closed());
assert!(!tx4.is_closed());
block_on(tx4.send(5)).unwrap();
assert_eq!(block_on(rx.next()), Some(5));
// dropping the final sender will close the channel
drop(tx4);
assert_eq!(block_on(rx.next()), None);
}
{
let (mut tx1, mut rx) = mpsc::unbounded();
let (tx2, mut tx3, mut tx4) = (tx1.clone(), tx1.clone(), tx1.clone());
// disconnect, dropping and Sink::poll_close should all close this sender but leave the
// channel open for other senders
tx1.disconnect();
drop(tx2);
block_on(tx3.close()).unwrap();
assert!(tx1.is_closed());
assert!(tx3.is_closed());
assert!(!tx4.is_closed());
block_on(tx4.send(5)).unwrap();
assert_eq!(block_on(rx.next()), Some(5));
// dropping the final sender will close the channel
drop(tx4);
assert_eq!(block_on(rx.next()), None);
}
}
#[test]
fn multiple_senders_close_channel() {
{
let (mut tx1, mut rx) = mpsc::channel(1);
let mut tx2 = tx1.clone();
// close_channel should shut down the whole channel
tx1.close_channel();
assert!(tx1.is_closed());
assert!(tx2.is_closed());
let err = block_on(tx2.send(5)).unwrap_err();
assert!(err.is_disconnected());
assert_eq!(block_on(rx.next()), None);
}
{
let (tx1, mut rx) = mpsc::unbounded();
let mut tx2 = tx1.clone();
// close_channel should shut down the whole channel
tx1.close_channel();
assert!(tx1.is_closed());
assert!(tx2.is_closed());
let err = block_on(tx2.send(5)).unwrap_err();
assert!(err.is_disconnected());
assert_eq!(block_on(rx.next()), None);
}
}
#[test]
fn single_receiver_drop_closes_channel_and_drains() {
{
let ref_count = Arc::new(0);
let weak_ref = Arc::downgrade(&ref_count);
let (sender, receiver) = mpsc::unbounded();
sender.unbounded_send(ref_count).expect("failed to send");
// Verify that the sent message is still live.
assert!(weak_ref.upgrade().is_some());
drop(receiver);
// The sender should know the channel is closed.
assert!(sender.is_closed());
// Verify that the sent message has been dropped.
assert!(weak_ref.upgrade().is_none());
}
{
let ref_count = Arc::new(0);
let weak_ref = Arc::downgrade(&ref_count);
let (mut sender, receiver) = mpsc::channel(1);
sender.try_send(ref_count).expect("failed to send");
// Verify that the sent message is still live.
assert!(weak_ref.upgrade().is_some());
drop(receiver);
// The sender should know the channel is closed.
assert!(sender.is_closed());
// Verify that the sent message has been dropped.
assert!(weak_ref.upgrade().is_none());
assert!(sender.is_closed());
}
}
// Stress test that `try_send()`s occurring concurrently with receiver
// close/drops don't appear as successful sends.
#[cfg_attr(miri, ignore)] // Miri is too slow
#[test]
fn stress_try_send_as_receiver_closes() {
const AMT: usize = 10000;
// To provide variable timing characteristics (in the hopes of
// reproducing the collision that leads to a race), we busy-re-poll
// the test MPSC receiver a variable number of times before actually
// stopping. We vary this countdown between 1 and the following
// value.
const MAX_COUNTDOWN: usize = 20;
// When we detect that a successfully sent item is still in the
// queue after a disconnect, we spin for up to 100ms to confirm that
// it is a persistent condition and not a concurrency illusion.
const SPIN_TIMEOUT_S: u64 = 10;
const SPIN_SLEEP_MS: u64 = 10;
struct TestRx {
rx: mpsc::Receiver<Arc<()>>,
// The number of times to query `rx` before dropping it.
poll_count: usize,
}
struct TestTask {
command_rx: mpsc::Receiver<TestRx>,
test_rx: Option<mpsc::Receiver<Arc<()>>>,
countdown: usize,
}
impl TestTask {
/// Create a new TestTask
fn new() -> (Self, mpsc::Sender<TestRx>) {
let (command_tx, command_rx) = mpsc::channel::<TestRx>(0);
(
Self {
command_rx,
test_rx: None,
countdown: 0, // 0 means no countdown is in progress.
},
command_tx,
)
}
}
impl Future for TestTask {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// Poll the test channel, if one is present.
if let Some(rx) = &mut self.test_rx {
if let Poll::Ready(v) = rx.poll_next_unpin(cx) {
let _ = v.expect("test finished unexpectedly!");
}
self.countdown -= 1;
// Busy-poll until the countdown is finished.
cx.waker().wake_by_ref();
}
// Accept any newly submitted MPSC channels for testing.
match self.command_rx.poll_next_unpin(cx) {
Poll::Ready(Some(TestRx { rx, poll_count })) => {
self.test_rx = Some(rx);
self.countdown = poll_count;
cx.waker().wake_by_ref();
}
Poll::Ready(None) => return Poll::Ready(()),
Poll::Pending => {}
}
if self.countdown == 0 {
// Countdown complete -- drop the Receiver.
self.test_rx = None;
}
Poll::Pending
}
}
let (f, mut cmd_tx) = TestTask::new();
let bg = thread::spawn(move || block_on(f));
for i in 0..AMT {
let (mut test_tx, rx) = mpsc::channel(0);
let poll_count = i % MAX_COUNTDOWN;
cmd_tx.try_send(TestRx { rx, poll_count }).unwrap();
let mut prev_weak: Option<Weak<()>> = None;
let mut attempted_sends = 0;
let mut successful_sends = 0;
loop {
// Create a test item.
let item = Arc::new(());
let weak = Arc::downgrade(&item);
match test_tx.try_send(item) {
Ok(_) => {
prev_weak = Some(weak);
successful_sends += 1;
}
Err(ref e) if e.is_full() => {}
Err(ref e) if e.is_disconnected() => {
// Test for evidence of the race condition.
if let Some(prev_weak) = prev_weak {
if prev_weak.upgrade().is_some() {
// The previously sent item is still allocated.
// However, there appears to be some aspect of the
// concurrency that can legitimately cause the Arc
// to be momentarily valid. Spin for up to 100ms
// waiting for the previously sent item to be
// dropped.
let t0 = Instant::now();
let mut spins = 0;
loop {
if prev_weak.upgrade().is_none() {
break;
}
assert!(
t0.elapsed() < Duration::from_secs(SPIN_TIMEOUT_S),
"item not dropped on iteration {} after \
{} sends ({} successful). spin=({})",
i,
attempted_sends,
successful_sends,
spins
);
spins += 1;
thread::sleep(Duration::from_millis(SPIN_SLEEP_MS));
}
}
}
break;
}
Err(ref e) => panic!("unexpected error: {}", e),
}
attempted_sends += 1;
}
}
drop(cmd_tx);
bg.join().expect("background thread join");
}
#[test]
fn unbounded_try_next_after_none() {
let (tx, mut rx) = mpsc::unbounded::<String>();
// Drop the sender, close the channel.
drop(tx);
// Receive the end of channel.
assert_eq!(Ok(None), rx.try_next().map_err(|_| ()));
// None received, check we can call `try_next` again.
assert_eq!(Ok(None), rx.try_next().map_err(|_| ()));
}
#[test]
fn bounded_try_next_after_none() {
let (tx, mut rx) = mpsc::channel::<String>(17);
// Drop the sender, close the channel.
drop(tx);
// Receive the end of channel.
assert_eq!(Ok(None), rx.try_next().map_err(|_| ()));
// None received, check we can call `try_next` again.
assert_eq!(Ok(None), rx.try_next().map_err(|_| ()));
}

View File

@@ -0,0 +1,40 @@
use futures::channel::mpsc;
use futures::stream::Stream;
#[test]
fn unbounded_size_hint() {
let (tx, mut rx) = mpsc::unbounded::<u32>();
assert_eq!((0, None), rx.size_hint());
tx.unbounded_send(1).unwrap();
assert_eq!((1, None), rx.size_hint());
rx.try_next().unwrap().unwrap();
assert_eq!((0, None), rx.size_hint());
tx.unbounded_send(2).unwrap();
tx.unbounded_send(3).unwrap();
assert_eq!((2, None), rx.size_hint());
drop(tx);
assert_eq!((2, Some(2)), rx.size_hint());
rx.try_next().unwrap().unwrap();
assert_eq!((1, Some(1)), rx.size_hint());
rx.try_next().unwrap().unwrap();
assert_eq!((0, Some(0)), rx.size_hint());
}
#[test]
fn channel_size_hint() {
let (mut tx, mut rx) = mpsc::channel::<u32>(10);
assert_eq!((0, None), rx.size_hint());
tx.try_send(1).unwrap();
assert_eq!((1, None), rx.size_hint());
rx.try_next().unwrap().unwrap();
assert_eq!((0, None), rx.size_hint());
tx.try_send(2).unwrap();
tx.try_send(3).unwrap();
assert_eq!((2, None), rx.size_hint());
drop(tx);
assert_eq!((2, Some(2)), rx.size_hint());
rx.try_next().unwrap().unwrap();
assert_eq!((1, Some(1)), rx.size_hint());
rx.try_next().unwrap().unwrap();
assert_eq!((0, Some(0)), rx.size_hint());
}

658
vendor/futures-channel/tests/mpsc.rs vendored Normal file
View File

@@ -0,0 +1,658 @@
use futures::channel::{mpsc, oneshot};
use futures::executor::{block_on, block_on_stream};
use futures::future::{poll_fn, FutureExt};
use futures::pin_mut;
use futures::sink::{Sink, SinkExt};
use futures::stream::{Stream, StreamExt};
use futures::task::{Context, Poll};
use futures_test::task::{new_count_waker, noop_context};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
use std::thread;
#[allow(dead_code)]
trait AssertSend: Send {}
impl AssertSend for mpsc::Sender<i32> {}
impl AssertSend for mpsc::Receiver<i32> {}
#[test]
fn send_recv() {
let (mut tx, rx) = mpsc::channel::<i32>(16);
block_on(tx.send(1)).unwrap();
drop(tx);
let v: Vec<_> = block_on(rx.collect());
assert_eq!(v, vec![1]);
}
#[test]
fn send_recv_no_buffer() {
// Run on a task context
block_on(poll_fn(move |cx| {
let (tx, rx) = mpsc::channel::<i32>(0);
pin_mut!(tx, rx);
assert!(tx.as_mut().poll_flush(cx).is_ready());
assert!(tx.as_mut().poll_ready(cx).is_ready());
// Send first message
assert!(tx.as_mut().start_send(1).is_ok());
assert!(tx.as_mut().poll_ready(cx).is_pending());
// poll_ready said Pending, so no room in buffer, therefore new sends
// should get rejected with is_full.
assert!(tx.as_mut().start_send(0).unwrap_err().is_full());
assert!(tx.as_mut().poll_ready(cx).is_pending());
// Take the value
assert_eq!(rx.as_mut().poll_next(cx), Poll::Ready(Some(1)));
assert!(tx.as_mut().poll_ready(cx).is_ready());
// Send second message
assert!(tx.as_mut().poll_ready(cx).is_ready());
assert!(tx.as_mut().start_send(2).is_ok());
assert!(tx.as_mut().poll_ready(cx).is_pending());
// Take the value
assert_eq!(rx.as_mut().poll_next(cx), Poll::Ready(Some(2)));
assert!(tx.as_mut().poll_ready(cx).is_ready());
Poll::Ready(())
}));
}
#[test]
fn send_shared_recv() {
let (mut tx1, rx) = mpsc::channel::<i32>(16);
let mut rx = block_on_stream(rx);
let mut tx2 = tx1.clone();
block_on(tx1.send(1)).unwrap();
assert_eq!(rx.next(), Some(1));
block_on(tx2.send(2)).unwrap();
assert_eq!(rx.next(), Some(2));
}
#[test]
fn send_recv_threads() {
let (mut tx, rx) = mpsc::channel::<i32>(16);
let t = thread::spawn(move || {
block_on(tx.send(1)).unwrap();
});
let v: Vec<_> = block_on(rx.take(1).collect());
assert_eq!(v, vec![1]);
t.join().unwrap();
}
#[test]
fn send_recv_threads_no_capacity() {
let (mut tx, rx) = mpsc::channel::<i32>(0);
let t = thread::spawn(move || {
block_on(tx.send(1)).unwrap();
block_on(tx.send(2)).unwrap();
});
let v: Vec<_> = block_on(rx.collect());
assert_eq!(v, vec![1, 2]);
t.join().unwrap();
}
#[test]
fn recv_close_gets_none() {
let (mut tx, mut rx) = mpsc::channel::<i32>(10);
// Run on a task context
block_on(poll_fn(move |cx| {
rx.close();
assert_eq!(rx.poll_next_unpin(cx), Poll::Ready(None));
match tx.poll_ready(cx) {
Poll::Pending | Poll::Ready(Ok(_)) => panic!(),
Poll::Ready(Err(e)) => assert!(e.is_disconnected()),
};
Poll::Ready(())
}));
}
#[test]
fn tx_close_gets_none() {
let (_, mut rx) = mpsc::channel::<i32>(10);
// Run on a task context
block_on(poll_fn(move |cx| {
assert_eq!(rx.poll_next_unpin(cx), Poll::Ready(None));
Poll::Ready(())
}));
}
// #[test]
// fn spawn_sends_items() {
// let core = local_executor::Core::new();
// let stream = unfold(0, |i| Some(ok::<_,u8>((i, i + 1))));
// let rx = mpsc::spawn(stream, &core, 1);
// assert_eq!(core.run(rx.take(4).collect()).unwrap(),
// [0, 1, 2, 3]);
// }
// #[test]
// fn spawn_kill_dead_stream() {
// use std::thread;
// use std::time::Duration;
// use futures::future::Either;
// use futures::sync::oneshot;
//
// // a stream which never returns anything (maybe a remote end isn't
// // responding), but dropping it leads to observable side effects
// // (like closing connections, releasing limited resources, ...)
// #[derive(Debug)]
// struct Dead {
// // when dropped you should get Err(oneshot::Canceled) on the
// // receiving end
// done: oneshot::Sender<()>,
// }
// impl Stream for Dead {
// type Item = ();
// type Error = ();
//
// fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
// Ok(Poll::Pending)
// }
// }
//
// // need to implement a timeout for the test, as it would hang
// // forever right now
// let (timeout_tx, timeout_rx) = oneshot::channel();
// thread::spawn(move || {
// thread::sleep(Duration::from_millis(1000));
// let _ = timeout_tx.send(());
// });
//
// let core = local_executor::Core::new();
// let (done_tx, done_rx) = oneshot::channel();
// let stream = Dead{done: done_tx};
// let rx = mpsc::spawn(stream, &core, 1);
// let res = core.run(
// Ok::<_, ()>(())
// .into_future()
// .then(move |_| {
// // now drop the spawned stream: maybe some timeout exceeded,
// // or some connection on this end was closed by the remote
// // end.
// drop(rx);
// // and wait for the spawned stream to release its resources
// done_rx
// })
// .select2(timeout_rx)
// );
// match res {
// Err(Either::A((oneshot::Canceled, _))) => (),
// _ => {
// panic!("dead stream wasn't canceled");
// },
// }
// }
#[test]
fn stress_shared_unbounded() {
const AMT: u32 = if cfg!(miri) { 100 } else { 10000 };
const NTHREADS: u32 = 8;
let (tx, rx) = mpsc::unbounded::<i32>();
let t = thread::spawn(move || {
let result: Vec<_> = block_on(rx.collect());
assert_eq!(result.len(), (AMT * NTHREADS) as usize);
for item in result {
assert_eq!(item, 1);
}
});
for _ in 0..NTHREADS {
let tx = tx.clone();
thread::spawn(move || {
for _ in 0..AMT {
tx.unbounded_send(1).unwrap();
}
});
}
drop(tx);
t.join().ok().unwrap();
}
#[test]
fn stress_shared_bounded_hard() {
const AMT: u32 = if cfg!(miri) { 100 } else { 10000 };
const NTHREADS: u32 = 8;
let (tx, rx) = mpsc::channel::<i32>(0);
let t = thread::spawn(move || {
let result: Vec<_> = block_on(rx.collect());
assert_eq!(result.len(), (AMT * NTHREADS) as usize);
for item in result {
assert_eq!(item, 1);
}
});
for _ in 0..NTHREADS {
let mut tx = tx.clone();
thread::spawn(move || {
for _ in 0..AMT {
block_on(tx.send(1)).unwrap();
}
});
}
drop(tx);
t.join().unwrap();
}
#[allow(clippy::same_item_push)]
#[test]
fn stress_receiver_multi_task_bounded_hard() {
const AMT: usize = if cfg!(miri) { 100 } else { 10_000 };
const NTHREADS: u32 = 2;
let (mut tx, rx) = mpsc::channel::<usize>(0);
let rx = Arc::new(Mutex::new(Some(rx)));
let n = Arc::new(AtomicUsize::new(0));
let mut th = vec![];
for _ in 0..NTHREADS {
let rx = rx.clone();
let n = n.clone();
let t = thread::spawn(move || {
let mut i = 0;
loop {
i += 1;
let mut rx_opt = rx.lock().unwrap();
if let Some(rx) = &mut *rx_opt {
if i % 5 == 0 {
let item = block_on(rx.next());
if item.is_none() {
*rx_opt = None;
break;
}
n.fetch_add(1, Ordering::Relaxed);
} else {
// Just poll
let n = n.clone();
match rx.poll_next_unpin(&mut noop_context()) {
Poll::Ready(Some(_)) => {
n.fetch_add(1, Ordering::Relaxed);
}
Poll::Ready(None) => {
*rx_opt = None;
break;
}
Poll::Pending => {}
}
}
} else {
break;
}
}
});
th.push(t);
}
for i in 0..AMT {
block_on(tx.send(i)).unwrap();
}
drop(tx);
for t in th {
t.join().unwrap();
}
assert_eq!(AMT, n.load(Ordering::Relaxed));
}
/// Stress test that receiver properly receives all the messages
/// after sender dropped.
#[test]
fn stress_drop_sender() {
const ITER: usize = if cfg!(miri) { 100 } else { 10000 };
fn list() -> impl Stream<Item = i32> {
let (tx, rx) = mpsc::channel(1);
thread::spawn(move || {
block_on(send_one_two_three(tx));
});
rx
}
for _ in 0..ITER {
let v: Vec<_> = block_on(list().collect());
assert_eq!(v, vec![1, 2, 3]);
}
}
async fn send_one_two_three(mut tx: mpsc::Sender<i32>) {
for i in 1..=3 {
tx.send(i).await.unwrap();
}
}
/// Stress test that after receiver dropped,
/// no messages are lost.
fn stress_close_receiver_iter() {
let (tx, rx) = mpsc::unbounded();
let mut rx = block_on_stream(rx);
let (unwritten_tx, unwritten_rx) = std::sync::mpsc::channel();
let th = thread::spawn(move || {
for i in 1.. {
if tx.unbounded_send(i).is_err() {
unwritten_tx.send(i).expect("unwritten_tx");
return;
}
}
});
// Read one message to make sure thread effectively started
assert_eq!(Some(1), rx.next());
rx.close();
for i in 2.. {
match rx.next() {
Some(r) => assert!(i == r),
None => {
let unwritten = unwritten_rx.recv().expect("unwritten_rx");
assert_eq!(unwritten, i);
th.join().unwrap();
return;
}
}
}
}
#[test]
fn stress_close_receiver() {
const ITER: usize = if cfg!(miri) { 50 } else { 10000 };
for _ in 0..ITER {
stress_close_receiver_iter();
}
}
async fn stress_poll_ready_sender(mut sender: mpsc::Sender<u32>, count: u32) {
for i in (1..=count).rev() {
sender.send(i).await.unwrap();
}
}
/// Tests that after `poll_ready` indicates capacity a channel can always send without waiting.
#[allow(clippy::same_item_push)]
#[test]
fn stress_poll_ready() {
const AMT: u32 = if cfg!(miri) { 100 } else { 1000 };
const NTHREADS: u32 = 8;
/// Run a stress test using the specified channel capacity.
fn stress(capacity: usize) {
let (tx, rx) = mpsc::channel(capacity);
let mut threads = Vec::new();
for _ in 0..NTHREADS {
let sender = tx.clone();
threads.push(thread::spawn(move || block_on(stress_poll_ready_sender(sender, AMT))));
}
drop(tx);
let result: Vec<_> = block_on(rx.collect());
assert_eq!(result.len() as u32, AMT * NTHREADS);
for thread in threads {
thread.join().unwrap();
}
}
stress(0);
stress(1);
stress(8);
stress(16);
}
#[test]
fn try_send_1() {
const N: usize = if cfg!(miri) { 100 } else { 3000 };
let (mut tx, rx) = mpsc::channel(0);
let t = thread::spawn(move || {
for i in 0..N {
loop {
if tx.try_send(i).is_ok() {
break;
}
}
}
});
let result: Vec<_> = block_on(rx.collect());
for (i, j) in result.into_iter().enumerate() {
assert_eq!(i, j);
}
t.join().unwrap();
}
#[test]
fn try_send_2() {
let (mut tx, rx) = mpsc::channel(0);
let mut rx = block_on_stream(rx);
tx.try_send("hello").unwrap();
let (readytx, readyrx) = oneshot::channel::<()>();
let th = thread::spawn(move || {
block_on(poll_fn(|cx| {
assert!(tx.poll_ready(cx).is_pending());
Poll::Ready(())
}));
drop(readytx);
block_on(tx.send("goodbye")).unwrap();
});
let _ = block_on(readyrx);
assert_eq!(rx.next(), Some("hello"));
assert_eq!(rx.next(), Some("goodbye"));
assert_eq!(rx.next(), None);
th.join().unwrap();
}
#[test]
fn try_send_fail() {
let (mut tx, rx) = mpsc::channel(0);
let mut rx = block_on_stream(rx);
tx.try_send("hello").unwrap();
// This should fail
assert!(tx.try_send("fail").is_err());
assert_eq!(rx.next(), Some("hello"));
tx.try_send("goodbye").unwrap();
drop(tx);
assert_eq!(rx.next(), Some("goodbye"));
assert_eq!(rx.next(), None);
}
#[test]
fn try_send_recv() {
let (mut tx, mut rx) = mpsc::channel(1);
tx.try_send("hello").unwrap();
tx.try_send("hello").unwrap();
tx.try_send("hello").unwrap_err(); // should be full
rx.try_next().unwrap();
rx.try_next().unwrap();
rx.try_next().unwrap_err(); // should be empty
tx.try_send("hello").unwrap();
rx.try_next().unwrap();
rx.try_next().unwrap_err(); // should be empty
}
#[test]
fn same_receiver() {
let (mut txa1, _) = mpsc::channel::<i32>(1);
let txa2 = txa1.clone();
let (mut txb1, _) = mpsc::channel::<i32>(1);
let txb2 = txb1.clone();
assert!(txa1.same_receiver(&txa2));
assert!(txb1.same_receiver(&txb2));
assert!(!txa1.same_receiver(&txb1));
txa1.disconnect();
txb1.close_channel();
assert!(!txa1.same_receiver(&txa2));
assert!(txb1.same_receiver(&txb2));
}
#[test]
fn is_connected_to() {
let (txa, rxa) = mpsc::channel::<i32>(1);
let (txb, rxb) = mpsc::channel::<i32>(1);
assert!(txa.is_connected_to(&rxa));
assert!(txb.is_connected_to(&rxb));
assert!(!txa.is_connected_to(&rxb));
assert!(!txb.is_connected_to(&rxa));
}
#[test]
fn hash_receiver() {
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
let mut hasher_a1 = DefaultHasher::new();
let mut hasher_a2 = DefaultHasher::new();
let mut hasher_b1 = DefaultHasher::new();
let mut hasher_b2 = DefaultHasher::new();
let (mut txa1, _) = mpsc::channel::<i32>(1);
let txa2 = txa1.clone();
let (mut txb1, _) = mpsc::channel::<i32>(1);
let txb2 = txb1.clone();
txa1.hash_receiver(&mut hasher_a1);
let hash_a1 = hasher_a1.finish();
txa2.hash_receiver(&mut hasher_a2);
let hash_a2 = hasher_a2.finish();
txb1.hash_receiver(&mut hasher_b1);
let hash_b1 = hasher_b1.finish();
txb2.hash_receiver(&mut hasher_b2);
let hash_b2 = hasher_b2.finish();
assert_eq!(hash_a1, hash_a2);
assert_eq!(hash_b1, hash_b2);
assert!(hash_a1 != hash_b1);
txa1.disconnect();
txb1.close_channel();
let mut hasher_a1 = DefaultHasher::new();
let mut hasher_a2 = DefaultHasher::new();
let mut hasher_b1 = DefaultHasher::new();
let mut hasher_b2 = DefaultHasher::new();
txa1.hash_receiver(&mut hasher_a1);
let hash_a1 = hasher_a1.finish();
txa2.hash_receiver(&mut hasher_a2);
let hash_a2 = hasher_a2.finish();
txb1.hash_receiver(&mut hasher_b1);
let hash_b1 = hasher_b1.finish();
txb2.hash_receiver(&mut hasher_b2);
let hash_b2 = hasher_b2.finish();
assert!(hash_a1 != hash_a2);
assert_eq!(hash_b1, hash_b2);
}
#[test]
fn send_backpressure() {
let (waker, counter) = new_count_waker();
let mut cx = Context::from_waker(&waker);
let (mut tx, mut rx) = mpsc::channel(1);
block_on(tx.send(1)).unwrap();
let mut task = tx.send(2);
assert_eq!(task.poll_unpin(&mut cx), Poll::Pending);
assert_eq!(counter, 0);
let item = block_on(rx.next()).unwrap();
assert_eq!(item, 1);
assert_eq!(counter, 1);
assert_eq!(task.poll_unpin(&mut cx), Poll::Ready(Ok(())));
let item = block_on(rx.next()).unwrap();
assert_eq!(item, 2);
}
#[test]
fn send_backpressure_multi_senders() {
let (waker, counter) = new_count_waker();
let mut cx = Context::from_waker(&waker);
let (mut tx1, mut rx) = mpsc::channel(1);
let mut tx2 = tx1.clone();
block_on(tx1.send(1)).unwrap();
let mut task = tx2.send(2);
assert_eq!(task.poll_unpin(&mut cx), Poll::Pending);
assert_eq!(counter, 0);
let item = block_on(rx.next()).unwrap();
assert_eq!(item, 1);
assert_eq!(counter, 1);
assert_eq!(task.poll_unpin(&mut cx), Poll::Ready(Ok(())));
let item = block_on(rx.next()).unwrap();
assert_eq!(item, 2);
}
/// Test that empty channel has zero length and that non-empty channel has length equal to number
/// of enqueued items
#[test]
fn unbounded_len() {
let (tx, mut rx) = mpsc::unbounded();
assert_eq!(tx.len(), 0);
assert!(tx.is_empty());
tx.unbounded_send(1).unwrap();
assert_eq!(tx.len(), 1);
assert!(!tx.is_empty());
tx.unbounded_send(2).unwrap();
assert_eq!(tx.len(), 2);
assert!(!tx.is_empty());
let item = block_on(rx.next()).unwrap();
assert_eq!(item, 1);
assert_eq!(tx.len(), 1);
assert!(!tx.is_empty());
let item = block_on(rx.next()).unwrap();
assert_eq!(item, 2);
assert_eq!(tx.len(), 0);
assert!(tx.is_empty());
}

256
vendor/futures-channel/tests/oneshot.rs vendored Normal file
View File

@@ -0,0 +1,256 @@
use futures::channel::oneshot::{self, Sender};
use futures::executor::block_on;
use futures::future::{poll_fn, FutureExt};
use futures::task::{Context, Poll};
use futures_test::task::panic_waker_ref;
use std::sync::mpsc;
use std::thread;
#[test]
fn smoke_poll() {
let (mut tx, rx) = oneshot::channel::<u32>();
let mut rx = Some(rx);
let f = poll_fn(|cx| {
assert!(tx.poll_canceled(cx).is_pending());
assert!(tx.poll_canceled(cx).is_pending());
drop(rx.take());
assert!(tx.poll_canceled(cx).is_ready());
assert!(tx.poll_canceled(cx).is_ready());
Poll::Ready(())
});
block_on(f);
}
#[test]
fn cancel_notifies() {
let (mut tx, rx) = oneshot::channel::<u32>();
let t = thread::spawn(move || {
block_on(tx.cancellation());
});
drop(rx);
t.join().unwrap();
}
#[test]
fn cancel_lots() {
const N: usize = if cfg!(miri) { 100 } else { 20000 };
let (tx, rx) = mpsc::channel::<(Sender<_>, mpsc::Sender<_>)>();
let t = thread::spawn(move || {
for (mut tx, tx2) in rx {
block_on(tx.cancellation());
tx2.send(()).unwrap();
}
});
for _ in 0..N {
let (otx, orx) = oneshot::channel::<u32>();
let (tx2, rx2) = mpsc::channel();
tx.send((otx, tx2)).unwrap();
drop(orx);
rx2.recv().unwrap();
}
drop(tx);
t.join().unwrap();
}
#[test]
fn cancel_after_sender_drop_doesnt_notify() {
let (mut tx, rx) = oneshot::channel::<u32>();
let mut cx = Context::from_waker(panic_waker_ref());
assert_eq!(tx.poll_canceled(&mut cx), Poll::Pending);
drop(tx);
drop(rx);
}
#[test]
fn close() {
let (mut tx, mut rx) = oneshot::channel::<u32>();
rx.close();
block_on(poll_fn(|cx| {
match rx.poll_unpin(cx) {
Poll::Ready(Err(_)) => {}
_ => panic!(),
};
assert!(tx.poll_canceled(cx).is_ready());
Poll::Ready(())
}));
}
#[test]
fn close_wakes() {
let (mut tx, mut rx) = oneshot::channel::<u32>();
let (tx2, rx2) = mpsc::channel();
let t = thread::spawn(move || {
rx.close();
rx2.recv().unwrap();
});
block_on(tx.cancellation());
tx2.send(()).unwrap();
t.join().unwrap();
}
#[test]
fn is_canceled() {
let (tx, rx) = oneshot::channel::<u32>();
assert!(!tx.is_canceled());
drop(rx);
assert!(tx.is_canceled());
}
#[test]
fn cancel_sends() {
const N: usize = if cfg!(miri) { 100 } else { 20000 };
let (tx, rx) = mpsc::channel::<Sender<_>>();
let t = thread::spawn(move || {
for otx in rx {
let _ = otx.send(42);
}
});
for _ in 0..N {
let (otx, mut orx) = oneshot::channel::<u32>();
tx.send(otx).unwrap();
orx.close();
let _ = block_on(orx);
}
drop(tx);
t.join().unwrap();
}
// #[test]
// fn spawn_sends_items() {
// let core = local_executor::Core::new();
// let future = ok::<_, ()>(1);
// let rx = spawn(future, &core);
// assert_eq!(core.run(rx).unwrap(), 1);
// }
//
// #[test]
// fn spawn_kill_dead_stream() {
// use std::thread;
// use std::time::Duration;
// use futures::future::Either;
// use futures::sync::oneshot;
//
// // a future which never returns anything (forever accepting incoming
// // connections), but dropping it leads to observable side effects
// // (like closing listening sockets, releasing limited resources,
// // ...)
// #[derive(Debug)]
// struct Dead {
// // when dropped you should get Err(oneshot::Canceled) on the
// // receiving end
// done: oneshot::Sender<()>,
// }
// impl Future for Dead {
// type Item = ();
// type Error = ();
//
// fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
// Ok(Poll::Pending)
// }
// }
//
// // need to implement a timeout for the test, as it would hang
// // forever right now
// let (timeout_tx, timeout_rx) = oneshot::channel();
// thread::spawn(move || {
// thread::sleep(Duration::from_millis(1000));
// let _ = timeout_tx.send(());
// });
//
// let core = local_executor::Core::new();
// let (done_tx, done_rx) = oneshot::channel();
// let future = Dead{done: done_tx};
// let rx = spawn(future, &core);
// let res = core.run(
// Ok::<_, ()>(())
// .into_future()
// .then(move |_| {
// // now drop the spawned future: maybe some timeout exceeded,
// // or some connection on this end was closed by the remote
// // end.
// drop(rx);
// // and wait for the spawned future to release its resources
// done_rx
// })
// .select2(timeout_rx)
// );
// match res {
// Err(Either::A((oneshot::Canceled, _))) => (),
// Ok(Either::B(((), _))) => {
// panic!("dead future wasn't canceled (timeout)");
// },
// _ => {
// panic!("dead future wasn't canceled (unexpected result)");
// },
// }
// }
//
// #[test]
// fn spawn_dont_kill_forgot_dead_stream() {
// use std::thread;
// use std::time::Duration;
// use futures::future::Either;
// use futures::sync::oneshot;
//
// // a future which never returns anything (forever accepting incoming
// // connections), but dropping it leads to observable side effects
// // (like closing listening sockets, releasing limited resources,
// // ...)
// #[derive(Debug)]
// struct Dead {
// // when dropped you should get Err(oneshot::Canceled) on the
// // receiving end
// done: oneshot::Sender<()>,
// }
// impl Future for Dead {
// type Item = ();
// type Error = ();
//
// fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
// Ok(Poll::Pending)
// }
// }
//
// // need to implement a timeout for the test, as it would hang
// // forever right now
// let (timeout_tx, timeout_rx) = oneshot::channel();
// thread::spawn(move || {
// thread::sleep(Duration::from_millis(1000));
// let _ = timeout_tx.send(());
// });
//
// let core = local_executor::Core::new();
// let (done_tx, done_rx) = oneshot::channel();
// let future = Dead{done: done_tx};
// let rx = spawn(future, &core);
// let res = core.run(
// Ok::<_, ()>(())
// .into_future()
// .then(move |_| {
// // forget the spawned future: should keep running, i.e. hit
// // the timeout below.
// rx.forget();
// // and wait for the spawned future to release its resources
// done_rx
// })
// .select2(timeout_rx)
// );
// match res {
// Err(Either::A((oneshot::Canceled, _))) => {
// panic!("forgotten dead future was canceled");
// },
// Ok(Either::B(((), _))) => (), // reached timeout
// _ => {
// panic!("forgotten dead future was canceled (unexpected result)");
// },
// }
// }