Rollup merge of #52721 - cramertj:try-poll, r=aturon

std::ops::Try impl for std::task::Poll

I originally left out the `Try` impl for `Poll` because I was curious if we needed it, and @MajorBreakfast and I had discussed the potential for it to introduce confusion about exactly what control-flow was happening at different points. However, after porting a pretty significant chunk of Fuchsia over to futures 0.3, I discovered that I was *constantly* having to do repetitive matching on `Poll<Result<...>>` or `Poll<Option<Result<...>>>` in order to propagate errors correctly. `try_poll` (propagate `Poll::Ready(Err(..))`s) helped in some places, but it was far more common to need some form of conversion between `Result`, `Poll<Result<...>>`, and `Poll<Option<Result<...>>>`. The `Try` trait conveniently provides all of these conversions in addition to a more concise syntax (`?`), so I'd like to experiment with using these instead.

cc @seanmonstar

r? @aturon

Note: this change means that far more futures 0.1 code can work without significant changes since it papers over the fact that `Result` is no longer at the top-level when using `Stream` and `Future` (since it's now `Poll<Result<...>>` or `Poll<Option<Result<...>>>` instead of `Result<Poll<..>>` and `Result<Poll<Option<...>>>`).
This commit is contained in:
Mark Rousskov 2018-07-26 09:18:40 -06:00 committed by GitHub
commit 858adfe21d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 115 additions and 0 deletions

View File

@ -12,6 +12,9 @@
reason = "futures in libcore are unstable",
issue = "50547")]
use ops::Try;
use result::Result;
/// Indicates whether a value is available or if the current task has been
/// scheduled to receive a wakeup instead.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
@ -39,6 +42,7 @@ impl<T> Poll<T> {
}
/// Returns whether this is `Poll::Ready`
#[inline]
pub fn is_ready(&self) -> bool {
match *self {
Poll::Ready(_) => true,
@ -47,6 +51,7 @@ impl<T> Poll<T> {
}
/// Returns whether this is `Poll::Pending`
#[inline]
pub fn is_pending(&self) -> bool {
!self.is_ready()
}
@ -81,3 +86,52 @@ impl<T> From<T> for Poll<T> {
Poll::Ready(t)
}
}
impl<T, E> Try for Poll<Result<T, E>> {
type Ok = Poll<T>;
type Error = E;
#[inline]
fn into_result(self) -> Result<Self::Ok, Self::Error> {
match self {
Poll::Ready(Ok(x)) => Ok(Poll::Ready(x)),
Poll::Ready(Err(e)) => Err(e),
Poll::Pending => Ok(Poll::Pending),
}
}
#[inline]
fn from_error(e: Self::Error) -> Self {
Poll::Ready(Err(e))
}
#[inline]
fn from_ok(x: Self::Ok) -> Self {
x.map(Ok)
}
}
impl<T, E> Try for Poll<Option<Result<T, E>>> {
type Ok = Poll<Option<T>>;
type Error = E;
#[inline]
fn into_result(self) -> Result<Self::Ok, Self::Error> {
match self {
Poll::Ready(Some(Ok(x))) => Ok(Poll::Ready(Some(x))),
Poll::Ready(Some(Err(e))) => Err(e),
Poll::Ready(None) => Ok(Poll::Ready(None)),
Poll::Pending => Ok(Poll::Pending),
}
}
#[inline]
fn from_error(e: Self::Error) -> Self {
Poll::Ready(Some(Err(e)))
}
#[inline]
fn from_ok(x: Self::Ok) -> Self {
x.map(|x| x.map(Ok))
}
}

61
src/test/ui/try-poll.rs Normal file
View File

@ -0,0 +1,61 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-pass
#![allow(dead_code, unused)]
#![feature(futures_api)]
use std::task::Poll;
struct K;
struct E;
fn as_result() -> Result<(), E> {
// From Result
let K = Ok::<K, E>(K)?;
// From Poll<Result>
let _: Poll<K> = Poll::Ready::<Result<K, E>>(Ok(K))?;
// From Poll<Option<Result>>
let _: Poll<Option<K>> = Poll::Ready::<Option<Result<K, E>>>(None)?;
Ok(())
}
fn as_poll_result() -> Poll<Result<(), E>> {
// From Result
let K = Ok::<K, E>(K)?;
// From Poll<Result>
let _: Poll<K> = Poll::Ready::<Result<K, E>>(Ok(K))?;
// From Poll<Option<Result>>
let _: Poll<Option<K>> = Poll::Ready::<Option<Result<K, E>>>(None)?;
Poll::Ready(Ok(()))
}
fn as_poll_option_result() -> Poll<Option<Result<(), E>>> {
// From Result
let K = Ok::<K, E>(K)?;
// From Poll<Result>
let _: Poll<K> = Poll::Ready::<Result<K, E>>(Ok(K))?;
// From Poll<Option<Result>>
let _: Poll<Option<K>> = Poll::Ready::<Option<Result<K, E>>>(None)?;
Poll::Ready(Some(Ok(())))
}
fn main() {
}