Added `.pad_time()` extension method for `T: Future` (TODO: Currently only compiles on nightly as it requires `impl Future` in trait impl, and must be boxed on stable. But `Future.boxed()` extension requires the future to be `Send` for some reason, which we don"t require. Find a way to box the future without it needing to be `Send`.) Fortune for rsh's current commit: Curse − 凶pipelined-socket-buffering
parent
fbf96276ca
commit
c658e8a702
@ -1,2 +1,75 @@
|
||||
//! Syncronisation helpers
|
||||
use super::*;
|
||||
use futures::{
|
||||
Future,
|
||||
};
|
||||
use tokio::time::Duration;
|
||||
|
||||
/// Force a future to take *at least* a specific amount of time to complete.
|
||||
///
|
||||
/// If the future takes longer than `time` to complete, no additional delay is added.
|
||||
/// If `time` is zero, no delay is added.
|
||||
///
|
||||
/// # Panics
|
||||
/// The returned future will panic if
|
||||
/// * The future itself panics
|
||||
/// * We are unable to convert the future's duration from `chrono`'s duration span to std's duration span
|
||||
pub fn timesync<'a, T, F>(future: F, time: Duration) -> impl Future<Output = T> + 'a
|
||||
where F: Future<Output=T> + 'a
|
||||
{
|
||||
use chrono::prelude::*;
|
||||
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn _panic_failed_tmconv(orig: chrono::Duration, error: impl Into<eyre::Report>)
|
||||
{
|
||||
panic!("Failed to convert chrono duration span {:?} to std duration span: {}", orig, error.into());
|
||||
}
|
||||
|
||||
async move {
|
||||
let now = Utc::now();
|
||||
let r = future.await;
|
||||
if time.is_zero() {
|
||||
return r;
|
||||
}
|
||||
let after = Utc::now();
|
||||
let duration = after - now;
|
||||
match duration.to_std() {
|
||||
Ok(taken)
|
||||
if taken < time => {
|
||||
// Delay for the remaining time
|
||||
tokio::time::delay_for(time - taken).await;
|
||||
},
|
||||
Err(error) => _panic_failed_tmconv(duration, error),
|
||||
// At least `time` has passed
|
||||
_ => (),
|
||||
}
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TimeSyncExt<'a>: Future + Sized + 'a
|
||||
{
|
||||
type OutputFuture: Future<Output = Self::Output> + 'a;
|
||||
fn pad_time(self, time: Duration) -> Self::OutputFuture;
|
||||
}
|
||||
|
||||
#[cfg(nightly)]
|
||||
impl<'a, F> TimeSyncExt<'a> for F
|
||||
where F: Future + 'a
|
||||
{
|
||||
|
||||
//#[cfg(nightly)]
|
||||
type OutputFuture = impl Future<Output = Self::Output> + 'a;
|
||||
//#[cfg(not(nightly))]
|
||||
//type OutputFuture = futures::future::BoxFuture<'a, Self::Output>; //TODO: Requires `Send` bound for some reason.
|
||||
fn pad_time(self, time: Duration) -> Self::OutputFuture {
|
||||
/*#[cfg(not(nightly))] {
|
||||
use futures::prelude::*;
|
||||
return timesync(self, time).boxed();
|
||||
}
|
||||
#[cfg(nightly)] {
|
||||
return*/ timesync(self, time)
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in new issue