crius 0.3.1

Crius is a simple hystrix-like circuit breaker
Documentation
use std::collections::vec_deque::VecDeque;
use std::time::{Instant, Duration};
use command::Config;

#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
pub enum Point {
    SUCCESS,
    FAILURE
}

#[derive(Clone, Debug)]
struct Bucket {
    points: Vec<Point>,
    timestamp: Instant
}

impl Bucket {
    fn new() -> Bucket {
        return Bucket {
            points: Vec::new(),
            timestamp: Instant::now()
        }
    }
}

#[derive(Clone, Debug)]
pub struct Window {
    buckets: VecDeque<Bucket>,
    bucket_ms: Duration,
    buckets_nr: i32
}

impl Window {

    pub fn new(config: Config) -> Self {
        return Window {
            buckets: VecDeque::new(),
            bucket_ms: Duration::from_millis(config.bucket_size_in_ms.unwrap()),
            buckets_nr: config.buckets_in_window.unwrap()
        }
    }

    pub fn add_point(&mut self, point: Point) {
        let mut current_bucket = self.update_window_returning_latest_bucket();
        current_bucket.points.push(point);
    }

    pub fn clear_window(&mut self) {
        self.buckets.clear();
    }

    pub fn update_and_get_points(&mut self) -> Vec<Point> {
        self.update_window_returning_latest_bucket();
        let points = self.buckets.iter().fold(vec![], |mut acc, bucket| {
            acc.extend(&bucket.points);
            return acc
        });
        return points;
    }

    fn update_window_returning_latest_bucket(&mut self) -> &mut Bucket {
        let now = Instant::now();

        let has_buckets = self.buckets.back_mut().is_some();
        if !has_buckets {
            let first_bucket = Bucket::new();
            self.buckets.push_back(first_bucket);
            return self.buckets.back_mut().unwrap()
        } else {
            let latest_bucket_timestamp = self.get_latest_bucket().unwrap().timestamp;
            loop {
                if latest_bucket_timestamp + self.bucket_ms > now {
                    return self.get_latest_bucket().unwrap()
                } else {
                    let new_bucket = Bucket {
                        points: Vec::new(),
                        timestamp: latest_bucket_timestamp + self.bucket_ms
                    };
                    self.buckets.push_back(new_bucket);
                    if self.buckets.len() > self.buckets_nr as usize {
                        self.buckets.pop_front();
                    }

                    return self.buckets.back_mut().unwrap()
                }
            }
        }
    }

    fn get_latest_bucket(&mut self) -> Option<&mut Bucket> {
        return self.buckets.back_mut()
    }

}