Revamp IO traits and Stream trait
parent
43d822cbc5
commit
e44451a042
@ -0,0 +1,19 @@
|
||||
/// Never resolves to a value.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # #![feature(async_await)]
|
||||
/// # fn main() { async_std::task::block_on(async {
|
||||
/// #
|
||||
/// use async_std::future::pending;
|
||||
/// use async_std::prelude::*;
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// let dur = Duration::from_secs(1);
|
||||
/// assert!(pending::<()>().timeout(dur).await.is_err());
|
||||
/// #
|
||||
/// # }) }
|
||||
/// ```
|
||||
pub async fn pending<T>() -> T {
|
||||
futures::future::pending::<T>().await
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
/// Resolves to the provided value.
|
||||
///
|
||||
/// This function is an async version of [`std::convert::identity`].
|
||||
///
|
||||
/// [`std::convert::identity`]: https://doc.rust-lang.org/std/convert/fn.identity.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(async_await)]
|
||||
/// # fn main() { async_std::task::block_on(async {
|
||||
/// #
|
||||
/// use async_std::future::ready;
|
||||
///
|
||||
/// assert_eq!(ready(10).await, 10);
|
||||
/// #
|
||||
/// # }) }
|
||||
/// ```
|
||||
pub async fn ready<T>(val: T) -> T {
|
||||
val
|
||||
}
|
@ -0,0 +1,321 @@
|
||||
use std::future::Future;
|
||||
use std::io::{self};
|
||||
use std::mem;
|
||||
use std::pin::Pin;
|
||||
use std::str;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use futures::io::AsyncBufRead;
|
||||
use futures::Stream;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "docs.rs")] {
|
||||
#[doc(hidden)]
|
||||
pub struct ImplFuture<'a, t>(std::marker::PhantomData<&'a t>);
|
||||
|
||||
macro_rules! ret {
|
||||
($a:lifetime, $f:tt, $o:ty) => (ImplFuture<$a, $o>);
|
||||
}
|
||||
} else {
|
||||
macro_rules! ret {
|
||||
($a:lifetime, $f:tt, $o:ty) => ($f<$a, Self>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows reading from a buffered byte stream.
|
||||
///
|
||||
/// This trait is an async version of [`std::io::BufRead`].
|
||||
///
|
||||
/// While it is currently not possible to implement this trait directly, it get implemented
|
||||
/// automatically for all types that implement [`futures::io::AsyncBufRead`].
|
||||
///
|
||||
/// [`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
|
||||
pub trait BufRead {
|
||||
/// Reads all bytes into `buf` until the delimiter `byte` or EOF is reached.
|
||||
///
|
||||
/// This function will read bytes from the underlying stream until the delimiter or EOF is
|
||||
/// found. Once found, all bytes up to, and including, the delimiter (if found) will be
|
||||
/// appended to `buf`.
|
||||
///
|
||||
/// If successful, this function will return the total number of bytes read.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # #![feature(async_await)]
|
||||
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
|
||||
/// #
|
||||
/// use async_std::{fs::File, io::BufReader, prelude::*};
|
||||
///
|
||||
/// let mut f = BufReader::new(File::open("a.txt").await?);
|
||||
///
|
||||
/// let mut buf = vec![0; 1024];
|
||||
/// let n = f.read_until(b'\n', &mut buf).await?;
|
||||
/// #
|
||||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
fn read_until<'a>(
|
||||
&'a mut self,
|
||||
byte: u8,
|
||||
buf: &'a mut Vec<u8>,
|
||||
) -> ret!('a, ReadUntilFuture, io::Result<usize>)
|
||||
where
|
||||
Self: Unpin,
|
||||
{
|
||||
ReadUntilFuture {
|
||||
reader: self,
|
||||
byte,
|
||||
buf,
|
||||
read: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads all bytes and appends them into `buf` until a newline (the 0xA byte) is reached.
|
||||
///
|
||||
/// This function will read bytes from the underlying stream until the newline delimiter (the
|
||||
/// 0xA byte) or EOF is found. Once found, all bytes up to, and 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
|
||||
/// # #![feature(async_await)]
|
||||
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
|
||||
/// #
|
||||
/// use async_std::{fs::File, io::BufReader, prelude::*};
|
||||
///
|
||||
/// let mut f = BufReader::new(File::open("a.txt").await?);
|
||||
///
|
||||
/// let mut buf = String::new();
|
||||
/// f.read_line(&mut buf).await?;
|
||||
/// #
|
||||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
fn read_line<'a>(
|
||||
&'a mut self,
|
||||
buf: &'a mut String,
|
||||
) -> ret!('a, ReadLineFuture, io::Result<usize>)
|
||||
where
|
||||
Self: Unpin,
|
||||
{
|
||||
ReadLineFuture {
|
||||
reader: self,
|
||||
bytes: unsafe { mem::replace(buf.as_mut_vec(), Vec::new()) },
|
||||
buf,
|
||||
read: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a stream over the lines of this byte stream.
|
||||
///
|
||||
/// The stream returned from this function will yield instances of
|
||||
/// [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline byte (the
|
||||
/// 0xA byte) or CRLF (0xD, 0xA bytes) at the end.
|
||||
///
|
||||
/// [`io::Result`]: type.Result.html
|
||||
/// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # #![feature(async_await)]
|
||||
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
|
||||
/// #
|
||||
/// use async_std::{fs::File, io::BufReader, prelude::*};
|
||||
///
|
||||
/// let mut f = BufReader::new(File::open("a.txt").await?);
|
||||
///
|
||||
/// let mut lines = f.lines();
|
||||
/// let mut count = 0;
|
||||
///
|
||||
/// for line in 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsyncBufRead + Unpin + ?Sized> BufRead for T {}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct ReadUntilFuture<'a, T: Unpin + ?Sized> {
|
||||
reader: &'a mut T,
|
||||
byte: u8,
|
||||
buf: &'a mut Vec<u8>,
|
||||
read: usize,
|
||||
}
|
||||
|
||||
impl<T: AsyncBufRead + Unpin + ?Sized> Future for ReadUntilFuture<'_, T> {
|
||||
type Output = io::Result<usize>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let Self {
|
||||
reader,
|
||||
byte,
|
||||
buf,
|
||||
read,
|
||||
} = &mut *self;
|
||||
read_until_internal(Pin::new(reader), cx, *byte, buf, read)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct ReadLineFuture<'a, T: Unpin + ?Sized> {
|
||||
reader: &'a mut T,
|
||||
buf: &'a mut String,
|
||||
bytes: Vec<u8>,
|
||||
read: usize,
|
||||
}
|
||||
|
||||
impl<T: AsyncBufRead + Unpin + ?Sized> Future for ReadLineFuture<'_, T> {
|
||||
type Output = io::Result<usize>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let Self {
|
||||
reader,
|
||||
buf,
|
||||
bytes,
|
||||
read,
|
||||
} = &mut *self;
|
||||
let reader = Pin::new(reader);
|
||||
|
||||
let ret = futures::ready!(read_until_internal(reader, cx, b'\n', bytes, read));
|
||||
if str::from_utf8(&bytes).is_err() {
|
||||
Poll::Ready(ret.and_then(|_| {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"stream did not contain valid UTF-8",
|
||||
))
|
||||
}))
|
||||
} else {
|
||||
debug_assert!(buf.is_empty());
|
||||
debug_assert_eq!(*read, 0);
|
||||
// Safety: `bytes` is a valid UTF-8 because `str::from_utf8` returned `Ok`.
|
||||
mem::swap(unsafe { buf.as_mut_vec() }, bytes);
|
||||
Poll::Ready(ret)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A stream of lines in a byte stream.
|
||||
///
|
||||
/// This stream is created by the [`lines`] method on types that implement [`BufRead`].
|
||||
///
|
||||
/// This type is an async version of [`std::io::Lines`].
|
||||
///
|
||||
/// [`lines`]: trait.BufRead.html#method.lines
|
||||
/// [`BufRead`]: trait.BufRead.html
|
||||
/// [`std::io::Lines`]: https://doc.rust-lang.org/nightly/std/io/struct.Lines.html
|
||||
#[derive(Debug)]
|
||||
pub struct Lines<R> {
|
||||
reader: R,
|
||||
buf: String,
|
||||
bytes: Vec<u8>,
|
||||
read: usize,
|
||||
}
|
||||
|
||||
impl<R: AsyncBufRead> Stream for Lines<R> {
|
||||
type Item = io::Result<String>;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
let Self {
|
||||
reader,
|
||||
buf,
|
||||
bytes,
|
||||
read,
|
||||
} = unsafe { self.get_unchecked_mut() };
|
||||
let reader = unsafe { Pin::new_unchecked(reader) };
|
||||
let n = futures::ready!(read_line_internal(reader, cx, buf, bytes, read))?;
|
||||
if n == 0 && buf.is_empty() {
|
||||
return Poll::Ready(None);
|
||||
}
|
||||
if buf.ends_with('\n') {
|
||||
buf.pop();
|
||||
if buf.ends_with('\r') {
|
||||
buf.pop();
|
||||
}
|
||||
}
|
||||
Poll::Ready(Some(Ok(mem::replace(buf, String::new()))))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_line_internal<R: AsyncBufRead + ?Sized>(
|
||||
reader: Pin<&mut R>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &mut String,
|
||||
bytes: &mut Vec<u8>,
|
||||
read: &mut usize,
|
||||
) -> Poll<io::Result<usize>> {
|
||||
let ret = futures::ready!(read_until_internal(reader, cx, b'\n', bytes, read));
|
||||
if str::from_utf8(&bytes).is_err() {
|
||||
Poll::Ready(ret.and_then(|_| {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"stream did not contain valid UTF-8",
|
||||
))
|
||||
}))
|
||||
} else {
|
||||
debug_assert!(buf.is_empty());
|
||||
debug_assert_eq!(*read, 0);
|
||||
// Safety: `bytes` is a valid UTF-8 because `str::from_utf8` returned `Ok`.
|
||||
mem::swap(unsafe { buf.as_mut_vec() }, bytes);
|
||||
Poll::Ready(ret)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_until_internal<R: AsyncBufRead + ?Sized>(
|
||||
mut reader: Pin<&mut R>,
|
||||
cx: &mut Context<'_>,
|
||||
byte: u8,
|
||||
buf: &mut Vec<u8>,
|
||||
read: &mut usize,
|
||||
) -> Poll<io::Result<usize>> {
|
||||
loop {
|
||||
let (done, used) = {
|
||||
let available = futures::ready!(reader.as_mut().poll_fill_buf(cx))?;
|
||||
if let Some(i) = memchr::memchr(byte, available) {
|
||||
buf.extend_from_slice(&available[..=i]);
|
||||
(true, i + 1)
|
||||
} else {
|
||||
buf.extend_from_slice(available);
|
||||
(false, available.len())
|
||||
}
|
||||
};
|
||||
reader.as_mut().consume(used);
|
||||
*read += used;
|
||||
if done || used == 0 {
|
||||
return Poll::Ready(Ok(mem::replace(read, 0)));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,253 @@
|
||||
use std::io::{self, IoSliceMut, Read, SeekFrom};
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use std::{cmp, fmt};
|
||||
|
||||
use futures::io::{AsyncBufRead, AsyncRead, AsyncSeek, Initializer};
|
||||
|
||||
// used by `BufReader` and `BufWriter`
|
||||
// https://github.com/rust-lang/rust/blob/master/src/libstd/sys_common/io.rs#L1
|
||||
const DEFAULT_BUF_SIZE: usize = 8 * 1024;
|
||||
|
||||
/// The `BufReader` struct adds buffering to any reader.
|
||||
///
|
||||
/// It can be excessively inefficient to work directly with a [`AsyncRead`]
|
||||
/// instance. A `BufReader` performs large, infrequent reads on the underlying
|
||||
/// [`AsyncRead`] and maintains an in-memory buffer of the results.
|
||||
///
|
||||
/// `BufReader` can improve the speed of programs that make *small* and
|
||||
/// *repeated* read calls to the same file or network socket. It does not
|
||||
/// help when reading very large amounts at once, or reading just one or a few
|
||||
/// times. It also provides no advantage when reading from a source that is
|
||||
/// already in memory, like a `Vec<u8>`.
|
||||
///
|
||||
/// When the `BufReader` is dropped, the contents of its buffer will be
|
||||
/// discarded. Creating multiple instances of a `BufReader` on the same
|
||||
/// stream can cause data loss.
|
||||
///
|
||||
/// [`AsyncRead`]: futures_io::AsyncRead
|
||||
///
|
||||
// TODO: Examples
|
||||
pub struct BufReader<R> {
|
||||
inner: R,
|
||||
buf: Box<[u8]>,
|
||||
pos: usize,
|
||||
cap: usize,
|
||||
}
|
||||
|
||||
impl<R: AsyncRead> BufReader<R> {
|
||||
/// Creates a new `BufReader` with a default buffer capacity. The default is currently 8 KB,
|
||||
/// but may change in the future.
|
||||
pub fn new(inner: R) -> Self {
|
||||
Self::with_capacity(DEFAULT_BUF_SIZE, inner)
|
||||
}
|
||||
|
||||
/// Creates a new `BufReader` with the specified buffer capacity.
|
||||
pub fn with_capacity(capacity: usize, inner: R) -> Self {
|
||||
unsafe {
|
||||
let mut buffer = Vec::with_capacity(capacity);
|
||||
buffer.set_len(capacity);
|
||||
inner.initializer().initialize(&mut buffer);
|
||||
Self {
|
||||
inner,
|
||||
buf: buffer.into_boxed_slice(),
|
||||
pos: 0,
|
||||
cap: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> BufReader<R> {
|
||||
pin_utils::unsafe_pinned!(inner: R);
|
||||
pin_utils::unsafe_unpinned!(pos: usize);
|
||||
pin_utils::unsafe_unpinned!(cap: usize);
|
||||
|
||||
/// Gets a reference to the underlying reader.
|
||||
///
|
||||
/// It is inadvisable to directly read from the underlying reader.
|
||||
pub fn get_ref(&self) -> &R {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the underlying reader.
|
||||
///
|
||||
/// It is inadvisable to directly read from the underlying reader.
|
||||
pub fn get_mut(&mut self) -> &mut R {
|
||||
&mut self.inner
|
||||
}
|
||||
|
||||
/// Gets a pinned mutable reference to the underlying reader.
|
||||
///
|
||||
/// It is inadvisable to directly read from the underlying reader.
|
||||
pub fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut R> {
|
||||
self.inner()
|
||||
}
|
||||
|
||||
/// Consumes this `BufWriter`, returning the underlying reader.
|
||||
///
|
||||
/// Note that any leftover data in the internal buffer is lost.
|
||||
pub fn into_inner(self) -> R {
|
||||
self.inner
|
||||
}
|
||||
|
||||
/// Returns a reference to the internally buffered data.
|
||||
///
|
||||
/// Unlike `fill_buf`, this will not attempt to fill the buffer if it is empty.
|
||||
pub fn buffer(&self) -> &[u8] {
|
||||
&self.buf[self.pos..self.cap]
|
||||
}
|
||||
|
||||
/// Invalidates all data in the internal buffer.
|
||||
#[inline]
|
||||
fn discard_buffer(mut self: Pin<&mut Self>) {
|
||||
*self.as_mut().pos() = 0;
|
||||
*self.cap() = 0;
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: AsyncRead> AsyncRead for BufReader<R> {
|
||||
fn poll_read(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &mut [u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
// If we don't have any buffered data and we're doing a massive read
|
||||
// (larger than our internal buffer), bypass our internal buffer
|
||||
// entirely.
|
||||
if self.pos == self.cap && buf.len() >= self.buf.len() {
|
||||
let res = futures::ready!(self.as_mut().inner().poll_read(cx, buf));
|
||||
self.discard_buffer();
|
||||
return Poll::Ready(res);
|
||||
}
|
||||
let mut rem = futures::ready!(self.as_mut().poll_fill_buf(cx))?;
|
||||
let nread = rem.read(buf)?;
|
||||
self.consume(nread);
|
||||
Poll::Ready(Ok(nread))
|
||||
}
|
||||
|
||||
fn poll_read_vectored(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
bufs: &mut [IoSliceMut<'_>],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
|
||||
if self.pos == self.cap && total_len >= self.buf.len() {
|
||||
let res = futures::ready!(self.as_mut().inner().poll_read_vectored(cx, bufs));
|
||||
self.discard_buffer();
|
||||
return Poll::Ready(res);
|
||||
}
|
||||
let mut rem = futures::ready!(self.as_mut().poll_fill_buf(cx))?;
|
||||
let nread = rem.read_vectored(bufs)?;
|
||||
self.consume(nread);
|
||||
Poll::Ready(Ok(nread))
|
||||
}
|
||||
|
||||
// we can't skip unconditionally because of the large buffer case in read.
|
||||
unsafe fn initializer(&self) -> Initializer {
|
||||
self.inner.initializer()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: AsyncRead> AsyncBufRead for BufReader<R> {
|
||||
fn poll_fill_buf<'a>(
|
||||
self: Pin<&'a mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<io::Result<&'a [u8]>> {
|
||||
let Self {
|
||||
inner,
|
||||
buf,
|
||||
cap,
|
||||
pos,
|
||||
} = unsafe { self.get_unchecked_mut() };
|
||||
let mut inner = unsafe { Pin::new_unchecked(inner) };
|
||||
|
||||
// If we've reached the end of our internal buffer then we need to fetch
|
||||
// some more data from the underlying reader.
|
||||
// Branch using `>=` instead of the more correct `==`
|
||||
// to tell the compiler that the pos..cap slice is always valid.
|
||||
if *pos >= *cap {
|
||||
debug_assert!(*pos == *cap);
|
||||
*cap = futures::ready!(inner.as_mut().poll_read(cx, buf))?;
|
||||
*pos = 0;
|
||||
}
|
||||
Poll::Ready(Ok(&buf[*pos..*cap]))
|
||||
}
|
||||
|
||||
fn consume(mut self: Pin<&mut Self>, amt: usize) {
|
||||
*self.as_mut().pos() = cmp::min(self.pos + amt, self.cap);
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: AsyncRead + fmt::Debug> fmt::Debug for BufReader<R> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("BufReader")
|
||||
.field("reader", &self.inner)
|
||||
.field(
|
||||
"buffer",
|
||||
&format_args!("{}/{}", self.cap - self.pos, self.buf.len()),
|
||||
)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: AsyncSeek> AsyncSeek for BufReader<R> {
|
||||
/// Seek to an offset, in bytes, in the underlying reader.
|
||||
///
|
||||
/// The position used for seeking with `SeekFrom::Current(_)` is the
|
||||
/// position the underlying reader would be at if the `BufReader` had no
|
||||
/// internal buffer.
|
||||
///
|
||||
/// Seeking always discards the internal buffer, even if the seek position
|
||||
/// would otherwise fall within it. This guarantees that calling
|
||||
/// `.into_inner()` immediately after a seek yields the underlying reader
|
||||
/// at the same position.
|
||||
///
|
||||
/// To seek without discarding the internal buffer, use
|
||||
/// [`BufReader::poll_seek_relative`](BufReader::poll_seek_relative).
|
||||
///
|
||||
/// See [`AsyncSeek`](futures_io::AsyncSeek) for more details.
|
||||
///
|
||||
/// Note: In the edge case where you're seeking with `SeekFrom::Current(n)`
|
||||
/// where `n` minus the internal buffer length overflows an `i64`, two
|
||||
/// seeks will be performed instead of one. If the second seek returns
|
||||
/// `Err`, the underlying reader will be left at the same position it would
|
||||
/// have if you called `seek` with `SeekFrom::Current(0)`.
|
||||
fn poll_seek(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
pos: SeekFrom,
|
||||
) -> Poll<io::Result<u64>> {
|
||||
let result: u64;
|
||||
if let SeekFrom::Current(n) = pos {
|
||||
let remainder = (self.cap - self.pos) as i64;
|
||||
// it should be safe to assume that remainder fits within an i64 as the alternative
|
||||
// means we managed to allocate 8 exbibytes and that's absurd.
|
||||
// But it's not out of the realm of possibility for some weird underlying reader to
|
||||
// support seeking by i64::min_value() so we need to handle underflow when subtracting
|
||||
// remainder.
|
||||
if let Some(offset) = n.checked_sub(remainder) {
|
||||
result = futures::ready!(
|
||||
self.as_mut()
|
||||
.inner()
|
||||
.poll_seek(cx, SeekFrom::Current(offset))
|
||||
)?;
|
||||
} else {
|
||||
// seek backwards by our remainder, and then by the offset
|
||||
futures::ready!(
|
||||
self.as_mut()
|
||||
.inner()
|
||||
.poll_seek(cx, SeekFrom::Current(-remainder))
|
||||
)?;
|
||||
self.as_mut().discard_buffer();
|
||||
result =
|
||||
futures::ready!(self.as_mut().inner().poll_seek(cx, SeekFrom::Current(n)))?;
|
||||
}
|
||||
} else {
|
||||
// Seeking with Start/End doesn't care about our buffer length.
|
||||
result = futures::ready!(self.as_mut().inner().poll_seek(cx, pos))?;
|
||||
}
|
||||
self.discard_buffer();
|
||||
Poll::Ready(Ok(result))
|
||||
}
|
||||
}
|
@ -0,0 +1,392 @@
|
||||
use std::future::Future;
|
||||
use std::io::{self, IoSliceMut};
|
||||
use std::mem;
|
||||
use std::pin::Pin;
|
||||
use std::str;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use futures::io::AsyncRead;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "docs.rs")] {
|
||||
#[doc(hidden)]
|
||||
pub struct ImplFuture<'a, t>(std::marker::PhantomData<&'a t>);
|
||||
|
||||
macro_rules! ret {
|
||||
($a:lifetime, $f:tt, $o:ty) => (ImplFuture<$a, $o>);
|
||||
}
|
||||
} else {
|
||||
macro_rules! ret {
|
||||
($a:lifetime, $f:tt, $o:ty) => ($f<$a, Self>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows reading from a byte stream.
|
||||
///
|
||||
/// This trait is an async version of [`std::io::Read`].
|
||||
///
|
||||
/// While it is currently not possible to implement this trait directly, it get implemented
|
||||
/// automatically for all types that implement [`futures::io::AsyncRead`].
|
||||
///
|
||||
/// [`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
|
||||
pub trait Read {
|
||||
/// Reads some bytes from the byte stream.
|
||||
///
|
||||
/// Returns the number of bytes read from the start of the buffer.
|
||||
///
|
||||
/// If the return value is `Ok(n)`, then it must be guaranteed that `0 <= n <= buf.len()`. A
|
||||
/// nonzero `n` value indicates that the buffer has been 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
|
||||
/// # #![feature(async_await)]
|
||||
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
|
||||
/// #
|
||||
/// use async_std::{fs::File, prelude::*};
|
||||
///
|
||||
/// let mut f = File::open("a.txt").await?;
|
||||
///
|
||||
/// let mut buf = vec![0; 1024];
|
||||
/// let n = f.read(&mut buf).await?;
|
||||
/// #
|
||||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> ret!('a, ReadFuture, io::Result<usize>)
|
||||
where
|
||||
Self: Unpin;
|
||||
|
||||
/// Like [`read`], except that it reads into a slice of buffers.
|
||||
///
|
||||
/// Data is copied to fill each buffer in order, with the final buffer written to possibly
|
||||
/// being only partially filled. This method must behave as a single call to [`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>],
|
||||
) -> ret!('a, ReadVectoredFuture, io::Result<usize>)
|
||||
where
|
||||
Self: Unpin,
|
||||
{
|
||||
ReadVectoredFuture { reader: self, bufs }
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// # #![feature(async_await)]
|
||||
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
|
||||
/// #
|
||||
/// use async_std::{fs::File, prelude::*};
|
||||
///
|
||||
/// let mut f = File::open("a.txt").await?;
|
||||
///
|
||||
/// let mut buf = Vec::new();
|
||||
/// f.read_to_end(&mut buf).await?;
|
||||
/// #
|
||||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
fn read_to_end<'a>(
|
||||
&'a mut self,
|
||||
buf: &'a mut Vec<u8>,
|
||||
) -> ret!('a, ReadToEndFuture, io::Result<usize>)
|
||||
where
|
||||
Self: Unpin,
|
||||
{
|
||||
let start_len = buf.len();
|
||||
ReadToEndFuture {
|
||||
reader: self,
|
||||
buf,
|
||||
start_len,
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// # #![feature(async_await)]
|
||||
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
|
||||
/// #
|
||||
/// use async_std::{fs::File, prelude::*};
|
||||
///
|
||||
/// let mut f = File::open("a.txt").await?;
|
||||
///
|
||||
/// let mut buf = String::new();
|
||||
/// f.read_to_string(&mut buf).await?;
|
||||
/// #
|
||||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
fn read_to_string<'a>(
|
||||
&'a mut self,
|
||||
buf: &'a mut String,
|
||||
) -> ret!('a, ReadToStringFuture, io::Result<usize>)
|
||||
where
|
||||
Self: Unpin,
|
||||
{
|
||||
let start_len = buf.len();
|
||||
ReadToStringFuture {
|
||||
reader: self,
|
||||
bytes: unsafe { mem::replace(buf.as_mut_vec(), Vec::new()) },
|
||||
buf,
|
||||
start_len,
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads the exact number of bytes required to fill `buf`.
|
||||
///
|
||||
/// 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
|
||||
/// # #![feature(async_await)]
|
||||
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
|
||||
/// #
|
||||
/// use async_std::{fs::File, prelude::*};
|
||||
///
|
||||
/// let mut f = File::open("a.txt").await?;
|
||||
///
|
||||
/// let mut buf = vec![0; 10];
|
||||
/// f.read_exact(&mut buf).await?;
|
||||
/// #
|
||||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> ret!('a, ReadExactFuture, io::Result<()>)
|
||||
where
|
||||
Self: Unpin,
|
||||
{
|
||||
ReadExactFuture { reader: self, buf }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsyncRead + Unpin + ?Sized> Read for T {
|
||||
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> ret!('a, ReadFuture, io::Result<usize>) {
|
||||
ReadFuture { reader: self, buf }
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct ReadFuture<'a, T: Unpin + ?Sized> {
|
||||
reader: &'a mut T,
|
||||
buf: &'a mut [u8],
|
||||
}
|
||||
|
||||
impl<T: AsyncRead + Unpin + ?Sized> Future for ReadFuture<'_, T> {
|
||||
type Output = io::Result<usize>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let Self { reader, buf } = &mut *self;
|
||||
Pin::new(reader).poll_read(cx, buf)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct ReadVectoredFuture<'a, T: Unpin + ?Sized> {
|
||||
reader: &'a mut T,
|
||||
bufs: &'a mut [IoSliceMut<'a>],
|
||||
}
|
||||
|
||||
impl<T: AsyncRead + Unpin + ?Sized> Future for ReadVectoredFuture<'_, T> {
|
||||
type Output = io::Result<usize>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let Self { reader, bufs } = &mut *self;
|
||||
Pin::new(reader).poll_read_vectored(cx, bufs)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct ReadToEndFuture<'a, T: Unpin + ?Sized> {
|
||||
reader: &'a mut T,
|
||||
buf: &'a mut Vec<u8>,
|
||||
start_len: usize,
|
||||
}
|
||||
|
||||
impl<T: AsyncRead + Unpin + ?Sized> Future for ReadToEndFuture<'_, T> {
|
||||
type Output = io::Result<usize>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let Self {
|
||||
reader,
|
||||
buf,
|
||||
start_len,
|
||||
} = &mut *self;
|
||||
read_to_end_internal(Pin::new(reader), cx, buf, *start_len)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct ReadToStringFuture<'a, T: Unpin + ?Sized> {
|
||||
reader: &'a mut T,
|
||||
buf: &'a mut String,
|
||||
bytes: Vec<u8>,
|
||||
start_len: usize,
|
||||
}
|
||||
|
||||
impl<T: AsyncRead + Unpin + ?Sized> Future for ReadToStringFuture<'_, T> {
|
||||
type Output = io::Result<usize>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let Self {
|
||||
reader,
|
||||
buf,
|
||||
bytes,
|
||||
start_len,
|
||||
} = &mut *self;
|
||||
let reader = Pin::new(reader);
|
||||
|
||||
let ret = futures::ready!(read_to_end_internal(reader, cx, bytes, *start_len));
|
||||
if str::from_utf8(&bytes).is_err() {
|
||||
Poll::Ready(ret.and_then(|_| {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"stream did not contain valid UTF-8",
|
||||
))
|
||||
}))
|
||||
} else {
|
||||
debug_assert!(buf.is_empty());
|
||||
// Safety: `bytes` is a valid UTF-8 because `str::from_utf8` returned `Ok`.
|
||||
mem::swap(unsafe { buf.as_mut_vec() }, bytes);
|
||||
Poll::Ready(ret)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct ReadExactFuture<'a, T: Unpin + ?Sized> {
|
||||
reader: &'a mut T,
|
||||
buf: &'a mut [u8],
|
||||
}
|
||||
|
||||
impl<T: AsyncRead + Unpin + ?Sized> Future for ReadExactFuture<'_, T> {
|
||||
type Output = io::Result<()>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let Self { reader, buf } = &mut *self;
|
||||
|
||||
while !buf.is_empty() {
|
||||
let n = futures::ready!(Pin::new(&mut *reader).poll_read(cx, buf))?;
|
||||
let (_, rest) = mem::replace(buf, &mut []).split_at_mut(n);
|
||||
*buf = rest;
|
||||
|
||||
if n == 0 {
|
||||
return Poll::Ready(Err(io::ErrorKind::UnexpectedEof.into()));
|
||||
}
|
||||
}
|
||||
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
// This uses an adaptive system to extend the vector when it fills. We want to
|
||||
// avoid paying to allocate and zero a huge chunk of memory if the reader only
|
||||
// has 4 bytes while still making large reads if the reader does have a ton
|
||||
// of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every
|
||||
// time is 4,500 times (!) slower than this if the reader has a very small
|
||||
// amount of data to return.
|
||||
//
|
||||
// Because we're extending the buffer with uninitialized data for trusted
|
||||
// readers, we need to make sure to truncate that if any of this panics.
|
||||
pub fn read_to_end_internal<R: AsyncRead + ?Sized>(
|
||||
mut rd: Pin<&mut R>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &mut Vec<u8>,
|
||||
start_len: usize,
|
||||
) -> Poll<io::Result<usize>> {
|
||||
struct Guard<'a> {
|
||||
buf: &'a mut Vec<u8>,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl Drop for Guard<'_> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.buf.set_len(self.len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut g = Guard {
|
||||
len: buf.len(),
|
||||
buf,
|
||||
};
|
||||
let ret;
|
||||
loop {
|
||||
if g.len == g.buf.len() {
|
||||
unsafe {
|
||||
g.buf.reserve(32);
|
||||
let capacity = g.buf.capacity();
|
||||
g.buf.set_len(capacity);
|
||||
rd.initializer().initialize(&mut g.buf[g.len..]);
|
||||
}
|
||||
}
|
||||
|
||||
match futures::ready!(rd.as_mut().poll_read(cx, &mut g.buf[g.len..])) {
|
||||
Ok(0) => {
|
||||
ret = Poll::Ready(Ok(g.len - start_len));
|
||||
break;
|
||||
}
|
||||
Ok(n) => g.len += n,
|
||||
Err(e) => {
|
||||
ret = Poll::Ready(Err(e));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
use std::future::Future;
|
||||
use std::io::{self, SeekFrom};
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use futures::io::AsyncSeek;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "docs.rs")] {
|
||||
#[doc(hidden)]
|
||||
pub struct ImplFuture<'a, t>(std::marker::PhantomData<&'a t>);
|
||||
|
||||
macro_rules! ret {
|
||||
($a:lifetime, $f:tt, $o:ty) => (ImplFuture<$a, $o>);
|
||||
}
|
||||
} else {
|
||||
macro_rules! ret {
|
||||
($a:lifetime, $f:tt, $o:ty) => ($f<$a, Self>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows seeking through a byte stream.
|
||||
///
|
||||
/// This trait is an async version of [`std::io::Seek`].
|
||||
///
|
||||
/// While it is currently not possible to implement this trait directly, it get implemented
|
||||
/// automatically for all types that implement [`futures::io::AsyncSeek`].
|
||||
///
|
||||
/// [`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
|
||||
pub trait Seek {
|
||||
/// 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
|
||||
/// # #![feature(async_await)]
|
||||
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
|
||||
/// #
|
||||
/// use async_std::{fs::File, io::SeekFrom, prelude::*};
|
||||
///
|
||||
/// let mut f = File::open("a.txt").await?;
|
||||
///
|
||||
/// let file_len = f.seek(SeekFrom::End(0)).await?;
|
||||
/// #
|
||||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
fn seek(&mut self, pos: SeekFrom) -> ret!('_, SeekFuture, io::Result<u64>)
|
||||
where
|
||||
Self: Unpin;
|
||||
}
|
||||
|
||||
impl<T: AsyncSeek + Unpin + ?Sized> Seek for T {
|
||||
fn seek(&mut self, pos: SeekFrom) -> ret!('_, SeekFuture, io::Result<u64>) {
|
||||
SeekFuture { seeker: self, pos }
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct SeekFuture<'a, T: Unpin + ?Sized> {
|
||||
seeker: &'a mut T,
|
||||
pos: SeekFrom,
|
||||
}
|
||||
|
||||
impl<T: AsyncSeek + Unpin + ?Sized> Future for SeekFuture<'_, T> {
|
||||
type Output = io::Result<u64>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let pos = self.pos;
|
||||
Pin::new(&mut *self.seeker).poll_seek(cx, pos)
|
||||
}
|
||||
}
|
@ -0,0 +1,213 @@
|
||||
use std::future::Future;
|
||||
use std::io::{self, IoSlice};
|
||||
use std::mem;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use futures::io::AsyncWrite;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "docs.rs")] {
|
||||
#[doc(hidden)]
|
||||
pub struct ImplFuture<'a, t>(std::marker::PhantomData<&'a t>);
|
||||
|
||||
macro_rules! ret {
|
||||
($a:lifetime, $f:tt, $o:ty) => (ImplFuture<$a, $o>);
|
||||
}
|
||||
} else {
|
||||
macro_rules! ret {
|
||||
($a:lifetime, $f:tt, $o:ty) => ($f<$a, Self>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows writing to a byte stream.
|
||||
///
|
||||
/// This trait is an async version of [`std::io::Write`].
|
||||
///
|
||||
/// While it is currently not possible to implement this trait directly, it get implemented
|
||||
/// automatically for all types that implement [`futures::io::AsyncWrite`].
|
||||
///
|
||||
/// [`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
|
||||
pub trait Write {
|
||||
/// Writes some bytes into the byte stream.
|
||||
///
|
||||
/// Returns the number of bytes written from the start of the buffer.
|
||||
///
|
||||
/// If the return value is `Ok(n)` then it must be guaranteed that `0 <= n <= buf.len()`. A
|
||||
/// return value of `0` typically means that the underlying object is no longer able to accept
|
||||
/// bytes and will likely not be able to in the future as well, or that the buffer provided is
|
||||
/// empty.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # #![feature(async_await)]
|
||||
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
|
||||
/// #
|
||||
/// use async_std::{fs::File, prelude::*};
|
||||
///
|
||||
/// let mut f = File::create("a.txt").await?;
|
||||
///
|
||||
/// let n = f.write(b"hello world").await?;
|
||||
/// #
|
||||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
fn write<'a>(&'a mut self, buf: &'a [u8]) -> ret!('a, WriteFuture, io::Result<usize>)
|
||||
where
|
||||
Self: Unpin;
|
||||
|
||||
/// Flushes the stream to ensure that all buffered contents reach their destination.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # #![feature(async_await)]
|
||||
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
|
||||
/// #
|
||||
/// use async_std::{fs::File, prelude::*};
|
||||
///
|
||||
/// let mut f = File::create("a.txt").await?;
|
||||
///
|
||||
/// f.write_all(b"hello world").await?;
|
||||
/// f.flush().await?;
|
||||
/// #
|
||||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
fn flush(&mut self) -> ret!('_, FlushFuture, io::Result<()>)
|
||||
where
|
||||
Self: Unpin;
|
||||
|
||||
/// 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>],
|
||||
) -> ret!('a, WriteVectoredFuture, io::Result<usize>)
|
||||
where
|
||||
Self: Unpin,
|
||||
{
|
||||
WriteVectoredFuture { writer: self, bufs }
|
||||
}
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # #![feature(async_await)]
|
||||
/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
|
||||
/// #
|
||||
/// use async_std::{fs::File, prelude::*};
|
||||
///
|
||||
/// let mut f = File::create("a.txt").await?;
|
||||
///
|
||||
/// f.write_all(b"hello world").await?;
|
||||
/// #
|
||||
/// # Ok(()) }) }
|
||||
/// ```
|
||||
fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> ret!('a, WriteAllFuture, io::Result<()>)
|
||||
where
|
||||
Self: Unpin,
|
||||
{
|
||||
WriteAllFuture { writer: self, buf }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsyncWrite + Unpin + ?Sized> Write for T {
|
||||
fn write<'a>(&'a mut self, buf: &'a [u8]) -> ret!('a, WriteFuture, io::Result<usize>) {
|
||||
WriteFuture { writer: self, buf }
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> ret!('_, FlushFuture, io::Result<()>) {
|
||||
FlushFuture { writer: self }
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct WriteFuture<'a, T: Unpin + ?Sized> {
|
||||
writer: &'a mut T,
|
||||
buf: &'a [u8],
|
||||
}
|
||||
|
||||
impl<T: AsyncWrite + Unpin + ?Sized> Future for WriteFuture<'_, T> {
|
||||
type Output = io::Result<usize>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let buf = self.buf;
|
||||
Pin::new(&mut *self.writer).poll_write(cx, buf)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct FlushFuture<'a, T: Unpin + ?Sized> {
|
||||
writer: &'a mut T,
|
||||
}
|
||||
|
||||
impl<T: AsyncWrite + Unpin + ?Sized> Future for FlushFuture<'_, T> {
|
||||
type Output = io::Result<()>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
Pin::new(&mut *self.writer).poll_flush(cx)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct WriteVectoredFuture<'a, T: Unpin + ?Sized> {
|
||||
writer: &'a mut T,
|
||||
bufs: &'a [IoSlice<'a>],
|
||||
}
|
||||
|
||||
impl<T: AsyncWrite + Unpin + ?Sized> Future for WriteVectoredFuture<'_, T> {
|
||||
type Output = io::Result<usize>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let bufs = self.bufs;
|
||||
Pin::new(&mut *self.writer).poll_write_vectored(cx, bufs)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct WriteAllFuture<'a, T: Unpin + ?Sized> {
|
||||
writer: &'a mut T,
|
||||
buf: &'a [u8],
|
||||
}
|
||||
|
||||
impl<T: AsyncWrite + Unpin + ?Sized> Future for WriteAllFuture<'_, T> {
|
||||
type Output = io::Result<()>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let Self { writer, buf } = &mut *self;
|
||||
|
||||
while !buf.is_empty() {
|
||||
let n = futures::ready!(Pin::new(&mut **writer).poll_write(cx, buf))?;
|
||||
let (_, rest) = mem::replace(buf, &[]).split_at(n);
|
||||
*buf = rest;
|
||||
|
||||
if n == 0 {
|
||||
return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
|
||||
}
|
||||
}
|
||||
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
/// Creates a stream that doesn't yield any items.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(async_await)]
|
||||
/// # fn main() { async_std::task::block_on(async {
|
||||
/// #
|
||||
/// use async_std::{prelude::*, stream};
|
||||
///
|
||||
/// let mut s = stream::empty::<i32>();
|
||||
///
|
||||
/// assert_eq!(s.next().await, None);
|
||||
/// #
|
||||
/// # }) }
|
||||
/// ```
|
||||
pub fn empty<T>() -> Empty<T> {
|
||||
Empty {
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// A stream that doesn't yield any items.
|
||||
///
|
||||
/// This stream is constructed by the [`empty`] function.
|
||||
///
|
||||
/// [`empty`]: fn.empty.html
|
||||
#[derive(Debug)]
|
||||
pub struct Empty<T> {
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> futures::Stream for Empty<T> {
|
||||
type Item = T;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
Poll::Ready(None)
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
/// Creates a stream that yields a single item.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(async_await)]
|
||||
/// # fn main() { async_std::task::block_on(async {
|
||||
/// #
|
||||
/// use async_std::{prelude::*, stream};
|
||||
///
|
||||
/// let mut s = stream::once(7);
|
||||
///
|
||||
/// assert_eq!(s.next().await, Some(7));
|
||||
/// assert_eq!(s.next().await, None);
|
||||
/// #
|
||||
/// # }) }
|
||||
/// ```
|
||||
pub fn once<T>(t: T) -> Once<T> {
|
||||
Once { value: Some(t) }
|
||||
}
|
||||
|
||||
/// A stream that yields a single item.
|
||||
///
|
||||
/// This stream is constructed by the [`once`] function.
|
||||
///
|
||||
/// [`once`]: fn.once.html
|
||||
#[derive(Debug)]
|
||||
pub struct Once<T> {
|
||||
value: Option<T>,
|
||||
}
|
||||
|
||||
impl<T: Unpin> futures::Stream for Once<T> {
|
||||
type Item = T;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Option<T>> {
|
||||
Poll::Ready(self.value.take())
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
/// Creates a stream that yields the same item repeatedly.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(async_await)]
|
||||
/// # fn main() { async_std::task::block_on(async {
|
||||
/// #
|
||||
/// use async_std::{prelude::*, stream};
|
||||
///
|
||||
/// let mut s = stream::repeat(7);
|
||||
///
|
||||
/// assert_eq!(s.next().await, Some(7));
|
||||
/// assert_eq!(s.next().await, Some(7));
|
||||
/// #
|
||||
/// # }) }
|
||||
/// ```
|
||||
pub fn repeat<T>(item: T) -> Repeat<T>
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
Repeat { item }
|
||||
}
|
||||
|
||||
/// A stream that yields the same item repeatedly.
|
||||
///
|
||||
/// This stream is constructed by the [`repeat`] function.
|
||||
///
|
||||
/// [`repeat`]: fn.repeat.html
|
||||
#[derive(Debug)]
|
||||
pub struct Repeat<T> {
|
||||
item: T,
|
||||
}
|
||||
|
||||
impl<T: Clone> futures::Stream for Repeat<T> {
|
||||
type Item = T;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
Poll::Ready(Some(self.item.clone()))
|
||||
}
|
||||
}
|
@ -0,0 +1,169 @@
|
||||
//! Asynchronous iteration.
|
||||
//!
|
||||
//! This module is an async version of [`std::iter`].
|
||||
//!
|
||||
//! [`std::iter`]: https://doc.rust-lang.org/std/iter/index.html
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! ```
|
||||
//! # #![feature(async_await)]
|
||||
//! # fn main() { async_std::task::block_on(async {
|
||||
//! #
|
||||
//! use async_std::{prelude::*, stream};
|
||||
//!
|
||||
//! let mut s = stream::repeat(9).take(3);
|
||||
//!
|
||||
//! while let Some(v) = s.next().await {
|
||||
//! assert_eq!(v, 9);
|
||||
//! }
|
||||
//! #
|
||||
//! # }) }
|
||||
//! ```
|
||||
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "docs.rs")] {
|
||||
#[doc(hidden)]
|
||||
pub struct ImplFuture<'a, T>(std::marker::PhantomData<&'a T>);
|
||||
|
||||
macro_rules! ret {
|
||||
($a:lifetime, $f:tt, $o:ty) => (ImplFuture<$a, $o>);
|
||||
}
|
||||
} else {
|
||||
macro_rules! ret {
|
||||
($a:lifetime, $f:tt, $o:ty) => ($f<$a, Self>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An asynchronous stream of values.
|
||||
///
|
||||
/// This trait is an async version of [`std::iter::Iterator`].
|
||||
///
|
||||
/// While it is currently not possible to implement this trait directly, it gets implemented
|
||||
/// automatically for all types that implement [`futures::stream::Stream`].
|
||||
///
|
||||
/// [`std::iter::Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html
|
||||
/// [`futures::stream::Stream`]:
|
||||
/// https://docs.rs/futures-preview/0.3.0-alpha.17/futures/stream/trait.Stream.html
|
||||
pub trait Stream {
|
||||
/// The type of items yielded by this stream.
|
||||
type Item;
|
||||
|
||||
/// Advances the stream and returns the next value.
|
||||
///
|
||||
/// Returns [`None`] when iteration is finished. Individual stream implementations may
|
||||
/// choose to resume iteration, and so calling `next()` again may or may not eventually
|
||||
/// start returning more values.
|
||||
///
|
||||
/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(async_await)]
|
||||
/// # fn main() { async_std::task::block_on(async {
|
||||
/// #
|
||||
/// use async_std::{prelude::*, stream};
|
||||
///
|
||||
/// let mut s = stream::once(7);
|
||||
///
|
||||
/// assert_eq!(s.next().await, Some(7));
|
||||
/// assert_eq!(s.next().await, None);
|
||||
/// #
|
||||
/// # }) }
|
||||
/// ```
|
||||
fn next<'a>(&'a mut self) -> ret!('a, NextFuture, Option<Self::Item>)
|
||||
where
|
||||
Self: Unpin;
|
||||
|
||||
/// Creates a stream that yields its first `n` elements.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(async_await)]
|
||||
/// # fn main() { async_std::task::block_on(async {
|
||||
/// #
|
||||
/// use async_std::{prelude::*, stream};
|
||||
///
|
||||
/// let mut s = stream::repeat(9).take(3);
|
||||
///
|
||||
/// while let Some(v) = s.next().await {
|
||||
/// assert_eq!(v, 9);
|
||||
/// }
|
||||
/// #
|
||||
/// # }) }
|
||||
/// ```
|
||||
fn take(self, n: usize) -> Take<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Take {
|
||||
stream: self,
|
||||
remaining: n,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: futures::Stream + Unpin + ?Sized> Stream for T {
|
||||
type Item = <Self as futures::Stream>::Item;
|
||||
|
||||
fn next<'a>(&'a mut self) -> ret!('a, NextFuture, Option<Self::Item>)
|
||||
where
|
||||
Self: Unpin,
|
||||
{
|
||||
NextFuture { stream: self }
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct NextFuture<'a, T: Unpin + ?Sized> {
|
||||
stream: &'a mut T,
|
||||
}
|
||||
|
||||
impl<T: futures::Stream + Unpin + ?Sized> Future for NextFuture<'_, T> {
|
||||
type Output = Option<T::Item>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
Pin::new(&mut *self.stream).poll_next(cx)
|
||||
}
|
||||
}
|
||||
|
||||
/// A stream that yields the first `n` items of another stream.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Take<S> {
|
||||
stream: S,
|
||||
remaining: usize,
|
||||
}
|
||||
|
||||
impl<S: Unpin> Unpin for Take<S> {}
|
||||
|
||||
impl<S: futures::Stream> Take<S> {
|
||||
pin_utils::unsafe_pinned!(stream: S);
|
||||
pin_utils::unsafe_unpinned!(remaining: usize);
|
||||
}
|
||||
|
||||
impl<S: futures::Stream> futures::Stream for Take<S> {
|
||||
type Item = S::Item;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<S::Item>> {
|
||||
if self.remaining == 0 {
|
||||
Poll::Ready(None)
|
||||
} else {
|
||||
let next = futures::ready!(self.as_mut().stream().poll_next(cx));
|
||||
match next {
|
||||
Some(_) => *self.as_mut().remaining() -= 1,
|
||||
None => *self.as_mut().remaining() = 0,
|
||||
}
|
||||
Poll::Ready(next)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue