rrw 0.1.2

A crate to easily build clients for REST-APIs.
Documentation
use std::sync::{Arc, Mutex};
use std::time::Instant;

use super::mechanism::ThrottleMechanism;

/// A [Throttle] uses a [ThrottleMechanism] to calculate the needed delay for a request and wait as
/// long as needeed.
///
/// # Example
///
/// ```rust
/// # use std::error::Error;
/// # use rrw::throttle::Throttle;
/// # use rrw::throttle::ThrottleMechanism;
/// # use rrw::throttle::StupidThrottle;
/// #
/// # #[tokio::main]
/// # async fn main() -> Result<(), Box<dyn Error>> {
/// // One request every second.
/// let throttle = Throttle::new(StupidThrottle::new(60.0));
/// // Will not wait
/// throttle.throttle().await;
/// // Will wait approximatly one second.
/// throttle.throttle().await;
/// #
/// #     Ok(())
/// # }
/// ```
#[derive(Clone)]
pub struct Throttle {
    mechanism: Arc<Mutex<Box<dyn ThrottleMechanism>>>,
}

impl Throttle {
    /// Create a new [Throttle] using the specified [ThrottleMechanism].
    pub fn new<T: 'static + ThrottleMechanism>(mechanism: T) -> Self {
        Self {
            mechanism: Arc::new(Mutex::new(Box::new(mechanism))),
        }
    }

    /// Sleec asynchronously for how long the [ThrottleMechanism] wants to throttle.
    pub async fn throttle(&self) {
        // Extra block needed to unlock the mechanism while sleeping.
        let delay = {
            let mut mechanism = self
                .mechanism
                .lock()
                .expect("Failed to lock the throttle mechanism");
            let time = Instant::now();
            mechanism.timeout_delay(time)
        };
        log::trace!("Throttle for {:?}.", delay);
        tokio::time::sleep(delay).await;
    }
}