You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
75 lines
2.0 KiB
75 lines
2.0 KiB
//! 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)
|
|
//}
|
|
}
|
|
}
|