338 lines
11 KiB
Rust
338 lines
11 KiB
Rust
|
//! Combinators and utilities for working with `Future`s, `Stream`s, `Sink`s,
|
||
|
//! and the `AsyncRead` and `AsyncWrite` traits.
|
||
|
|
||
|
#![cfg_attr(feature = "write-all-vectored", feature(io_slice_advance))]
|
||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||
|
#![warn(
|
||
|
missing_debug_implementations,
|
||
|
missing_docs,
|
||
|
rust_2018_idioms,
|
||
|
single_use_lifetimes,
|
||
|
unreachable_pub
|
||
|
)]
|
||
|
#![doc(test(
|
||
|
no_crate_inject,
|
||
|
attr(
|
||
|
deny(warnings, rust_2018_idioms, single_use_lifetimes),
|
||
|
allow(dead_code, unused_assignments, unused_variables)
|
||
|
)
|
||
|
))]
|
||
|
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||
|
|
||
|
#[cfg(all(feature = "bilock", not(feature = "unstable")))]
|
||
|
compile_error!("The `bilock` feature requires the `unstable` feature as an explicit opt-in to unstable features");
|
||
|
|
||
|
#[cfg(feature = "alloc")]
|
||
|
extern crate alloc;
|
||
|
|
||
|
// Macro re-exports
|
||
|
pub use futures_core::ready;
|
||
|
pub use pin_utils::pin_mut;
|
||
|
|
||
|
#[cfg(feature = "async-await")]
|
||
|
#[macro_use]
|
||
|
mod async_await;
|
||
|
#[cfg(feature = "async-await")]
|
||
|
#[doc(hidden)]
|
||
|
pub use self::async_await::*;
|
||
|
|
||
|
// Not public API.
|
||
|
#[cfg(feature = "async-await")]
|
||
|
#[doc(hidden)]
|
||
|
pub mod __private {
|
||
|
pub use crate::*;
|
||
|
pub use core::{
|
||
|
option::Option::{self, None, Some},
|
||
|
pin::Pin,
|
||
|
result::Result::{Err, Ok},
|
||
|
};
|
||
|
|
||
|
pub mod async_await {
|
||
|
pub use crate::async_await::*;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[cfg(feature = "sink")]
|
||
|
macro_rules! delegate_sink {
|
||
|
($field:ident, $item:ty) => {
|
||
|
fn poll_ready(
|
||
|
self: core::pin::Pin<&mut Self>,
|
||
|
cx: &mut core::task::Context<'_>,
|
||
|
) -> core::task::Poll<Result<(), Self::Error>> {
|
||
|
self.project().$field.poll_ready(cx)
|
||
|
}
|
||
|
|
||
|
fn start_send(self: core::pin::Pin<&mut Self>, item: $item) -> Result<(), Self::Error> {
|
||
|
self.project().$field.start_send(item)
|
||
|
}
|
||
|
|
||
|
fn poll_flush(
|
||
|
self: core::pin::Pin<&mut Self>,
|
||
|
cx: &mut core::task::Context<'_>,
|
||
|
) -> core::task::Poll<Result<(), Self::Error>> {
|
||
|
self.project().$field.poll_flush(cx)
|
||
|
}
|
||
|
|
||
|
fn poll_close(
|
||
|
self: core::pin::Pin<&mut Self>,
|
||
|
cx: &mut core::task::Context<'_>,
|
||
|
) -> core::task::Poll<Result<(), Self::Error>> {
|
||
|
self.project().$field.poll_close(cx)
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
macro_rules! delegate_future {
|
||
|
($field:ident) => {
|
||
|
fn poll(
|
||
|
self: core::pin::Pin<&mut Self>,
|
||
|
cx: &mut core::task::Context<'_>,
|
||
|
) -> core::task::Poll<Self::Output> {
|
||
|
self.project().$field.poll(cx)
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
macro_rules! delegate_stream {
|
||
|
($field:ident) => {
|
||
|
fn poll_next(
|
||
|
self: core::pin::Pin<&mut Self>,
|
||
|
cx: &mut core::task::Context<'_>,
|
||
|
) -> core::task::Poll<Option<Self::Item>> {
|
||
|
self.project().$field.poll_next(cx)
|
||
|
}
|
||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||
|
self.$field.size_hint()
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
#[cfg(feature = "io")]
|
||
|
#[cfg(feature = "std")]
|
||
|
macro_rules! delegate_async_write {
|
||
|
($field:ident) => {
|
||
|
fn poll_write(
|
||
|
self: core::pin::Pin<&mut Self>,
|
||
|
cx: &mut core::task::Context<'_>,
|
||
|
buf: &[u8],
|
||
|
) -> core::task::Poll<std::io::Result<usize>> {
|
||
|
self.project().$field.poll_write(cx, buf)
|
||
|
}
|
||
|
fn poll_write_vectored(
|
||
|
self: core::pin::Pin<&mut Self>,
|
||
|
cx: &mut core::task::Context<'_>,
|
||
|
bufs: &[std::io::IoSlice<'_>],
|
||
|
) -> core::task::Poll<std::io::Result<usize>> {
|
||
|
self.project().$field.poll_write_vectored(cx, bufs)
|
||
|
}
|
||
|
fn poll_flush(
|
||
|
self: core::pin::Pin<&mut Self>,
|
||
|
cx: &mut core::task::Context<'_>,
|
||
|
) -> core::task::Poll<std::io::Result<()>> {
|
||
|
self.project().$field.poll_flush(cx)
|
||
|
}
|
||
|
fn poll_close(
|
||
|
self: core::pin::Pin<&mut Self>,
|
||
|
cx: &mut core::task::Context<'_>,
|
||
|
) -> core::task::Poll<std::io::Result<()>> {
|
||
|
self.project().$field.poll_close(cx)
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
#[cfg(feature = "io")]
|
||
|
#[cfg(feature = "std")]
|
||
|
macro_rules! delegate_async_read {
|
||
|
($field:ident) => {
|
||
|
fn poll_read(
|
||
|
self: core::pin::Pin<&mut Self>,
|
||
|
cx: &mut core::task::Context<'_>,
|
||
|
buf: &mut [u8],
|
||
|
) -> core::task::Poll<std::io::Result<usize>> {
|
||
|
self.project().$field.poll_read(cx, buf)
|
||
|
}
|
||
|
|
||
|
fn poll_read_vectored(
|
||
|
self: core::pin::Pin<&mut Self>,
|
||
|
cx: &mut core::task::Context<'_>,
|
||
|
bufs: &mut [std::io::IoSliceMut<'_>],
|
||
|
) -> core::task::Poll<std::io::Result<usize>> {
|
||
|
self.project().$field.poll_read_vectored(cx, bufs)
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
#[cfg(feature = "io")]
|
||
|
#[cfg(feature = "std")]
|
||
|
macro_rules! delegate_async_buf_read {
|
||
|
($field:ident) => {
|
||
|
fn poll_fill_buf(
|
||
|
self: core::pin::Pin<&mut Self>,
|
||
|
cx: &mut core::task::Context<'_>,
|
||
|
) -> core::task::Poll<std::io::Result<&[u8]>> {
|
||
|
self.project().$field.poll_fill_buf(cx)
|
||
|
}
|
||
|
|
||
|
fn consume(self: core::pin::Pin<&mut Self>, amt: usize) {
|
||
|
self.project().$field.consume(amt)
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
macro_rules! delegate_access_inner {
|
||
|
($field:ident, $inner:ty, ($($ind:tt)*)) => {
|
||
|
/// Acquires a reference to the underlying sink or stream that this combinator is
|
||
|
/// pulling from.
|
||
|
pub fn get_ref(&self) -> &$inner {
|
||
|
(&self.$field) $($ind get_ref())*
|
||
|
}
|
||
|
|
||
|
/// Acquires a mutable reference to the underlying sink or stream that this
|
||
|
/// combinator is pulling from.
|
||
|
///
|
||
|
/// Note that care must be taken to avoid tampering with the state of the
|
||
|
/// sink or stream which may otherwise confuse this combinator.
|
||
|
pub fn get_mut(&mut self) -> &mut $inner {
|
||
|
(&mut self.$field) $($ind get_mut())*
|
||
|
}
|
||
|
|
||
|
/// Acquires a pinned mutable reference to the underlying sink or stream that this
|
||
|
/// combinator is pulling from.
|
||
|
///
|
||
|
/// Note that care must be taken to avoid tampering with the state of the
|
||
|
/// sink or stream which may otherwise confuse this combinator.
|
||
|
pub fn get_pin_mut(self: core::pin::Pin<&mut Self>) -> core::pin::Pin<&mut $inner> {
|
||
|
self.project().$field $($ind get_pin_mut())*
|
||
|
}
|
||
|
|
||
|
/// Consumes this combinator, returning the underlying sink or stream.
|
||
|
///
|
||
|
/// Note that this may discard intermediate state of this combinator, so
|
||
|
/// care should be taken to avoid losing resources when this is called.
|
||
|
pub fn into_inner(self) -> $inner {
|
||
|
self.$field $($ind into_inner())*
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
macro_rules! delegate_all {
|
||
|
(@trait Future $name:ident < $($arg:ident),* > ($t:ty) $(where $($bound:tt)*)*) => {
|
||
|
impl<$($arg),*> futures_core::future::Future for $name<$($arg),*> where $t: futures_core::future::Future $(, $($bound)*)* {
|
||
|
type Output = <$t as futures_core::future::Future>::Output;
|
||
|
|
||
|
delegate_future!(inner);
|
||
|
}
|
||
|
};
|
||
|
(@trait FusedFuture $name:ident < $($arg:ident),* > ($t:ty) $(where $($bound:tt)*)*) => {
|
||
|
impl<$($arg),*> futures_core::future::FusedFuture for $name<$($arg),*> where $t: futures_core::future::FusedFuture $(, $($bound)*)* {
|
||
|
fn is_terminated(&self) -> bool {
|
||
|
self.inner.is_terminated()
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
(@trait Stream $name:ident < $($arg:ident),* > ($t:ty) $(where $($bound:tt)*)*) => {
|
||
|
impl<$($arg),*> futures_core::stream::Stream for $name<$($arg),*> where $t: futures_core::stream::Stream $(, $($bound)*)* {
|
||
|
type Item = <$t as futures_core::stream::Stream>::Item;
|
||
|
|
||
|
delegate_stream!(inner);
|
||
|
}
|
||
|
};
|
||
|
(@trait FusedStream $name:ident < $($arg:ident),* > ($t:ty) $(where $($bound:tt)*)*) => {
|
||
|
impl<$($arg),*> futures_core::stream::FusedStream for $name<$($arg),*> where $t: futures_core::stream::FusedStream $(, $($bound)*)* {
|
||
|
fn is_terminated(&self) -> bool {
|
||
|
self.inner.is_terminated()
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
(@trait Sink $name:ident < $($arg:ident),* > ($t:ty) $(where $($bound:tt)*)*) => {
|
||
|
#[cfg(feature = "sink")]
|
||
|
impl<_Item, $($arg),*> futures_sink::Sink<_Item> for $name<$($arg),*> where $t: futures_sink::Sink<_Item> $(, $($bound)*)* {
|
||
|
type Error = <$t as futures_sink::Sink<_Item>>::Error;
|
||
|
|
||
|
delegate_sink!(inner, _Item);
|
||
|
}
|
||
|
};
|
||
|
(@trait Debug $name:ident < $($arg:ident),* > ($t:ty) $(where $($bound:tt)*)*) => {
|
||
|
impl<$($arg),*> core::fmt::Debug for $name<$($arg),*> where $t: core::fmt::Debug $(, $($bound)*)* {
|
||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||
|
core::fmt::Debug::fmt(&self.inner, f)
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
(@trait AccessInner[$inner:ty, ($($ind:tt)*)] $name:ident < $($arg:ident),* > ($t:ty) $(where $($bound:tt)*)*) => {
|
||
|
impl<$($arg),*> $name<$($arg),*> $(where $($bound)*)* {
|
||
|
delegate_access_inner!(inner, $inner, ($($ind)*));
|
||
|
}
|
||
|
};
|
||
|
(@trait New[|$($param:ident: $paramt:ty),*| $cons:expr] $name:ident < $($arg:ident),* > ($t:ty) $(where $($bound:tt)*)*) => {
|
||
|
impl<$($arg),*> $name<$($arg),*> $(where $($bound)*)* {
|
||
|
pub(crate) fn new($($param: $paramt),*) -> Self {
|
||
|
Self { inner: $cons }
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
($(#[$attr:meta])* $name:ident<$($arg:ident),*>($t:ty) : $ftrait:ident $([$($targs:tt)*])* $({$($item:tt)*})* $(where $($bound:tt)*)*) => {
|
||
|
pin_project_lite::pin_project! {
|
||
|
#[must_use = "futures/streams/sinks do nothing unless you `.await` or poll them"]
|
||
|
$(#[$attr])*
|
||
|
pub struct $name< $($arg),* > $(where $($bound)*)* { #[pin] inner: $t }
|
||
|
}
|
||
|
|
||
|
impl<$($arg),*> $name< $($arg),* > $(where $($bound)*)* {
|
||
|
$($($item)*)*
|
||
|
}
|
||
|
|
||
|
delegate_all!(@trait $ftrait $([$($targs)*])* $name<$($arg),*>($t) $(where $($bound)*)*);
|
||
|
};
|
||
|
($(#[$attr:meta])* $name:ident<$($arg:ident),*>($t:ty) : $ftrait:ident $([$($ftargs:tt)*])* + $strait:ident $([$($stargs:tt)*])* $(+ $trait:ident $([$($targs:tt)*])*)* $({$($item:tt)*})* $(where $($bound:tt)*)*) => {
|
||
|
delegate_all!($(#[$attr])* $name<$($arg),*>($t) : $strait $([$($stargs)*])* $(+ $trait $([$($targs)*])*)* $({$($item)*})* $(where $($bound)*)*);
|
||
|
|
||
|
delegate_all!(@trait $ftrait $([$($ftargs)*])* $name<$($arg),*>($t) $(where $($bound)*)*);
|
||
|
};
|
||
|
}
|
||
|
|
||
|
pub mod future;
|
||
|
#[doc(no_inline)]
|
||
|
pub use crate::future::{Future, FutureExt, TryFuture, TryFutureExt};
|
||
|
|
||
|
pub mod stream;
|
||
|
#[doc(no_inline)]
|
||
|
pub use crate::stream::{Stream, StreamExt, TryStream, TryStreamExt};
|
||
|
|
||
|
#[cfg(feature = "sink")]
|
||
|
#[cfg_attr(docsrs, doc(cfg(feature = "sink")))]
|
||
|
pub mod sink;
|
||
|
#[cfg(feature = "sink")]
|
||
|
#[doc(no_inline)]
|
||
|
pub use crate::sink::{Sink, SinkExt};
|
||
|
|
||
|
pub mod task;
|
||
|
|
||
|
pub mod never;
|
||
|
|
||
|
#[cfg(feature = "compat")]
|
||
|
#[cfg_attr(docsrs, doc(cfg(feature = "compat")))]
|
||
|
pub mod compat;
|
||
|
|
||
|
#[cfg(feature = "io")]
|
||
|
#[cfg_attr(docsrs, doc(cfg(feature = "io")))]
|
||
|
#[cfg(feature = "std")]
|
||
|
pub mod io;
|
||
|
#[cfg(feature = "io")]
|
||
|
#[cfg(feature = "std")]
|
||
|
#[doc(no_inline)]
|
||
|
pub use crate::io::{
|
||
|
AsyncBufRead, AsyncBufReadExt, AsyncRead, AsyncReadExt, AsyncSeek, AsyncSeekExt, AsyncWrite,
|
||
|
AsyncWriteExt,
|
||
|
};
|
||
|
|
||
|
#[cfg(feature = "alloc")]
|
||
|
pub mod lock;
|
||
|
|
||
|
#[cfg(not(futures_no_atomic_cas))]
|
||
|
#[cfg(feature = "alloc")]
|
||
|
mod abortable;
|
||
|
|
||
|
mod fns;
|
||
|
mod unfold_state;
|