summaryrefslogtreecommitdiffstats
path: root/tokio
diff options
context:
space:
mode:
authorJeb Rosen <jeb@jebrosen.com>2020-01-08 19:15:57 -0800
committerGitHub <noreply@github.com>2020-01-08 19:15:57 -0800
commitf28c9f0d17a4dca2003bbee57a09f62c3795c2d2 (patch)
treec5314dc3d74ee7f8b5eb62221c3383fc49759c82 /tokio
parent7ee554218208a9f3919d840079bd96c6ba881caf (diff)
Fix Seek adapter and AsyncSeek error handling for File
* io: Fix the Seek adapter and add a tested example. If the first 'AsyncRead::start_seek' call returns Ready, 'AsyncRead::poll_complete' will be called. Previously, a start_seek that immediately returned 'Ready' would cause the Seek adapter to return 'Pending' without registering a Waker. * fs: Do not return write errors from methods on AsyncSeek. Write errors should only be returned on subsequent writes or on flush. Also copy the last_write_err assert from 'poll_read' to both 'start_seek' and 'poll_complete' for consistency.
Diffstat (limited to 'tokio')
-rw-r--r--tokio/src/fs/file.rs10
-rw-r--r--tokio/src/io/seek.rs16
-rw-r--r--tokio/src/io/util/async_seek_ext.rs22
3 files changed, 32 insertions, 16 deletions
diff --git a/tokio/src/fs/file.rs b/tokio/src/fs/file.rs
index 301d2380..9110831a 100644
--- a/tokio/src/fs/file.rs
+++ b/tokio/src/fs/file.rs
@@ -558,10 +558,6 @@ impl AsyncSeek for File {
cx: &mut Context<'_>,
mut pos: SeekFrom,
) -> Poll<io::Result<()>> {
- if let Some(e) = self.last_write_err.take() {
- return Ready(Err(e.into()));
- }
-
loop {
match self.state {
Idle(ref mut buf_cell) => {
@@ -592,6 +588,7 @@ impl AsyncSeek for File {
match op {
Operation::Read(_) => {}
Operation::Write(Err(e)) => {
+ assert!(self.last_write_err.is_none());
self.last_write_err = Some(e.kind());
}
Operation::Write(_) => {}
@@ -603,10 +600,6 @@ impl AsyncSeek for File {
}
fn poll_complete(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<u64>> {
- if let Some(e) = self.last_write_err.take() {
- return Ready(Err(e.into()));
- }
-
loop {
match self.state {
Idle(_) => panic!("must call start_seek before calling poll_complete"),
@@ -617,6 +610,7 @@ impl AsyncSeek for File {
match op {
Operation::Read(_) => {}
Operation::Write(Err(e)) => {
+ assert!(self.last_write_err.is_none());
self.last_write_err = Some(e.kind());
}
Operation::Write(_) => {}
diff --git a/tokio/src/io/seek.rs b/tokio/src/io/seek.rs
index 080141f0..e3b5bf6b 100644
--- a/tokio/src/io/seek.rs
+++ b/tokio/src/io/seek.rs
@@ -31,14 +31,14 @@ where
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let me = &mut *self;
match me.pos {
- Some(pos) => {
- match Pin::new(&mut me.seek).start_seek(cx, pos) {
- Poll::Ready(Ok(())) => me.pos = None,
- Poll::Ready(Err(e)) => return Poll::Ready(Err(e)),
- Poll::Pending => (),
- };
- Poll::Pending
- }
+ Some(pos) => match Pin::new(&mut me.seek).start_seek(cx, pos) {
+ Poll::Ready(Ok(())) => {
+ me.pos = None;
+ Pin::new(&mut me.seek).poll_complete(cx)
+ }
+ Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
+ Poll::Pending => Poll::Pending,
+ },
None => Pin::new(&mut me.seek).poll_complete(cx),
}
}
diff --git a/tokio/src/io/util/async_seek_ext.rs b/tokio/src/io/util/async_seek_ext.rs
index 3063884b..c7243c7f 100644
--- a/tokio/src/io/util/async_seek_ext.rs
+++ b/tokio/src/io/util/async_seek_ext.rs
@@ -3,6 +3,28 @@ use crate::io::AsyncSeek;
use std::io::SeekFrom;
/// An extension trait which adds utility methods to `AsyncSeek` types.
+///
+/// # Examples
+///
+/// ```
+/// use std::io::{Cursor, SeekFrom};
+/// use tokio::prelude::*;
+///
+/// #[tokio::main]
+/// async fn main() -> io::Result<()> {
+/// let mut cursor = Cursor::new(b"abcdefg");
+///
+/// // the `seek` method is defined by this trait
+/// cursor.seek(SeekFrom::Start(3)).await?;
+///
+/// let mut buf = [0; 1];
+/// let n = cursor.read(&mut buf).await?;
+/// assert_eq!(n, 1);
+/// assert_eq!(buf, [b'd']);
+///
+/// Ok(())
+/// }
+/// ```
pub trait AsyncSeekExt: AsyncSeek {
/// Creates a future which will seek an IO object, and then yield the
/// new position in the object and the object itself.