mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-09-07 00:00:08 +02:00
Update Tokio to use std::future. (#1120)
A first pass at updating Tokio to use `std::future`. Implementations of `Future` from the futures crate are updated to implement `Future` from std. Implementations of `Stream` are moved to a feature flag. This commits disables a number of crates that have not yet been updated.
This commit is contained in:
+26
-111
@@ -1,11 +1,12 @@
|
||||
//! Slow down a stream by enforcing a delay between items.
|
||||
|
||||
use crate::{clock, Delay, Error};
|
||||
use futures::future::Either;
|
||||
use futures::{try_ready, Async, Future, Poll, Stream};
|
||||
use crate::{clock, Delay};
|
||||
use futures_core::Stream;
|
||||
use std::{
|
||||
error::Error as StdError,
|
||||
fmt::{Display, Formatter, Result as FmtResult},
|
||||
future::Future,
|
||||
marker::Unpin,
|
||||
pin::Pin,
|
||||
task::{self, Poll},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
@@ -13,26 +14,25 @@ use std::{
|
||||
#[derive(Debug)]
|
||||
#[must_use = "streams do nothing unless polled"]
|
||||
pub struct Throttle<T> {
|
||||
delay: Option<Delay>,
|
||||
duration: Duration,
|
||||
delay: Delay,
|
||||
/// Set to true when `delay` has returned ready, but `stream` hasn't.
|
||||
has_delayed: bool,
|
||||
stream: T,
|
||||
}
|
||||
|
||||
/// Either the error of the underlying stream, or an error within
|
||||
/// tokio's timing machinery.
|
||||
#[derive(Debug)]
|
||||
pub struct ThrottleError<T>(Either<T, Error>);
|
||||
|
||||
impl<T> Throttle<T> {
|
||||
/// Slow down a stream by enforcing a delay between items.
|
||||
pub fn new(stream: T, duration: Duration) -> Self {
|
||||
Self {
|
||||
delay: None,
|
||||
duration: duration,
|
||||
delay: Delay::new_timeout(clock::now() + duration, duration),
|
||||
has_delayed: false,
|
||||
stream: stream,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: are these safe if `T: !Unpin`?
|
||||
impl<T: Unpin> Throttle<T> {
|
||||
/// Acquires a reference to the underlying stream that this combinator is
|
||||
/// pulling from.
|
||||
pub fn get_ref(&self) -> &T {
|
||||
@@ -59,107 +59,22 @@ impl<T> Throttle<T> {
|
||||
|
||||
impl<T: Stream> Stream for Throttle<T> {
|
||||
type Item = T::Item;
|
||||
type Error = ThrottleError<T::Error>;
|
||||
|
||||
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
|
||||
if let Some(ref mut delay) = self.delay {
|
||||
try_ready!({ delay.poll().map_err(ThrottleError::from_timer_err) });
|
||||
}
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
unsafe {
|
||||
if !self.has_delayed {
|
||||
ready!(self.as_mut().map_unchecked_mut(|me| &mut me.delay).poll(cx));
|
||||
self.as_mut().get_unchecked_mut().has_delayed = true;
|
||||
}
|
||||
|
||||
self.delay = None;
|
||||
let value = try_ready!({ self.stream.poll().map_err(ThrottleError::from_stream_err) });
|
||||
let value = ready!(self.as_mut().map_unchecked_mut(|me| &mut me.stream).poll_next(cx));
|
||||
|
||||
if value.is_some() {
|
||||
self.delay = Some(Delay::new(clock::now() + self.duration));
|
||||
}
|
||||
if value.is_some() {
|
||||
self.as_mut().get_unchecked_mut().delay.reset_timeout();
|
||||
self.as_mut().get_unchecked_mut().has_delayed = false;
|
||||
}
|
||||
|
||||
Ok(Async::Ready(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ThrottleError<T> {
|
||||
/// Creates a new `ThrottleError` from the given stream error.
|
||||
pub fn from_stream_err(err: T) -> Self {
|
||||
ThrottleError(Either::A(err))
|
||||
}
|
||||
|
||||
/// Creates a new `ThrottleError` from the given tokio timer error.
|
||||
pub fn from_timer_err(err: Error) -> Self {
|
||||
ThrottleError(Either::B(err))
|
||||
}
|
||||
|
||||
/// Attempts to get the underlying stream error, if it is present.
|
||||
pub fn get_stream_error(&self) -> Option<&T> {
|
||||
match self.0 {
|
||||
Either::A(ref x) => Some(x),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to get the underlying timer error, if it is present.
|
||||
pub fn get_timer_error(&self) -> Option<&Error> {
|
||||
match self.0 {
|
||||
Either::B(ref x) => Some(x),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to extract the underlying stream error, if it is present.
|
||||
pub fn into_stream_error(self) -> Option<T> {
|
||||
match self.0 {
|
||||
Either::A(x) => Some(x),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to extract the underlying timer error, if it is present.
|
||||
pub fn into_timer_error(self) -> Option<Error> {
|
||||
match self.0 {
|
||||
Either::B(x) => Some(x),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the throttle error has occured because of an error
|
||||
/// in the underlying stream.
|
||||
pub fn is_stream_error(&self) -> bool {
|
||||
!self.is_timer_error()
|
||||
}
|
||||
|
||||
/// Returns whether the throttle error has occured because of an error
|
||||
/// in tokio's timer system.
|
||||
pub fn is_timer_error(&self) -> bool {
|
||||
match self.0 {
|
||||
Either::A(_) => false,
|
||||
Either::B(_) => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: StdError> Display for ThrottleError<T> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
match self.0 {
|
||||
Either::A(ref err) => write!(f, "stream error: {}", err),
|
||||
Either::B(ref err) => write!(f, "timer error: {}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: StdError + 'static> StdError for ThrottleError<T> {
|
||||
fn description(&self) -> &str {
|
||||
match self.0 {
|
||||
Either::A(_) => "stream error",
|
||||
Either::B(_) => "timer error",
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(taiki-e): When the minimum support version of tokio reaches Rust 1.30,
|
||||
// replace this with Error::source.
|
||||
#[allow(deprecated)]
|
||||
fn cause(&self) -> Option<&dyn StdError> {
|
||||
match self.0 {
|
||||
Either::A(ref err) => Some(err),
|
||||
Either::B(ref err) => Some(err),
|
||||
Poll::Ready(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user