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
|
//! 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