docs: annotate io mod with doc_cfg (#1808)

Annotates types in `tokio::io` module with their required feature flag.
This annotation is included in generated documentation.

Notes:

* The annotation must be on the type or function itself. Annotating just
  the re-export is not sufficient.

* The annotation must be **inside** the `pin_project!` macro or it is
  lost.
This commit is contained in:
Carl Lerche
2019-11-22 09:56:08 -08:00
committed by GitHub
parent 8546ff826d
commit 9b2aa14bb1
34 changed files with 768 additions and 679 deletions
+1
View File
@@ -126,3 +126,4 @@ tempfile = "3.1.0"
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true
rustdoc-args = ["--cfg", "docsrs"]
+95 -92
View File
@@ -10,98 +10,101 @@ use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::Relaxed; use std::sync::atomic::Ordering::Relaxed;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
/// Associates an I/O resource that implements the [`std::io::Read`] and/or cfg_io_driver! {
/// [`std::io::Write`] traits with the reactor that drives it. /// Associates an I/O resource that implements the [`std::io::Read`] and/or
/// /// [`std::io::Write`] traits with the reactor that drives it.
/// `PollEvented` uses [`Registration`] internally to take a type that ///
/// implements [`mio::Evented`] as well as [`std::io::Read`] and or /// `PollEvented` uses [`Registration`] internally to take a type that
/// [`std::io::Write`] and associate it with a reactor that will drive it. /// implements [`mio::Evented`] as well as [`std::io::Read`] and or
/// /// [`std::io::Write`] and associate it with a reactor that will drive it.
/// Once the [`mio::Evented`] type is wrapped by `PollEvented`, it can be ///
/// used from within the future's execution model. As such, the `PollEvented` /// Once the [`mio::Evented`] type is wrapped by `PollEvented`, it can be
/// type provides [`AsyncRead`] and [`AsyncWrite`] implementations using the /// used from within the future's execution model. As such, the
/// underlying I/O resource as well as readiness events provided by the reactor. /// `PollEvented` type provides [`AsyncRead`] and [`AsyncWrite`]
/// /// implementations using the underlying I/O resource as well as readiness
/// **Note**: While `PollEvented` is `Sync` (if the underlying I/O type is /// events provided by the reactor.
/// `Sync`), the caller must ensure that there are at most two tasks that use a ///
/// `PollEvented` instance concurrently. One for reading and one for writing. /// **Note**: While `PollEvented` is `Sync` (if the underlying I/O type is
/// While violating this requirement is "safe" from a Rust memory model point of /// `Sync`), the caller must ensure that there are at most two tasks that
/// view, it will result in unexpected behavior in the form of lost /// use a `PollEvented` instance concurrently. One for reading and one for
/// notifications and tasks hanging. /// writing. While violating this requirement is "safe" from a Rust memory
/// /// model point of view, it will result in unexpected behavior in the form
/// ## Readiness events /// of lost notifications and tasks hanging.
/// ///
/// Besides just providing [`AsyncRead`] and [`AsyncWrite`] implementations, /// ## Readiness events
/// this type also supports access to the underlying readiness event stream. ///
/// While similar in function to what [`Registration`] provides, the semantics /// Besides just providing [`AsyncRead`] and [`AsyncWrite`] implementations,
/// are a bit different. /// this type also supports access to the underlying readiness event stream.
/// /// While similar in function to what [`Registration`] provides, the
/// Two functions are provided to access the readiness events: /// semantics are a bit different.
/// [`poll_read_ready`] and [`poll_write_ready`]. These functions return the ///
/// current readiness state of the `PollEvented` instance. If /// Two functions are provided to access the readiness events:
/// [`poll_read_ready`] indicates read readiness, immediately calling /// [`poll_read_ready`] and [`poll_write_ready`]. These functions return the
/// [`poll_read_ready`] again will also indicate read readiness. /// current readiness state of the `PollEvented` instance. If
/// /// [`poll_read_ready`] indicates read readiness, immediately calling
/// When the operation is attempted and is unable to succeed due to the I/O /// [`poll_read_ready`] again will also indicate read readiness.
/// resource not being ready, the caller must call [`clear_read_ready`] or ///
/// [`clear_write_ready`]. This clears the readiness state until a new readiness /// When the operation is attempted and is unable to succeed due to the I/O
/// event is received. /// resource not being ready, the caller must call [`clear_read_ready`] or
/// /// [`clear_write_ready`]. This clears the readiness state until a new
/// This allows the caller to implement additional functions. For example, /// readiness event is received.
/// [`TcpListener`] implements poll_accept by using [`poll_read_ready`] and ///
/// [`clear_read_ready`]. /// This allows the caller to implement additional functions. For example,
/// /// [`TcpListener`] implements poll_accept by using [`poll_read_ready`] and
/// ```rust /// [`clear_read_ready`].
/// use tokio::io::PollEvented; ///
/// /// ```rust
/// use futures::ready; /// use tokio::io::PollEvented;
/// use mio::Ready; ///
/// use mio::net::{TcpStream, TcpListener}; /// use futures::ready;
/// use std::io; /// use mio::Ready;
/// use std::task::{Context, Poll}; /// use mio::net::{TcpStream, TcpListener};
/// /// use std::io;
/// struct MyListener { /// use std::task::{Context, Poll};
/// poll_evented: PollEvented<TcpListener>, ///
/// } /// struct MyListener {
/// /// poll_evented: PollEvented<TcpListener>,
/// impl MyListener { /// }
/// pub fn poll_accept(&mut self, cx: &mut Context<'_>) -> Poll<Result<TcpStream, io::Error>> { ///
/// let ready = Ready::readable(); /// impl MyListener {
/// /// pub fn poll_accept(&mut self, cx: &mut Context<'_>) -> Poll<Result<TcpStream, io::Error>> {
/// ready!(self.poll_evented.poll_read_ready(cx, ready))?; /// let ready = Ready::readable();
/// ///
/// match self.poll_evented.get_ref().accept() { /// ready!(self.poll_evented.poll_read_ready(cx, ready))?;
/// Ok((socket, _)) => Poll::Ready(Ok(socket)), ///
/// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { /// match self.poll_evented.get_ref().accept() {
/// self.poll_evented.clear_read_ready(cx, ready)?; /// Ok((socket, _)) => Poll::Ready(Ok(socket)),
/// Poll::Pending /// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
/// } /// self.poll_evented.clear_read_ready(cx, ready)?;
/// Err(e) => Poll::Ready(Err(e)), /// Poll::Pending
/// } /// }
/// } /// Err(e) => Poll::Ready(Err(e)),
/// } /// }
/// ``` /// }
/// /// }
/// ## Platform-specific events /// ```
/// ///
/// `PollEvented` also allows receiving platform-specific `mio::Ready` events. /// ## Platform-specific events
/// These events are included as part of the read readiness event stream. The ///
/// write readiness event stream is only for `Ready::writable()` events. /// `PollEvented` also allows receiving platform-specific `mio::Ready` events.
/// /// These events are included as part of the read readiness event stream. The
/// [`std::io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html /// write readiness event stream is only for `Ready::writable()` events.
/// [`std::io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html ///
/// [`AsyncRead`]: ../io/trait.AsyncRead.html /// [`std::io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
/// [`AsyncWrite`]: ../io/trait.AsyncWrite.html /// [`std::io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
/// [`mio::Evented`]: https://docs.rs/mio/0.6/mio/trait.Evented.html /// [`AsyncRead`]: ../io/trait.AsyncRead.html
/// [`Registration`]: struct.Registration.html /// [`AsyncWrite`]: ../io/trait.AsyncWrite.html
/// [`TcpListener`]: ../net/struct.TcpListener.html /// [`mio::Evented`]: https://docs.rs/mio/0.6/mio/trait.Evented.html
/// [`clear_read_ready`]: #method.clear_read_ready /// [`Registration`]: struct.Registration.html
/// [`clear_write_ready`]: #method.clear_write_ready /// [`TcpListener`]: ../net/struct.TcpListener.html
/// [`poll_read_ready`]: #method.poll_read_ready /// [`clear_read_ready`]: #method.clear_read_ready
/// [`poll_write_ready`]: #method.poll_write_ready /// [`clear_write_ready`]: #method.clear_write_ready
pub struct PollEvented<E: Evented> { /// [`poll_read_ready`]: #method.poll_read_ready
io: Option<E>, /// [`poll_write_ready`]: #method.poll_write_ready
inner: Inner, pub struct PollEvented<E: Evented> {
io: Option<E>,
inner: Inner,
}
} }
struct Inner { struct Inner {
+37 -34
View File
@@ -5,40 +5,43 @@ use mio::{self, Evented};
use std::task::{Context, Poll}; use std::task::{Context, Poll};
use std::io; use std::io;
/// Associates an I/O resource with the reactor instance that drives it. cfg_io_driver! {
/// /// Associates an I/O resource with the reactor instance that drives it.
/// A registration represents an I/O resource registered with a Reactor such ///
/// that it will receive task notifications on readiness. This is the lowest /// A registration represents an I/O resource registered with a Reactor such
/// level API for integrating with a reactor. /// that it will receive task notifications on readiness. This is the lowest
/// /// level API for integrating with a reactor.
/// The association between an I/O resource is made by calling [`new`]. Once ///
/// the association is established, it remains established until the /// The association between an I/O resource is made by calling [`new`]. Once
/// registration instance is dropped. /// the association is established, it remains established until the
/// /// registration instance is dropped.
/// A registration instance represents two separate readiness streams. One for ///
/// the read readiness and one for write readiness. These streams are /// A registration instance represents two separate readiness streams. One
/// independent and can be consumed from separate tasks. /// for the read readiness and one for write readiness. These streams are
/// /// independent and can be consumed from separate tasks.
/// **Note**: while `Registration` is `Sync`, the caller must ensure that there ///
/// are at most two tasks that use a registration instance concurrently. One /// **Note**: while `Registration` is `Sync`, the caller must ensure that
/// task for [`poll_read_ready`] and one task for [`poll_write_ready`]. While /// there are at most two tasks that use a registration instance
/// violating this requirement is "safe" from a Rust memory safety point of /// concurrently. One task for [`poll_read_ready`] and one task for
/// view, it will result in unexpected behavior in the form of lost /// [`poll_write_ready`]. While violating this requirement is "safe" from a
/// notifications and tasks hanging. /// Rust memory safety point of view, it will result in unexpected behavior
/// /// in the form of lost notifications and tasks hanging.
/// ## Platform-specific events ///
/// /// ## Platform-specific events
/// `Registration` also allows receiving platform-specific `mio::Ready` events. ///
/// These events are included as part of the read readiness event stream. The /// `Registration` also allows receiving platform-specific `mio::Ready`
/// write readiness event stream is only for `Ready::writable()` events. /// events. These events are included as part of the read readiness event
/// /// stream. The write readiness event stream is only for `Ready::writable()`
/// [`new`]: #method.new /// events.
/// [`poll_read_ready`]: #method.poll_read_ready`] ///
/// [`poll_write_ready`]: #method.poll_write_ready`] /// [`new`]: #method.new
#[derive(Debug)] /// [`poll_read_ready`]: #method.poll_read_ready`]
pub struct Registration { /// [`poll_write_ready`]: #method.poll_write_ready`]
handle: Handle, #[derive(Debug)]
address: Address, pub struct Registration {
handle: Handle,
address: Address,
}
} }
// ===== impl Registration ===== // ===== impl Registration =====
+32 -30
View File
@@ -16,14 +16,39 @@ use std::sync::atomic::Ordering::{Acquire, Release};
use std::sync::Arc; use std::sync::Arc;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
/// The readable half of a value returned from `split`. cfg_io_util! {
pub struct ReadHalf<T> { /// The readable half of a value returned from `split`.
inner: Arc<Inner<T>>, pub struct ReadHalf<T> {
} inner: Arc<Inner<T>>,
}
/// The writable half of a value returned from `split`. /// The writable half of a value returned from `split`.
pub struct WriteHalf<T> { pub struct WriteHalf<T> {
inner: Arc<Inner<T>>, inner: Arc<Inner<T>>,
}
/// Split a single value implementing `AsyncRead + AsyncWrite` into separate
/// `AsyncRead` and `AsyncWrite` handles.
///
/// To restore this read/write object from its `split::ReadHalf` and
/// `split::WriteHalf` use `unsplit`.
pub fn split<T>(stream: T) -> (ReadHalf<T>, WriteHalf<T>)
where
T: AsyncRead + AsyncWrite,
{
let inner = Arc::new(Inner {
locked: AtomicBool::new(false),
stream: UnsafeCell::new(stream),
});
let rd = ReadHalf {
inner: inner.clone(),
};
let wr = WriteHalf { inner };
(rd, wr)
}
} }
struct Inner<T> { struct Inner<T> {
@@ -35,29 +60,6 @@ struct Guard<'a, T> {
inner: &'a Inner<T>, inner: &'a Inner<T>,
} }
/// Split a single value implementing `AsyncRead + AsyncWrite` into separate
/// `AsyncRead` and `AsyncWrite` handles.
///
/// To restore this read/write object from its `split::ReadHalf` and
/// `split::WriteHalf` use `unsplit`.
pub fn split<T>(stream: T) -> (ReadHalf<T>, WriteHalf<T>)
where
T: AsyncRead + AsyncWrite,
{
let inner = Arc::new(Inner {
locked: AtomicBool::new(false),
stream: UnsafeCell::new(stream),
});
let rd = ReadHalf {
inner: inner.clone(),
};
let wr = WriteHalf { inner };
(rd, wr)
}
impl<T> ReadHalf<T> { impl<T> ReadHalf<T> {
/// Reunite with a previously split `WriteHalf`. /// Reunite with a previously split `WriteHalf`.
/// ///
+23 -21
View File
@@ -6,28 +6,30 @@ use std::pin::Pin;
use std::task::Context; use std::task::Context;
use std::task::Poll; use std::task::Poll;
/// A handle to the standard error stream of a process. cfg_io_std! {
/// /// A handle to the standard error stream of a process.
/// The handle implements the [`AsyncWrite`] trait, but beware that concurrent ///
/// writes to `Stderr` must be executed with care. /// The handle implements the [`AsyncWrite`] trait, but beware that concurrent
/// /// writes to `Stderr` must be executed with care.
/// Created by the [`stderr`] function. ///
/// /// Created by the [`stderr`] function.
/// [`stderr`]: fn.stderr.html ///
/// [`AsyncWrite`]: trait.AsyncWrite.html /// [`stderr`]: fn.stderr.html
#[derive(Debug)] /// [`AsyncWrite`]: trait.AsyncWrite.html
pub struct Stderr { #[derive(Debug)]
std: Blocking<std::io::Stderr>, pub struct Stderr {
} std: Blocking<std::io::Stderr>,
}
/// Constructs a new handle to the standard error of the current process. /// Constructs a new handle to the standard error of the current process.
/// ///
/// The returned handle allows writing to standard error from the within the /// The returned handle allows writing to standard error from the within the
/// Tokio runtime. /// Tokio runtime.
pub fn stderr() -> Stderr { pub fn stderr() -> Stderr {
let std = io::stderr(); let std = io::stderr();
Stderr { Stderr {
std: Blocking::new(std), std: Blocking::new(std),
}
} }
} }
+29 -27
View File
@@ -6,34 +6,36 @@ use std::pin::Pin;
use std::task::Context; use std::task::Context;
use std::task::Poll; use std::task::Poll;
/// A handle to the standard input stream of a process. cfg_io_std! {
/// /// A handle to the standard input stream of a process.
/// The handle implements the [`AsyncRead`] trait, but beware that concurrent ///
/// reads of `Stdin` must be executed with care. /// The handle implements the [`AsyncRead`] trait, but beware that concurrent
/// /// reads of `Stdin` must be executed with care.
/// As an additional caveat, reading from the handle may block the calling ///
/// future indefinitely, if there is not enough data available. This makes this /// As an additional caveat, reading from the handle may block the calling
/// handle unsuitable for use in any circumstance where immediate reaction to /// future indefinitely, if there is not enough data available. This makes this
/// available data is required, e.g. interactive use or when implementing a /// handle unsuitable for use in any circumstance where immediate reaction to
/// subprocess driven by requests on the standard input. /// available data is required, e.g. interactive use or when implementing a
/// /// subprocess driven by requests on the standard input.
/// Created by the [`stdin`] function. ///
/// /// Created by the [`stdin`] function.
/// [`stdin`]: fn.stdin.html ///
/// [`AsyncRead`]: trait.AsyncRead.html /// [`stdin`]: fn.stdin.html
#[derive(Debug)] /// [`AsyncRead`]: trait.AsyncRead.html
pub struct Stdin { #[derive(Debug)]
std: Blocking<std::io::Stdin>, pub struct Stdin {
} std: Blocking<std::io::Stdin>,
}
/// Constructs a new handle to the standard input of the current process. /// Constructs a new handle to the standard input of the current process.
/// ///
/// The returned handle allows reading from standard input from the within the /// The returned handle allows reading from standard input from the within the
/// Tokio runtime. /// Tokio runtime.
pub fn stdin() -> Stdin { pub fn stdin() -> Stdin {
let std = io::stdin(); let std = io::stdin();
Stdin { Stdin {
std: Blocking::new(std), std: Blocking::new(std),
}
} }
} }
+23 -21
View File
@@ -6,28 +6,30 @@ use std::pin::Pin;
use std::task::Context; use std::task::Context;
use std::task::Poll; use std::task::Poll;
/// A handle to the standard output stream of a process. cfg_io_std! {
/// /// A handle to the standard output stream of a process.
/// The handle implements the [`AsyncWrite`] trait, but beware that concurrent ///
/// writes to `Stdout` must be executed with care. /// The handle implements the [`AsyncWrite`] trait, but beware that concurrent
/// /// writes to `Stdout` must be executed with care.
/// Created by the [`stdout`] function. ///
/// /// Created by the [`stdout`] function.
/// [`stdout`]: fn.stdout.html ///
/// [`AsyncWrite`]: trait.AsyncWrite.html /// [`stdout`]: fn.stdout.html
#[derive(Debug)] /// [`AsyncWrite`]: trait.AsyncWrite.html
pub struct Stdout { #[derive(Debug)]
std: Blocking<std::io::Stdout>, pub struct Stdout {
} std: Blocking<std::io::Stdout>,
}
/// Constructs a new handle to the standard output of the current process. /// Constructs a new handle to the standard output of the current process.
/// ///
/// The returned handle allows writing to standard out from the within the Tokio /// The returned handle allows writing to standard out from the within the Tokio
/// runtime. /// runtime.
pub fn stdout() -> Stdout { pub fn stdout() -> Stdout {
let std = io::stdout(); let std = io::stdout();
Stdout { Stdout {
std: Blocking::new(std), std: Blocking::new(std),
}
} }
} }
+111 -109
View File
@@ -4,118 +4,120 @@ use crate::io::util::read_until::{read_until, ReadUntil};
use crate::io::util::split::{split, Split}; use crate::io::util::split::{split, Split};
use crate::io::AsyncBufRead; use crate::io::AsyncBufRead;
/// An extension trait which adds utility methods to `AsyncBufRead` types. cfg_io_util! {
pub trait AsyncBufReadExt: AsyncBufRead { /// An extension trait which adds utility methods to `AsyncBufRead` types.
/// Creates a future which will read all the bytes associated with this I/O pub trait AsyncBufReadExt: AsyncBufRead {
/// object into `buf` until the delimiter `byte` or EOF is reached. /// Creates a future which will read all the bytes associated with this I/O
/// This method is the async equivalent to [`BufRead::read_until`](std::io::BufRead::read_until). /// object into `buf` until the delimiter `byte` or EOF is reached.
/// /// This method is the async equivalent to [`BufRead::read_until`](std::io::BufRead::read_until).
/// This function will read bytes from the underlying stream until the ///
/// delimiter or EOF is found. Once found, all bytes up to, and including, /// This function will read bytes from the underlying stream until the
/// the delimiter (if found) will be appended to `buf`. /// delimiter or EOF is found. Once found, all bytes up to, and including,
/// /// the delimiter (if found) will be appended to `buf`.
/// The returned future will resolve to the number of bytes read once the read ///
/// operation is completed. /// The returned future will resolve to the number of bytes read once the read
/// /// operation is completed.
/// In the case of an error the buffer and the object will be discarded, with ///
/// the error yielded. /// In the case of an error the buffer and the object will be discarded, with
fn read_until<'a>(&'a mut self, byte: u8, buf: &'a mut Vec<u8>) -> ReadUntil<'a, Self> /// the error yielded.
where fn read_until<'a>(&'a mut self, byte: u8, buf: &'a mut Vec<u8>) -> ReadUntil<'a, Self>
Self: Unpin, where
{ Self: Unpin,
read_until(self, byte, buf) {
} read_until(self, byte, buf)
}
/// Creates a future which will read all the bytes associated with this I/O /// Creates a future which will read all the bytes associated with this I/O
/// object into `buf` until a newline (the 0xA byte) or EOF is reached, /// object into `buf` until a newline (the 0xA byte) or EOF is reached,
/// This method is the async equivalent to [`BufRead::read_line`](std::io::BufRead::read_line). /// This method is the async equivalent to [`BufRead::read_line`](std::io::BufRead::read_line).
/// ///
/// This function will read bytes from the underlying stream until the /// This function will read bytes from the underlying stream until the
/// newline delimiter (the 0xA byte) or EOF is found. Once found, all bytes /// newline delimiter (the 0xA byte) or EOF is found. Once found, all bytes
/// up to, and including, the delimiter (if found) will be appended to /// up to, and including, the delimiter (if found) will be appended to
/// `buf`. /// `buf`.
/// ///
/// The returned future will resolve to the number of bytes read once the read /// The returned future will resolve to the number of bytes read once the read
/// operation is completed. /// operation is completed.
/// ///
/// In the case of an error the buffer and the object will be discarded, with /// In the case of an error the buffer and the object will be discarded, with
/// the error yielded. /// the error yielded.
/// ///
/// # Errors /// # Errors
/// ///
/// This function has the same error semantics as [`read_until`] and will /// 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 /// 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 /// error is encountered then `buf` may contain some bytes already read in
/// the event that all data read so far was valid UTF-8. /// the event that all data read so far was valid UTF-8.
/// ///
/// [`read_until`]: AsyncBufReadExt::read_until /// [`read_until`]: AsyncBufReadExt::read_until
fn read_line<'a>(&'a mut self, buf: &'a mut String) -> ReadLine<'a, Self> fn read_line<'a>(&'a mut self, buf: &'a mut String) -> ReadLine<'a, Self>
where where
Self: Unpin, Self: Unpin,
{ {
read_line(self, buf) read_line(self, buf)
} }
/// Returns a stream of the contents of this reader split on the byte /// Returns a stream of the contents of this reader split on the byte
/// `byte`. /// `byte`.
/// ///
/// This method is the asynchronous equivalent to /// This method is the asynchronous equivalent to
/// [`BufRead::split`](std::io::BufRead::split). /// [`BufRead::split`](std::io::BufRead::split).
/// ///
/// The stream returned from this function will yield instances of /// The stream returned from this function will yield instances of
/// [`io::Result`]`<`[`Vec<u8>`]`>`. Each vector returned will *not* have /// [`io::Result`]`<`[`Vec<u8>`]`>`. Each vector returned will *not* have
/// the delimiter byte at the end. /// the delimiter byte at the end.
/// ///
/// [`io::Result`]: std::io::Result /// [`io::Result`]: std::io::Result
/// [`Vec<u8>`]: std::vec::Vec /// [`Vec<u8>`]: std::vec::Vec
/// ///
/// # Errors /// # Errors
/// ///
/// Each item of the stream has the same error semantics as /// Each item of the stream has the same error semantics as
/// [`AsyncBufReadExt::read_until`](AsyncBufReadExt::read_until). /// [`AsyncBufReadExt::read_until`](AsyncBufReadExt::read_until).
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// # use tokio::io::AsyncBufRead; /// # use tokio::io::AsyncBufRead;
/// use tokio::io::AsyncBufReadExt; /// use tokio::io::AsyncBufReadExt;
/// ///
/// # async fn dox(my_buf_read: impl AsyncBufRead + Unpin) -> std::io::Result<()> { /// # async fn dox(my_buf_read: impl AsyncBufRead + Unpin) -> std::io::Result<()> {
/// let mut segments = my_buf_read.split(b'f'); /// let mut segments = my_buf_read.split(b'f');
/// ///
/// while let Some(segment) = segments.next_segment().await? { /// while let Some(segment) = segments.next_segment().await? {
/// println!("length = {}", segment.len()) /// println!("length = {}", segment.len())
/// } /// }
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
fn split(self, byte: u8) -> Split<Self> fn split(self, byte: u8) -> Split<Self>
where where
Self: Sized + Unpin, Self: Sized + Unpin,
{ {
split(self, byte) split(self, byte)
} }
/// Returns a stream over the lines of this reader. /// Returns a stream over the lines of this reader.
/// This method is the async equivalent to [`BufRead::lines`](std::io::BufRead::lines). /// This method is the async equivalent to [`BufRead::lines`](std::io::BufRead::lines).
/// ///
/// The stream returned from this function will yield instances of /// The stream returned from this function will yield instances of
/// [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline /// [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline
/// byte (the 0xA byte) or CRLF (0xD, 0xA bytes) at the end. /// byte (the 0xA byte) or CRLF (0xD, 0xA bytes) at the end.
/// ///
/// [`io::Result`]: std::io::Result /// [`io::Result`]: std::io::Result
/// [`String`]: String /// [`String`]: String
/// ///
/// # Errors /// # Errors
/// ///
/// Each line of the stream has the same error semantics as [`AsyncBufReadExt::read_line`]. /// Each line of the stream has the same error semantics as [`AsyncBufReadExt::read_line`].
/// ///
/// [`AsyncBufReadExt::read_line`]: AsyncBufReadExt::read_line /// [`AsyncBufReadExt::read_line`]: AsyncBufReadExt::read_line
fn lines(self) -> Lines<Self> fn lines(self) -> Lines<Self>
where where
Self: Sized, Self: Sized,
{ {
lines(self) lines(self)
}
} }
} }
+75 -73
View File
@@ -7,85 +7,87 @@ use crate::io::util::read_to_string::{read_to_string, ReadToString};
use crate::io::util::take::{take, Take}; use crate::io::util::take::{take, Take};
use crate::io::{AsyncRead, AsyncWrite}; use crate::io::{AsyncRead, AsyncWrite};
/// An extension trait which adds utility methods to `AsyncRead` types. cfg_io_util! {
pub trait AsyncReadExt: AsyncRead { /// An extension trait which adds utility methods to `AsyncRead` types.
/// Creates an adaptor which will chain this stream with another. pub trait AsyncReadExt: AsyncRead {
/// /// Creates an adaptor which will chain this stream with another.
/// The returned `AsyncRead` instance will first read all bytes from this object ///
/// until EOF is encountered. Afterwards the output is equivalent to the /// The returned `AsyncRead` instance will first read all bytes from this object
/// output of `next`. /// until EOF is encountered. Afterwards the output is equivalent to the
fn chain<R>(self, next: R) -> Chain<Self, R> /// output of `next`.
where fn chain<R>(self, next: R) -> Chain<Self, R>
Self: Sized, where
R: AsyncRead, Self: Sized,
{ R: AsyncRead,
chain(self, next) {
} chain(self, next)
}
/// Copy all data from `self` into the provided `AsyncWrite`. /// Copy all data from `self` into the provided `AsyncWrite`.
/// ///
/// The returned future will copy all the bytes read from `reader` into the /// The returned future will copy all the bytes read from `reader` into the
/// `writer` specified. This future will only complete once the `reader` /// `writer` specified. This future will only complete once the `reader`
/// has hit EOF and all bytes have been written to and flushed from the /// has hit EOF and all bytes have been written to and flushed from the
/// `writer` provided. /// `writer` provided.
/// ///
/// On success the number of bytes is returned and the `reader` and `writer` /// On success the number of bytes is returned and the `reader` and `writer`
/// are consumed. On error the error is returned and the I/O objects are /// are consumed. On error the error is returned and the I/O objects are
/// consumed as well. /// consumed as well.
fn copy<'a, W>(&'a mut self, dst: &'a mut W) -> Copy<'a, Self, W> fn copy<'a, W>(&'a mut self, dst: &'a mut W) -> Copy<'a, Self, W>
where where
Self: Unpin, Self: Unpin,
W: AsyncWrite + Unpin + ?Sized, W: AsyncWrite + Unpin + ?Sized,
{ {
copy(self, dst) copy(self, dst)
} }
/// Read data into the provided buffer. /// Read data into the provided buffer.
/// ///
/// The returned future will resolve to the number of bytes read once the /// The returned future will resolve to the number of bytes read once the
/// read operation is completed. /// read operation is completed.
fn read<'a>(&'a mut self, dst: &'a mut [u8]) -> Read<'a, Self> fn read<'a>(&'a mut self, dst: &'a mut [u8]) -> Read<'a, Self>
where where
Self: Unpin, Self: Unpin,
{ {
read(self, dst) read(self, dst)
} }
/// Read exactly the amount of data needed to fill the provided buffer. /// Read exactly the amount of data needed to fill the provided buffer.
fn read_exact<'a>(&'a mut self, dst: &'a mut [u8]) -> ReadExact<'a, Self> fn read_exact<'a>(&'a mut self, dst: &'a mut [u8]) -> ReadExact<'a, Self>
where where
Self: Unpin, Self: Unpin,
{ {
read_exact(self, dst) read_exact(self, dst)
} }
/// Read all bytes until EOF in this source, placing them into `dst`. /// Read all bytes until EOF in this source, placing them into `dst`.
/// ///
/// On success the total number of bytes read is returned. /// On success the total number of bytes read is returned.
fn read_to_end<'a>(&'a mut self, dst: &'a mut Vec<u8>) -> ReadToEnd<'a, Self> fn read_to_end<'a>(&'a mut self, dst: &'a mut Vec<u8>) -> ReadToEnd<'a, Self>
where where
Self: Unpin, Self: Unpin,
{ {
read_to_end(self, dst) read_to_end(self, dst)
} }
/// Read all bytes until EOF in this source, placing them into `dst`. /// Read all bytes until EOF in this source, placing them into `dst`.
/// ///
/// On success the total number of bytes read is returned. /// On success the total number of bytes read is returned.
fn read_to_string<'a>(&'a mut self, dst: &'a mut String) -> ReadToString<'a, Self> fn read_to_string<'a>(&'a mut self, dst: &'a mut String) -> ReadToString<'a, Self>
where where
Self: Unpin, Self: Unpin,
{ {
read_to_string(self, dst) read_to_string(self, dst)
} }
/// Creates an AsyncRead adapter which will read at most `limit` bytes /// Creates an AsyncRead adapter which will read at most `limit` bytes
/// from the underlying reader. /// from the underlying reader.
fn take(self, limit: u64) -> Take<Self> fn take(self, limit: u64) -> Take<Self>
where where
Self: Sized, Self: Sized,
{ {
take(self, limit) take(self, limit)
}
} }
} }
+31 -29
View File
@@ -4,38 +4,40 @@ use crate::io::util::write::{write, Write};
use crate::io::util::write_all::{write_all, WriteAll}; use crate::io::util::write_all::{write_all, WriteAll};
use crate::io::AsyncWrite; use crate::io::AsyncWrite;
/// An extension trait which adds utility methods to `AsyncWrite` types. cfg_io_util! {
pub trait AsyncWriteExt: AsyncWrite { /// An extension trait which adds utility methods to `AsyncWrite` types.
/// Write a buffer into this writter, returning how many bytes were written. pub trait AsyncWriteExt: AsyncWrite {
fn write<'a>(&'a mut self, src: &'a [u8]) -> Write<'a, Self> /// Write a buffer into this writter, returning how many bytes were written.
where fn write<'a>(&'a mut self, src: &'a [u8]) -> Write<'a, Self>
Self: Unpin, where
{ Self: Unpin,
write(self, src) {
} write(self, src)
}
/// Attempt to write an entire buffer into this writter. /// Attempt to write an entire buffer into this writter.
fn write_all<'a>(&'a mut self, src: &'a [u8]) -> WriteAll<'a, Self> fn write_all<'a>(&'a mut self, src: &'a [u8]) -> WriteAll<'a, Self>
where where
Self: Unpin, Self: Unpin,
{ {
write_all(self, src) write_all(self, src)
} }
/// Flush the contents of this writer. /// Flush the contents of this writer.
fn flush(&mut self) -> Flush<'_, Self> fn flush(&mut self) -> Flush<'_, Self>
where where
Self: Unpin, Self: Unpin,
{ {
flush(self) flush(self)
} }
/// Shutdown this writer. /// Shutdown this writer.
fn shutdown(&mut self) -> Shutdown<'_, Self> fn shutdown(&mut self) -> Shutdown<'_, Self>
where where
Self: Unpin, Self: Unpin,
{ {
shutdown(self) shutdown(self)
}
} }
} }
+1 -1
View File
@@ -24,7 +24,7 @@ pin_project! {
/// When the `BufReader` is dropped, the contents of its buffer will be /// When the `BufReader` is dropped, the contents of its buffer will be
/// discarded. Creating multiple instances of a `BufReader` on the same /// discarded. Creating multiple instances of a `BufReader` on the same
/// stream can cause data loss. /// stream can cause data loss.
// TODO: Examples #[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
pub struct BufReader<R> { pub struct BufReader<R> {
#[pin] #[pin]
pub(super) inner: R, pub(super) inner: R,
+1
View File
@@ -16,6 +16,7 @@ pin_project! {
/// types aid with these problems respectively, but do so in only one direction. `BufStream` wraps /// types aid with these problems respectively, but do so in only one direction. `BufStream` wraps
/// one in the other so that both directions are buffered. See their documentation for details. /// one in the other so that both directions are buffered. See their documentation for details.
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
pub struct BufStream<RW> { pub struct BufStream<RW> {
#[pin] #[pin]
inner: BufReader<BufWriter<RW>>, inner: BufReader<BufWriter<RW>>,
+1 -1
View File
@@ -29,7 +29,7 @@ pin_project! {
/// [`AsyncWrite`]: AsyncWrite /// [`AsyncWrite`]: AsyncWrite
/// [`flush`]: super::AsyncWriteExt::flush /// [`flush`]: super::AsyncWriteExt::flush
/// ///
// TODO: Examples #[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
pub struct BufWriter<W> { pub struct BufWriter<W> {
#[pin] #[pin]
pub(super) inner: W, pub(super) inner: W,
+1
View File
@@ -9,6 +9,7 @@ use std::task::{Context, Poll};
pin_project! { pin_project! {
/// Stream for the [`chain`](super::AsyncReadExt::chain) method. /// Stream for the [`chain`](super::AsyncReadExt::chain) method.
#[must_use = "streams do nothing unless polled"] #[must_use = "streams do nothing unless polled"]
#[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
pub struct Chain<T, U> { pub struct Chain<T, U> {
#[pin] #[pin]
first: T, first: T,
+66 -64
View File
@@ -5,71 +5,73 @@ use std::io;
use std::pin::Pin; use std::pin::Pin;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
/// A future that asynchronously copies the entire contents of a reader into a cfg_io_util! {
/// writer. /// A future that asynchronously copies the entire contents of a reader into a
/// /// writer.
/// This struct is generally created by calling [`copy`][copy]. Please ///
/// see the documentation of `copy()` for more details. /// This struct is generally created by calling [`copy`][copy]. Please
/// /// see the documentation of `copy()` for more details.
/// [copy]: fn.copy.html ///
#[derive(Debug)] /// [copy]: fn.copy.html
#[must_use = "futures do nothing unless you `.await` or poll them"] #[derive(Debug)]
pub struct Copy<'a, R: ?Sized, W: ?Sized> { #[must_use = "futures do nothing unless you `.await` or poll them"]
reader: &'a mut R, pub struct Copy<'a, R: ?Sized, W: ?Sized> {
read_done: bool, reader: &'a mut R,
writer: &'a mut W, read_done: bool,
pos: usize, writer: &'a mut W,
cap: usize, pos: usize,
amt: u64, cap: usize,
buf: Box<[u8]>, amt: u64,
} buf: Box<[u8]>,
}
/// Asynchronously copies the entire contents of a reader into a writer. /// Asynchronously copies the entire contents of a reader into a writer.
/// ///
/// This function returns a future that will continuously read data from /// This function returns a future that will continuously read data from
/// `reader` and then write it into `writer` in a streaming fashion until /// `reader` and then write it into `writer` in a streaming fashion until
/// `reader` returns EOF. /// `reader` returns EOF.
/// ///
/// On success, the total number of bytes that were copied from /// On success, the total number of bytes that were copied from `reader` to
/// `reader` to `writer` is returned. /// `writer` is returned.
/// ///
/// This is an asynchronous version of [`std::io::copy`][std]. /// This is an asynchronous version of [`std::io::copy`][std].
/// ///
/// # Errors /// # Errors
/// ///
/// The returned future will finish with an error will return an error /// The returned future will finish with an error will return an error
/// immediately if any call to `poll_read` or `poll_write` returns an error. /// immediately if any call to `poll_read` or `poll_write` returns an error.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use tokio::io; /// use tokio::io;
/// ///
/// # async fn dox() -> std::io::Result<()> { /// # async fn dox() -> std::io::Result<()> {
/// let mut reader: &[u8] = b"hello"; /// let mut reader: &[u8] = b"hello";
/// let mut writer: Vec<u8> = vec![]; /// let mut writer: Vec<u8> = vec![];
/// ///
/// io::copy(&mut reader, &mut writer).await?; /// io::copy(&mut reader, &mut writer).await?;
/// ///
/// assert_eq!(&b"hello"[..], &writer[..]); /// assert_eq!(&b"hello"[..], &writer[..]);
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
/// ///
/// [std]: https://doc.rust-lang.org/std/io/fn.copy.html /// [std]: https://doc.rust-lang.org/std/io/fn.copy.html
pub fn copy<'a, R, W>(reader: &'a mut R, writer: &'a mut W) -> Copy<'a, R, W> pub fn copy<'a, R, W>(reader: &'a mut R, writer: &'a mut W) -> Copy<'a, R, W>
where where
R: AsyncRead + Unpin + ?Sized, R: AsyncRead + Unpin + ?Sized,
W: AsyncWrite + Unpin + ?Sized, W: AsyncWrite + Unpin + ?Sized,
{ {
Copy { Copy {
reader, reader,
read_done: false, read_done: false,
writer, writer,
amt: 0, amt: 0,
pos: 0, pos: 0,
cap: 0, cap: 0,
buf: Box::new([0; 2048]), buf: Box::new([0; 2048]),
}
} }
} }
+36 -34
View File
@@ -5,41 +5,43 @@ use std::io;
use std::pin::Pin; use std::pin::Pin;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
// An async reader which is always at EOF. cfg_io_util! {
/// // An async reader which is always at EOF.
/// This struct is generally created by calling [`empty`]. Please see ///
/// the documentation of [`empty()`][`empty`] for more details. /// This struct is generally created by calling [`empty`]. Please see
/// /// the documentation of [`empty()`][`empty`] for more details.
/// This is an asynchronous version of [`std::io::empty`][std]. ///
/// /// This is an asynchronous version of [`std::io::empty`][std].
/// [`empty`]: fn.empty.html ///
/// [std]: https://doc.rust-lang.org/std/io/struct.Empty.html /// [`empty`]: fn.empty.html
pub struct Empty { /// [std]: https://doc.rust-lang.org/std/io/struct.Empty.html
_p: (), pub struct Empty {
} _p: (),
}
/// Creates a new empty async reader. /// Creates a new empty async reader.
/// ///
/// All reads from the returned reader will return `Poll::Ready(Ok(0))`. /// All reads from the returned reader will return `Poll::Ready(Ok(0))`.
/// ///
/// This is an asynchronous version of [`std::io::empty`][std]. /// This is an asynchronous version of [`std::io::empty`][std].
/// ///
/// # Examples /// # Examples
/// ///
/// A slightly sad example of not reading anything into a buffer: /// A slightly sad example of not reading anything into a buffer:
/// ///
/// ```rust /// ```rust
/// # use tokio::io::{self, AsyncReadExt}; /// # use tokio::io::{self, AsyncReadExt};
/// # async fn dox() { /// # async fn dox() {
/// let mut buffer = String::new(); /// let mut buffer = String::new();
/// io::empty().read_to_string(&mut buffer).await.unwrap(); /// io::empty().read_to_string(&mut buffer).await.unwrap();
/// assert!(buffer.is_empty()); /// assert!(buffer.is_empty());
/// # } /// # }
/// ``` /// ```
/// ///
/// [std]: https://doc.rust-lang.org/std/io/fn.empty.html /// [std]: https://doc.rust-lang.org/std/io/fn.empty.html
pub fn empty() -> Empty { pub fn empty() -> Empty {
Empty { _p: () } Empty { _p: () }
}
} }
impl AsyncRead for Empty { impl AsyncRead for Empty {
+8 -6
View File
@@ -5,12 +5,14 @@ use std::io;
use std::pin::Pin; use std::pin::Pin;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
/// A future used to fully flush an I/O object. cfg_io_util! {
/// /// A future used to fully flush an I/O object.
/// Created by the [`AsyncWriteExt::flush`] function. ///
#[derive(Debug)] /// Created by the [`AsyncWriteExt::flush`] function.
pub struct Flush<'a, A: ?Sized> { #[derive(Debug)]
a: &'a mut A, pub struct Flush<'a, A: ?Sized> {
a: &'a mut A,
}
} }
/// Creates a future which will entirely flush an I/O object. /// Creates a future which will entirely flush an I/O object.
+1
View File
@@ -11,6 +11,7 @@ pin_project! {
/// Stream for the [`lines`](crate::io::AsyncBufReadExt::lines) method. /// Stream for the [`lines`](crate::io::AsyncBufReadExt::lines) method.
#[derive(Debug)] #[derive(Debug)]
#[must_use = "streams do nothing unless polled"] #[must_use = "streams do nothing unless polled"]
#[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
pub struct Lines<R> { pub struct Lines<R> {
#[pin] #[pin]
reader: R, reader: R,
+11 -9
View File
@@ -18,15 +18,17 @@ where
Read { reader, buf } Read { reader, buf }
} }
/// A future which can be used to easily read available number of bytes to fill cfg_io_util! {
/// a buffer. /// A future which can be used to easily read available number of bytes to fill
/// /// a buffer.
/// Created by the [`read`] function. ///
#[derive(Debug)] /// Created by the [`read`] function.
#[must_use = "futures do nothing unless you `.await` or poll them"] #[derive(Debug)]
pub struct Read<'a, R: ?Sized> { #[must_use = "futures do nothing unless you `.await` or poll them"]
reader: &'a mut R, pub struct Read<'a, R: ?Sized> {
buf: &'a mut [u8], reader: &'a mut R,
buf: &'a mut [u8],
}
} }
impl<R> Future for Read<'_, R> impl<R> Future for Read<'_, R>
+12 -10
View File
@@ -21,16 +21,18 @@ where
} }
} }
/// Creates a future which will read exactly enough bytes to fill `buf`, cfg_io_util! {
/// returning an error if EOF is hit sooner. /// Creates a future which will read exactly enough bytes to fill `buf`,
/// /// returning an error if EOF is hit sooner.
/// On success the number of bytes is returned ///
#[derive(Debug)] /// On success the number of bytes is returned
#[must_use = "futures do nothing unless you `.await` or poll them"] #[derive(Debug)]
pub struct ReadExact<'a, A: ?Sized> { #[must_use = "futures do nothing unless you `.await` or poll them"]
reader: &'a mut A, pub struct ReadExact<'a, A: ?Sized> {
buf: &'a mut [u8], reader: &'a mut A,
pos: usize, buf: &'a mut [u8],
pos: usize,
}
} }
fn eof() -> io::Error { fn eof() -> io::Error {
+10 -8
View File
@@ -8,14 +8,16 @@ use std::pin::Pin;
use std::str; use std::str;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
/// Future for the [`read_line`](crate::io::AsyncBufReadExt::read_line) method. cfg_io_util! {
#[derive(Debug)] /// Future for the [`read_line`](crate::io::AsyncBufReadExt::read_line) method.
#[must_use = "futures do nothing unless you `.await` or poll them"] #[derive(Debug)]
pub struct ReadLine<'a, R: ?Sized> { #[must_use = "futures do nothing unless you `.await` or poll them"]
reader: &'a mut R, pub struct ReadLine<'a, R: ?Sized> {
buf: &'a mut String, reader: &'a mut R,
bytes: Vec<u8>, buf: &'a mut String,
read: usize, bytes: Vec<u8>,
read: usize,
}
} }
pub(crate) fn read_line<'a, R>(reader: &'a mut R, buf: &'a mut String) -> ReadLine<'a, R> pub(crate) fn read_line<'a, R>(reader: &'a mut R, buf: &'a mut String) -> ReadLine<'a, R>
+1
View File
@@ -8,6 +8,7 @@ use std::task::{Context, Poll};
#[derive(Debug)] #[derive(Debug)]
#[must_use = "futures do nothing unless you `.await` or poll them"] #[must_use = "futures do nothing unless you `.await` or poll them"]
#[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
pub struct ReadToEnd<'a, R: ?Sized> { pub struct ReadToEnd<'a, R: ?Sized> {
reader: &'a mut R, reader: &'a mut R,
buf: &'a mut Vec<u8>, buf: &'a mut Vec<u8>,
+10 -8
View File
@@ -6,14 +6,16 @@ use std::pin::Pin;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
use std::{io, mem, str}; use std::{io, mem, str};
/// Future for the [`read_to_string`](super::AsyncReadExt::read_to_string) method. cfg_io_util! {
#[derive(Debug)] /// Future for the [`read_to_string`](super::AsyncReadExt::read_to_string) method.
#[must_use = "futures do nothing unless you `.await` or poll them"] #[derive(Debug)]
pub struct ReadToString<'a, R: ?Sized> { #[must_use = "futures do nothing unless you `.await` or poll them"]
reader: &'a mut R, pub struct ReadToString<'a, R: ?Sized> {
buf: &'a mut String, reader: &'a mut R,
bytes: Vec<u8>, buf: &'a mut String,
start_len: usize, bytes: Vec<u8>,
start_len: usize,
}
} }
pub(crate) fn read_to_string<'a, R>(reader: &'a mut R, buf: &'a mut String) -> ReadToString<'a, R> pub(crate) fn read_to_string<'a, R>(reader: &'a mut R, buf: &'a mut String) -> ReadToString<'a, R>
+10 -8
View File
@@ -6,14 +6,16 @@ use std::mem;
use std::pin::Pin; use std::pin::Pin;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
/// Future for the [`read_until`](crate::io::AsyncBufReadExt::read_until) method. cfg_io_util! {
#[derive(Debug)] /// Future for the [`read_until`](crate::io::AsyncBufReadExt::read_until) method.
#[must_use = "futures do nothing unless you `.await` or poll them"] #[derive(Debug)]
pub struct ReadUntil<'a, R: ?Sized> { #[must_use = "futures do nothing unless you `.await` or poll them"]
reader: &'a mut R, pub struct ReadUntil<'a, R: ?Sized> {
byte: u8, reader: &'a mut R,
buf: &'a mut Vec<u8>, byte: u8,
read: usize, buf: &'a mut Vec<u8>,
read: usize,
}
} }
pub(crate) fn read_until<'a, R>( pub(crate) fn read_until<'a, R>(
+37 -35
View File
@@ -4,42 +4,44 @@ use std::io;
use std::pin::Pin; use std::pin::Pin;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
/// An async reader which yields one byte over and over and over and over and cfg_io_util! {
/// over and... /// An async reader which yields one byte over and over and over and over and
/// /// over and...
/// This struct is generally created by calling [`repeat`][repeat]. Please ///
/// see the documentation of `repeat()` for more details. /// This struct is generally created by calling [`repeat`][repeat]. Please
/// /// see the documentation of `repeat()` for more details.
/// This is an asynchronous version of [`std::io::Repeat`][std]. ///
/// /// This is an asynchronous version of [`std::io::Repeat`][std].
/// [repeat]: fn.repeat.html ///
/// [std]: https://doc.rust-lang.org/std/io/struct.Repeat.html /// [repeat]: fn.repeat.html
#[derive(Debug)] /// [std]: https://doc.rust-lang.org/std/io/struct.Repeat.html
pub struct Repeat { #[derive(Debug)]
byte: u8, pub struct Repeat {
} byte: u8,
}
/// Creates an instance of an async reader that infinitely repeats one byte. /// Creates an instance of an async reader that infinitely repeats one byte.
/// ///
/// All reads from this reader will succeed by filling the specified buffer with /// All reads from this reader will succeed by filling the specified buffer with
/// the given byte. /// the given byte.
/// ///
/// This is an asynchronous version of [`std::io::repeat`][std]. /// This is an asynchronous version of [`std::io::repeat`][std].
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// # use tokio::io::{self, AsyncReadExt}; /// # use tokio::io::{self, AsyncReadExt};
/// # async fn dox() { /// # async fn dox() {
/// let mut buffer = [0; 3]; /// let mut buffer = [0; 3];
/// io::repeat(0b101).read_exact(&mut buffer).await.unwrap(); /// io::repeat(0b101).read_exact(&mut buffer).await.unwrap();
/// assert_eq!(buffer, [0b101, 0b101, 0b101]); /// assert_eq!(buffer, [0b101, 0b101, 0b101]);
/// # } /// # }
/// ``` /// ```
/// ///
/// [std]: https://doc.rust-lang.org/std/io/fn.repeat.html /// [std]: https://doc.rust-lang.org/std/io/fn.repeat.html
pub fn repeat(byte: u8) -> Repeat { pub fn repeat(byte: u8) -> Repeat {
Repeat { byte } Repeat { byte }
}
} }
impl AsyncRead for Repeat { impl AsyncRead for Repeat {
+8 -6
View File
@@ -5,12 +5,14 @@ use std::io;
use std::pin::Pin; use std::pin::Pin;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
/// A future used to shutdown an I/O object. cfg_io_util! {
/// /// A future used to shutdown an I/O object.
/// Created by the [`AsyncWriteExt::shutdown`] function. ///
#[derive(Debug)] /// Created by the [`AsyncWriteExt::shutdown`] function.
pub struct Shutdown<'a, A: ?Sized> { #[derive(Debug)]
a: &'a mut A, pub struct Shutdown<'a, A: ?Sized> {
a: &'a mut A,
}
} }
/// Creates a future which will shutdown an I/O object. /// Creates a future which will shutdown an I/O object.
+34 -32
View File
@@ -5,39 +5,41 @@ use std::io;
use std::pin::Pin; use std::pin::Pin;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
/// An async writer which will move data into the void. cfg_io_util! {
/// /// An async writer which will move data into the void.
/// This struct is generally created by calling [`sink`][sink]. Please ///
/// see the documentation of `sink()` for more details. /// This struct is generally created by calling [`sink`][sink]. Please
/// /// see the documentation of `sink()` for more details.
/// This is an asynchronous version of `std::io::Sink`. ///
/// /// This is an asynchronous version of `std::io::Sink`.
/// [sink]: fn.sink.html ///
pub struct Sink { /// [sink]: fn.sink.html
_p: (), pub struct Sink {
} _p: (),
}
/// Creates an instance of an async writer which will successfully consume all /// Creates an instance of an async writer which will successfully consume all
/// data. /// data.
/// ///
/// All calls to `poll_write` on the returned instance will return /// All calls to `poll_write` on the returned instance will return
/// `Poll::Ready(Ok(buf.len()))` and the contents of the buffer will not be /// `Poll::Ready(Ok(buf.len()))` and the contents of the buffer will not be
/// inspected. /// inspected.
/// ///
/// This is an asynchronous version of `std::io::sink`. /// This is an asynchronous version of `std::io::sink`.
/// ///
/// # Examples /// # Examples
/// ///
/// ```rust /// ```rust
/// # use tokio::io::{self, AsyncWriteExt}; /// # use tokio::io::{self, AsyncWriteExt};
/// # async fn dox() { /// # async fn dox() {
/// let buffer = vec![1, 2, 3, 5, 8]; /// let buffer = vec![1, 2, 3, 5, 8];
/// let num_bytes = io::sink().write(&buffer).await.unwrap(); /// let num_bytes = io::sink().write(&buffer).await.unwrap();
/// assert_eq!(num_bytes, 5); /// assert_eq!(num_bytes, 5);
/// # } /// # }
/// ``` /// ```
pub fn sink() -> Sink { pub fn sink() -> Sink {
Sink { _p: () } Sink { _p: () }
}
} }
impl AsyncWrite for Sink { impl AsyncWrite for Sink {
+1
View File
@@ -11,6 +11,7 @@ pin_project! {
/// Stream for the [`split`](crate::io::AsyncBufReadExt::split) method. /// Stream for the [`split`](crate::io::AsyncBufReadExt::split) method.
#[derive(Debug)] #[derive(Debug)]
#[must_use = "streams do nothing unless polled"] #[must_use = "streams do nothing unless polled"]
#[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
pub struct Split<R> { pub struct Split<R> {
#[pin] #[pin]
reader: R, reader: R,
+1
View File
@@ -10,6 +10,7 @@ pin_project! {
/// Stream for the [`take`](super::AsyncReadExt::take) method. /// Stream for the [`take`](super::AsyncReadExt::take) method.
#[derive(Debug)] #[derive(Debug)]
#[must_use = "streams do nothing unless you `.await` or poll them"] #[must_use = "streams do nothing unless you `.await` or poll them"]
#[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
pub struct Take<R> { pub struct Take<R> {
#[pin] #[pin]
inner: R, inner: R,
+8 -6
View File
@@ -5,12 +5,14 @@ use std::io;
use std::pin::Pin; use std::pin::Pin;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
/// A future to write some of the buffer to an `AsyncWrite`. cfg_io_util! {
#[derive(Debug)] /// A future to write some of the buffer to an `AsyncWrite`.
#[must_use = "futures do nothing unless you `.await` or poll them"] #[derive(Debug)]
pub struct Write<'a, W: ?Sized> { #[must_use = "futures do nothing unless you `.await` or poll them"]
writer: &'a mut W, pub struct Write<'a, W: ?Sized> {
buf: &'a [u8], writer: &'a mut W,
buf: &'a [u8],
}
} }
/// Tries to write some bytes from the given `buf` to the writer in an /// Tries to write some bytes from the given `buf` to the writer in an
+7 -5
View File
@@ -6,11 +6,13 @@ use std::mem;
use std::pin::Pin; use std::pin::Pin;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
#[derive(Debug)] cfg_io_util! {
#[must_use = "futures do nothing unless you `.await` or poll them"] #[derive(Debug)]
pub struct WriteAll<'a, W: ?Sized> { #[must_use = "futures do nothing unless you `.await` or poll them"]
writer: &'a mut W, pub struct WriteAll<'a, W: ?Sized> {
buf: &'a [u8], writer: &'a mut W,
buf: &'a [u8],
}
} }
pub(crate) fn write_all<'a, W>(writer: &'a mut W, buf: &'a [u8]) -> WriteAll<'a, W> pub(crate) fn write_all<'a, W>(writer: &'a mut W, buf: &'a [u8]) -> WriteAll<'a, W>
+2 -1
View File
@@ -10,6 +10,7 @@
no_crate_inject, no_crate_inject,
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables)) attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
))] ))]
#![cfg_attr(docsrs, feature(doc_cfg))]
//! A runtime for writing reliable, asynchronous, and slim applications. //! A runtime for writing reliable, asynchronous, and slim applications.
//! //!
@@ -71,7 +72,7 @@
//! [`tokio::task`]: crate::task //! [`tokio::task`]: crate::task
//! [`spawn`]: crate::task::spawn() //! [`spawn`]: crate::task::spawn()
//! [`JoinHandle`]: crate::task::JoinHandle //! [`JoinHandle`]: crate::task::JoinHandle
//! [`blocking`]: task/index.html#blocking-and-yielding //! [blocking]: task/index.html#blocking-and-yielding
//! //!
//! The [`tokio::sync`] module contains synchronization primitives to use when //! The [`tokio::sync`] module contains synchronization primitives to use when
//! need to communicate or share data. These include: //! need to communicate or share data. These include:
+38 -7
View File
@@ -12,7 +12,11 @@ macro_rules! cfg_resource_drivers {
macro_rules! cfg_blocking { macro_rules! cfg_blocking {
($($item:item)*) => { ($($item:item)*) => {
$( #[cfg(feature = "blocking")] $item )* $(
#[cfg(feature = "blocking")]
#[cfg_attr(docsrs, doc(cfg(feature = "blocking")))]
$item
)*
} }
} }
@@ -50,12 +54,22 @@ macro_rules! cfg_not_blocking_impl {
macro_rules! cfg_dns { macro_rules! cfg_dns {
($($item:item)*) => { ($($item:item)*) => {
$( #[cfg(feature = "dns")] $item )* $(
#[cfg(feature = "dns")]
#[cfg_attr(docsrs, doc(cfg(feature = "dns")))]
$item
)*
} }
} }
macro_rules! cfg_fs { macro_rules! cfg_fs {
($($item:item)*) => { $( #[cfg(feature = "fs")] $item )* } ($($item:item)*) => {
$(
#[cfg(feature = "fs")]
#[cfg_attr(docsrs, doc(cfg(feature = "fs")))]
$item
)*
}
} }
macro_rules! cfg_io_blocking { macro_rules! cfg_io_blocking {
@@ -66,25 +80,40 @@ macro_rules! cfg_io_blocking {
macro_rules! cfg_io_driver { macro_rules! cfg_io_driver {
($($item:item)*) => { ($($item:item)*) => {
$( #[cfg(feature = "io-driver")] $item )* $(
#[cfg(feature = "io-driver")]
#[cfg_attr(docsrs, doc(cfg(feature = "io-driver")))]
$item
)*
} }
} }
macro_rules! cfg_not_io_driver { macro_rules! cfg_not_io_driver {
($($item:item)*) => { ($($item:item)*) => {
$( #[cfg(not(feature = "io-driver"))] $item )* $(
#[cfg(not(feature = "io-driver"))]
$item
)*
} }
} }
macro_rules! cfg_io_std { macro_rules! cfg_io_std {
($($item:item)*) => { ($($item:item)*) => {
$( #[cfg(feature = "io-std")] $item )* $(
#[cfg(feature = "io-std")]
#[cfg_attr(docsrs, doc(cfg(feature = "io-std")))]
$item
)*
} }
} }
macro_rules! cfg_io_util { macro_rules! cfg_io_util {
($($item:item)*) => { ($($item:item)*) => {
$( #[cfg(feature = "io-util")] $item )* $(
#[cfg(feature = "io-util")]
#[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
$item
)*
} }
} }
@@ -110,6 +139,7 @@ macro_rules! cfg_macros {
($($item:item)*) => { ($($item:item)*) => {
$( $(
#[cfg(feature = "macros")] #[cfg(feature = "macros")]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
#[doc(inline)] #[doc(inline)]
$item $item
)* )*
@@ -120,6 +150,7 @@ macro_rules! cfg_process {
($($item:item)*) => { ($($item:item)*) => {
$( $(
#[cfg(feature = "process")] #[cfg(feature = "process")]
#[cfg_attr(docsrs, doc(cfg(feature = "process")))]
#[cfg(not(loom))] #[cfg(not(loom))]
$item $item
)* )*
+6 -2
View File
@@ -101,10 +101,14 @@
//! While similar to the standard library, this crate's `Child` type differs //! While similar to the standard library, this crate's `Child` type differs
//! importantly in the behavior of `drop`. In the standard library, a child //! importantly in the behavior of `drop`. In the standard library, a child
//! process will continue running after the instance of [`std::process::Child`] //! process will continue running after the instance of [`std::process::Child`]
//! is dropped. In this crate, however, because [`tokio::process::Child`][Child] is a //! is dropped. In this crate, however, because [`tokio::process::Child`] is a
//! future of the child's `ExitStatus`, a child process is terminated if //! future of the child's `ExitStatus`, a child process is terminated if
//! `tokio::process::Child` is dropped. The behavior of the standard library can //! `tokio::process::Child` is dropped. The behavior of the standard library can
//! be regained with the [`Child::forget`](crate::process::Child::forget) method. //! be regained with the [`Child::forget`](crate::process::Child::forget)
//! method.
//!
//! [`Command`]: crate::process::Command
//! [`tokio::process::Child`]: crate::process::Child
#[path = "unix/mod.rs"] #[path = "unix/mod.rs"]
#[cfg(unix)] #[cfg(unix)]