From 330568ec2f043ae284391a217b99b12e765f8a63 Mon Sep 17 00:00:00 2001 From: noa Date: Thu, 11 Jul 2024 19:05:37 +0200 Subject: [PATCH] initial commit --- .gitignore | 1 + .vscode/launch.json | 10 + Cargo.lock | 481 ++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 8 + protocol.md | 19 ++ src/main.rs | 364 +++++++++++++++++++++++++++++++++ 6 files changed, 883 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/launch.json create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 protocol.md create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..435a56c --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,10 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + + ] +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..4b5705c --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,481 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "cc" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaff6f8ce506b9773fa786672d63fc7a191ffea1be33f72bbd4aeacefca9ffc8" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "flurry" +version = "0.1.0" +dependencies = [ + "tokio", + "tokio-test", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" +dependencies = [ + "memchr", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "syn" +version = "2.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tokio" +version = "1.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-stream" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-test" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" +dependencies = [ + "async-stream", + "bytes", + "futures-core", + "tokio", + "tokio-stream", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..1639c03 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "flurry" +version = "0.1.0" +edition = "2021" + +[dependencies] +tokio = { version = "1.38", features = ["full"] } +tokio-test = "*" \ No newline at end of file diff --git a/protocol.md b/protocol.md new file mode 100644 index 0000000..d36f91b --- /dev/null +++ b/protocol.md @@ -0,0 +1,19 @@ +set rgba +set rgb +set w +get +lock bytes +help +size + + +RESERVED 01001000 +RESERVED 01010011 +RESERVED 01010000 +help 01101000 +size 01110011 {canvas} +lock 00000000 {amt lsb} {amt msb} {lock command} {lock bytes msb} {lock bytes lsb} {lock values}.. {insert values}... +get 00100000 {canvas} {x lsb} {x msb} {y lsb} {y msb} +set rgb 10000000 {canvas} {x lsb} {x msb} {y lsb} {y msb} {r byte} {g byte} {b byte} +set rgba 10000001 {canvas} {x lsb} {x msb} {y lsb} {y msb} {r byte} {g byte} {b byte} {a byte} +set w 10000010 {canvas} {x lsb} {x msb} {y lsb} {y msb} {w byte} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..3a76740 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,364 @@ +#![feature(test)] + +use std::{ + io::{self, Error, ErrorKind}, + iter::{self, once}, + vec, +}; + +use tokio::{ + io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, BufStream}, + net::TcpListener, +}; + +extern crate test; + +trait Grid { + fn get(&self, x: I, y: I) -> Option<&V>; + fn set(&mut self, x: I, y: I, value: V); +} + +struct FlutGrid { + size_x: usize, + size_y: usize, + cells: Vec, +} + +impl FlutGrid { + fn init(size_x: usize, size_y: usize, value: T) -> FlutGrid { + let mut vec = Vec::with_capacity(size_x * size_y); + for _ in 0..(size_x * size_y) { + vec.push(value.clone()); + } + return FlutGrid { + size_x, + size_y, + cells: vec, + }; + } +} + +impl FlutGrid { + fn index(&self, x: u16, y: u16) -> Option { + let x = x as usize; + let y = y as usize; + if x >= self.size_x || y >= self.size_y { + return None; + } + return Some((y * self.size_x) + x); + } +} + +impl Grid for FlutGrid { + fn get(&self, x: u16, y: u16) -> Option<&T> { + match self.index(x, y) { + None => None, + Some(idx) => Some(&self.cells[idx]), + } + } + + fn set(&mut self, x: u16, y: u16, value: T) { + match self.index(x, y) { + None => (), + Some(idx) => self.cells[idx] = value, + } + } +} + +const HELP_TEXT: u8 = 72; +const SIZE_TEXT: u8 = 83; +const PX_TEXT: u8 = 80; +const SIZE_BIN: u8 = 115; +const HELP_BIN: u8 = 104; +const LOCK: u8 = 0; +const GET_PX_BIN: u8 = 32; +const SET_PX_RGB_BIN: u8 = 128; +const SET_PX_RGBA_BIN: u8 = 129; +const SET_PX_W_BIN: u8 = 130; + +const SET_PX_RGB_BIN_LENGTH: usize = 8; + +fn set_pixel_rgba(grids: &mut [FlutGrid], canvas: u8, x: u16, y: u16, rgb: u32) { + match grids.get_mut(canvas as usize) { + Some(grid) => grid.set(x, y, rgb), + None => (), + } +} + +fn get_pixel(grids: &mut [FlutGrid], canvas: u8, x: u16, y: u16) -> Option<&u32> { + match grids.get_mut(canvas as usize) { + Some(grid) => return grid.get(x, y), + None => return None, + } +} + +async fn process_msg( + stream: &mut T, + grids: &mut [FlutGrid], +) -> io::Result<()> { + match stream.read_u8().await { + Ok(i) => match i { + HELP_TEXT => todo!("HELP command check and message"), + SIZE_TEXT => todo!("SIZE command check and message"), + PX_TEXT => todo!("PX command handling"), + HELP_BIN => todo!("HELP command message"), + SIZE_BIN => todo!("SIZE command check and message"), + LOCK => { + let amount = stream.read_u16_le().await?; + let command = stream.read_u8().await?; + let lockmask = stream.read_u16().await?; + let mut buf = vec![0; lockmask.count_ones() as usize]; + let statics = stream.read_exact(&mut buf).await?; + + match command { + GET_PX_BIN => todo!("GET pixel lock"), + SET_PX_RGB_BIN => { + let per = SET_PX_RGB_BIN_LENGTH - statics; + let mut j = 0; + let mut a; + let static_buf: Vec> = (0..SET_PX_RGB_BIN_LENGTH) + .map(|i| match lockmask >> (15 - i) & 1 { + 1 => { + let b = Some(buf[j]); + + j += 1; + return b; + } + 0 => None, + _ => todo!("WTF"), + }) + .collect(); + let mut mod_buf: Vec = vec![0; per]; + for z in 0..amount { + a = 0; + let _ = stream.read_exact(&mut mod_buf).await?; + let aa = static_buf + .iter() + .map(|x| *match x { + Some(val) => val, + None => { + let b = mod_buf[a]; + a += 1; + return b; + } + }) + .map(|z| z) + .collect::>(); + match grids.get_mut(aa[0] as usize) { + Some(grid) => grid.set( + u16::from_le_bytes([aa[1], aa[2]]), + u16::from_le_bytes([aa[3], aa[4]]), + u32::from_be_bytes([aa[5], aa[6], aa[7], 0]), + ), + None => (), + } + } + } + SET_PX_RGBA_BIN => todo!("Set rgba lock"), + SET_PX_W_BIN => todo!("set w lock"), + _ => return Err(Error::from(ErrorKind::InvalidInput)), + } + + return Ok(()); + } + GET_PX_BIN => { + let canvas = stream.read_u8().await?; + let x = stream.read_u16_le().await?; + let y = stream.read_u16_le().await?; + match get_pixel(grids, canvas, x, y) { + None => (), + Some(color) => { + stream + .write_all( + &once(canvas) + .chain(x.to_le_bytes()) + .chain(y.to_le_bytes()) + .chain(color.to_be_bytes()) + .collect::>(), + ) + .await?; + () + } + } + return Ok(()); + } + SET_PX_RGB_BIN => { + let canvas = stream.read_u8().await?; + let x = stream.read_u16_le().await?; + let y = stream.read_u16_le().await?; + let r = stream.read_u8().await?; + let g = stream.read_u8().await?; + let b = stream.read_u8().await?; + let rgb = (r as u32) << 24 | (g as u32) << 16 | (b as u32) << 8; + set_pixel_rgba(grids, canvas, x, y, rgb); + return Ok(()); + } + SET_PX_RGBA_BIN => todo!("SET rgba"), + SET_PX_W_BIN => todo!("SET w"), + _ => { + eprintln!("received illegal command: {}", i); + return Err(Error::from(ErrorKind::InvalidInput)); + } + }, + Err(err) => { + eprintln!("{}", err); + return Err(err); + } + } +} + +async fn process_socket( + socket: T, + grids: &mut [FlutGrid], +) -> io::Result<()> { + let mut stream = BufStream::new(socket); + loop { + match process_msg(&mut stream, grids).await { + Ok(()) => (), + Err(e) => return Err(e), + } + } +} + +#[tokio::main] +async fn main() -> io::Result<()> { + let mut grids = [FlutGrid::init(800, 600, 0xff00ff)]; + let flut_listener = TcpListener::bind("0.0.0.0:7791").await?; + + loop { + let (socket, _) = flut_listener.accept().await?; + match process_socket(socket, &mut grids).await { + Ok(_) => println!("socket closed okay"), + Err(err) => { + eprintln!("received illegal command: {}", err) + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use test::Bencher; + + #[tokio::test] + async fn test_grid_init_values() { + let grid = FlutGrid::init(3, 3, 0); + + assert_eq!(grid.cells, vec![0, 0, 0, 0, 0, 0, 0, 0, 0]) + } + + #[tokio::test] + async fn test_grid_init_size() { + let grid = FlutGrid::init(800, 600, 0); + + assert_eq!(grid.size_x, 800); + assert_eq!(grid.size_y, 600); + } + + #[tokio::test] + async fn test_grid_set() { + let mut grid = FlutGrid::init(3, 3, 0); + grid.set(1, 1, 255); + grid.set(2, 1, 256); + assert_eq!(grid.cells, vec![0, 0, 0, 0, 255, 256, 0, 0, 0]) + } + + #[tokio::test] + async fn test_grid_set_out_of_range() { + let mut grid = FlutGrid::init(3, 3, 0); + grid.set(1, 1, 255); + grid.set(3, 1, 256); + assert_eq!(grid.cells, vec![0, 0, 0, 0, 255, 0, 0, 0, 0]) + } + + #[tokio::test] + async fn test_grid_get() { + let mut grid = FlutGrid::init(3, 3, 0); + grid.set(1, 2, 222); + assert_eq!(grid.get(1, 2), Some(&222)); + } + + #[tokio::test] + async fn test_grid_get_out_of_range() { + let mut grid = FlutGrid::init(3, 3, 0); + grid.set(3, 1, 256); + assert_eq!(grid.get(3, 1), None); + assert_eq!(grid.get(1, 2), Some(&0)); + } + + #[bench] + fn bench_init(b: &mut Bencher) { + b.iter(|| FlutGrid::init(800, 600, 0 as u32)) + } + + #[bench] + fn bench_set(b: &mut Bencher) { + let mut grid = FlutGrid::init(800, 600, 0 as u32); + b.iter(|| { + let x = test::black_box(293); + let y = test::black_box(222); + let color = test::black_box(293923); + grid.set(x, y, color); + }) + } + + #[bench] + fn bench_get(b: &mut Bencher) { + let grid = FlutGrid::init(800, 600, 0 as u32); + b.iter(|| { + let x = test::black_box(293); + let y = test::black_box(222); + grid.get(x, y) + }) + } + + #[tokio::test] + async fn test_set_rgb_bin() { + let mut grids = [FlutGrid::init(800, 600, 0xFF00FF)]; + let writer = tokio_test::io::Builder::new() + .read(&[SET_PX_RGB_BIN, 0, 16, 0, 32, 0, 0, 0, 0]) + .read(&[SET_PX_RGB_BIN, 0, 16, 0, 33, 0, 2, 3, 5]) + .build(); + let res = process_socket(writer, &mut grids).await; + match res { + Ok(()) => (), + Err(err) => eprintln!("{}", err), + }; + assert_eq!(grids[0].get(16, 32), Some(&0x00000000)); + assert_eq!(grids[0].get(16, 33), Some(&0x02030500)); + } + + #[tokio::test] + async fn test_set_rgb_lock() { + let mut grids = [FlutGrid::init(800, 600, 0xFF00FF)]; + let writer = tokio_test::io::Builder::new() + .read(&[ + LOCK, + 3, + 0, + SET_PX_RGB_BIN, + 0b1011_1110, + 0b0000_0000, + 0, + 0, + 0, + 0, + 2, + 3, + ]) + .read(&[100, 4]) + .read(&[101, 5]) + .read(&[102, 6]) + .build(); + let res = process_socket(writer, &mut grids).await; + match res { + Ok(()) => (), + Err(err) => eprintln!("{}", err), + }; + + assert_eq!(grids[0].get(100, 0), Some(&0x02030400)); + assert_eq!(grids[0].get(101, 0), Some(&0x02030500)); + assert_eq!(grids[0].get(102, 0), Some(&0x02030600)); + } +}