init repo + add edge-telemetry puzzle
This commit is contained in:
commit
b1f730630a
7 changed files with 210 additions and 0 deletions
157
edge-telemetry/src/main.rs
Normal file
157
edge-telemetry/src/main.rs
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
pub trait EdgeTelemetry<E> {
|
||||
/// Add a new telemetry reading to the underlying storage type
|
||||
// TODO: update the timestamp to something that makes more sense maybe?
|
||||
fn add_reading(&mut self, entry: E);
|
||||
|
||||
/// Returns the compressed data as a collection of tuples, where each tuple has the format:
|
||||
/// `(usage, consecutive occurances)`
|
||||
fn get_compressed_data<'a>(&'a self) -> impl Iterator<Item = &'a (E, usize)>
|
||||
where
|
||||
E: 'a;
|
||||
}
|
||||
|
||||
mod entry {
|
||||
#[derive(Clone)]
|
||||
pub struct Entry {
|
||||
timestamp: usize,
|
||||
reading: usize,
|
||||
}
|
||||
|
||||
impl Entry {
|
||||
pub fn new(timestamp: usize, reading: usize) -> Self {
|
||||
Self { timestamp, reading }
|
||||
}
|
||||
pub fn timestamp(&self) -> usize {
|
||||
self.timestamp
|
||||
}
|
||||
pub fn reading(&self) -> usize {
|
||||
self.reading
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn create_entry() {
|
||||
let t = 3;
|
||||
let r = 1;
|
||||
|
||||
let e = Entry::new(t, r);
|
||||
|
||||
assert_eq!(t, e.timestamp());
|
||||
assert_eq!(r, e.reading());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod storage {
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use crate::EdgeTelemetry;
|
||||
use crate::entry::Entry;
|
||||
|
||||
pub struct RingBufferStorage {
|
||||
size: usize,
|
||||
buf: VecDeque<(Entry, usize)>,
|
||||
}
|
||||
|
||||
impl RingBufferStorage {
|
||||
pub fn new(size: usize) -> Self {
|
||||
Self {
|
||||
size,
|
||||
buf: VecDeque::with_capacity(size),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_entry(&mut self, entry: Entry) {
|
||||
// buffer is not empty, and the previous value matches
|
||||
if let Some((prev, quantity)) = self.buf.iter_mut().last()
|
||||
&& prev.reading() == entry.reading()
|
||||
{
|
||||
// TODO: add some logic here to overflow into a new entry if needed
|
||||
*quantity = quantity.saturating_add(1);
|
||||
}
|
||||
// buffer is either empty, or the previous value does not match
|
||||
else {
|
||||
// check capacity to make sure we aren't full (not really necessary on the empty case but this is a little easier to read)
|
||||
if self.buf.len() == self.size {
|
||||
self.buf.pop_front();
|
||||
}
|
||||
self.buf.push_back((entry, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EdgeTelemetry<Entry> for RingBufferStorage {
|
||||
fn add_reading(&mut self, entry: Entry) {
|
||||
self.add_entry(entry);
|
||||
}
|
||||
|
||||
fn get_compressed_data<'a>(&'a self) -> impl Iterator<Item = &'a (Entry, usize)>
|
||||
where
|
||||
Entry: 'a,
|
||||
{
|
||||
self.buf.iter()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::EdgeTelemetry;
|
||||
use crate::entry::Entry;
|
||||
use crate::storage::RingBufferStorage;
|
||||
|
||||
#[test]
|
||||
fn add_and_get_reading() {
|
||||
let size = 10;
|
||||
let mut s = RingBufferStorage::new(size);
|
||||
|
||||
let t = 1;
|
||||
let r = 3;
|
||||
let e = Entry::new(t, r);
|
||||
|
||||
s.add_reading(e);
|
||||
|
||||
let data = s.get_compressed_data();
|
||||
|
||||
data.into_iter().for_each(|(entry, quantity)| {
|
||||
assert_eq!(entry.timestamp(), t);
|
||||
assert_eq!(entry.reading(), r);
|
||||
assert_eq!(*quantity, 1);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duplicate_readings() {
|
||||
let size = 10;
|
||||
let mut s = RingBufferStorage::new(size);
|
||||
|
||||
let t = 1;
|
||||
let r = 3;
|
||||
let q = 3;
|
||||
|
||||
for _ in 0..q {
|
||||
let e = Entry::new(t, r);
|
||||
s.add_reading(e);
|
||||
}
|
||||
|
||||
let data = s.get_compressed_data();
|
||||
|
||||
data.into_iter().for_each(|(entry, quantity)| {
|
||||
assert_eq!(entry.timestamp(), t);
|
||||
assert_eq!(entry.reading(), r);
|
||||
assert_eq!(*quantity, q);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
|
||||
// NOTES
|
||||
// * assuming the sample rate is constant, we can extract sample time from the run length by knowing the base stamp, and incrementing to the offset
|
||||
// * this also means we can actually just stamp the start time and then compute the sample time via the offset
|
||||
Loading…
Add table
Add a link
Reference in a new issue