From 25f5257562dab1948b8508a12ddde712413e23f8 Mon Sep 17 00:00:00 2001 From: Caleb Webber Date: Tue, 14 May 2024 22:34:27 -0400 Subject: [PATCH] add means_to_an_end --- Cargo.toml | 3 + src/bin/means_to_an_end.rs | 192 +++++++++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 src/bin/means_to_an_end.rs diff --git a/Cargo.toml b/Cargo.toml index c6aef4f..69eb8d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/src/bin/means_to_an_end.rs b/src/bin/means_to_an_end.rs new file mode 100644 index 0000000..afec8a6 --- /dev/null +++ b/src/bin/means_to_an_end.rs @@ -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 { + 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, query: &QueryData) -> i32 { + let prices: Vec = insertions + .iter() + .filter(|i| i.timestamp >= query.mintime && i.timestamp <= query.maxtime) + .map(|i| i.price) + .collect(); + + // safe? + prices.iter().sum::() / 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 = 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 = 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 = 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 = 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 = 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 = 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 + ); + } +}