use std::borrow::Borrow; use std::error::Error; use std::net::SocketAddr; use std::ops::{Add, Mul}; use std::time::Duration; use victorem; use victorem::{ClientSocket, ContinueRunning, Exception, Game, GameServer, ServerEvent}; struct GameData { events: Vec, updates: Vec<(Duration, Vec>, SocketAddr)>, continue_on_command: bool, disconnect_this_client: Option, draw: Vec, drawn: Vec, new_client: Option, continue_on_event: bool, } impl GameData { fn new() -> GameData { GameData { events: Vec::new(), updates: Vec::new(), continue_on_command: true, disconnect_this_client: None, draw: Vec::new(), drawn: Vec::new(), new_client: Some(SocketAddr::new( std::net::IpAddr::V4(std::net::Ipv4Addr::new(127, 0, 0, 1)), 7777, )), continue_on_event: true, } } } struct GameMock<'a> { data: &'a mut GameData, counter: usize, current: usize, } impl<'a> GameMock<'a> { fn new(data: &'a mut GameData, counter: usize) -> GameMock { GameMock { data, counter, current: 0, } } } impl<'a> Game for GameMock<'a> { fn handle_command( &mut self, delta_time: Duration, commands: Vec>, from: SocketAddr, ) -> bool { self.data.updates.push((delta_time, commands, from)); self.data.continue_on_command } fn draw(&mut self, delta_time: Duration) -> Vec { self.data.drawn.push(delta_time); self.current += 1; if self.current > self.counter { self.data.continue_on_event = false; } self.data.draw.clone() } fn handle_server_event(&mut self, event: ServerEvent) -> ContinueRunning { self.data.events.push(event); self.data.continue_on_event.clone() } fn add_client(&mut self) -> Option { self.data.new_client.clone() } fn remove_client(&mut self) -> Option { self.data.disconnect_this_client.clone() } } fn create_server(game: GameMock, port: u16) -> Result, Exception> { GameServer::new(game, port) } #[test] fn server_should_send_state_to_client_on_draw() -> Result<(), Exception> { std::thread::spawn(|| { let mut game_data = GameData::new(); game_data.draw = vec![3u8, 7, 8]; let game_mock = GameMock::new(&mut game_data, 100000); if let Ok(mut game_server) = create_server(game_mock, 3336) { game_server.run(); } }); let mut client = ClientSocket::new(4444, "127.0.0.1:3336")?; client.send(vec![1u8]); client.send(vec![1u8]); client.send(vec![1u8]); let res = loop { match client.recv() { Ok(r) => break r, Err(_) => continue, } }; assert_eq!(vec![3u8, 7, 8], res); Ok(()) } #[test] fn server_should_stop_if_handle_command_returns_false() -> Result<(), Exception> { std::thread::spawn(|| { let res = ClientSocket::new(1112, "127.0.0.1:3333") .map(|mut c| { for _i in 0..1000 { let _ = c.send(vec![1u8, 3u8]); } 1 }) .unwrap_or(0); res }); let timer = std::time::Instant::now(); let start = timer.elapsed(); let mut game_data = GameData::new(); game_data.continue_on_command = false; let game_mock = GameMock::new(&mut game_data, 1000); let mut game_server = create_server(game_mock, 3333)?; game_server.run(); let stop = timer.elapsed(); assert!(stop - start < std::time::Duration::from_millis(100)); Ok(()) } #[test] fn server_should_stop_if_handle_event_returns_false() -> Result<(), Exception> { let timer = std::time::Instant::now(); let start = timer.elapsed(); let mut game_data = GameData::new(); game_data.continue_on_event = false; let game_mock = GameMock::new(&mut game_data, 1000); let mut game_server = create_server(game_mock, 3334)?; game_server.run(); let stop = timer.elapsed(); assert!(stop - start < std::time::Duration::from_millis(100)); Ok(()) } #[test] fn server_should_recv_commands_from_client() -> Result<(), Exception> { std::thread::spawn(|| { let res = ClientSocket::new(1111, "127.0.0.1:3335") .map(|mut c| { for _i in 0..1000 { let _ = c.send(vec![1u8, 3u8]); } 1 }) .unwrap_or(0); res }); let mut game_data = GameData::new(); let game_mock = GameMock::new(&mut game_data, 100); let mut game_server = create_server(game_mock, 3335)?; game_server.run(); // assert!(t.join().unwrap_or(0) > 0); assert!( game_data .updates .iter() .any(|(_, y, _)| y.iter().any(|v| *v == vec![1u8, 3u8])), "len {}", game_data.updates.len() ); Ok(()) } trait Middleware { fn execute(&mut self, data: T) -> Result>; fn next(&mut self) -> &mut Option>>; fn run(&mut self, data: T) -> Result> { let data = self.execute(data)?; match &mut self.next() { Some(next) => next.execute(data), None => Ok(data), } } } fn compose, U>( rhs: impl FnOnce(T) -> U, lhs: impl FnOnce(T) -> U, ) -> impl FnOnce(T) -> U { move |x| lhs(rhs(x).into()) } fn curry(x: T, f: impl FnOnce(T, U) -> Z) -> impl FnOnce(U) -> Z { move |y| f(x, y) } fn add(x: i32, y: i32) -> i32 { x + y } fn add_static(mut x: i32) -> impl FnMut(i32) -> i32 { move |y| { x += 10; x + y } } struct AddOne { next: Option>>, } impl Middleware for AddOne { fn execute(&mut self, data: i32) -> Result> { Ok(data + 1) } fn next(&mut self) -> &mut Option>> { &mut self.next } } enum Operation { Add, Mul, } struct Calculator { pub op: Operation, pub lhs: T, pub rhs: T, pub result: Option, } impl<'a, 'b: 'a, T: 'b + Add + Mul + Borrow> Calculator where &'a T: Add + Mul, { pub fn calculate_procedurally(&'b mut self) { let res: T = match self.op { Operation::Add => &self.lhs + &self.rhs, Operation::Mul => &self.lhs * &self.rhs, }; self.result = Some(res); } } impl + Mul + Clone> Calculator { pub fn calculate_functionally(mut self) -> Self { self.result = Some(match self.op { Operation::Add => self.lhs.clone() + self.rhs.clone(), Operation::Mul => self.lhs.clone() * self.rhs.clone(), }); self } } #[cfg(test)] mod example { #[test] fn test_add() { let mut calc = self::super::Calculator:: { op: self::super::Operation::Add, lhs: 2, rhs: 3, result: None, }; calc = calc.calculate_functionally(); assert_eq!(5, calc.result.unwrap()); } #[test] fn test_mul() { let mut calc = self::super::Calculator:: { op: self::super::Operation::Mul, lhs: 2, rhs: 3, result: None, }; calc = calc.calculate_functionally(); assert_eq!(6, calc.result.unwrap()); } #[test] fn test_add_proc() { let mut calc = self::super::Calculator:: { op: self::super::Operation::Add, lhs: 2, rhs: 3, result: None, }; calc.calculate_procedurally(); assert_eq!(5, calc.result.unwrap()); } #[test] fn test_mul_proc() { let mut calc = self::super::Calculator:: { op: self::super::Operation::Mul, lhs: 2, rhs: 3, result: None, }; calc.calculate_procedurally(); assert_eq!(6, calc.result.unwrap()); } }