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,294 +13,278 @@ 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:
///
/// ```
/// # #[allow(unused_imports)]
/// use async_std::prelude::*;
/// ```
///
/// [`std::io::BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html
/// [`futures::io::AsyncBufRead`]:
/// https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncBufRead.html
/// [provided methods]: #provided-methods
pub trait BufRead {
/// Returns the contents of the internal buffer, filling it with more data from the
/// inner reader if it is empty.
///
/// 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
/// "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
/// this buffer to ensure that the bytes are never returned twice.
///
/// [`consume`]: #tymethod.consume
///
/// An empty buffer returned indicates that the stream has reached EOF.
// TODO: write a proper doctest with `consume`
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 The [provided methods] do not really exist in the trait itself, but they become
/// should no longer be returned in calls to `read`. available when the prelude is imported:
fn consume(self: Pin<&mut Self>, amt: usize);
/// Reads all bytes into `buf` until the delimiter `byte` or EOF is reached. ```
/// # #[allow(unused_imports)]
/// This function will read bytes from the underlying stream until the delimiter or EOF use async_std::prelude::*;
/// 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.
///
/// # Examples
///
/// ```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::prelude::*;
///
/// 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?;
/// #
/// # Ok(()) }) }
/// ```
///
/// 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 {
/// #
/// use async_std::io::BufReader;
/// use async_std::prelude::*;
///
/// let from: &[u8] = b"append\nexample\n";
/// 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);
/// assert_eq!(buf, b"append\n");
///
/// size += reader.read_until(b'\n', &mut buf).await?;
/// assert_eq!(size, from.len());
///
/// assert_eq!(buf, from);
/// #
/// # Ok(()) }) }
/// ```
fn read_until<'a>(
&'a mut self,
byte: u8,
buf: &'a mut Vec<u8>,
) -> ImplFuture<'a, io::Result<usize>>
where
Self: Unpin,
{
unreachable!()
}
/// Reads all bytes and appends them into `buf` until a newline (the 0xA byte) is [`std::io::BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html
/// reached. [`futures::io::AsyncBufRead`]:
/// https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncBufRead.html
/// This function will read bytes from the underlying stream until the newline [provided methods]: #provided-methods
/// 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`. pub trait BufRead [BufReadExt: futures_io::AsyncBufRead] {
/// #[doc = r#"
/// If successful, this function will return the total number of bytes read. Returns the contents of the internal buffer, filling it with more data from the
/// inner reader if it is empty.
/// If this function returns `Ok(0)`, the stream has reached EOF.
///
/// # 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
/// `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
///
/// # Examples
///
/// ```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::prelude::*;
///
/// let mut file = BufReader::new(File::open("a.txt").await?);
///
/// let mut buf = String::new();
/// file.read_line(&mut buf).await?;
/// #
/// # Ok(()) }) }
/// ```
fn read_line<'a>(
&'a mut self,
buf: &'a mut String,
) -> ImplFuture<'a, io::Result<usize>>
where
Self: Unpin,
{
unreachable!()
}
/// Returns a stream over the lines of this byte stream. 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
/// The stream returned from this function will yield instances of "read" in the sense that later calling `read` may return the same contents. As
/// [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline byte such, [`consume`] must be called with the number of bytes that are consumed from
/// (the 0xA byte) or CRLF (0xD, 0xA bytes) at the end. this buffer to ensure that the bytes are never returned twice.
///
/// [`io::Result`]: type.Result.html
/// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html
///
/// # Examples
///
/// ```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::prelude::*;
///
/// let file = File::open("a.txt").await?;
/// let mut lines = BufReader::new(file).lines();
/// let mut count = 0;
///
/// while let Some(line) = lines.next().await {
/// line?;
/// count += 1;
/// }
/// #
/// # Ok(()) }) }
/// ```
fn lines(self) -> Lines<Self>
where
Self: Unpin + Sized,
{
unreachable!()
}
}
impl<T: BufRead + Unpin + ?Sized> BufRead for Box<T> { [`consume`]: #tymethod.consume
fn poll_fill_buf(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<io::Result<&[u8]>> {
unreachable!()
}
fn consume(self: Pin<&mut Self>, amt: usize) { An empty buffer returned indicates that the stream has reached EOF.
unreachable!() "#]
} // TODO: write a proper doctest with `consume`
} fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>>;
impl<T: BufRead + Unpin + ?Sized> BufRead for &mut T { #[doc = r#"
fn poll_fill_buf( Tells this buffer that `amt` bytes have been consumed from the buffer, so they
self: Pin<&mut Self>, should no longer be returned in calls to `read`.
cx: &mut Context<'_>, "#]
) -> Poll<io::Result<&[u8]>> { fn consume(self: Pin<&mut Self>, amt: usize);
unreachable!()
}
fn consume(self: Pin<&mut Self>, amt: usize) { #[doc = r#"
unreachable!() Reads all bytes into `buf` until the delimiter `byte` or EOF is reached.
}
}
impl<P> BufRead for Pin<P> 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
be appended to `buf`.
If successful, this function will return the total number of bytes read.
# Examples
```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::prelude::*;
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?;
#
# Ok(()) }) }
```
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 {
#
use async_std::io::BufReader;
use async_std::prelude::*;
let from: &[u8] = b"append\nexample\n";
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);
assert_eq!(buf, b"append\n");
size += reader.read_until(b'\n', &mut buf).await?;
assert_eq!(size, from.len());
assert_eq!(buf, from);
#
# Ok(()) }) }
```
"#]
fn read_until<'a>(
&'a mut self,
byte: u8,
buf: &'a mut Vec<u8>,
) -> impl Future<Output = usize> + 'a [ReadUntilFuture<'a, Self>]
where where
P: DerefMut + Unpin, Self: Unpin,
<P as Deref>::Target: BufRead,
{ {
fn poll_fill_buf( ReadUntilFuture {
self: Pin<&mut Self>, reader: self,
cx: &mut Context<'_>, byte,
) -> Poll<io::Result<&[u8]>> { buf,
unreachable!() read: 0,
}
fn consume(self: Pin<&mut Self>, amt: usize) {
unreachable!()
} }
} }
impl BufRead for &[u8] { #[doc = r#"
fn poll_fill_buf( Reads all bytes and appends them into `buf` until a newline (the 0xA byte) is
self: Pin<&mut Self>, reached.
cx: &mut Context<'_>,
) -> Poll<io::Result<&[u8]>> {
unreachable!()
}
fn consume(self: Pin<&mut Self>, amt: usize) { This function will read bytes from the underlying stream until the newline
unreachable!() 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 this function returns `Ok(0)`, the stream has reached EOF.
# 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
`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
# Examples
```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::prelude::*;
let mut file = BufReader::new(File::open("a.txt").await?);
let mut buf = String::new();
file.read_line(&mut buf).await?;
#
# Ok(()) }) }
```
"#]
fn read_line<'a>(
&'a mut self,
buf: &'a mut String,
) -> impl Future<Output = io::Result<usize>> + 'a [ReadLineFuture<'a, Self>]
where
Self: Unpin,
{
ReadLineFuture {
reader: self,
bytes: unsafe { mem::replace(buf.as_mut_vec(), Vec::new()) },
buf,
read: 0,
} }
} }
} else {
pub use futures_io::AsyncBufRead as BufRead;
}
}
#[doc(hidden)] #[doc = r#"
pub trait BufReadExt: futures_io::AsyncBufRead { Returns a stream over the lines of this byte stream.
fn read_until<'a>(&'a mut self, byte: u8, buf: &'a mut Vec<u8>) -> ReadUntilFuture<'a, Self>
where The stream returned from this function will yield instances of
Self: Unpin, [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline byte
{ (the 0xA byte) or CRLF (0xD, 0xA bytes) at the end.
ReadUntilFuture {
reader: self, [`io::Result`]: type.Result.html
byte, [`String`]: https://doc.rust-lang.org/std/string/struct.String.html
buf,
read: 0, # Examples
```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::prelude::*;
let file = File::open("a.txt").await?;
let mut lines = BufReader::new(file).lines();
let mut count = 0;
while let Some(line) = lines.next().await {
line?;
count += 1;
}
#
# Ok(()) }) }
```
"#]
fn lines(self) -> Lines<Self>
where
Self: Unpin + Sized,
{
Lines {
reader: self,
buf: String::new(),
bytes: Vec::new(),
read: 0,
}
} }
} }
fn read_line<'a>(&'a mut self, buf: &'a mut String) -> ReadLineFuture<'a, Self> impl<T: BufRead + Unpin + ?Sized> BufRead for Box<T> {
where fn poll_fill_buf(
Self: Unpin, self: Pin<&mut Self>,
{ cx: &mut Context<'_>,
ReadLineFuture { ) -> Poll<io::Result<&[u8]>> {
reader: self, unreachable!("this impl only appears in the rendered docs")
bytes: unsafe { mem::replace(buf.as_mut_vec(), Vec::new()) }, }
buf,
read: 0, fn consume(self: Pin<&mut Self>, amt: usize) {
unreachable!("this impl only appears in the rendered docs")
} }
} }
fn lines(self) -> Lines<Self> impl<T: BufRead + Unpin + ?Sized> BufRead for &mut T {
fn poll_fill_buf(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<io::Result<&[u8]>> {
unreachable!("this impl only appears in the rendered docs")
}
fn consume(self: Pin<&mut Self>, amt: usize) {
unreachable!("this impl only appears in the rendered docs")
}
}
impl<P> BufRead for Pin<P>
where where
Self: Unpin + Sized, P: DerefMut + Unpin,
<P as Deref>::Target: BufRead,
{ {
Lines { fn poll_fill_buf(
reader: self, self: Pin<&mut Self>,
buf: String::new(), cx: &mut Context<'_>,
bytes: Vec::new(), ) -> Poll<io::Result<&[u8]>> {
read: 0, unreachable!("this impl only appears in the rendered docs")
}
fn consume(self: Pin<&mut Self>, amt: usize) {
unreachable!("this impl only appears in the rendered docs")
}
}
impl BufRead for &[u8] {
fn poll_fill_buf(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<io::Result<&[u8]>> {
unreachable!()
}
fn consume(self: Pin<&mut Self>, amt: usize) {
unreachable!("this impl only appears in the rendered docs")
} }
} }
} }
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,311 +23,287 @@ 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:
///
/// ```
/// # #[allow(unused_imports)]
/// use async_std::prelude::*;
/// ```
///
/// [`std::io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
/// [`futures::io::AsyncRead`]:
/// https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncRead.html
/// [`poll_read`]: #tymethod.poll_read
/// [`poll_read_vectored`]: #method.poll_read_vectored
pub trait Read {
/// Attempt to read from the `AsyncRead` into `buf`.
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>>;
/// Attempt to read from the `AsyncRead` into `bufs` using vectored IO operations. Methods other than [`poll_read`] and [`poll_read_vectored`] do not really exist in the
fn poll_read_vectored( trait itself, but they become available when the prelude is imported:
self: Pin<&mut Self>,
cx: &mut Context<'_>,
bufs: &mut [IoSliceMut<'_>],
) -> Poll<io::Result<usize>> {
unreachable!()
}
/// Reads some bytes from the byte stream. ```
/// # #[allow(unused_imports)]
/// Returns the number of bytes read from the start of the buffer. use async_std::prelude::*;
/// ```
/// 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
/// 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
/// longer be able to produce bytes.
/// 2. The buffer specified was 0 bytes in length.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
/// use async_std::prelude::*;
///
/// let mut file = File::open("a.txt").await?;
///
/// let mut buf = vec![0; 1024];
/// let n = file.read(&mut buf).await?;
/// #
/// # Ok(()) }) }
/// ```
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> ImplFuture<'a, io::Result<usize>>
where
Self: Unpin
{
unreachable!()
}
/// Like [`read`], except that it reads into a slice of buffers. [`std::io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
/// [`futures::io::AsyncRead`]:
/// Data is copied to fill each buffer in order, with the final buffer written to https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncRead.html
/// possibly being only partially filled. This method must behave as a single call to [`poll_read`]: #tymethod.poll_read
/// [`read`] with the buffers concatenated would. [`poll_read_vectored`]: #method.poll_read_vectored
/// "#]
/// The default implementation calls [`read`] with either the first nonempty buffer pub trait Read [ReadExt: futures_io::AsyncRead] {
/// provided, or an empty one if none exists. #[doc = r#"
/// Attempt to read from the `AsyncRead` into `buf`.
/// [`read`]: #tymethod.read "#]
fn read_vectored<'a>( fn poll_read(
&'a mut self, self: Pin<&mut Self>,
bufs: &'a mut [IoSliceMut<'a>], cx: &mut Context<'_>,
) -> ImplFuture<'a, io::Result<usize>> buf: &mut [u8],
where ) -> Poll<io::Result<usize>>;
Self: Unpin,
{
unreachable!()
}
/// Reads all bytes from the byte stream. #[doc = r#"
/// Attempt to read from the `AsyncRead` into `bufs` using vectored IO operations.
/// 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 fn poll_read_vectored(
/// [`read`] returns either `Ok(0)` or an error. self: Pin<&mut Self>,
/// cx: &mut Context<'_>,
/// If successful, this function will return the total number of bytes read. bufs: &mut [IoSliceMut<'_>],
/// ) -> Poll<io::Result<usize>> {
/// [`read`]: #tymethod.read unreachable!("this impl only appears in the rendered docs")
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
/// use async_std::prelude::*;
///
/// let mut file = File::open("a.txt").await?;
///
/// let mut buf = Vec::new();
/// file.read_to_end(&mut buf).await?;
/// #
/// # Ok(()) }) }
/// ```
fn read_to_end<'a>(
&'a mut self,
buf: &'a mut Vec<u8>,
) -> ImplFuture<'a, io::Result<usize>>
where
Self: Unpin,
{
unreachable!()
}
/// 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 the data in this stream is not valid UTF-8 then an error will be returned and
/// `buf` will be left unmodified.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
/// use async_std::prelude::*;
///
/// let mut file = File::open("a.txt").await?;
///
/// let mut buf = String::new();
/// file.read_to_string(&mut buf).await?;
/// #
/// # Ok(()) }) }
/// ```
fn read_to_string<'a>(
&'a mut self,
buf: &'a mut String,
) -> ImplFuture<'a, io::Result<usize>>
where
Self: Unpin,
{
unreachable!()
}
/// 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`.
///
/// 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
/// 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
/// `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.
///
/// [`ErrorKind::UnexpectedEof`]: enum.ErrorKind.html#variant.UnexpectedEof
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
/// use async_std::prelude::*;
///
/// let mut file = File::open("a.txt").await?;
///
/// let mut buf = vec![0; 10];
/// file.read_exact(&mut buf).await?;
/// #
/// # Ok(()) }) }
/// ```
fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> ImplFuture<'a, io::Result<()>>
where
Self: Unpin,
{
unreachable!()
}
} }
impl<T: Read + Unpin + ?Sized> Read for Box<T> { #[doc = r#"
fn poll_read( Reads some bytes from the byte stream.
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
unreachable!()
}
}
impl<T: Read + Unpin + ?Sized> Read for &mut T { Returns the number of bytes read from the start of the buffer.
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
unreachable!()
}
}
impl<P> Read for Pin<P> 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
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
longer be able to produce bytes.
2. The buffer specified was 0 bytes in length.
# Examples
```no_run
# fn main() -> std::io::Result<()> { async_std::task::block_on(async {
#
use async_std::fs::File;
use async_std::prelude::*;
let mut file = File::open("a.txt").await?;
let mut buf = vec![0; 1024];
let n = file.read(&mut buf).await?;
#
# Ok(()) }) }
```
"#]
fn read<'a>(
&'a mut self,
buf: &'a mut [u8],
) -> impl Future<Output = io::Result<usize>> + 'a [ReadFuture<'a, Self>]
where where
P: DerefMut + Unpin, Self: Unpin
<P as Deref>::Target: Read,
{ {
fn poll_read( ReadFuture { reader: self, buf }
self: Pin<&mut Self>, }
cx: &mut Context<'_>,
buf: &mut [u8], #[doc = r#"
) -> Poll<io::Result<usize>> { Like [`read`], except that it reads into a slice of buffers.
unreachable!()
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
[`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.
[`read`]: #tymethod.read
"#]
fn read_vectored<'a>(
&'a mut self,
bufs: &'a mut [IoSliceMut<'a>],
) -> impl Future<Output = io::Result<usize>> + 'a [ReadVectoredFuture<'a, Self>]
where
Self: Unpin,
{
ReadVectoredFuture { reader: self, bufs }
}
#[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
[`read`] returns either `Ok(0)` or an error.
If successful, this function will return the total number of bytes read.
[`read`]: #tymethod.read
# Examples
```no_run
# fn main() -> std::io::Result<()> { async_std::task::block_on(async {
#
use async_std::fs::File;
use async_std::prelude::*;
let mut file = File::open("a.txt").await?;
let mut buf = Vec::new();
file.read_to_end(&mut buf).await?;
#
# Ok(()) }) }
```
"#]
fn read_to_end<'a>(
&'a mut self,
buf: &'a mut Vec<u8>,
) -> impl Future<Output = io::Result<usize>> + 'a [ReadToEndFuture<'a, Self>]
where
Self: Unpin,
{
let start_len = buf.len();
ReadToEndFuture {
reader: self,
buf,
start_len,
} }
} }
impl Read for &[u8] { #[doc = r#"
fn poll_read( Reads all bytes from the byte stream and appends them into a string.
self: Pin<&mut Self>,
cx: &mut Context<'_>, If successful, this function will return the number of bytes read.
buf: &mut [u8],
) -> Poll<io::Result<usize>> { If the data in this stream is not valid UTF-8 then an error will be returned and
unreachable!() `buf` will be left unmodified.
# Examples
```no_run
# fn main() -> std::io::Result<()> { async_std::task::block_on(async {
#
use async_std::fs::File;
use async_std::prelude::*;
let mut file = File::open("a.txt").await?;
let mut buf = String::new();
file.read_to_string(&mut buf).await?;
#
# Ok(()) }) }
```
"#]
fn read_to_string<'a>(
&'a mut self,
buf: &'a mut String,
) -> impl Future<Output = io::Result<usize>> + 'a [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,
} }
} }
} else {
pub use futures_io::AsyncRead as Read;
}
}
#[doc(hidden)] #[doc = r#"
pub trait ReadExt: futures_io::AsyncRead { Reads the exact number of bytes required to fill `buf`.
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadFuture<'a, Self>
where
Self: Unpin,
{
ReadFuture { reader: self, buf }
}
fn read_vectored<'a>( This function reads as many bytes as necessary to completely fill the specified
&'a mut self, buffer `buf`.
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> No guarantees are provided about the contents of `buf` when this function is
where called, implementations cannot rely on any property of the contents of `buf` being
Self: Unpin, true. It is recommended that implementations only write data to `buf` instead of
{ reading its contents.
let start_len = buf.len();
ReadToEndFuture { If this function encounters an "end of file" before completely filling the buffer,
reader: self, it returns an error of the kind [`ErrorKind::UnexpectedEof`]. The contents of
buf, `buf` are unspecified in this case.
start_len,
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.
[`ErrorKind::UnexpectedEof`]: enum.ErrorKind.html#variant.UnexpectedEof
# Examples
```no_run
# fn main() -> std::io::Result<()> { async_std::task::block_on(async {
#
use async_std::fs::File;
use async_std::prelude::*;
let mut file = File::open("a.txt").await?;
let mut buf = vec![0; 10];
file.read_exact(&mut buf).await?;
#
# Ok(()) }) }
```
"#]
fn read_exact<'a>(
&'a mut self,
buf: &'a mut [u8],
) -> impl Future<Output = io::Result<()>> + 'a [ReadExactFuture<'a, Self>]
where
Self: Unpin,
{
ReadExactFuture { reader: self, buf }
} }
} }
fn read_to_string<'a>(&'a mut self, buf: &'a mut String) -> ReadToStringFuture<'a, Self> impl<T: Read + Unpin + ?Sized> Read for Box<T> {
where fn poll_read(
Self: Unpin, self: Pin<&mut Self>,
{ cx: &mut Context<'_>,
let start_len = buf.len(); buf: &mut [u8],
ReadToStringFuture { ) -> Poll<io::Result<usize>> {
reader: self, unreachable!("this impl only appears in the rendered docs")
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> impl<T: Read + Unpin + ?Sized> Read for &mut T {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
unreachable!("this impl only appears in the rendered docs")
}
}
impl<P> Read for Pin<P>
where where
Self: Unpin, P: DerefMut + Unpin,
<P as Deref>::Target: Read,
{ {
ReadExactFuture { reader: self, buf } fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
unreachable!("this impl only appears in the rendered docs")
}
}
impl Read for &[u8] {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
unreachable!("this impl only appears in the rendered docs")
}
} }
} }
impl<T: futures_io::AsyncRead + ?Sized> ReadExt for T {}

View file

@ -5,119 +5,114 @@ 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:
///
/// ```
/// # #[allow(unused_imports)]
/// use async_std::prelude::*;
/// ```
///
/// [`std::io::Seek`]: https://doc.rust-lang.org/std/io/trait.Seek.html
/// [`futures::io::AsyncSeek`]:
/// https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncSeek.html
/// [provided methods]: #provided-methods
pub trait Seek {
/// Attempt to seek to an offset, in bytes, in a stream.
fn poll_seek(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
pos: SeekFrom,
) -> Poll<io::Result<u64>>;
/// Seeks to a new position in a byte stream. The [provided methods] do not really exist in the trait itself, but they become
/// available when the prelude is imported:
/// Returns the new position in the byte stream.
///
/// A seek beyond the end of stream is allowed, but behavior is defined by the
/// implementation.
///
/// # Examples
///
/// ```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::prelude::*;
///
/// let mut file = File::open("a.txt").await?;
///
/// let file_len = file.seek(SeekFrom::End(0)).await?;
/// #
/// # Ok(()) }) }
/// ```
fn seek(&mut self, pos: SeekFrom) -> ImplFuture<io::Result<u64>>
where
Self: Unpin
{
unreachable!()
}
}
impl<T: Seek + Unpin + ?Sized> Seek for Box<T> { ```
fn poll_seek( # #[allow(unused_imports)]
self: Pin<&mut Self>, use async_std::prelude::*;
cx: &mut Context<'_>, ```
pos: SeekFrom,
) -> Poll<io::Result<u64>> {
unreachable!()
}
}
impl<T: Seek + Unpin + ?Sized> Seek for &mut T { [`std::io::Seek`]: https://doc.rust-lang.org/std/io/trait.Seek.html
fn poll_seek( [`futures::io::AsyncSeek`]:
self: Pin<&mut Self>, https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncSeek.html
cx: &mut Context<'_>, [provided methods]: #provided-methods
pos: SeekFrom, "#]
) -> Poll<io::Result<u64>> { pub trait Seek [SeekExt: futures_io::AsyncSeek] {
unreachable!() #[doc = r#"
} Attempt to seek to an offset, in bytes, in a stream.
} "#]
fn poll_seek(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
pos: SeekFrom,
) -> Poll<io::Result<u64>>;
impl<P> Seek for Pin<P> #[doc = r#"
Seeks to a new position in a 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.
# Examples
```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::prelude::*;
let mut file = File::open("a.txt").await?;
let file_len = file.seek(SeekFrom::End(0)).await?;
#
# Ok(()) }) }
```
"#]
fn seek(
&mut self,
pos: SeekFrom,
) -> impl Future<Output = io::Result<u64>> [SeekFuture<'_, Self>]
where where
P: DerefMut + Unpin, Self: Unpin,
<P as Deref>::Target: Seek,
{ {
fn poll_seek( SeekFuture { seeker: self, pos }
self: Pin<&mut Self>,
cx: &mut Context<'_>,
pos: SeekFrom,
) -> Poll<io::Result<u64>> {
unreachable!()
}
} }
} else {
pub use futures_io::AsyncSeek as Seek;
} }
}
#[doc(hidden)] impl<T: Seek + Unpin + ?Sized> Seek for Box<T> {
pub trait SeekExt: futures_io::AsyncSeek { fn poll_seek(
fn seek(&mut self, pos: SeekFrom) -> SeekFuture<'_, Self> self: Pin<&mut Self>,
cx: &mut Context<'_>,
pos: SeekFrom,
) -> Poll<io::Result<u64>> {
unreachable!("this impl only appears in the rendered docs")
}
}
impl<T: Seek + Unpin + ?Sized> Seek for &mut T {
fn poll_seek(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
pos: SeekFrom,
) -> Poll<io::Result<u64>> {
unreachable!("this impl only appears in the rendered docs")
}
}
impl<P> Seek for Pin<P>
where where
Self: Unpin, P: DerefMut + Unpin,
<P as Deref>::Target: Seek,
{ {
SeekFuture { seeker: self, pos } fn poll_seek(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
pos: SeekFrom,
) -> Poll<io::Result<u64>> {
unreachable!("this impl only appears in the rendered docs")
}
} }
} }
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,271 +20,258 @@ 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
/// the prelude is imported:
///
/// ```
/// # #[allow(unused_imports)]
/// use async_std::prelude::*;
/// ```
///
/// [`std::io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
/// [`futures::io::AsyncWrite`]:
/// https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncWrite.html
/// [`poll_write`]: #tymethod.poll_write
/// [`poll_write_vectored`]: #method.poll_write_vectored
/// [`poll_flush`]: #tymethod.poll_flush
/// [`poll_close`]: #tymethod.poll_close
pub trait Write {
/// Attempt to write bytes from `buf` into the object.
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>>;
/// Attempt to write bytes from `bufs` into the object using vectored Methods other than [`poll_write`], [`poll_write_vectored`], [`poll_flush`], and
/// IO operations. [`poll_close`] do not really exist in the trait itself, but they become available when
fn poll_write_vectored( the prelude is imported:
self: Pin<&mut Self>,
cx: &mut Context<'_>,
bufs: &[IoSlice<'_>]
) -> Poll<io::Result<usize>> {
unreachable!()
}
/// Attempt to flush the object, ensuring that any buffered data reach ```
/// their destination. # #[allow(unused_imports)]
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>>; use async_std::prelude::*;
```
/// Attempt to close the object. [`std::io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>>; [`futures::io::AsyncWrite`]:
https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncWrite.html
[`poll_write`]: #tymethod.poll_write
[`poll_write_vectored`]: #method.poll_write_vectored
[`poll_flush`]: #tymethod.poll_flush
[`poll_close`]: #tymethod.poll_close
"#]
pub trait Write [WriteExt: futures_io::AsyncWrite] {
#[doc = r#"
Attempt to write bytes from `buf` into the object.
"#]
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>>;
/// Writes some bytes into the byte stream. #[doc = r#"
/// Attempt to write bytes from `bufs` into the object using vectored IO operations.
/// Returns the number of bytes written from the start of the buffer. "#]
/// fn poll_write_vectored(
/// If the return value is `Ok(n)` then it must be guaranteed that self: Pin<&mut Self>,
/// `0 <= n <= buf.len()`. A return value of `0` typically means that the underlying cx: &mut Context<'_>,
/// object is no longer able to accept bytes and will likely not be able to in the bufs: &[IoSlice<'_>]
/// future as well, or that the buffer provided is empty. ) -> Poll<io::Result<usize>> {
/// unreachable!("this impl only appears in the rendered docs")
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
/// use async_std::prelude::*;
///
/// let mut file = File::create("a.txt").await?;
///
/// let n = file.write(b"hello world").await?;
/// #
/// # Ok(()) }) }
/// ```
fn write<'a>(&'a mut self, buf: &'a [u8]) -> ImplFuture<'a, io::Result<usize>>
where
Self: Unpin,
{
unreachable!()
}
/// Flushes the stream to ensure that all buffered contents reach their destination.
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
/// use async_std::prelude::*;
///
/// let mut file = File::create("a.txt").await?;
///
/// file.write_all(b"hello world").await?;
/// file.flush().await?;
/// #
/// # Ok(()) }) }
/// ```
fn flush(&mut self) -> ImplFuture<'_, io::Result<()>>
where
Self: Unpin,
{
unreachable!()
}
/// 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
/// the buffers concatenated would.
///
/// The default implementation calls [`write`] with either the first nonempty buffer
/// provided, or an empty one if none exists.
///
/// [`write`]: #tymethod.write
fn write_vectored<'a>(
&'a mut self,
bufs: &'a [IoSlice<'a>],
) -> ImplFuture<'a, io::Result<usize>>
where
Self: Unpin,
{
unreachable!()
}
/// 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
/// buffer has been successfully written or such an error occurs.
///
/// [`write`]: #tymethod.write
///
/// # Examples
///
/// ```no_run
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
/// #
/// use async_std::fs::File;
/// use async_std::prelude::*;
///
/// let mut file = File::create("a.txt").await?;
///
/// file.write_all(b"hello world").await?;
/// #
/// # Ok(()) }) }
/// ```
///
/// [`write`]: #tymethod.write
fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> ImplFuture<'a, io::Result<()>>
where
Self: Unpin,
{
unreachable!()
}
} }
impl<T: Write + Unpin + ?Sized> Write for Box<T> { #[doc = r#"
fn poll_write( Attempt to flush the object, ensuring that any buffered data reach
self: Pin<&mut Self>, their destination.
cx: &mut Context<'_>, "#]
buf: &[u8], fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>>;
) -> Poll<io::Result<usize>> {
unreachable!()
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { #[doc = r#"
unreachable!() 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<()>> { #[doc = r#"
unreachable!() Writes some bytes into the byte stream.
}
}
impl<T: Write + Unpin + ?Sized> Write for &mut T { Returns the number of bytes written from the start of the buffer.
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
unreachable!()
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { If the return value is `Ok(n)` then it must be guaranteed that
unreachable!() `0 <= n <= buf.len()`. A return value of `0` typically means that the underlying
} 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.
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { # Examples
unreachable!()
}
}
impl<P> Write for Pin<P> ```no_run
# fn main() -> std::io::Result<()> { async_std::task::block_on(async {
#
use async_std::fs::File;
use async_std::prelude::*;
let mut file = File::create("a.txt").await?;
let n = file.write(b"hello world").await?;
#
# Ok(()) }) }
```
"#]
fn write<'a>(
&'a mut self,
buf: &'a [u8],
) -> impl Future<Output = io::Result<usize>> + 'a [WriteFuture<'a, Self>]
where where
P: DerefMut + Unpin, Self: Unpin,
<P as Deref>::Target: Write,
{ {
fn poll_write( WriteFuture { writer: self, buf }
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
unreachable!()
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
unreachable!()
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
unreachable!()
}
} }
impl Write for Vec<u8> { #[doc = r#"
fn poll_write( Flushes the stream to ensure that all buffered contents reach their destination.
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
unreachable!()
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { # Examples
unreachable!()
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { ```no_run
unreachable!() # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
} #
use async_std::fs::File;
use async_std::prelude::*;
let mut file = File::create("a.txt").await?;
file.write_all(b"hello world").await?;
file.flush().await?;
#
# Ok(()) }) }
```
"#]
fn flush(&mut self) -> impl Future<Output = io::Result<()>> + '_ [FlushFuture<'_, Self>]
where
Self: Unpin,
{
FlushFuture { writer: self }
}
#[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
the buffers concatenated would.
The default implementation calls [`write`] with either the first nonempty buffer
provided, or an empty one if none exists.
[`write`]: #tymethod.write
"#]
fn write_vectored<'a>(
&'a mut self,
bufs: &'a [IoSlice<'a>],
) -> impl Future<Output = io::Result<usize>> + 'a [WriteVectoredFuture<'a, Self>]
where
Self: Unpin,
{
WriteVectoredFuture { writer: self, bufs }
}
#[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
buffer has been successfully written or such an error occurs.
[`write`]: #tymethod.write
# Examples
```no_run
# fn main() -> std::io::Result<()> { async_std::task::block_on(async {
#
use async_std::fs::File;
use async_std::prelude::*;
let mut file = File::create("a.txt").await?;
file.write_all(b"hello world").await?;
#
# Ok(()) }) }
```
[`write`]: #tymethod.write
"#]
fn write_all<'a>(
&'a mut self,
buf: &'a [u8],
) -> impl Future<Output = io::Result<()>> + 'a [WriteAllFuture<'a, Self>]
where
Self: Unpin,
{
WriteAllFuture { writer: self, buf }
}
}
impl<T: Write + Unpin + ?Sized> Write for Box<T> {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
unreachable!("this impl only appears in the rendered docs")
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
unreachable!("this impl only appears in the rendered docs")
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
unreachable!("this impl only appears in the rendered docs")
}
}
impl<T: Write + Unpin + ?Sized> Write for &mut T {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
unreachable!("this impl only appears in the rendered docs")
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
unreachable!("this impl only appears in the rendered docs")
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
unreachable!("this impl only appears in the rendered docs")
}
}
impl<P> Write for Pin<P>
where
P: DerefMut + Unpin,
<P as Deref>::Target: Write,
{
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
unreachable!("this impl only appears in the rendered docs")
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
unreachable!("this impl only appears in the rendered docs")
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
unreachable!("this impl only appears in the rendered docs")
}
}
impl Write for Vec<u8> {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
unreachable!("this impl only appears in the rendered docs")
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
unreachable!("this impl only appears in the rendered docs")
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
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;