forgefix 0.3.0

ForgeFIX is an opinionated FIX 4.2 client library for the buy-side written in Rust. ForgeFIX is optimized for the subset of the FIX protocol used by buy-side firms connecting to brokers and exchanges for communicating orders and fills.
Documentation
use crate::fix::session::Event;
use tokio::time::{Duration, Instant, Sleep, sleep_until};

pub(super) struct Timeout {
    next_instant: Instant,
    duration: Duration,
    event: Event,
}

impl Timeout {
    pub(super) fn new(instant: Instant, duration: Duration, event: Event) -> Timeout {
        Timeout {
            next_instant: instant,
            duration,
            event,
        }
    }

    pub(super) fn reset_timeout(&mut self) {
        self.next_instant = Instant::now() + self.duration;
    }

    pub(super) fn set_timeout_duration(&mut self, dur: Duration) {
        self.duration = dur;
        self.reset_timeout();
    }

    pub(super) fn timeout(&self) -> (Sleep, &Event) {
        (sleep_until(self.next_instant), &self.event)
    }
}

pub(super) struct FixTimeouts {
    heartbeat_timeout: Timeout,
    test_request_timeout: Timeout,
    logout_timeout: Timeout,
    awaiting_logout: bool,
}

impl FixTimeouts {
    pub(super) fn new(
        heartbeat_dur: Duration,
        test_request_dur: Duration,
        logout_dur: Duration,
    ) -> FixTimeouts {
        let next_heartbeat_timeout = Instant::now() + heartbeat_dur;
        let next_test_request_timeout = Instant::now() + test_request_dur;
        let next_logout_timeout = Instant::now() + logout_dur;
        let awaiting_logout = false;

        let heartbeat_timeout =
            Timeout::new(next_heartbeat_timeout, heartbeat_dur, Event::SendHeartbeat);
        let test_request_timeout = Timeout::new(
            next_test_request_timeout,
            test_request_dur,
            Event::SendTestRequest,
        );
        let logout_timeout = Timeout::new(next_logout_timeout, logout_dur, Event::LogoutExpired);

        FixTimeouts {
            heartbeat_timeout,
            test_request_timeout,
            logout_timeout,
            awaiting_logout,
        }
    }

    pub(super) fn next_expiring_timeout(&mut self) -> &mut Timeout {
        if !self.awaiting_logout
            && self.heartbeat_timeout.next_instant < self.test_request_timeout.next_instant
        {
            &mut self.heartbeat_timeout
        } else if !self.awaiting_logout {
            &mut self.test_request_timeout
        } else {
            &mut self.logout_timeout
        }
    }

    pub(super) fn reset_heartbeat(&mut self) {
        self.heartbeat_timeout.reset_timeout();
    }

    pub(super) fn reset_test_request(&mut self) {
        self.test_request_timeout.reset_timeout();
    }

    pub(super) fn start_logout_timeout(&mut self) {
        self.awaiting_logout = true;
        self.logout_timeout.reset_timeout();
    }

    pub(super) fn set_durations(
        &mut self,
        heartbeat_dur: Duration,
        test_request_dur: Duration,
        logout_dur: Duration,
    ) {
        self.heartbeat_timeout.set_timeout_duration(heartbeat_dur);
        self.heartbeat_timeout.reset_timeout();
        self.test_request_timeout
            .set_timeout_duration(test_request_dur);
        self.test_request_timeout.reset_timeout();
        self.logout_timeout.set_timeout_duration(logout_dur);
        self.logout_timeout.reset_timeout();
    }
}