scuriolus 0.3.0

Scuriolus is a modular trading bot platform.
Documentation
use chrono::{DateTime, TimeDelta, Utc};
use std::time::Duration;
use tokio::time::{Instant, sleep, sleep_until};

use crate::{
    clock::{ClockFactory, NoRemote},
    core::CoreResult,
};

use super::{Clock, ClockBase};

/// [`ClockFactory`] for [`TrueClock`].
pub struct TrueClockFactory {}

impl ClockFactory for TrueClockFactory {
    type _Clock = TrueClock;

    fn build(self) -> CoreResult<(Option<NoRemote>, TrueClock)> {
        Ok((None, TrueClock::new()))
    }
}

/// Standard [`Clock`] based on [`Utc`].
#[derive(Debug, Clone)]
pub struct TrueClock;

impl TrueClock {
    pub fn new() -> Self {
        Self {}
    }
}

impl Default for TrueClock {
    fn default() -> Self {
        Self::new()
    }
}

impl ClockBase for TrueClock {
    const NAME: &'static str = "TrueClock";
    fn now(&self) -> DateTime<Utc> {
        Utc::now()
    }
}

impl Clock for TrueClock {
    type Remote = NoRemote;

    async fn sleep(&self, delay: TimeDelta) {
        tracing::trace!("Sleeping for {}", delay.to_string());
        sleep(Duration::from_millis(delay.num_milliseconds() as u64)).await
    }

    async fn sleep_until(&self, deadline: DateTime<Utc>) {
        tracing::trace!("Sleeping until {}", deadline.to_string());
        sleep_until(
            Instant::now()
                + deadline
                    .signed_duration_since(Utc::now())
                    .to_std()
                    .unwrap_or_default(),
        )
        .await
    }

    fn synchronize(&self) {}
}

#[cfg(test)]
mod tests {
    use chrono::{TimeDelta, Utc};

    use super::{Clock as _, ClockBase as _, TrueClock};

    const TOLERANCE: TimeDelta = TimeDelta::milliseconds(10);
    const DELAY: TimeDelta = TimeDelta::milliseconds(100);

    #[tokio::test]
    async fn true_clock() {
        let clock = TrueClock::new();
        assert!(clock.now() - Utc::now() < TOLERANCE);

        let before = Utc::now();
        clock.sleep(DELAY).await;
        let after = Utc::now();

        assert!(after - before > DELAY - TOLERANCE);
        assert!(after - before < DELAY + TOLERANCE);

        assert!(clock.now() - Utc::now() < TOLERANCE);
    }
}