fix: make clippy happy

This commit is contained in:
Noa Aarts 2024-10-05 16:02:20 +02:00
parent eeb030e68a
commit dec36867d6
Signed by: noa
GPG key ID: 1850932741EFF672
5 changed files with 152 additions and 108 deletions

39
flake.lock generated
View file

@ -1,5 +1,26 @@
{ {
"nodes": { "nodes": {
"fenix": {
"inputs": {
"nixpkgs": [
"nixpkgs"
],
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
"lastModified": 1728109939,
"narHash": "sha256-g4kb34YbEbpeLXv6GNONjZtafFkfl9Cd8jTmuYYON8E=",
"owner": "nix-community",
"repo": "fenix",
"rev": "cdfd7bf3e3edaf9e3f6d1e397d3ee601e513613c",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "fenix",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1720542800, "lastModified": 1720542800,
@ -18,8 +39,26 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"fenix": "fenix",
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
} }
},
"rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1728064742,
"narHash": "sha256-tFvUGvqUZjES1yxYT2zEFiTAE0iQKYd+eWKX/6ZqeVw=",
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "5982d9c420d0dc90739171829f0d2e9c80d98979",
"type": "github"
},
"original": {
"owner": "rust-lang",
"ref": "nightly",
"repo": "rust-analyzer",
"type": "github"
}
} }
}, },
"root": "root", "root": "root",

View file

@ -1,27 +1,21 @@
use std::io::{self, Error, ErrorKind}; use std::io::{self, Error, ErrorKind};
use atoi_radix10::parse_from_str;
use tokio::io::{AsyncBufRead, AsyncBufReadExt, AsyncReadExt, AsyncWriteExt}; use tokio::io::{AsyncBufRead, AsyncBufReadExt, AsyncReadExt, AsyncWriteExt};
use crate::{ use crate::{Canvas, Color, Command, IOProtocol, Parser, Responder, Response};
increment_counter, Canvas, Color, Command, Coordinate, Parser, Protocol, Responder, Response,
MEEHHEH,
};
const SIZE_BIN: u8 = 115; const SIZE_BIN: u8 = 115;
const HELP_BIN: u8 = 104; const HELP_BIN: u8 = 104;
const LOCK: u8 = 0;
const GET_PX_BIN: u8 = 32; const GET_PX_BIN: u8 = 32;
const SET_PX_RGB_BIN: u8 = 128; const SET_PX_RGB_BIN: u8 = 128;
const SET_PX_RGBA_BIN: u8 = 129; const SET_PX_RGBA_BIN: u8 = 129;
const SET_PX_W_BIN: u8 = 130; const SET_PX_W_BIN: u8 = 130;
const SET_PX_RGB_BIN_LENGTH: usize = 8;
pub struct BinaryParser {} pub struct BinaryParser {}
impl BinaryParser { impl BinaryParser {
pub fn new() -> BinaryParser { pub fn new() -> BinaryParser {
return BinaryParser {}; BinaryParser {}
} }
} }
@ -30,23 +24,23 @@ impl<R: AsyncBufRead + AsyncBufReadExt + std::marker::Unpin> Parser<R> for Binar
let fst = reader.read_u8().await; let fst = reader.read_u8().await;
match fst { match fst {
Ok(i) => match i { Ok(i) => match i {
HELP_BIN => return Ok(Command::Help), HELP_BIN => Ok(Command::Help),
SIZE_BIN => { SIZE_BIN => {
let canvas = reader.read_u8().await?; let canvas = reader.read_u8().await?;
return Ok(Command::Size(canvas)); Ok(Command::Size(canvas))
} }
GET_PX_BIN => { GET_PX_BIN => {
let canvas = reader.read_u8().await?; let canvas = reader.read_u8().await?;
let x = reader.read_u16_le().await?; let x = reader.read_u16_le().await?;
let y = reader.read_u16_le().await?; let y = reader.read_u16_le().await?;
return Ok(Command::GetPixel(canvas, x, y)); Ok(Command::GetPixel(canvas, x, y))
} }
SET_PX_W_BIN => { SET_PX_W_BIN => {
let canvas = reader.read_u8().await?; let canvas = reader.read_u8().await?;
let x = reader.read_u16_le().await?; let x = reader.read_u16_le().await?;
let y = reader.read_u16_le().await?; let y = reader.read_u16_le().await?;
let w = reader.read_u8().await?; let w = reader.read_u8().await?;
return Ok(Command::SetPixel(canvas, x, y, Color::W8(w))); Ok(Command::SetPixel(canvas, x, y, Color::W8(w)))
} }
SET_PX_RGB_BIN => { SET_PX_RGB_BIN => {
let canvas = reader.read_u8().await?; let canvas = reader.read_u8().await?;
@ -55,7 +49,7 @@ impl<R: AsyncBufRead + AsyncBufReadExt + std::marker::Unpin> Parser<R> for Binar
let r = reader.read_u8().await?; let r = reader.read_u8().await?;
let g = reader.read_u8().await?; let g = reader.read_u8().await?;
let b = reader.read_u8().await?; let b = reader.read_u8().await?;
return Ok(Command::SetPixel(canvas, x, y, Color::RGB24(r, g, b))); Ok(Command::SetPixel(canvas, x, y, Color::RGB24(r, g, b)))
} }
SET_PX_RGBA_BIN => { SET_PX_RGBA_BIN => {
let canvas = reader.read_u8().await?; let canvas = reader.read_u8().await?;
@ -65,24 +59,24 @@ impl<R: AsyncBufRead + AsyncBufReadExt + std::marker::Unpin> Parser<R> for Binar
let g = reader.read_u8().await?; let g = reader.read_u8().await?;
let b = reader.read_u8().await?; let b = reader.read_u8().await?;
let a = reader.read_u8().await?; let a = reader.read_u8().await?;
return Ok(Command::SetPixel(canvas, x, y, Color::RGBA32(r, g, b, a))); Ok(Command::SetPixel(canvas, x, y, Color::RGBA32(r, g, b, a)))
} }
_ => { _ => {
eprintln!("received illegal command: {}", i); eprintln!("received illegal command: {}", i);
return Err(Error::from(ErrorKind::InvalidInput)); Err(Error::from(ErrorKind::InvalidInput))
} }
}, },
Err(err) => { Err(err) => {
eprintln!("{}", err); eprintln!("{}", err);
return Err(err); Err(err)
} }
} }
} }
} }
impl MEEHHEH for BinaryParser { impl IOProtocol for BinaryParser {
fn change_canvas(&mut self, _canvas: Canvas) -> io::Result<()> { fn change_canvas(&mut self, _canvas: Canvas) -> io::Result<()> {
return Err(Error::from(ErrorKind::Unsupported)); Err(Error::from(ErrorKind::Unsupported))
} }
} }
@ -111,9 +105,7 @@ To set a pixel using RGB, use ({:02X}) (u8 canvas) (x as u16_le) (y as u16_le) (
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::grid::FlutGrid;
use tokio::io::BufReader; use tokio::io::BufReader;
use tokio_test::assert_ok;
#[tokio::test] #[tokio::test]
async fn test_bin_help_parse() { async fn test_bin_help_parse() {

View file

@ -1,9 +1,10 @@
use std::cell::SyncUnsafeCell; use std::cell::SyncUnsafeCell;
use crate::{Coordinate, Response}; use crate::Coordinate;
pub trait Grid<I, V> { pub trait Grid<I, V> {
fn get(&self, x: I, y: I) -> Option<&V>; fn get(&self, x: I, y: I) -> Option<&V>;
#[allow(dead_code)]
fn get_unchecked(&self, x: I, y: I) -> &V; fn get_unchecked(&self, x: I, y: I) -> &V;
fn set(&self, x: I, y: I, value: V); fn set(&self, x: I, y: I, value: V);
} }
@ -20,15 +21,15 @@ impl<T: Clone> FlutGrid<T> {
for _ in 0..(size_x * size_y) { for _ in 0..(size_x * size_y) {
vec.push(value.clone()); vec.push(value.clone());
} }
return FlutGrid { FlutGrid {
size_x, size_x,
size_y, size_y,
cells: vec.into(), cells: vec.into(),
}; }
} }
pub fn get_size(&self) -> (usize, usize) { pub fn get_size(&self) -> (usize, usize) {
return (self.size_x, self.size_y); (self.size_x, self.size_y)
} }
} }
@ -39,16 +40,14 @@ impl<T> FlutGrid<T> {
if x >= self.size_x || y >= self.size_y { if x >= self.size_x || y >= self.size_y {
return None; return None;
} }
return Some((y * self.size_x) + x); Some((y * self.size_x) + x)
} }
} }
impl<T> Grid<Coordinate, T> for FlutGrid<T> { impl<T> Grid<Coordinate, T> for FlutGrid<T> {
fn get(&self, x: Coordinate, y: Coordinate) -> Option<&T> { fn get(&self, x: Coordinate, y: Coordinate) -> Option<&T> {
match self.index(x, y) { self.index(x, y)
None => None, .map(|idx| unsafe { &(*self.cells.get())[idx] })
Some(idx) => Some(unsafe { &(*self.cells.get())[idx] }),
}
} }
fn set(&self, x: Coordinate, y: Coordinate, value: T) { fn set(&self, x: Coordinate, y: Coordinate, value: T) {
@ -60,7 +59,7 @@ impl<T> Grid<Coordinate, T> for FlutGrid<T> {
fn get_unchecked(&self, x: Coordinate, y: Coordinate) -> &T { fn get_unchecked(&self, x: Coordinate, y: Coordinate) -> &T {
let idx = y as usize * self.size_x + x as usize; let idx = y as usize * self.size_x + x as usize;
return unsafe { &(*self.cells.get())[idx] }; unsafe { &(*self.cells.get())[idx] }
} }
} }
@ -127,7 +126,7 @@ mod tests {
b.iter(|| { b.iter(|| {
let x = test::black_box(293); let x = test::black_box(293);
let y = test::black_box(222); let y = test::black_box(222);
let color = test::black_box(293923); let color = test::black_box(293_923);
grid.set(x, y, color); grid.set(x, y, color);
}) })
} }

View file

@ -6,9 +6,7 @@ mod grid;
mod text_protocol; mod text_protocol;
use std::{ use std::{
cell::SyncUnsafeCell,
io::{self, Error, ErrorKind}, io::{self, Error, ErrorKind},
iter::once,
sync::{atomic::AtomicU64, Arc}, sync::{atomic::AtomicU64, Arc},
time::Duration, time::Duration,
}; };
@ -17,11 +15,13 @@ use binary_protocol::BinaryParser;
use grid::{FlutGrid, Grid}; use grid::{FlutGrid, Grid};
use text_protocol::TextParser; use text_protocol::TextParser;
use tokio::{ use tokio::{
io::{AsyncBufRead, AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader, BufWriter}, io::{AsyncReadExt, AsyncWriteExt, BufReader, BufWriter},
net::TcpListener, net::TcpListener,
}; };
extern crate test; extern crate test;
const GRID_LENGTH: usize = 1;
const HOST: &str = "0.0.0.0:7791";
const HELP_TEXT: &[u8] = b"Flurry is a pixelflut implementation, this means you can use commands to get and set pixels in the canvas const HELP_TEXT: &[u8] = b"Flurry is a pixelflut implementation, this means you can use commands to get and set pixels in the canvas
SIZE returns the size of the canvas SIZE returns the size of the canvas
@ -31,7 +31,6 @@ PX {x} {y} {RGB} sets the color of the pixel at {x}, {y} to the rgb value
PX {x} {y} {RGBA} blends the pixel at {x}, {y} with the rgb value weighted by the a PX {x} {y} {RGBA} blends the pixel at {x}, {y} with the rgb value weighted by the a
PX {x} {y} {W} sets the color of the pixel at {x}, {y} to the grayscale value PX {x} {y} {W} sets the color of the pixel at {x}, {y} to the grayscale value
"; ";
const GRID_LENGTH: usize = 1;
static COUNTER: AtomicU64 = AtomicU64::new(0); static COUNTER: AtomicU64 = AtomicU64::new(0);
@ -45,9 +44,8 @@ fn set_pixel_rgba(
y: Coordinate, y: Coordinate,
rgb: u32, rgb: u32,
) { ) {
match grids.get(canvas as usize) { if let Some(grid) = grids.get(canvas as usize) {
Some(grid) => grid.set(x, y, rgb), grid.set(x, y, rgb)
None => (),
} }
} }
@ -58,8 +56,8 @@ fn get_pixel(
y: Coordinate, y: Coordinate,
) -> Option<&u32> { ) -> Option<&u32> {
match grids.get(canvas as usize) { match grids.get(canvas as usize) {
Some(grid) => return grid.get(x, y), Some(grid) => grid.get(x, y),
None => return None, None => None,
} }
} }
@ -105,7 +103,7 @@ where
async fn parse(&self, reader: &mut R) -> io::Result<Command>; async fn parse(&self, reader: &mut R) -> io::Result<Command>;
} }
trait MEEHHEH { trait IOProtocol {
fn change_canvas(&mut self, canvas: Canvas) -> io::Result<()>; fn change_canvas(&mut self, canvas: Canvas) -> io::Result<()>;
} }
@ -116,12 +114,12 @@ where
async fn unparse(&self, response: Response, writer: &mut W) -> io::Result<()>; async fn unparse(&self, response: Response, writer: &mut W) -> io::Result<()>;
} }
async fn listen_handle() { async fn listen_handle() -> io::Result<()> {
let mut interval = tokio::time::interval(Duration::from_millis(1000)); let mut interval = tokio::time::interval(Duration::from_millis(1000));
loop { loop {
interval.tick().await; interval.tick().await;
let cnt = COUNTER.load(std::sync::atomic::Ordering::Relaxed); let cnt = COUNTER.load(std::sync::atomic::Ordering::Relaxed);
println!("{} pixels were changed", cnt); println!("{cnt} pixels were changed");
} }
} }
@ -170,15 +168,16 @@ where
match_parser!(parser: self.parser => parser.unparse(Response::Help, &mut self.writer).await?); match_parser!(parser: self.parser => parser.unparse(Response::Help, &mut self.writer).await?);
self.writer.flush().await?; self.writer.flush().await?;
return Ok(()); Ok(())
} }
async fn size_command(&mut self, canvas: Canvas) -> io::Result<()> { async fn size_command(&mut self, canvas: Canvas) -> io::Result<()> {
let (x, y) = self.grids[canvas as usize].get_size(); let (x, y) = self.grids[canvas as usize].get_size();
match_parser!(parser: self.parser => parser.unparse(Response::Size(x as Coordinate, y as Coordinate), &mut self.writer).await?); match_parser!(parser: self.parser => parser.unparse(
Response::Size(Coordinate::try_from(x).unwrap(), Coordinate::try_from(y).unwrap()), &mut self.writer).await?);
self.writer.flush().await?; self.writer.flush().await?;
return Ok(()); Ok(())
} }
async fn get_pixel_command( async fn get_pixel_command(
@ -194,10 +193,10 @@ where
match_parser!(parser: self.parser => parser.unparse(Response::GetPixel(x,y,[color[0], color[1], color[2]]), &mut self.writer).await?); match_parser!(parser: self.parser => parser.unparse(Response::GetPixel(x,y,[color[0], color[1], color[2]]), &mut self.writer).await?);
self.writer.flush().await?; self.writer.flush().await?;
return Ok(()); Ok(())
} }
async fn set_pixel_command( fn set_pixel_command(
&mut self, &mut self,
canvas: Canvas, canvas: Canvas,
x: Coordinate, x: Coordinate,
@ -211,28 +210,28 @@ where
}; };
set_pixel_rgba(self.grids.as_ref(), canvas, x, y, c); set_pixel_rgba(self.grids.as_ref(), canvas, x, y, c);
increment_counter(); increment_counter();
return Ok(()); Ok(())
} }
async fn change_canvas_command(&mut self, canvas: Canvas) -> io::Result<()> { fn change_canvas_command(&mut self, canvas: Canvas) -> io::Result<()> {
match_parser!(parser: self.parser => parser.change_canvas(canvas)) match_parser!(parser: self.parser => parser.change_canvas(canvas))
} }
async fn change_protocol(&mut self, protocol: Protocol) -> io::Result<()> { fn change_protocol(&mut self, protocol: Protocol) -> io::Result<()> {
match protocol { match protocol {
Protocol::Text => self.parser = ParserTypes::TextParser(TextParser::new(0)), Protocol::Text => self.parser = ParserTypes::TextParser(TextParser::new(0)),
Protocol::Binary => self.parser = ParserTypes::BinaryParser(BinaryParser::new()), Protocol::Binary => self.parser = ParserTypes::BinaryParser(BinaryParser::new()),
} }
return Ok(()); Ok(())
} }
pub fn new(reader: R, writer: W, grids: Arc<[grid::FlutGrid<u32>]>) -> FlutClient<R, W> { pub fn new(reader: R, writer: W, grids: Arc<[grid::FlutGrid<u32>]>) -> FlutClient<R, W> {
return FlutClient { FlutClient {
reader: BufReader::new(reader), reader: BufReader::new(reader),
writer: BufWriter::new(writer), writer: BufWriter::new(writer),
grids, grids,
parser: ParserTypes::TextParser(TextParser::new(0)), parser: ParserTypes::TextParser(TextParser::new(0)),
}; }
} }
pub async fn process_socket(&mut self) -> io::Result<()> { pub async fn process_socket(&mut self) -> io::Result<()> {
@ -247,10 +246,10 @@ where
Ok(Command::Size(canvas)) => self.size_command(canvas).await?, Ok(Command::Size(canvas)) => self.size_command(canvas).await?,
Ok(Command::GetPixel(canvas, x, y)) => self.get_pixel_command(canvas, x, y).await?, Ok(Command::GetPixel(canvas, x, y)) => self.get_pixel_command(canvas, x, y).await?,
Ok(Command::SetPixel(canvas, x, y, color)) => { Ok(Command::SetPixel(canvas, x, y, color)) => {
self.set_pixel_command(canvas, x, y, color).await? self.set_pixel_command(canvas, x, y, color)?;
} }
Ok(Command::ChangeCanvas(canvas)) => self.change_canvas_command(canvas).await?, Ok(Command::ChangeCanvas(canvas)) => self.change_canvas_command(canvas)?,
Ok(Command::ChangeProtocol(protocol)) => self.change_protocol(protocol).await?, Ok(Command::ChangeProtocol(protocol)) => self.change_protocol(protocol)?,
Err(err) if err.kind() == ErrorKind::UnexpectedEof => { Err(err) if err.kind() == ErrorKind::UnexpectedEof => {
return Ok(()); return Ok(());
@ -263,35 +262,53 @@ where
} }
} }
#[tokio::main] async fn handle_flut(
async fn main() -> io::Result<()> { flut_listener: TcpListener,
println!("created grids"); grids: Arc<[grid::FlutGrid<u32>]>,
let grids: Arc<[FlutGrid<u32>; GRID_LENGTH]> = ) -> io::Result<()> {
[grid::FlutGrid::init(800, 600, 0xff00ffff)].into(); let mut handles = Vec::new();
let flut_listener = TcpListener::bind("0.0.0.0:7791").await?;
println!("bound flut listener");
let _ = tokio::spawn(listen_handle());
loop { loop {
let (mut socket, _) = flut_listener.accept().await?; let (mut socket, _) = flut_listener.accept().await?;
let grids = grids.clone(); let grids = grids.clone();
let _ = tokio::spawn(async move { handles.push(tokio::spawn(async move {
let (reader, writer) = socket.split(); let (reader, writer) = socket.split();
let mut connection = FlutClient::new(reader, writer, grids); let mut connection = FlutClient::new(reader, writer, grids);
let resp = connection.process_socket().await; let resp = connection.process_socket().await;
match resp { match resp {
Ok(()) => return Ok(()), Ok(()) => Ok(()),
Err(err) => return Err(err), Err(err) => Err(err),
} }
}); }));
}
}
#[tokio::main]
#[allow(clippy::needless_return)]
async fn main() {
println!("created grids");
let grids: Arc<[FlutGrid<u32>; GRID_LENGTH]> =
[grid::FlutGrid::init(800, 600, 0xff00ffff)].into();
let flut_listener = match TcpListener::bind(HOST).await {
Ok(listener) => listener,
Err(_) => {
eprintln!("Was unable to bind to {HOST}, please check if a different process is bound");
return;
}
};
println!("bound flut listener");
let handles = vec![
// log the amount of changed pixels each second
(tokio::spawn(listen_handle())),
// accept and handle flut connections
(tokio::spawn(handle_flut(flut_listener, grids))),
];
for handle in handles {
println!("joined handle had result {:?}", handle.await)
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {}
use super::*;
use crate::grid::FlutGrid;
use tokio_test::assert_ok;
}

View file

@ -4,18 +4,19 @@ use atoi_radix10::parse_from_str;
use tokio::io::{AsyncBufRead, AsyncBufReadExt, AsyncWriteExt}; use tokio::io::{AsyncBufRead, AsyncBufReadExt, AsyncWriteExt};
use crate::{ use crate::{
Canvas, Color, Command, Coordinate, Parser, Protocol, Responder, Response, GRID_LENGTH, Canvas, Color, Command, Coordinate, IOProtocol, Parser, Protocol, Responder, Response,
HELP_TEXT, MEEHHEH, GRID_LENGTH, HELP_TEXT,
}; };
pub struct TextParser { pub struct TextParser {
canvas: Canvas, canvas: Canvas,
} }
#[allow(dead_code)]
fn parse_coordinate(string: &str) -> io::Result<Coordinate> { fn parse_coordinate(string: &str) -> io::Result<Coordinate> {
match parse_from_str(string) { match parse_from_str(string) {
Ok(coord) => return Ok(coord), Ok(coord) => Ok(coord),
Err(_) => return Err(Error::from(ErrorKind::InvalidInput)), Err(_) => Err(Error::from(ErrorKind::InvalidInput)),
} }
} }
@ -28,12 +29,12 @@ fn parse_color(color: &str) -> io::Result<Color> {
_ => return Err(Error::from(ErrorKind::InvalidInput)), _ => return Err(Error::from(ErrorKind::InvalidInput)),
} }
} }
return Err(Error::from(ErrorKind::InvalidInput)); Err(Error::from(ErrorKind::InvalidInput))
} }
impl TextParser { impl TextParser {
pub fn new(canvas: Canvas) -> TextParser { pub fn new(canvas: Canvas) -> TextParser {
return TextParser { canvas }; TextParser { canvas }
} }
fn parse_pixel(&self, line: &str) -> io::Result<Command> { fn parse_pixel(&self, line: &str) -> io::Result<Command> {
@ -44,16 +45,14 @@ impl TextParser {
let y_coordinate = split.next().ok_or(Error::from(ErrorKind::InvalidInput))?; let y_coordinate = split.next().ok_or(Error::from(ErrorKind::InvalidInput))?;
if let (Ok(horizontal), Ok(vertical)) = (x_coordinate.parse(), y_coordinate.parse()) { if let (Ok(horizontal), Ok(vertical)) = (x_coordinate.parse(), y_coordinate.parse()) {
match split.next() { match split.next() {
None => return Ok(Command::GetPixel(self.canvas, horizontal, vertical)), None => Ok(Command::GetPixel(self.canvas, horizontal, vertical)),
Some(color) => match parse_color(color) { Some(color) => match parse_color(color) {
Ok(color) => { Ok(color) => Ok(Command::SetPixel(self.canvas, horizontal, vertical, color)),
return Ok(Command::SetPixel(self.canvas, horizontal, vertical, color)) Err(err) => Err(err),
}
Err(err) => return Err(err),
}, },
} }
} else { } else {
return Err(Error::from(ErrorKind::InvalidInput)); Err(Error::from(ErrorKind::InvalidInput))
} }
} }
fn parse_canvas(&self, line: &str) -> io::Result<Command> { fn parse_canvas(&self, line: &str) -> io::Result<Command> {
@ -62,9 +61,9 @@ impl TextParser {
let _command = split.next().ok_or(Error::from(ErrorKind::InvalidInput))?; let _command = split.next().ok_or(Error::from(ErrorKind::InvalidInput))?;
let canvas = split.next().ok_or(Error::from(ErrorKind::InvalidInput))?; let canvas = split.next().ok_or(Error::from(ErrorKind::InvalidInput))?;
if let Ok(canvas) = canvas.parse() { if let Ok(canvas) = canvas.parse() {
return Ok(Command::ChangeCanvas(canvas)); Ok(Command::ChangeCanvas(canvas))
} else { } else {
return Err(Error::from(ErrorKind::InvalidInput)); Err(Error::from(ErrorKind::InvalidInput))
} }
} }
fn parse_protocol(&self, line: &str) -> io::Result<Command> { fn parse_protocol(&self, line: &str) -> io::Result<Command> {
@ -73,9 +72,9 @@ impl TextParser {
let _command = split.next().ok_or(Error::from(ErrorKind::InvalidInput))?; let _command = split.next().ok_or(Error::from(ErrorKind::InvalidInput))?;
let protocol = split.next().ok_or(Error::from(ErrorKind::InvalidInput))?; let protocol = split.next().ok_or(Error::from(ErrorKind::InvalidInput))?;
match protocol { match protocol {
"binary" => return Ok(Command::ChangeProtocol(Protocol::Binary)), "binary" => Ok(Command::ChangeProtocol(Protocol::Binary)),
"text" => return Ok(Command::ChangeProtocol(Protocol::Text)), "text" => Ok(Command::ChangeProtocol(Protocol::Text)),
_ => return Err(Error::from(ErrorKind::InvalidInput)), _ => Err(Error::from(ErrorKind::InvalidInput)),
} }
} }
} }
@ -83,7 +82,7 @@ impl TextParser {
impl<R: AsyncBufRead + AsyncBufReadExt + std::marker::Unpin> Parser<R> for TextParser { impl<R: AsyncBufRead + AsyncBufReadExt + std::marker::Unpin> Parser<R> for TextParser {
async fn parse(&self, reader: &mut R) -> io::Result<Command> { async fn parse(&self, reader: &mut R) -> io::Result<Command> {
let mut line = "".to_string(); let mut line = "".to_string();
if let Ok(_) = reader.read_line(&mut line).await { if reader.read_line(&mut line).await.is_ok() {
if line.starts_with("HELP") { if line.starts_with("HELP") {
return Ok(Command::Help); return Ok(Command::Help);
} else if line.starts_with("SIZE") { } else if line.starts_with("SIZE") {
@ -96,17 +95,17 @@ impl<R: AsyncBufRead + AsyncBufReadExt + std::marker::Unpin> Parser<R> for TextP
return self.parse_protocol(&line); return self.parse_protocol(&line);
} }
} }
return Err(Error::from(ErrorKind::InvalidInput)); Err(Error::from(ErrorKind::InvalidInput))
} }
} }
impl MEEHHEH for TextParser { impl IOProtocol for TextParser {
fn change_canvas(&mut self, canvas: Canvas) -> io::Result<()> { fn change_canvas(&mut self, canvas: Canvas) -> io::Result<()> {
if (canvas as usize) < GRID_LENGTH { if (canvas as usize) < GRID_LENGTH {
self.canvas = canvas; self.canvas = canvas;
return Ok(()); Ok(())
} else { } else {
return Err(Error::from(ErrorKind::InvalidInput)); Err(Error::from(ErrorKind::InvalidInput))
} }
} }
} }
@ -132,9 +131,7 @@ impl<W: AsyncWriteExt + std::marker::Unpin> Responder<W> for TextParser {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::grid::FlutGrid;
use tokio::io::BufReader; use tokio::io::BufReader;
use tokio_test::assert_ok;
#[tokio::test] #[tokio::test]
async fn test_help_parse() { async fn test_help_parse() {
@ -142,7 +139,7 @@ mod tests {
let reader = tokio_test::io::Builder::new().read(b"HELP\n").build(); let reader = tokio_test::io::Builder::new().read(b"HELP\n").build();
let mut bufreader = BufReader::new(reader); let mut bufreader = BufReader::new(reader);
let thingy = parser.parse(&mut bufreader).await; let thingy = parser.parse(&mut bufreader).await;
assert_eq!(thingy.unwrap(), Command::Help) assert_eq!(thingy.unwrap(), Command::Help);
} }
#[tokio::test] #[tokio::test]
@ -151,7 +148,7 @@ mod tests {
let reader = tokio_test::io::Builder::new().read(b"SIZE\n").build(); let reader = tokio_test::io::Builder::new().read(b"SIZE\n").build();
let mut bufreader = BufReader::new(reader); let mut bufreader = BufReader::new(reader);
let thingy = parser.parse(&mut bufreader).await; let thingy = parser.parse(&mut bufreader).await;
assert_eq!(thingy.unwrap(), Command::Size(0)) assert_eq!(thingy.unwrap(), Command::Size(0));
} }
#[tokio::test] #[tokio::test]
@ -160,7 +157,7 @@ mod tests {
let reader = tokio_test::io::Builder::new().read(b"CANVAS 12\n").build(); let reader = tokio_test::io::Builder::new().read(b"CANVAS 12\n").build();
let mut bufreader = BufReader::new(reader); let mut bufreader = BufReader::new(reader);
let thingy = parser.parse(&mut bufreader).await; let thingy = parser.parse(&mut bufreader).await;
assert_eq!(thingy.unwrap(), Command::ChangeCanvas(12)) assert_eq!(thingy.unwrap(), Command::ChangeCanvas(12));
} }
#[tokio::test] #[tokio::test]
@ -174,7 +171,7 @@ mod tests {
assert_eq!( assert_eq!(
thingy.unwrap(), thingy.unwrap(),
Command::SetPixel(0, 28283, 29991, Color::W8(0x81)) Command::SetPixel(0, 28283, 29991, Color::W8(0x81))
) );
} }
#[tokio::test] #[tokio::test]
@ -188,7 +185,7 @@ mod tests {
assert_eq!( assert_eq!(
thingy.unwrap(), thingy.unwrap(),
Command::SetPixel(0, 28283, 29991, Color::RGB24(0x88, 0x00, 0xff)) Command::SetPixel(0, 28283, 29991, Color::RGB24(0x88, 0x00, 0xff))
) );
} }
#[tokio::test] #[tokio::test]
@ -202,7 +199,7 @@ mod tests {
assert_eq!( assert_eq!(
thingy.unwrap(), thingy.unwrap(),
Command::SetPixel(0, 28283, 29991, Color::RGBA32(0x88, 0x00, 0xff, 0x28)) Command::SetPixel(0, 28283, 29991, Color::RGBA32(0x88, 0x00, 0xff, 0x28))
) );
} }
#[tokio::test] #[tokio::test]
@ -213,7 +210,7 @@ mod tests {
.build(); .build();
let mut bufreader = BufReader::new(reader); let mut bufreader = BufReader::new(reader);
let thingy = parser.parse(&mut bufreader).await; let thingy = parser.parse(&mut bufreader).await;
assert_eq!(thingy.unwrap(), Command::GetPixel(0, 28283, 29991)) assert_eq!(thingy.unwrap(), Command::GetPixel(0, 28283, 29991));
} }
#[tokio::test] #[tokio::test]