scosh-core 0.1.0

Portable session state and terminal event core for scosh
Documentation
//! Finite recovery budget shared by desktop and mobile adapters.

use std::time::{Duration, Instant};

use crate::errors::SdkError;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct RecoveryPolicy {
    pub max_attempts: u8,
    pub budget: Duration,
}

impl Default for RecoveryPolicy {
    fn default() -> Self {
        Self {
            max_attempts: 5,
            budget: Duration::from_secs(30),
        }
    }
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct RecoveryBudget {
    policy: RecoveryPolicy,
    started_at: Option<Instant>,
    attempts: u8,
}

impl RecoveryBudget {
    pub const fn new(policy: RecoveryPolicy) -> Self {
        Self {
            policy,
            started_at: None,
            attempts: 0,
        }
    }

    pub const fn attempts(self) -> u8 {
        self.attempts
    }

    pub fn begin(&mut self, now: Instant) {
        self.started_at = Some(now);
        self.attempts = 0;
    }

    pub fn next_attempt(&mut self, now: Instant) -> Result<u8, SdkError> {
        let started = self.started_at.get_or_insert(now);
        if self.attempts >= self.policy.max_attempts
            || now.duration_since(*started) >= self.policy.budget
        {
            return Err(SdkError::RecoveryExhausted);
        }
        self.attempts = self.attempts.saturating_add(1);
        Ok(self.attempts)
    }

    pub fn reset(&mut self) {
        self.started_at = None;
        self.attempts = 0;
    }
}