2
0
Fork 1
mirror of https://github.com/async-rs/async-std.git synced 2025-04-24 01:06:46 +00:00
241: Simplify extension traits using a macro r=yoshuawuyts a=stjepang

This PR would fix #235 

Async methods in our extension traits are now written in the simpler `-> impl Future<Output = T> [ConcreteFuture<Self>]` style. At the same time, doc tests are used even when the `docs` feature is not enabled.

Co-authored-by: Stjepan Glavina <stjepang@gmail.com>
This commit is contained in:
bors[bot] 2019-09-27 11:36:32 +00:00 committed by GitHub
commit f6a2393fb5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 1902 additions and 1929 deletions

View file

@ -13,190 +13,218 @@ use cfg_if::cfg_if;
use crate::io; use crate::io;
use crate::task::{Context, Poll}; use crate::task::{Context, Poll};
use crate::utils::extension_trait;
cfg_if! { cfg_if! {
if #[cfg(feature = "docs")] { if #[cfg(feature = "docs")] {
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
}
}
#[doc(hidden)] extension_trait! {
pub struct ImplFuture<'a, T>(std::marker::PhantomData<&'a T>); #[doc = r#"
Allows reading from a buffered byte stream.
/// Allows reading from a buffered byte stream. This trait is a re-export of [`futures::io::AsyncBufRead`] and is an async version of
/// [`std::io::BufRead`].
/// This trait is a re-export of [`futures::io::AsyncBufRead`] and is an async version of
/// [`std::io::BufRead`]. The [provided methods] do not really exist in the trait itself, but they become
/// available when the prelude is imported:
/// The [provided methods] do not really exist in the trait itself, but they become
/// available when the prelude is imported: ```
/// # #[allow(unused_imports)]
/// ``` use async_std::prelude::*;
/// # #[allow(unused_imports)] ```
/// use async_std::prelude::*;
/// ``` [`std::io::BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html
/// [`futures::io::AsyncBufRead`]:
/// [`std::io::BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncBufRead.html
/// [`futures::io::AsyncBufRead`]: [provided methods]: #provided-methods
/// https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncBufRead.html "#]
/// [provided methods]: #provided-methods pub trait BufRead [BufReadExt: futures_io::AsyncBufRead] {
pub trait BufRead { #[doc = r#"
/// Returns the contents of the internal buffer, filling it with more data from the Returns the contents of the internal buffer, filling it with more data from the
/// inner reader if it is empty. inner reader if it is empty.
///
/// This function is a lower-level call. It needs to be paired with the [`consume`] This function is a lower-level call. It needs to be paired with the [`consume`]
/// method to function properly. When calling this method, none of the contents will be method to function properly. When calling this method, none of the contents will be
/// "read" in the sense that later calling `read` may return the same contents. As "read" in the sense that later calling `read` may return the same contents. As
/// such, [`consume`] must be called with the number of bytes that are consumed from such, [`consume`] must be called with the number of bytes that are consumed from
/// this buffer to ensure that the bytes are never returned twice. this buffer to ensure that the bytes are never returned twice.
///
/// [`consume`]: #tymethod.consume [`consume`]: #tymethod.consume
///
/// An empty buffer returned indicates that the stream has reached EOF. An empty buffer returned indicates that the stream has reached EOF.
"#]
// TODO: write a proper doctest with `consume` // TODO: write a proper doctest with `consume`
fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>>; fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>>;
/// Tells this buffer that `amt` bytes have been consumed from the buffer, so they #[doc = r#"
/// should no longer be returned in calls to `read`. Tells this buffer that `amt` bytes have been consumed from the buffer, so they
should no longer be returned in calls to `read`.
"#]
fn consume(self: Pin<&mut Self>, amt: usize); fn consume(self: Pin<&mut Self>, amt: usize);
/// Reads all bytes into `buf` until the delimiter `byte` or EOF is reached. #[doc = r#"
/// Reads all bytes into `buf` until the delimiter `byte` or EOF is reached.
/// This function will read bytes from the underlying stream until the delimiter or EOF
/// is found. Once found, all bytes up to, and including, the delimiter (if found) will This function will read bytes from the underlying stream until the delimiter or EOF
/// be appended to `buf`. is found. Once found, all bytes up to, and including, the delimiter (if found) will
/// be appended to `buf`.
/// If successful, this function will return the total number of bytes read.
/// If successful, this function will return the total number of bytes read.
/// # Examples
/// # Examples
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { ```no_run
/// # # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::fs::File; #
/// use async_std::io::BufReader; use async_std::fs::File;
/// use async_std::prelude::*; use async_std::io::BufReader;
/// use async_std::prelude::*;
/// let mut file = BufReader::new(File::open("a.txt").await?);
/// let mut file = BufReader::new(File::open("a.txt").await?);
/// let mut buf = Vec::with_capacity(1024);
/// let n = file.read_until(b'\n', &mut buf).await?; let mut buf = Vec::with_capacity(1024);
/// # let n = file.read_until(b'\n', &mut buf).await?;
/// # Ok(()) }) } #
/// ``` # Ok(()) }) }
/// ```
/// Multiple successful calls to `read_until` append all bytes up to and including to
/// `buf`: Multiple successful calls to `read_until` append all bytes up to and including to
/// ``` `buf`:
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { ```
/// # # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::io::BufReader; #
/// use async_std::prelude::*; use async_std::io::BufReader;
/// use async_std::prelude::*;
/// let from: &[u8] = b"append\nexample\n";
/// let mut reader = BufReader::new(from); let from: &[u8] = b"append\nexample\n";
/// let mut buf = vec![]; let mut reader = BufReader::new(from);
/// let mut buf = vec![];
/// let mut size = reader.read_until(b'\n', &mut buf).await?;
/// assert_eq!(size, 7); let mut size = reader.read_until(b'\n', &mut buf).await?;
/// assert_eq!(buf, b"append\n"); assert_eq!(size, 7);
/// assert_eq!(buf, b"append\n");
/// size += reader.read_until(b'\n', &mut buf).await?;
/// assert_eq!(size, from.len()); size += reader.read_until(b'\n', &mut buf).await?;
/// assert_eq!(size, from.len());
/// assert_eq!(buf, from);
/// # assert_eq!(buf, from);
/// # Ok(()) }) } #
/// ``` # Ok(()) }) }
```
"#]
fn read_until<'a>( fn read_until<'a>(
&'a mut self, &'a mut self,
byte: u8, byte: u8,
buf: &'a mut Vec<u8>, buf: &'a mut Vec<u8>,
) -> ImplFuture<'a, io::Result<usize>> ) -> impl Future<Output = usize> + 'a [ReadUntilFuture<'a, Self>]
where where
Self: Unpin, Self: Unpin,
{ {
unreachable!() ReadUntilFuture {
reader: self,
byte,
buf,
read: 0,
}
} }
/// Reads all bytes and appends them into `buf` until a newline (the 0xA byte) is #[doc = r#"
/// reached. Reads all bytes and appends them into `buf` until a newline (the 0xA byte) is
/// reached.
/// This function will read bytes from the underlying stream until the newline
/// delimiter (the 0xA byte) or EOF is found. Once found, all bytes up to, and This function will read bytes from the underlying stream until the newline
/// including, the delimiter (if found) will be appended to `buf`. delimiter (the 0xA byte) or EOF is found. Once found, all bytes up to, and
/// including, the delimiter (if found) will be appended to `buf`.
/// If successful, this function will return the total number of bytes read.
/// If successful, this function will return the total number of bytes read.
/// If this function returns `Ok(0)`, the stream has reached EOF.
/// If this function returns `Ok(0)`, the stream has reached EOF.
/// # Errors
/// # Errors
/// This function has the same error semantics as [`read_until`] and will also return
/// an error if the read bytes are not valid UTF-8. If an I/O error is encountered then This function has the same error semantics as [`read_until`] and will also return
/// `buf` may contain some bytes already read in the event that all data read so far an error if the read bytes are not valid UTF-8. If an I/O error is encountered then
/// was valid UTF-8. `buf` may contain some bytes already read in the event that all data read so far
/// was valid UTF-8.
/// [`read_until`]: #method.read_until
/// [`read_until`]: #method.read_until
/// # Examples
/// # Examples
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { ```no_run
/// # # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::fs::File; #
/// use async_std::io::BufReader; use async_std::fs::File;
/// use async_std::prelude::*; use async_std::io::BufReader;
/// use async_std::prelude::*;
/// let mut file = BufReader::new(File::open("a.txt").await?);
/// let mut file = BufReader::new(File::open("a.txt").await?);
/// let mut buf = String::new();
/// file.read_line(&mut buf).await?; let mut buf = String::new();
/// # file.read_line(&mut buf).await?;
/// # Ok(()) }) } #
/// ``` # Ok(()) }) }
```
"#]
fn read_line<'a>( fn read_line<'a>(
&'a mut self, &'a mut self,
buf: &'a mut String, buf: &'a mut String,
) -> ImplFuture<'a, io::Result<usize>> ) -> impl Future<Output = io::Result<usize>> + 'a [ReadLineFuture<'a, Self>]
where where
Self: Unpin, Self: Unpin,
{ {
unreachable!() ReadLineFuture {
reader: self,
bytes: unsafe { mem::replace(buf.as_mut_vec(), Vec::new()) },
buf,
read: 0,
}
} }
/// Returns a stream over the lines of this byte stream. #[doc = r#"
/// Returns a stream over the lines of this byte stream.
/// The stream returned from this function will yield instances of
/// [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline byte The stream returned from this function will yield instances of
/// (the 0xA byte) or CRLF (0xD, 0xA bytes) at the end. [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline byte
/// (the 0xA byte) or CRLF (0xD, 0xA bytes) at the end.
/// [`io::Result`]: type.Result.html
/// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html [`io::Result`]: type.Result.html
/// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html
/// # Examples
/// # Examples
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { ```no_run
/// # # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::fs::File; #
/// use async_std::io::BufReader; use async_std::fs::File;
/// use async_std::prelude::*; use async_std::io::BufReader;
/// use async_std::prelude::*;
/// let file = File::open("a.txt").await?;
/// let mut lines = BufReader::new(file).lines(); let file = File::open("a.txt").await?;
/// let mut count = 0; let mut lines = BufReader::new(file).lines();
/// let mut count = 0;
/// while let Some(line) = lines.next().await {
/// line?; while let Some(line) = lines.next().await {
/// count += 1; line?;
/// } count += 1;
/// # }
/// # Ok(()) }) } #
/// ``` # Ok(()) }) }
```
"#]
fn lines(self) -> Lines<Self> fn lines(self) -> Lines<Self>
where where
Self: Unpin + Sized, Self: Unpin + Sized,
{ {
unreachable!() Lines {
reader: self,
buf: String::new(),
bytes: Vec::new(),
read: 0,
}
} }
} }
@ -205,11 +233,11 @@ cfg_if! {
self: Pin<&mut Self>, self: Pin<&mut Self>,
cx: &mut Context<'_>, cx: &mut Context<'_>,
) -> Poll<io::Result<&[u8]>> { ) -> Poll<io::Result<&[u8]>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
fn consume(self: Pin<&mut Self>, amt: usize) { fn consume(self: Pin<&mut Self>, amt: usize) {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
} }
@ -218,11 +246,11 @@ cfg_if! {
self: Pin<&mut Self>, self: Pin<&mut Self>,
cx: &mut Context<'_>, cx: &mut Context<'_>,
) -> Poll<io::Result<&[u8]>> { ) -> Poll<io::Result<&[u8]>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
fn consume(self: Pin<&mut Self>, amt: usize) { fn consume(self: Pin<&mut Self>, amt: usize) {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
} }
@ -235,11 +263,11 @@ cfg_if! {
self: Pin<&mut Self>, self: Pin<&mut Self>,
cx: &mut Context<'_>, cx: &mut Context<'_>,
) -> Poll<io::Result<&[u8]>> { ) -> Poll<io::Result<&[u8]>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
fn consume(self: Pin<&mut Self>, amt: usize) { fn consume(self: Pin<&mut Self>, amt: usize) {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
} }
@ -252,55 +280,11 @@ cfg_if! {
} }
fn consume(self: Pin<&mut Self>, amt: usize) { fn consume(self: Pin<&mut Self>, amt: usize) {
unreachable!() unreachable!("this impl only appears in the rendered docs")
}
}
} else {
pub use futures_io::AsyncBufRead as BufRead;
}
}
#[doc(hidden)]
pub trait BufReadExt: futures_io::AsyncBufRead {
fn read_until<'a>(&'a mut self, byte: u8, buf: &'a mut Vec<u8>) -> ReadUntilFuture<'a, Self>
where
Self: Unpin,
{
ReadUntilFuture {
reader: self,
byte,
buf,
read: 0,
}
}
fn read_line<'a>(&'a mut self, buf: &'a mut String) -> ReadLineFuture<'a, Self>
where
Self: Unpin,
{
ReadLineFuture {
reader: self,
bytes: unsafe { mem::replace(buf.as_mut_vec(), Vec::new()) },
buf,
read: 0,
}
}
fn lines(self) -> Lines<Self>
where
Self: Unpin + Sized,
{
Lines {
reader: self,
buf: String::new(),
bytes: Vec::new(),
read: 0,
} }
} }
} }
impl<T: futures_io::AsyncBufRead + ?Sized> BufReadExt for T {}
pub fn read_until_internal<R: BufReadExt + ?Sized>( pub fn read_until_internal<R: BufReadExt + ?Sized>(
mut reader: Pin<&mut R>, mut reader: Pin<&mut R>,
cx: &mut Context<'_>, cx: &mut Context<'_>,

View file

@ -10,11 +10,11 @@ use read_to_end::{read_to_end_internal, ReadToEndFuture};
use read_to_string::ReadToStringFuture; use read_to_string::ReadToStringFuture;
use read_vectored::ReadVectoredFuture; use read_vectored::ReadVectoredFuture;
use cfg_if::cfg_if;
use std::mem; use std::mem;
use cfg_if::cfg_if;
use crate::io::IoSliceMut; use crate::io::IoSliceMut;
use crate::utils::extension_trait;
cfg_if! { cfg_if! {
if #[cfg(feature = "docs")] { if #[cfg(feature = "docs")] {
@ -23,210 +23,243 @@ cfg_if! {
use crate::io; use crate::io;
use crate::task::{Context, Poll}; use crate::task::{Context, Poll};
}
}
#[doc(hidden)] extension_trait! {
pub struct ImplFuture<'a, T>(std::marker::PhantomData<&'a T>); #[doc = r#"
Allows reading from a byte stream.
/// Allows reading from a byte stream. This trait is a re-export of [`futures::io::AsyncRead`] and is an async version of
/// [`std::io::Read`].
/// This trait is a re-export of [`futures::io::AsyncRead`] and is an async version of
/// [`std::io::Read`]. Methods other than [`poll_read`] and [`poll_read_vectored`] do not really exist in the
/// trait itself, but they become available when the prelude is imported:
/// Methods other than [`poll_read`] and [`poll_read_vectored`] do not really exist in the
/// trait itself, but they become available when the prelude is imported: ```
/// # #[allow(unused_imports)]
/// ``` use async_std::prelude::*;
/// # #[allow(unused_imports)] ```
/// use async_std::prelude::*;
/// ``` [`std::io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
/// [`futures::io::AsyncRead`]:
/// [`std::io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncRead.html
/// [`futures::io::AsyncRead`]: [`poll_read`]: #tymethod.poll_read
/// https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncRead.html [`poll_read_vectored`]: #method.poll_read_vectored
/// [`poll_read`]: #tymethod.poll_read "#]
/// [`poll_read_vectored`]: #method.poll_read_vectored pub trait Read [ReadExt: futures_io::AsyncRead] {
pub trait Read { #[doc = r#"
/// Attempt to read from the `AsyncRead` into `buf`. Attempt to read from the `AsyncRead` into `buf`.
"#]
fn poll_read( fn poll_read(
self: Pin<&mut Self>, self: Pin<&mut Self>,
cx: &mut Context<'_>, cx: &mut Context<'_>,
buf: &mut [u8], buf: &mut [u8],
) -> Poll<io::Result<usize>>; ) -> Poll<io::Result<usize>>;
/// Attempt to read from the `AsyncRead` into `bufs` using vectored IO operations. #[doc = r#"
Attempt to read from the `AsyncRead` into `bufs` using vectored IO operations.
"#]
fn poll_read_vectored( fn poll_read_vectored(
self: Pin<&mut Self>, self: Pin<&mut Self>,
cx: &mut Context<'_>, cx: &mut Context<'_>,
bufs: &mut [IoSliceMut<'_>], bufs: &mut [IoSliceMut<'_>],
) -> Poll<io::Result<usize>> { ) -> Poll<io::Result<usize>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
/// Reads some bytes from the byte stream. #[doc = r#"
/// Reads some bytes from the byte stream.
/// Returns the number of bytes read from the start of the buffer.
/// Returns the number of bytes read from the start of the buffer.
/// If the return value is `Ok(n)`, then it must be guaranteed that
/// `0 <= n <= buf.len()`. A nonzero `n` value indicates that the buffer has been If the return value is `Ok(n)`, then it must be guaranteed that
/// filled in with `n` bytes of data. If `n` is `0`, then it can indicate one of two `0 <= n <= buf.len()`. A nonzero `n` value indicates that the buffer has been
/// scenarios: filled in with `n` bytes of data. If `n` is `0`, then it can indicate one of two
/// scenarios:
/// 1. This reader has reached its "end of file" and will likely no longer be able to
/// produce bytes. Note that this does not mean that the reader will always no 1. This reader has reached its "end of file" and will likely no longer be able to
/// longer be able to produce bytes. produce bytes. Note that this does not mean that the reader will always no
/// 2. The buffer specified was 0 bytes in length. longer be able to produce bytes.
/// 2. The buffer specified was 0 bytes in length.
/// # Examples
/// # Examples
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { ```no_run
/// # # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::fs::File; #
/// use async_std::prelude::*; use async_std::fs::File;
/// use async_std::prelude::*;
/// let mut file = File::open("a.txt").await?;
/// let mut file = File::open("a.txt").await?;
/// let mut buf = vec![0; 1024];
/// let n = file.read(&mut buf).await?; let mut buf = vec![0; 1024];
/// # let n = file.read(&mut buf).await?;
/// # Ok(()) }) } #
/// ``` # Ok(()) }) }
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> ImplFuture<'a, io::Result<usize>> ```
"#]
fn read<'a>(
&'a mut self,
buf: &'a mut [u8],
) -> impl Future<Output = io::Result<usize>> + 'a [ReadFuture<'a, Self>]
where where
Self: Unpin Self: Unpin
{ {
unreachable!() ReadFuture { reader: self, buf }
} }
/// Like [`read`], except that it reads into a slice of buffers. #[doc = r#"
/// Like [`read`], except that it reads into a slice of buffers.
/// Data is copied to fill each buffer in order, with the final buffer written to
/// possibly being only partially filled. This method must behave as a single call to Data is copied to fill each buffer in order, with the final buffer written to
/// [`read`] with the buffers concatenated would. possibly being only partially filled. This method must behave as a single call to
/// [`read`] with the buffers concatenated would.
/// The default implementation calls [`read`] with either the first nonempty buffer
/// provided, or an empty one if none exists. The default implementation calls [`read`] with either the first nonempty buffer
/// provided, or an empty one if none exists.
/// [`read`]: #tymethod.read
[`read`]: #tymethod.read
"#]
fn read_vectored<'a>( fn read_vectored<'a>(
&'a mut self, &'a mut self,
bufs: &'a mut [IoSliceMut<'a>], bufs: &'a mut [IoSliceMut<'a>],
) -> ImplFuture<'a, io::Result<usize>> ) -> impl Future<Output = io::Result<usize>> + 'a [ReadVectoredFuture<'a, Self>]
where where
Self: Unpin, Self: Unpin,
{ {
unreachable!() ReadVectoredFuture { reader: self, bufs }
} }
/// Reads all bytes from the byte stream. #[doc = r#"
/// Reads all bytes from the byte stream.
/// All bytes read from this stream will be appended to the specified buffer `buf`.
/// This function will continuously call [`read`] to append more data to `buf` until All bytes read from this stream will be appended to the specified buffer `buf`.
/// [`read`] returns either `Ok(0)` or an error. This function will continuously call [`read`] to append more data to `buf` until
/// [`read`] returns either `Ok(0)` or an error.
/// If successful, this function will return the total number of bytes read.
/// If successful, this function will return the total number of bytes read.
/// [`read`]: #tymethod.read
/// [`read`]: #tymethod.read
/// # Examples
/// # Examples
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { ```no_run
/// # # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::fs::File; #
/// use async_std::prelude::*; use async_std::fs::File;
/// use async_std::prelude::*;
/// let mut file = File::open("a.txt").await?;
/// let mut file = File::open("a.txt").await?;
/// let mut buf = Vec::new();
/// file.read_to_end(&mut buf).await?; let mut buf = Vec::new();
/// # file.read_to_end(&mut buf).await?;
/// # Ok(()) }) } #
/// ``` # Ok(()) }) }
```
"#]
fn read_to_end<'a>( fn read_to_end<'a>(
&'a mut self, &'a mut self,
buf: &'a mut Vec<u8>, buf: &'a mut Vec<u8>,
) -> ImplFuture<'a, io::Result<usize>> ) -> impl Future<Output = io::Result<usize>> + 'a [ReadToEndFuture<'a, Self>]
where where
Self: Unpin, Self: Unpin,
{ {
unreachable!() let start_len = buf.len();
ReadToEndFuture {
reader: self,
buf,
start_len,
}
} }
/// Reads all bytes from the byte stream and appends them into a string. #[doc = r#"
/// Reads all bytes from the byte stream and appends them into a string.
/// If successful, this function will return the number of bytes read.
/// If successful, this function will return the number of bytes read.
/// If the data in this stream is not valid UTF-8 then an error will be returned and
/// `buf` will be left unmodified. If the data in this stream is not valid UTF-8 then an error will be returned and
/// `buf` will be left unmodified.
/// # Examples
/// # Examples
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { ```no_run
/// # # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::fs::File; #
/// use async_std::prelude::*; use async_std::fs::File;
/// use async_std::prelude::*;
/// let mut file = File::open("a.txt").await?;
/// let mut file = File::open("a.txt").await?;
/// let mut buf = String::new();
/// file.read_to_string(&mut buf).await?; let mut buf = String::new();
/// # file.read_to_string(&mut buf).await?;
/// # Ok(()) }) } #
/// ``` # Ok(()) }) }
```
"#]
fn read_to_string<'a>( fn read_to_string<'a>(
&'a mut self, &'a mut self,
buf: &'a mut String, buf: &'a mut String,
) -> ImplFuture<'a, io::Result<usize>> ) -> impl Future<Output = io::Result<usize>> + 'a [ReadToStringFuture<'a, Self>]
where where
Self: Unpin, Self: Unpin,
{ {
unreachable!() let start_len = buf.len();
ReadToStringFuture {
reader: self,
bytes: unsafe { mem::replace(buf.as_mut_vec(), Vec::new()) },
buf,
start_len,
}
} }
/// Reads the exact number of bytes required to fill `buf`. #[doc = r#"
/// Reads the exact number of bytes required to fill `buf`.
/// This function reads as many bytes as necessary to completely fill the specified
/// buffer `buf`. This function reads as many bytes as necessary to completely fill the specified
/// buffer `buf`.
/// No guarantees are provided about the contents of `buf` when this function is
/// called, implementations cannot rely on any property of the contents of `buf` being No guarantees are provided about the contents of `buf` when this function is
/// true. It is recommended that implementations only write data to `buf` instead of called, implementations cannot rely on any property of the contents of `buf` being
/// reading its contents. true. It is recommended that implementations only write data to `buf` instead of
/// reading its contents.
/// If this function encounters an "end of file" before completely filling the buffer,
/// it returns an error of the kind [`ErrorKind::UnexpectedEof`]. The contents of If this function encounters an "end of file" before completely filling the buffer,
/// `buf` are unspecified in this case. it returns an error of the kind [`ErrorKind::UnexpectedEof`]. The contents of
/// `buf` are unspecified in this case.
/// If any other read error is encountered then this function immediately returns. The
/// contents of `buf` are unspecified in this case. If any other read error is encountered then this function immediately returns. The
/// contents of `buf` are unspecified in this case.
/// If this function returns an error, it is unspecified how many bytes it has read,
/// but it will never read more than would be necessary to completely fill the buffer. If this function returns an error, it is unspecified how many bytes it has read,
/// but it will never read more than would be necessary to completely fill the buffer.
/// [`ErrorKind::UnexpectedEof`]: enum.ErrorKind.html#variant.UnexpectedEof
/// [`ErrorKind::UnexpectedEof`]: enum.ErrorKind.html#variant.UnexpectedEof
/// # Examples
/// # Examples
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { ```no_run
/// # # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::fs::File; #
/// use async_std::prelude::*; use async_std::fs::File;
/// use async_std::prelude::*;
/// let mut file = File::open("a.txt").await?;
/// let mut file = File::open("a.txt").await?;
/// let mut buf = vec![0; 10];
/// file.read_exact(&mut buf).await?; let mut buf = vec![0; 10];
/// # file.read_exact(&mut buf).await?;
/// # Ok(()) }) } #
/// ``` # Ok(()) }) }
fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> ImplFuture<'a, io::Result<()>> ```
"#]
fn read_exact<'a>(
&'a mut self,
buf: &'a mut [u8],
) -> impl Future<Output = io::Result<()>> + 'a [ReadExactFuture<'a, Self>]
where where
Self: Unpin, Self: Unpin,
{ {
unreachable!() ReadExactFuture { reader: self, buf }
} }
} }
@ -236,7 +269,7 @@ cfg_if! {
cx: &mut Context<'_>, cx: &mut Context<'_>,
buf: &mut [u8], buf: &mut [u8],
) -> Poll<io::Result<usize>> { ) -> Poll<io::Result<usize>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
} }
@ -246,7 +279,7 @@ cfg_if! {
cx: &mut Context<'_>, cx: &mut Context<'_>,
buf: &mut [u8], buf: &mut [u8],
) -> Poll<io::Result<usize>> { ) -> Poll<io::Result<usize>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
} }
@ -260,7 +293,7 @@ cfg_if! {
cx: &mut Context<'_>, cx: &mut Context<'_>,
buf: &mut [u8], buf: &mut [u8],
) -> Poll<io::Result<usize>> { ) -> Poll<io::Result<usize>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
} }
@ -270,64 +303,7 @@ cfg_if! {
cx: &mut Context<'_>, cx: &mut Context<'_>,
buf: &mut [u8], buf: &mut [u8],
) -> Poll<io::Result<usize>> { ) -> Poll<io::Result<usize>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
} }
} else {
pub use futures_io::AsyncRead as Read;
}
} }
#[doc(hidden)]
pub trait ReadExt: futures_io::AsyncRead {
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadFuture<'a, Self>
where
Self: Unpin,
{
ReadFuture { reader: self, buf }
}
fn read_vectored<'a>(
&'a mut self,
bufs: &'a mut [IoSliceMut<'a>],
) -> ReadVectoredFuture<'a, Self>
where
Self: Unpin,
{
ReadVectoredFuture { reader: self, bufs }
}
fn read_to_end<'a>(&'a mut self, buf: &'a mut Vec<u8>) -> ReadToEndFuture<'a, Self>
where
Self: Unpin,
{
let start_len = buf.len();
ReadToEndFuture {
reader: self,
buf,
start_len,
}
}
fn read_to_string<'a>(&'a mut self, buf: &'a mut String) -> ReadToStringFuture<'a, Self>
where
Self: Unpin,
{
let start_len = buf.len();
ReadToStringFuture {
reader: self,
bytes: unsafe { mem::replace(buf.as_mut_vec(), Vec::new()) },
buf,
start_len,
}
}
fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadExactFuture<'a, Self>
where
Self: Unpin,
{
ReadExactFuture { reader: self, buf }
}
}
impl<T: futures_io::AsyncRead + ?Sized> ReadExt for T {}

View file

@ -5,66 +5,76 @@ use cfg_if::cfg_if;
use crate::future::Future; use crate::future::Future;
use crate::io::{self, SeekFrom}; use crate::io::{self, SeekFrom};
use crate::task::{Context, Poll}; use crate::task::{Context, Poll};
use crate::utils::extension_trait;
cfg_if! { cfg_if! {
if #[cfg(feature = "docs")] { if #[cfg(feature = "docs")] {
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
}
}
#[doc(hidden)] extension_trait! {
pub struct ImplFuture<T>(std::marker::PhantomData<T>); #[doc = r#"
Allows seeking through a byte stream.
/// Allows seeking through a byte stream. This trait is a re-export of [`futures::io::AsyncSeek`] and is an async version of
/// [`std::io::Seek`].
/// This trait is a re-export of [`futures::io::AsyncSeek`] and is an async version of
/// [`std::io::Seek`]. The [provided methods] do not really exist in the trait itself, but they become
/// available when the prelude is imported:
/// The [provided methods] do not really exist in the trait itself, but they become
/// available when the prelude is imported: ```
/// # #[allow(unused_imports)]
/// ``` use async_std::prelude::*;
/// # #[allow(unused_imports)] ```
/// use async_std::prelude::*;
/// ``` [`std::io::Seek`]: https://doc.rust-lang.org/std/io/trait.Seek.html
/// [`futures::io::AsyncSeek`]:
/// [`std::io::Seek`]: https://doc.rust-lang.org/std/io/trait.Seek.html https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncSeek.html
/// [`futures::io::AsyncSeek`]: [provided methods]: #provided-methods
/// https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncSeek.html "#]
/// [provided methods]: #provided-methods pub trait Seek [SeekExt: futures_io::AsyncSeek] {
pub trait Seek { #[doc = r#"
/// Attempt to seek to an offset, in bytes, in a stream. Attempt to seek to an offset, in bytes, in a stream.
"#]
fn poll_seek( fn poll_seek(
self: Pin<&mut Self>, self: Pin<&mut Self>,
cx: &mut Context<'_>, cx: &mut Context<'_>,
pos: SeekFrom, pos: SeekFrom,
) -> Poll<io::Result<u64>>; ) -> Poll<io::Result<u64>>;
/// Seeks to a new position in a byte stream. #[doc = r#"
/// Seeks to a new position in a byte stream.
/// Returns the new position in the byte stream.
/// Returns the new position in the byte stream.
/// A seek beyond the end of stream is allowed, but behavior is defined by the
/// implementation. A seek beyond the end of stream is allowed, but behavior is defined by the
/// implementation.
/// # Examples
/// # Examples
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { ```no_run
/// # # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::fs::File; #
/// use async_std::io::SeekFrom; use async_std::fs::File;
/// use async_std::prelude::*; use async_std::io::SeekFrom;
/// use async_std::prelude::*;
/// let mut file = File::open("a.txt").await?;
/// let mut file = File::open("a.txt").await?;
/// let file_len = file.seek(SeekFrom::End(0)).await?;
/// # let file_len = file.seek(SeekFrom::End(0)).await?;
/// # Ok(()) }) } #
/// ``` # Ok(()) }) }
fn seek(&mut self, pos: SeekFrom) -> ImplFuture<io::Result<u64>> ```
"#]
fn seek(
&mut self,
pos: SeekFrom,
) -> impl Future<Output = io::Result<u64>> [SeekFuture<'_, Self>]
where where
Self: Unpin Self: Unpin,
{ {
unreachable!() SeekFuture { seeker: self, pos }
} }
} }
@ -74,7 +84,7 @@ cfg_if! {
cx: &mut Context<'_>, cx: &mut Context<'_>,
pos: SeekFrom, pos: SeekFrom,
) -> Poll<io::Result<u64>> { ) -> Poll<io::Result<u64>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
} }
@ -84,7 +94,7 @@ cfg_if! {
cx: &mut Context<'_>, cx: &mut Context<'_>,
pos: SeekFrom, pos: SeekFrom,
) -> Poll<io::Result<u64>> { ) -> Poll<io::Result<u64>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
} }
@ -98,26 +108,11 @@ cfg_if! {
cx: &mut Context<'_>, cx: &mut Context<'_>,
pos: SeekFrom, pos: SeekFrom,
) -> Poll<io::Result<u64>> { ) -> Poll<io::Result<u64>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
} }
} else {
pub use futures_io::AsyncSeek as Seek;
}
} }
#[doc(hidden)]
pub trait SeekExt: futures_io::AsyncSeek {
fn seek(&mut self, pos: SeekFrom) -> SeekFuture<'_, Self>
where
Self: Unpin,
{
SeekFuture { seeker: self, pos }
}
}
impl<T: futures_io::AsyncSeek + ?Sized> SeekExt for T {}
#[doc(hidden)] #[doc(hidden)]
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
pub struct SeekFuture<'a, T: Unpin + ?Sized> { pub struct SeekFuture<'a, T: Unpin + ?Sized> {

View file

@ -11,6 +11,7 @@ use write_vectored::WriteVectoredFuture;
use cfg_if::cfg_if; use cfg_if::cfg_if;
use crate::io::IoSlice; use crate::io::IoSlice;
use crate::utils::extension_trait;
cfg_if! { cfg_if! {
if #[cfg(feature = "docs")] { if #[cfg(feature = "docs")] {
@ -19,159 +20,182 @@ cfg_if! {
use crate::io; use crate::io;
use crate::task::{Context, Poll}; use crate::task::{Context, Poll};
}
}
#[doc(hidden)] extension_trait! {
pub struct ImplFuture<'a, T>(std::marker::PhantomData<&'a T>); #[doc = r#"
Allows writing to a byte stream.
/// Allows writing to a byte stream. This trait is a re-export of [`futures::io::AsyncWrite`] and is an async version of
/// [`std::io::Write`].
/// This trait is a re-export of [`futures::io::AsyncWrite`] and is an async version of
/// [`std::io::Write`]. Methods other than [`poll_write`], [`poll_write_vectored`], [`poll_flush`], and
/// [`poll_close`] do not really exist in the trait itself, but they become available when
/// Methods other than [`poll_write`], [`poll_write_vectored`], [`poll_flush`], and the prelude is imported:
/// [`poll_close`] do not really exist in the trait itself, but they become available when
/// the prelude is imported: ```
/// # #[allow(unused_imports)]
/// ``` use async_std::prelude::*;
/// # #[allow(unused_imports)] ```
/// use async_std::prelude::*;
/// ``` [`std::io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
/// [`futures::io::AsyncWrite`]:
/// [`std::io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncWrite.html
/// [`futures::io::AsyncWrite`]: [`poll_write`]: #tymethod.poll_write
/// https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncWrite.html [`poll_write_vectored`]: #method.poll_write_vectored
/// [`poll_write`]: #tymethod.poll_write [`poll_flush`]: #tymethod.poll_flush
/// [`poll_write_vectored`]: #method.poll_write_vectored [`poll_close`]: #tymethod.poll_close
/// [`poll_flush`]: #tymethod.poll_flush "#]
/// [`poll_close`]: #tymethod.poll_close pub trait Write [WriteExt: futures_io::AsyncWrite] {
pub trait Write { #[doc = r#"
/// Attempt to write bytes from `buf` into the object. Attempt to write bytes from `buf` into the object.
"#]
fn poll_write( fn poll_write(
self: Pin<&mut Self>, self: Pin<&mut Self>,
cx: &mut Context<'_>, cx: &mut Context<'_>,
buf: &[u8], buf: &[u8],
) -> Poll<io::Result<usize>>; ) -> Poll<io::Result<usize>>;
/// Attempt to write bytes from `bufs` into the object using vectored #[doc = r#"
/// IO operations. Attempt to write bytes from `bufs` into the object using vectored IO operations.
"#]
fn poll_write_vectored( fn poll_write_vectored(
self: Pin<&mut Self>, self: Pin<&mut Self>,
cx: &mut Context<'_>, cx: &mut Context<'_>,
bufs: &[IoSlice<'_>] bufs: &[IoSlice<'_>]
) -> Poll<io::Result<usize>> { ) -> Poll<io::Result<usize>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
/// Attempt to flush the object, ensuring that any buffered data reach #[doc = r#"
/// their destination. Attempt to flush the object, ensuring that any buffered data reach
their destination.
"#]
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>>; fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>>;
/// Attempt to close the object. #[doc = r#"
Attempt to close the object.
"#]
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>>; fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>>;
/// Writes some bytes into the byte stream. #[doc = r#"
/// Writes some bytes into the byte stream.
/// Returns the number of bytes written from the start of the buffer.
/// Returns the number of bytes written from the start of the buffer.
/// If the return value is `Ok(n)` then it must be guaranteed that
/// `0 <= n <= buf.len()`. A return value of `0` typically means that the underlying If the return value is `Ok(n)` then it must be guaranteed that
/// object is no longer able to accept bytes and will likely not be able to in the `0 <= n <= buf.len()`. A return value of `0` typically means that the underlying
/// future as well, or that the buffer provided is empty. object is no longer able to accept bytes and will likely not be able to in the
/// future as well, or that the buffer provided is empty.
/// # Examples
/// # Examples
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { ```no_run
/// # # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::fs::File; #
/// use async_std::prelude::*; use async_std::fs::File;
/// use async_std::prelude::*;
/// let mut file = File::create("a.txt").await?;
/// let mut file = File::create("a.txt").await?;
/// let n = file.write(b"hello world").await?;
/// # let n = file.write(b"hello world").await?;
/// # Ok(()) }) } #
/// ``` # Ok(()) }) }
fn write<'a>(&'a mut self, buf: &'a [u8]) -> ImplFuture<'a, io::Result<usize>> ```
"#]
fn write<'a>(
&'a mut self,
buf: &'a [u8],
) -> impl Future<Output = io::Result<usize>> + 'a [WriteFuture<'a, Self>]
where where
Self: Unpin, Self: Unpin,
{ {
unreachable!() WriteFuture { writer: self, buf }
} }
/// Flushes the stream to ensure that all buffered contents reach their destination. #[doc = r#"
/// Flushes the stream to ensure that all buffered contents reach their destination.
/// # Examples
/// # Examples
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { ```no_run
/// # # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::fs::File; #
/// use async_std::prelude::*; use async_std::fs::File;
/// use async_std::prelude::*;
/// let mut file = File::create("a.txt").await?;
/// let mut file = File::create("a.txt").await?;
/// file.write_all(b"hello world").await?;
/// file.flush().await?; file.write_all(b"hello world").await?;
/// # file.flush().await?;
/// # Ok(()) }) } #
/// ``` # Ok(()) }) }
fn flush(&mut self) -> ImplFuture<'_, io::Result<()>> ```
"#]
fn flush(&mut self) -> impl Future<Output = io::Result<()>> + '_ [FlushFuture<'_, Self>]
where where
Self: Unpin, Self: Unpin,
{ {
unreachable!() FlushFuture { writer: self }
} }
/// Like [`write`], except that it writes from a slice of buffers. #[doc = r#"
/// Like [`write`], except that it writes from a slice of buffers.
/// Data is copied from each buffer in order, with the final buffer read from possibly
/// being only partially consumed. This method must behave as a call to [`write`] with Data is copied from each buffer in order, with the final buffer read from possibly
/// the buffers concatenated would. being only partially consumed. This method must behave as a call to [`write`] with
/// the buffers concatenated would.
/// The default implementation calls [`write`] with either the first nonempty buffer
/// provided, or an empty one if none exists. The default implementation calls [`write`] with either the first nonempty buffer
/// provided, or an empty one if none exists.
/// [`write`]: #tymethod.write
[`write`]: #tymethod.write
"#]
fn write_vectored<'a>( fn write_vectored<'a>(
&'a mut self, &'a mut self,
bufs: &'a [IoSlice<'a>], bufs: &'a [IoSlice<'a>],
) -> ImplFuture<'a, io::Result<usize>> ) -> impl Future<Output = io::Result<usize>> + 'a [WriteVectoredFuture<'a, Self>]
where where
Self: Unpin, Self: Unpin,
{ {
unreachable!() WriteVectoredFuture { writer: self, bufs }
} }
/// Writes an entire buffer into the byte stream. #[doc = r#"
/// Writes an entire buffer into the byte stream.
/// This method will continuously call [`write`] until there is no more data to be
/// written or an error is returned. This method will not return until the entire This method will continuously call [`write`] until there is no more data to be
/// buffer has been successfully written or such an error occurs. written or an error is returned. This method will not return until the entire
/// buffer has been successfully written or such an error occurs.
/// [`write`]: #tymethod.write
/// [`write`]: #tymethod.write
/// # Examples
/// # Examples
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { ```no_run
/// # # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// use async_std::fs::File; #
/// use async_std::prelude::*; use async_std::fs::File;
/// use async_std::prelude::*;
/// let mut file = File::create("a.txt").await?;
/// let mut file = File::create("a.txt").await?;
/// file.write_all(b"hello world").await?;
/// # file.write_all(b"hello world").await?;
/// # Ok(()) }) } #
/// ``` # Ok(()) }) }
/// ```
/// [`write`]: #tymethod.write
fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> ImplFuture<'a, io::Result<()>> [`write`]: #tymethod.write
"#]
fn write_all<'a>(
&'a mut self,
buf: &'a [u8],
) -> impl Future<Output = io::Result<()>> + 'a [WriteAllFuture<'a, Self>]
where where
Self: Unpin, Self: Unpin,
{ {
unreachable!() WriteAllFuture { writer: self, buf }
} }
} }
@ -181,15 +205,15 @@ cfg_if! {
cx: &mut Context<'_>, cx: &mut Context<'_>,
buf: &[u8], buf: &[u8],
) -> Poll<io::Result<usize>> { ) -> Poll<io::Result<usize>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
} }
@ -199,15 +223,15 @@ cfg_if! {
cx: &mut Context<'_>, cx: &mut Context<'_>,
buf: &[u8], buf: &[u8],
) -> Poll<io::Result<usize>> { ) -> Poll<io::Result<usize>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
} }
@ -221,15 +245,15 @@ cfg_if! {
cx: &mut Context<'_>, cx: &mut Context<'_>,
buf: &[u8], buf: &[u8],
) -> Poll<io::Result<usize>> { ) -> Poll<io::Result<usize>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
} }
@ -239,51 +263,15 @@ cfg_if! {
cx: &mut Context<'_>, cx: &mut Context<'_>,
buf: &[u8], buf: &[u8],
) -> Poll<io::Result<usize>> { ) -> Poll<io::Result<usize>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
} }
} else {
pub use futures_io::AsyncWrite as Write;
}
} }
#[doc(hidden)]
pub trait WriteExt: Write {
fn write<'a>(&'a mut self, buf: &'a [u8]) -> WriteFuture<'a, Self>
where
Self: Unpin,
{
WriteFuture { writer: self, buf }
}
fn flush(&mut self) -> FlushFuture<'_, Self>
where
Self: Unpin,
{
FlushFuture { writer: self }
}
fn write_vectored<'a>(&'a mut self, bufs: &'a [IoSlice<'a>]) -> WriteVectoredFuture<'a, Self>
where
Self: Unpin,
{
WriteVectoredFuture { writer: self, bufs }
}
fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> WriteAllFuture<'a, Self>
where
Self: Unpin,
{
WriteAllFuture { writer: self, buf }
}
}
impl<T: Write + ?Sized> WriteExt for T {}

View file

@ -46,6 +46,7 @@
#![doc(test(attr(deny(rust_2018_idioms, warnings))))] #![doc(test(attr(deny(rust_2018_idioms, warnings))))]
#![doc(test(attr(allow(unused_extern_crates, unused_variables))))] #![doc(test(attr(allow(unused_extern_crates, unused_variables))))]
#![doc(html_logo_url = "https://async.rs/images/logo--hero.svg")] #![doc(html_logo_url = "https://async.rs/images/logo--hero.svg")]
#![recursion_limit = "1024"]
use cfg_if::cfg_if; use cfg_if::cfg_if;

View file

@ -55,7 +55,7 @@ cfg_if! {
/// assert_eq!(addr.is_unnamed(), true); /// assert_eq!(addr.is_unnamed(), true);
/// ``` /// ```
pub fn is_unnamed(&self) -> bool { pub fn is_unnamed(&self) -> bool {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
/// Returns the contents of this address if it is a `pathname` address. /// Returns the contents of this address if it is a `pathname` address.
@ -84,13 +84,13 @@ cfg_if! {
/// assert_eq!(addr.as_pathname(), None); /// assert_eq!(addr.as_pathname(), None);
/// ``` /// ```
pub fn as_pathname(&self) -> Option<&Path> { pub fn as_pathname(&self) -> Option<&Path> {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
} }
impl fmt::Debug for SocketAddr { impl fmt::Debug for SocketAddr {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
unreachable!() unreachable!("this impl only appears in the rendered docs")
} }
} }
} else { } else {

File diff suppressed because it is too large Load diff

View file

@ -19,3 +19,120 @@ pub fn abort_on_panic<T>(f: impl FnOnce() -> T) -> T {
mem::forget(bomb); mem::forget(bomb);
t t
} }
/// Defines an extension trait for a base trait from the `futures` crate.
///
/// In generated docs, the base trait will contain methods from the extension trait. In actual
/// code, the base trait will be re-exported and the extension trait will be hidden. We then
/// re-export the extension trait from the prelude.
///
/// Inside invocations of this macro, we write a definitions that looks similar to the final
/// rendered docs, and the macro then generates all the boilerplate for us.
#[doc(hidden)]
#[macro_export]
macro_rules! extension_trait {
(
// Interesting patterns:
// - `$name`: trait name that gets rendered in the docs
// - `$ext`: name of the hidden extension trait
// - `$base`: base trait from the `futures` crate
$(#[$attr:meta])*
pub trait $name:ident [$ext:ident: $base:path] {
$($body:tt)*
}
// Shim trait impls that only appear in docs.
$($imp:item)*
) => {
// A fake `impl Future` type that doesn't borrow.
#[allow(dead_code)]
mod owned {
#[doc(hidden)]
pub struct ImplFuture<T>(std::marker::PhantomData<T>);
}
// A fake `impl Future` type that borrows its environment.
#[allow(dead_code)]
mod borrowed {
#[doc(hidden)]
pub struct ImplFuture<'a, T>(std::marker::PhantomData<&'a T>);
}
// Render a fake trait containing all methods from the base trait and the extension trait.
#[cfg(feature = "docs")]
$(#[$attr])*
pub trait $name {
extension_trait!(@doc () $($body)*);
}
// When not rendering docs, re-export the base trait from the futures crate.
#[cfg(not(feature = "docs"))]
pub use $base as $name;
// The extension trait that adds methods to any type implementing the base trait.
$(#[$attr])*
pub trait $ext: $base {
extension_trait!(@ext () $($body)*);
}
// Blanket implementation of the extension trait for any type implementing the base trait.
impl<T: $base + ?Sized> $ext for T {}
// Shim trait impls that only appear in docs.
$(#[cfg(feature = "docs")] $imp)*
};
// Parse an associated type.
(@doc ($($head:tt)*) type $name:ident; $($tail:tt)*) => {
extension_trait!(@doc ($($head)* type $name;) $($tail)*);
};
(@ext ($($head:tt)*) type $ident:ty; $($tail:tt)*) => {
extension_trait!(@ext ($($head)*) $($tail)*);
};
// Parse a required method.
(@doc ($($head:tt)*) fn $name:ident $args:tt $(-> $ret:ty)?; $($tail:tt)*) => {
extension_trait!(@doc ($($head)* fn $name $args $(-> $ret)?;) $($tail)*);
};
(@ext ($($head:tt)*) fn $name:ident $args:tt $(-> $ret:ty)?; $($tail:tt)*) => {
extension_trait!(@ext ($($head)*) $($tail)*);
};
// Parse a provided method that exists in the base trait.
(@doc ($($head:tt)*) fn $name:ident $args:tt $(-> $ret:ty)? { $($body:tt)* } $($tail:tt)*) => {
extension_trait!(@doc ($($head)* fn $name $args $(-> $ret)? { $($body)* }) $($tail)*);
};
(@ext ($($head:tt)*) fn $name:ident $args:tt $(-> $ret:ty)? { $($body:tt)* } $($tail:tt)*) => {
extension_trait!(@ext ($($head)*) $($tail)*);
};
// Parse the return type in an extension method where the future doesn't borrow.
(@doc ($($head:tt)*) -> impl Future<Output = $out:ty> [$f:ty] $($tail:tt)*) => {
extension_trait!(@doc ($($head)* -> owned::ImplFuture<$out>) $($tail)*);
};
(@ext ($($head:tt)*) -> impl Future<Output = $out:ty> [$f:ty] $($tail:tt)*) => {
extension_trait!(@ext ($($head)* -> $f) $($tail)*);
};
// Parse the return type in an extension method where the future borrows its environment.
(@doc ($($head:tt)*) -> impl Future<Output = $out:ty> + $lt:lifetime [$f:ty] $($tail:tt)*) => {
extension_trait!(@doc ($($head)* -> borrowed::ImplFuture<$lt, $out>) $($tail)*);
};
(@ext ($($head:tt)*) -> impl Future<Output = $out:ty> + $lt:lifetime [$f:ty] $($tail:tt)*) => {
extension_trait!(@ext ($($head)* -> $f) $($tail)*);
};
// Parse a token that doesn't fit into any of the previous patterns.
(@doc ($($head:tt)*) $token:tt $($tail:tt)*) => {
extension_trait!(@doc ($($head)* $token) $($tail)*);
};
(@ext ($($head:tt)*) $token:tt $($tail:tt)*) => {
extension_trait!(@ext ($($head)* $token) $($tail)*);
};
// Handle the end of the token list.
(@doc ($($head:tt)*)) => { $($head)* };
(@ext ($($head:tt)*)) => { $($head)* };
}
pub use crate::extension_trait;