use std::sync::Arc;
use std::time::Duration;
use minstant::Instant;
use once_cell::sync::OnceCell;
type DurationCell = Arc<OnceCell<Duration>>;
#[derive(Default, Debug, Clone)]
pub struct GasDuration(Option<DurationCell>);
impl GasDuration {
pub fn get(&self) -> Option<&Duration> {
self.0.as_ref().and_then(|d| d.get())
}
}
pub type GasInstant = Instant;
#[derive(Debug)]
pub struct GasTimer(Option<GasTimerInner>);
#[derive(Debug)]
struct GasTimerInner {
start: GasInstant,
elapsed: DurationCell,
}
impl GasTimer {
pub fn start() -> GasInstant {
GasInstant::now()
}
pub fn empty() -> Self {
GasTimer(None)
}
pub fn new(duration: &mut GasDuration) -> Self {
assert!(duration.get().is_none(), "GasCharge::elapsed already set!");
let cell = match &duration.0 {
Some(cell) => cell.clone(),
None => {
let cell = DurationCell::default();
duration.0 = Some(cell.clone());
cell
}
};
Self(Some(GasTimerInner {
start: Self::start(),
elapsed: cell,
}))
}
pub fn stop(self) {
if let Some(timer) = self.0 {
Self::set_elapsed(timer.elapsed, timer.start)
}
}
pub fn stop_with(self, start: GasInstant) {
if let Some(timer) = self.0 {
Self::set_elapsed(timer.elapsed, start)
}
}
fn set_elapsed(elapsed: Arc<OnceCell<Duration>>, start: GasInstant) {
elapsed
.set(start.elapsed())
.expect("GasCharge::elapsed already set!")
}
pub fn record<R, E>(self, result: Result<R, E>) -> Result<R, E> {
if result.is_ok() {
self.stop()
}
result
}
}