add means_to_an_end

This commit is contained in:
Caleb Webber 2024-05-14 22:34:27 -04:00
parent 0d2c997fb3
commit 25f5257562
2 changed files with 195 additions and 0 deletions

View file

@ -8,6 +8,9 @@ edition = "2021"
[[bin]]
name = "smoke"
[[bin]]
name = "means_to_an_end"
[dependencies]
serde = { version = "1.0.197", features = ["serde_derive"] }
serde_json = "1.0.114"

192
src/bin/means_to_an_end.rs Normal file
View file

@ -0,0 +1,192 @@
use std::{io::{Read, Write}, net::TcpListener};
#[derive(PartialEq, Debug)]
struct InsertData {
timestamp: u32, // seconds since 00:00, 1st Jan 1970.
price: i32, // price in pennies
}
#[derive(PartialEq, Debug)]
struct QueryData {
mintime: u32,
maxtime: u32,
}
#[derive(PartialEq, Debug)]
enum Message {
Insert(InsertData),
Query(QueryData),
}
#[derive(PartialEq, Debug)]
enum ParseError {
UnknownType,
OutOfBytes
}
impl Message {
fn from_bytes(bytes: [u8; 9]) -> Result<Self, ParseError> {
let t = bytes[0];
let u: Result<[u8; 4], _> = bytes[1..=4].try_into();
let v: Result<[u8; 4], _> = bytes[5..=8].try_into();
if u.is_err() || v.is_err() {
return Err(ParseError::OutOfBytes);
}
let u = u.unwrap();
let v = v.unwrap();
match t {
b'I' => Ok(Message::Insert(InsertData {
timestamp: u32::from_be_bytes(u),
price: i32::from_be_bytes(v),
})),
b'Q' => Ok(Message::Query(QueryData {
mintime: u32::from_be_bytes(u),
maxtime: u32::from_be_bytes(v),
})),
_ => Err(ParseError::UnknownType),
}
}
}
fn get_mean_price(insertions: &Vec<InsertData>, query: &QueryData) -> i32 {
let prices: Vec<i32> = insertions
.iter()
.filter(|i| i.timestamp >= query.mintime && i.timestamp <= query.maxtime)
.map(|i| i.price)
.collect();
// safe?
prices.iter().sum::<i32>() / prices.len() as i32
}
const PORT: usize = 10001;
fn main() -> std::io::Result<()> {
let listener = TcpListener::bind(format!("0.0.0.0:{PORT}"))?;
for stream in listener.incoming() {
std::thread::spawn(move || {
match stream {
Ok(mut stream) => {
let mut inserts: Vec<InsertData> = vec![];
loop {
let mut bb: [u8; 9] = [0; 9];
if let Ok(_) = stream.read_exact(&mut bb) {
let m = Message::from_bytes(bb);
match m {
Ok(Message::Insert(i)) => {
inserts.push(i);
},
Ok(Message::Query(q)) => {
let _ = stream.write(&i32::to_be_bytes(get_mean_price(&inserts, &q)));
},
Err(e) => {
panic!("{:?}", e);
}
}
} else {
break;
}
}
},
Err(e) => panic!("{:?}", e)
}
});
}
Ok(())
}
#[cfg(test)]
mod tests {
use crate::{get_mean_price, InsertData, Message, QueryData};
#[test]
fn can_deserialize_messages() {
// 49 00 00 30 39 00 00 00 65 I 12345 101
let test_bytes: Vec<u8> = vec![0x49, 0x00, 0x00, 0x30, 0x39, 0x00, 0x00, 0x00, 0x65];
let message = Message::from_bytes(test_bytes.as_slice().try_into().unwrap());
assert_eq!(
message,
Ok(Message::Insert(InsertData {
timestamp: 12345,
price: 101
}))
);
// 49 00 00 30 3a 00 00 00 66 I 12346 102
let test_bytes: Vec<u8> = vec![0x49, 0x00, 0x00, 0x30, 0x3a, 0x00, 0x00, 0x00, 0x66];
let message = Message::from_bytes(test_bytes.as_slice().try_into().unwrap());
assert_eq!(
message,
Ok(Message::Insert(InsertData {
timestamp: 12346,
price: 102
}))
);
// 49 00 00 30 3b 00 00 00 64 I 12347 100
let test_bytes: Vec<u8> = vec![0x49, 0x00, 0x00, 0x30, 0x3b, 0x00, 0x00, 0x00, 0x64];
let message = Message::from_bytes(test_bytes.as_slice().try_into().unwrap());
assert_eq!(
message,
Ok(Message::Insert(InsertData {
timestamp: 12347,
price: 100
}))
);
// 49 00 00 a0 00 00 00 00 05 I 40960 5
let test_bytes: Vec<u8> = vec![0x49, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x05];
let message = Message::from_bytes(test_bytes.as_slice().try_into().unwrap());
assert_eq!(
message,
Ok(Message::Insert(InsertData {
timestamp: 40960,
price: 5
}))
);
// 51 00 00 30 00 00 00 40 00 Q 12288 16384
let test_bytes: Vec<u8> = vec![0x51, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x40, 0x00];
let message = Message::from_bytes(test_bytes.as_slice().try_into().unwrap());
assert_eq!(
message,
Ok(Message::Query(QueryData {
mintime: 12288,
maxtime: 16384
}))
);
}
#[test]
fn gets_correct_mean_price() {
let insertions = vec![
InsertData {
timestamp: 12346,
price: 102,
},
InsertData {
timestamp: 12347,
price: 100,
},
InsertData {
timestamp: 40960,
price: 5,
},
];
assert_eq!(
get_mean_price(
&insertions,
&QueryData {
mintime: 12288,
maxtime: 16384,
},
),
101
);
}
}