1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
use std::time::{Duration, SystemTime};

use circular_buffer::CircularBuffer;

const WINDOW_SIZE: usize = 64;

type Sample = u128;
pub struct Sampler {
    buffer: CircularBuffer<WINDOW_SIZE, Sample>,
    interval: Duration,
    last_sample_time: SystemTime,
}

impl Sampler {
    pub fn new(interval_ms: u64) -> Self {
        Sampler {
            buffer: CircularBuffer::new(),
            last_sample_time: SystemTime::now(),
            interval: Duration::from_millis(interval_ms),
        }
    }

    pub fn add_sample(&mut self, absolute: u128) -> bool {
        if let Ok(elapsed) = self.last_sample_time.elapsed() {
            if elapsed > self.interval {
                self.last_sample_time = SystemTime::now();
                self.buffer.push_back(absolute);
                true
            } else {
                false
            }
        } else {
            false
        }
    }

    pub fn buffer(&self) -> &CircularBuffer<WINDOW_SIZE, Sample> {
        &self.buffer
    }

    pub fn delta_entries(&self) -> Vec<u128> {
        let mut result = Vec::with_capacity(WINDOW_SIZE);
        let mut previous = 0;
        for entry in &self.buffer {
            let delta = entry - previous;
            previous = *entry;
            result.push(delta);
        }
        result
    }
}