// Copyright 2015-2019 Parity Technologies (UK) Ltd. // This file is part of Parity Ethereum. // Parity Ethereum is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Parity Ethereum is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Parity Ethereum. If not, see . use std::io; use std::time::Duration; use futures::{Future, Poll}; use tokio::timer::timeout::{Timeout, Error as TimeoutError}; type DeadlineBox = Box::Item>, Error = TimeoutError<::Error> > + Send>; /// Complete a passed future or fail if it is not completed within timeout. pub fn deadline(duration: Duration, future: F) -> Result, io::Error> where F: Future + Send + 'static, T: Send + 'static { let timeout = Box::new(Timeout::new(future, duration) .then(|res| { match res { Ok(fut) => Ok(DeadlineStatus::Meet(fut)), Err(err) => { if err.is_elapsed() { Ok(DeadlineStatus::Timeout) } else { Err(err) } }, } }) ); let deadline = Deadline { future: timeout, }; Ok(deadline) } /// Deadline future completion status. #[derive(Debug, PartialEq)] pub enum DeadlineStatus { /// Completed a future. Meet(T), /// Faled with timeout. Timeout, } /// Future, which waits for passed future completion within given period, or fails with timeout. pub struct Deadline where F: Future { future: DeadlineBox, } impl Future for Deadline where F: Future { type Item = DeadlineStatus; type Error = TimeoutError; fn poll(&mut self) -> Poll { self.future.poll() } } #[cfg(test)] mod tests { use std::time::Duration; use futures::{Future, done}; use tokio::reactor::Reactor; use super::{deadline, DeadlineStatus}; #[test] fn deadline_result_works() { let mut reactor = Reactor::new().unwrap(); let deadline = deadline(Duration::from_millis(1000), done(Ok(()))).unwrap(); reactor.turn(Some(Duration::from_millis(3))).unwrap(); assert_eq!(deadline.wait().unwrap(), DeadlineStatus::Meet(())); } }