refactor: split into more logical files
This commit is contained in:
parent
19eb943865
commit
9dc681086d
11 changed files with 728 additions and 276 deletions
380
Cargo.lock
generated
380
Cargo.lock
generated
|
|
@ -23,6 +23,15 @@ version = "2.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aligned-vec"
|
name = "aligned-vec"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
|
@ -44,6 +53,18 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anes"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.89"
|
version = "1.0.89"
|
||||||
|
|
@ -216,6 +237,12 @@ version = "1.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3"
|
checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cast"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.1.29"
|
version = "1.1.29"
|
||||||
|
|
@ -257,6 +284,58 @@ dependencies = [
|
||||||
"windows-targets",
|
"windows-targets",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ciborium"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
|
||||||
|
dependencies = [
|
||||||
|
"ciborium-io",
|
||||||
|
"ciborium-ll",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ciborium-io"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ciborium-ll"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
|
||||||
|
dependencies = [
|
||||||
|
"ciborium-io",
|
||||||
|
"half",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "4.5.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
|
||||||
|
dependencies = [
|
||||||
|
"clap_builder",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_builder"
|
||||||
|
version = "4.5.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"clap_lex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "color_quant"
|
name = "color_quant"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|
@ -278,6 +357,42 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "criterion"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
|
||||||
|
dependencies = [
|
||||||
|
"anes",
|
||||||
|
"cast",
|
||||||
|
"ciborium",
|
||||||
|
"clap",
|
||||||
|
"criterion-plot",
|
||||||
|
"is-terminal",
|
||||||
|
"itertools 0.10.5",
|
||||||
|
"num-traits",
|
||||||
|
"once_cell",
|
||||||
|
"oorandom",
|
||||||
|
"plotters",
|
||||||
|
"rayon",
|
||||||
|
"regex",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"tinytemplate",
|
||||||
|
"walkdir",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "criterion-plot"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
|
||||||
|
dependencies = [
|
||||||
|
"cast",
|
||||||
|
"itertools 0.10.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-deque"
|
name = "crossbeam-deque"
|
||||||
version = "0.8.5"
|
version = "0.8.5"
|
||||||
|
|
@ -321,6 +436,16 @@ version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "exr"
|
name = "exr"
|
||||||
version = "1.72.0"
|
version = "1.72.0"
|
||||||
|
|
@ -337,6 +462,12 @@ dependencies = [
|
||||||
"zune-inflate",
|
"zune-inflate",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fastrand"
|
||||||
|
version = "2.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fdeflate"
|
name = "fdeflate"
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
|
|
@ -373,7 +504,11 @@ dependencies = [
|
||||||
"atoi_radix10",
|
"atoi_radix10",
|
||||||
"bytes",
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"criterion",
|
||||||
"image",
|
"image",
|
||||||
|
"rand",
|
||||||
|
"tempfile",
|
||||||
|
"test-case",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-test",
|
"tokio-test",
|
||||||
]
|
]
|
||||||
|
|
@ -439,6 +574,12 @@ version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iana-time-zone"
|
name = "iana-time-zone"
|
||||||
version = "0.1.61"
|
version = "0.1.61"
|
||||||
|
|
@ -522,6 +663,26 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is-terminal"
|
||||||
|
version = "0.4.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi 0.4.0",
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.10.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
|
|
@ -531,6 +692,12 @@ dependencies = [
|
||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jobserver"
|
name = "jobserver"
|
||||||
version = "0.1.32"
|
version = "0.1.32"
|
||||||
|
|
@ -578,6 +745,12 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.4.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.12"
|
version = "0.4.12"
|
||||||
|
|
@ -649,10 +822,10 @@ version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
|
checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi",
|
"hermit-abi 0.3.9",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi",
|
||||||
"windows-sys",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -742,6 +915,12 @@ version = "1.20.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "oorandom"
|
||||||
|
version = "11.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.3"
|
version = "0.12.3"
|
||||||
|
|
@ -783,6 +962,34 @@ version = "0.3.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "plotters"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
"plotters-backend",
|
||||||
|
"plotters-svg",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "plotters-backend"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "plotters-svg"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670"
|
||||||
|
dependencies = [
|
||||||
|
"plotters-backend",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "png"
|
name = "png"
|
||||||
version = "0.17.14"
|
version = "0.17.14"
|
||||||
|
|
@ -901,7 +1108,7 @@ dependencies = [
|
||||||
"built",
|
"built",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"interpolate_name",
|
"interpolate_name",
|
||||||
"itertools",
|
"itertools 0.12.1",
|
||||||
"libc",
|
"libc",
|
||||||
"libfuzzer-sys",
|
"libfuzzer-sys",
|
||||||
"log",
|
"log",
|
||||||
|
|
@ -965,6 +1172,35 @@ dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rgb"
|
name = "rgb"
|
||||||
version = "0.8.50"
|
version = "0.8.50"
|
||||||
|
|
@ -980,6 +1216,34 @@ version = "0.1.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "0.38.37"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.6.0",
|
||||||
|
"errno",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "same-file"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
|
@ -1006,6 +1270,18 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.129"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6dbcf9b78a125ee667ae19388837dd12294b858d101fdd393cb9d5501ef09eb2"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"memchr",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_spanned"
|
name = "serde_spanned"
|
||||||
version = "0.6.8"
|
version = "0.6.8"
|
||||||
|
|
@ -1058,7 +1334,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
|
checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1100,6 +1376,52 @@ version = "0.12.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempfile"
|
||||||
|
version = "3.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"fastrand",
|
||||||
|
"once_cell",
|
||||||
|
"rustix",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "test-case"
|
||||||
|
version = "3.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8"
|
||||||
|
dependencies = [
|
||||||
|
"test-case-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "test-case-core"
|
||||||
|
version = "3.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "test-case-macros"
|
||||||
|
version = "3.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"test-case-core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.64"
|
version = "1.0.64"
|
||||||
|
|
@ -1131,6 +1453,16 @@ dependencies = [
|
||||||
"weezl",
|
"weezl",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinytemplate"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.40.0"
|
version = "1.40.0"
|
||||||
|
|
@ -1146,7 +1478,7 @@ dependencies = [
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"windows-sys",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1241,6 +1573,16 @@ version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b"
|
checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "walkdir"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||||
|
dependencies = [
|
||||||
|
"same-file",
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
|
@ -1302,12 +1644,31 @@ version = "0.2.95"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
|
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "web-sys"
|
||||||
|
version = "0.3.72"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112"
|
||||||
|
dependencies = [
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "weezl"
|
name = "weezl"
|
||||||
version = "0.1.8"
|
version = "0.1.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082"
|
checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-util"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-core"
|
name = "windows-core"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
|
|
@ -1326,6 +1687,15 @@ dependencies = [
|
||||||
"windows-targets",
|
"windows-targets",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.59.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,12 @@ image = "0.25.2"
|
||||||
tokio = { version = "1.38", features = ["full"] }
|
tokio = { version = "1.38", features = ["full"] }
|
||||||
tokio-test = "*"
|
tokio-test = "*"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tempfile = "*"
|
||||||
|
test-case = "*"
|
||||||
|
criterion = "*"
|
||||||
|
rand = "*"
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
opt-level = 1
|
opt-level = 1
|
||||||
|
|
||||||
|
|
|
||||||
11
src/config.rs
Normal file
11
src/config.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
pub const GRID_LENGTH: usize = 1;
|
||||||
|
pub const HOST: &str = "0.0.0.0:7791";
|
||||||
|
|
||||||
|
pub 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
|
||||||
|
PX {x} {y} returns the color of the pixel at {x}, {y}
|
||||||
|
If you include a color in hex format you set a pixel instead
|
||||||
|
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} {W} sets the color of the pixel at {x}, {y} to the grayscale value
|
||||||
|
";
|
||||||
151
src/flutclient.rs
Normal file
151
src/flutclient.rs
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
use std::{
|
||||||
|
io::{self, Error, ErrorKind},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
|
use tokio::io::{AsyncReadExt, AsyncWriteExt, BufReader, BufWriter};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
get_pixel,
|
||||||
|
grid::{self, Flut},
|
||||||
|
increment_counter,
|
||||||
|
protocols::{BinaryParser, IOProtocol, Parser, Responder, TextParser},
|
||||||
|
set_pixel_rgba, Canvas, Color, Command, Coordinate, Protocol, Response,
|
||||||
|
};
|
||||||
|
|
||||||
|
macro_rules! build_parser_type_enum {
|
||||||
|
($($name:ident: $t:ty,)*) => {
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
enum ParserTypes {
|
||||||
|
$($name($t),)*
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! match_parser {
|
||||||
|
($pident:ident: $parser:expr => $f:expr) => (
|
||||||
|
match &mut $parser {
|
||||||
|
$(
|
||||||
|
ParserTypes::$name($pident) => $f,
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
build_parser_type_enum! {
|
||||||
|
TextParser: TextParser,
|
||||||
|
BinaryParser: BinaryParser,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FlutClient<R, W>
|
||||||
|
where
|
||||||
|
R: AsyncReadExt + std::marker::Unpin,
|
||||||
|
W: AsyncWriteExt + std::marker::Unpin,
|
||||||
|
{
|
||||||
|
reader: BufReader<R>,
|
||||||
|
writer: BufWriter<W>,
|
||||||
|
grids: Arc<[Flut<u32>]>,
|
||||||
|
parser: ParserTypes,
|
||||||
|
counter: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R, W> FlutClient<R, W>
|
||||||
|
where
|
||||||
|
R: AsyncReadExt + std::marker::Unpin,
|
||||||
|
W: AsyncWriteExt + std::marker::Unpin,
|
||||||
|
{
|
||||||
|
async fn help_command(&mut self) -> io::Result<()> {
|
||||||
|
println!("HELP wanted");
|
||||||
|
match_parser!(parser: self.parser => parser.unparse(Response::Help, &mut self.writer).await?);
|
||||||
|
|
||||||
|
self.writer.flush().await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn size_command(&mut self, canvas: Canvas) -> io::Result<()> {
|
||||||
|
let (x, y) = self.grids[canvas as usize].get_size();
|
||||||
|
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?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_pixel_command(
|
||||||
|
&mut self,
|
||||||
|
canvas: Canvas,
|
||||||
|
x: Coordinate,
|
||||||
|
y: Coordinate,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
let color = match get_pixel(&self.grids, canvas, x, y) {
|
||||||
|
None => return Err(Error::from(ErrorKind::InvalidInput)),
|
||||||
|
Some(color) => color.to_be_bytes(),
|
||||||
|
};
|
||||||
|
match_parser!(parser: self.parser => parser.unparse(
|
||||||
|
Response::GetPixel(x,y,[color[0], color[1], color[2]]), &mut self.writer).await?
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_pixel_command(&mut self, canvas: Canvas, x: Coordinate, y: Coordinate, color: &Color) {
|
||||||
|
let c: u32 = match color {
|
||||||
|
Color::RGB24(red, green, blue) => u32::from_be_bytes([*red, *green, *blue, 0xff]),
|
||||||
|
Color::RGBA32(red, green, blue, alpha) => {
|
||||||
|
u32::from_be_bytes([*red, *green, *blue, *alpha])
|
||||||
|
}
|
||||||
|
Color::W8(white) => u32::from_be_bytes([*white, *white, *white, 0xff]),
|
||||||
|
};
|
||||||
|
set_pixel_rgba(self.grids.as_ref(), canvas, x, y, c);
|
||||||
|
self.counter += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change_canvas_command(&mut self, canvas: Canvas) -> io::Result<()> {
|
||||||
|
match_parser!(parser: self.parser => parser.change_canvas(canvas))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change_protocol(&mut self, protocol: &Protocol) {
|
||||||
|
match protocol {
|
||||||
|
Protocol::Text => self.parser = ParserTypes::TextParser(TextParser::new(0)),
|
||||||
|
Protocol::Binary => self.parser = ParserTypes::BinaryParser(BinaryParser::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(reader: R, writer: W, grids: Arc<[grid::Flut<u32>]>) -> Self {
|
||||||
|
FlutClient {
|
||||||
|
reader: BufReader::new(reader),
|
||||||
|
writer: BufWriter::new(writer),
|
||||||
|
grids,
|
||||||
|
parser: ParserTypes::TextParser(TextParser::new(0)),
|
||||||
|
counter: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn process_socket(&mut self) -> io::Result<()> {
|
||||||
|
loop {
|
||||||
|
match_parser!(parser: &self.parser.clone() => 'outer: loop {
|
||||||
|
for _ in 0..1000 {
|
||||||
|
let parsed = parser.parse(&mut self.reader).await;
|
||||||
|
match parsed {
|
||||||
|
Ok(Command::Help) => self.help_command().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::SetPixel(canvas, x, y, color)) => self.set_pixel_command(canvas, x, y, &color),
|
||||||
|
Ok(Command::ChangeCanvas(canvas)) => {
|
||||||
|
self.change_canvas_command(canvas)?;
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
|
Ok(Command::ChangeProtocol(protocol)) => {
|
||||||
|
self.change_protocol(&protocol);
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
|
Err(err) if err.kind() == ErrorKind::UnexpectedEof => return Ok(()),
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
increment_counter(self.counter);
|
||||||
|
self.counter = 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
src/grid.rs
35
src/grid.rs
|
|
@ -1,6 +1,6 @@
|
||||||
use std::cell::SyncUnsafeCell;
|
use std::cell::SyncUnsafeCell;
|
||||||
|
|
||||||
use image::{DynamicImage, GenericImage, GenericImageView, ImageBuffer, Pixel, Rgb, Rgba};
|
use image::{GenericImageView, Rgb};
|
||||||
|
|
||||||
use crate::Coordinate;
|
use crate::Coordinate;
|
||||||
|
|
||||||
|
|
@ -74,7 +74,7 @@ impl GenericImageView for Flut<u32> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
|
fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
|
||||||
let pixel = self.get_unchecked(x as u16, y as u16);
|
let pixel = self.get_unchecked(x as Coordinate, y as Coordinate);
|
||||||
let [r, g, b, _a] = pixel.to_be_bytes();
|
let [r, g, b, _a] = pixel.to_be_bytes();
|
||||||
Rgb::from([r, g, b])
|
Rgb::from([r, g, b])
|
||||||
}
|
}
|
||||||
|
|
@ -83,9 +83,8 @@ impl GenericImageView for Flut<u32> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[allow(clippy::needless_return)]
|
#[allow(clippy::needless_return)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::Flut;
|
||||||
use crate::grid::Flut;
|
use super::Grid;
|
||||||
use test::Bencher;
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_grid_init_values() {
|
async fn test_grid_init_values() {
|
||||||
|
|
@ -132,30 +131,4 @@ mod tests {
|
||||||
assert_eq!(grid.get(3, 1), None);
|
assert_eq!(grid.get(3, 1), None);
|
||||||
assert_eq!(grid.get(1, 2), Some(&0));
|
assert_eq!(grid.get(1, 2), Some(&0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn bench_init(b: &mut Bencher) {
|
|
||||||
b.iter(|| Flut::init(800, 600, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn bench_set(b: &mut Bencher) {
|
|
||||||
let grid = Flut::init(800, 600, 0);
|
|
||||||
b.iter(|| {
|
|
||||||
let x = test::black_box(293);
|
|
||||||
let y = test::black_box(222);
|
|
||||||
let color = test::black_box(0x29_39_23);
|
|
||||||
grid.set(x, y, color);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn bench_get(b: &mut Bencher) {
|
|
||||||
let grid = Flut::init(800, 600, 0);
|
|
||||||
b.iter(|| {
|
|
||||||
let x = test::black_box(293);
|
|
||||||
let y = test::black_box(222);
|
|
||||||
grid.get(x, y)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
77
src/lib.rs
Normal file
77
src/lib.rs
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
#![feature(test)]
|
||||||
|
#![feature(sync_unsafe_cell)]
|
||||||
|
#![feature(if_let_guard)]
|
||||||
|
|
||||||
|
use std::sync::atomic::AtomicU64;
|
||||||
|
|
||||||
|
use grid::Grid;
|
||||||
|
|
||||||
|
pub mod config;
|
||||||
|
pub mod flutclient;
|
||||||
|
pub mod grid;
|
||||||
|
pub mod protocols;
|
||||||
|
pub mod utils;
|
||||||
|
|
||||||
|
pub type Canvas = u8;
|
||||||
|
pub type Coordinate = u16;
|
||||||
|
|
||||||
|
pub static COUNTER: AtomicU64 = AtomicU64::new(0);
|
||||||
|
|
||||||
|
fn set_pixel_rgba(
|
||||||
|
grids: &[grid::Flut<u32>],
|
||||||
|
canvas: Canvas,
|
||||||
|
x: Coordinate,
|
||||||
|
y: Coordinate,
|
||||||
|
rgb: u32,
|
||||||
|
) {
|
||||||
|
if let Some(grid) = grids.get(canvas as usize) {
|
||||||
|
grid.set(x, y, rgb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_pixel(
|
||||||
|
grids: &[grid::Flut<u32>],
|
||||||
|
canvas: Canvas,
|
||||||
|
x: Coordinate,
|
||||||
|
y: Coordinate,
|
||||||
|
) -> Option<&u32> {
|
||||||
|
match grids.get(canvas as usize) {
|
||||||
|
Some(grid) => grid.get(x, y),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn increment_counter(amount: u64) {
|
||||||
|
COUNTER.fetch_add(amount, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum Color {
|
||||||
|
RGB24(u8, u8, u8),
|
||||||
|
RGBA32(u8, u8, u8, u8),
|
||||||
|
W8(u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum Protocol {
|
||||||
|
Text,
|
||||||
|
Binary,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum Command {
|
||||||
|
Help,
|
||||||
|
Size(Canvas),
|
||||||
|
GetPixel(Canvas, Coordinate, Coordinate),
|
||||||
|
SetPixel(Canvas, Coordinate, Coordinate, Color),
|
||||||
|
ChangeCanvas(Canvas),
|
||||||
|
ChangeProtocol(Protocol),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum Response {
|
||||||
|
Help,
|
||||||
|
Size(Coordinate, Coordinate),
|
||||||
|
GetPixel(Coordinate, Coordinate, [u8; 3]),
|
||||||
|
}
|
||||||
243
src/main.rs
243
src/main.rs
|
|
@ -2,10 +2,6 @@
|
||||||
#![feature(sync_unsafe_cell)]
|
#![feature(sync_unsafe_cell)]
|
||||||
#![feature(if_let_guard)]
|
#![feature(if_let_guard)]
|
||||||
|
|
||||||
mod binary_protocol;
|
|
||||||
mod grid;
|
|
||||||
mod text_protocol;
|
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
fs::{create_dir_all, File},
|
fs::{create_dir_all, File},
|
||||||
io::{self, Error, ErrorKind},
|
io::{self, Error, ErrorKind},
|
||||||
|
|
@ -14,11 +10,14 @@ use std::{
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
use binary_protocol::BinaryParser;
|
|
||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
use grid::{Flut, Grid};
|
use flurry::{
|
||||||
|
config::{GRID_LENGTH, HOST},
|
||||||
|
flutclient::FlutClient,
|
||||||
|
grid::{self, Flut},
|
||||||
|
COUNTER,
|
||||||
|
};
|
||||||
use image::{codecs::jpeg::JpegEncoder, GenericImageView, SubImage};
|
use image::{codecs::jpeg::JpegEncoder, GenericImageView, SubImage};
|
||||||
use text_protocol::TextParser;
|
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::{AsyncReadExt, AsyncWriteExt, BufReader, BufWriter},
|
io::{AsyncReadExt, AsyncWriteExt, BufReader, BufWriter},
|
||||||
net::TcpListener,
|
net::TcpListener,
|
||||||
|
|
@ -26,99 +25,6 @@ use tokio::{
|
||||||
};
|
};
|
||||||
|
|
||||||
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
|
|
||||||
SIZE returns the size of the canvas
|
|
||||||
PX {x} {y} returns the color of the pixel at {x}, {y}
|
|
||||||
If you include a color in hex format you set a pixel instead
|
|
||||||
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} {W} sets the color of the pixel at {x}, {y} to the grayscale value
|
|
||||||
";
|
|
||||||
|
|
||||||
static COUNTER: AtomicU64 = AtomicU64::new(0);
|
|
||||||
|
|
||||||
type Canvas = u8;
|
|
||||||
type Coordinate = u16;
|
|
||||||
|
|
||||||
fn set_pixel_rgba(
|
|
||||||
grids: &[grid::Flut<u32>],
|
|
||||||
canvas: Canvas,
|
|
||||||
x: Coordinate,
|
|
||||||
y: Coordinate,
|
|
||||||
rgb: u32,
|
|
||||||
) {
|
|
||||||
if let Some(grid) = grids.get(canvas as usize) {
|
|
||||||
grid.set(x, y, rgb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_pixel(
|
|
||||||
grids: &[grid::Flut<u32>],
|
|
||||||
canvas: Canvas,
|
|
||||||
x: Coordinate,
|
|
||||||
y: Coordinate,
|
|
||||||
) -> Option<&u32> {
|
|
||||||
match grids.get(canvas as usize) {
|
|
||||||
Some(grid) => grid.get(x, y),
|
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn increment_counter(amount: u64) {
|
|
||||||
COUNTER.fetch_add(amount, std::sync::atomic::Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
enum Color {
|
|
||||||
RGB24(u8, u8, u8),
|
|
||||||
RGBA32(u8, u8, u8, u8),
|
|
||||||
W8(u8),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
enum Protocol {
|
|
||||||
Text,
|
|
||||||
Binary,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
enum Command {
|
|
||||||
Help,
|
|
||||||
Size(Canvas),
|
|
||||||
GetPixel(Canvas, Coordinate, Coordinate),
|
|
||||||
SetPixel(Canvas, Coordinate, Coordinate, Color),
|
|
||||||
ChangeCanvas(Canvas),
|
|
||||||
ChangeProtocol(Protocol),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
enum Response {
|
|
||||||
Help,
|
|
||||||
Size(Coordinate, Coordinate),
|
|
||||||
GetPixel(Coordinate, Coordinate, [u8; 3]),
|
|
||||||
}
|
|
||||||
|
|
||||||
trait Parser<R>
|
|
||||||
where
|
|
||||||
R: std::marker::Unpin + tokio::io::AsyncBufRead,
|
|
||||||
{
|
|
||||||
async fn parse(&self, reader: &mut R) -> io::Result<Command>;
|
|
||||||
}
|
|
||||||
|
|
||||||
trait IOProtocol {
|
|
||||||
fn change_canvas(&mut self, canvas: Canvas) -> io::Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
trait Responder<W>
|
|
||||||
where
|
|
||||||
W: AsyncWriteExt + std::marker::Unpin,
|
|
||||||
{
|
|
||||||
async fn unparse(&self, response: Response, writer: &mut W) -> io::Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn listen_handle() -> io::Result<()> {
|
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));
|
||||||
|
|
@ -129,143 +35,6 @@ async fn listen_handle() -> io::Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! build_parser_type_enum {
|
|
||||||
($($name:ident: $t:ty,)*) => {
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
enum ParserTypes {
|
|
||||||
$($name($t),)*
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! match_parser {
|
|
||||||
($pident:ident: $parser:expr => $f:expr) => (
|
|
||||||
match &mut $parser {
|
|
||||||
$(
|
|
||||||
ParserTypes::$name($pident) => $f,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
build_parser_type_enum! {
|
|
||||||
TextParser: TextParser,
|
|
||||||
BinaryParser: BinaryParser,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FlutClient<R, W>
|
|
||||||
where
|
|
||||||
R: AsyncReadExt + std::marker::Unpin,
|
|
||||||
W: AsyncWriteExt + std::marker::Unpin,
|
|
||||||
{
|
|
||||||
reader: BufReader<R>,
|
|
||||||
writer: BufWriter<W>,
|
|
||||||
grids: Arc<[Flut<u32>]>,
|
|
||||||
parser: ParserTypes,
|
|
||||||
counter: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R, W> FlutClient<R, W>
|
|
||||||
where
|
|
||||||
R: AsyncReadExt + std::marker::Unpin,
|
|
||||||
W: AsyncWriteExt + std::marker::Unpin,
|
|
||||||
{
|
|
||||||
async fn help_command(&mut self) -> io::Result<()> {
|
|
||||||
println!("HELP wanted");
|
|
||||||
match_parser!(parser: self.parser => parser.unparse(Response::Help, &mut self.writer).await?);
|
|
||||||
|
|
||||||
self.writer.flush().await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn size_command(&mut self, canvas: Canvas) -> io::Result<()> {
|
|
||||||
let (x, y) = self.grids[canvas as usize].get_size();
|
|
||||||
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?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_pixel_command(
|
|
||||||
&mut self,
|
|
||||||
canvas: Canvas,
|
|
||||||
x: Coordinate,
|
|
||||||
y: Coordinate,
|
|
||||||
) -> io::Result<()> {
|
|
||||||
let color = match get_pixel(&self.grids, canvas, x, y) {
|
|
||||||
None => return Err(Error::from(ErrorKind::InvalidInput)),
|
|
||||||
Some(color) => color.to_be_bytes(),
|
|
||||||
};
|
|
||||||
match_parser!(parser: self.parser => parser.unparse(
|
|
||||||
Response::GetPixel(x,y,[color[0], color[1], color[2]]), &mut self.writer).await?
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_pixel_command(&mut self, canvas: Canvas, x: Coordinate, y: Coordinate, color: &Color) {
|
|
||||||
let c: u32 = match color {
|
|
||||||
Color::RGB24(red, green, blue) => u32::from_be_bytes([*red, *green, *blue, 0xff]),
|
|
||||||
Color::RGBA32(red, green, blue, alpha) => {
|
|
||||||
u32::from_be_bytes([*red, *green, *blue, *alpha])
|
|
||||||
}
|
|
||||||
Color::W8(white) => u32::from_be_bytes([*white, *white, *white, 0xff]),
|
|
||||||
};
|
|
||||||
set_pixel_rgba(self.grids.as_ref(), canvas, x, y, c);
|
|
||||||
self.counter += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn change_canvas_command(&mut self, canvas: Canvas) -> io::Result<()> {
|
|
||||||
match_parser!(parser: self.parser => parser.change_canvas(canvas))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn change_protocol(&mut self, protocol: &Protocol) {
|
|
||||||
match protocol {
|
|
||||||
Protocol::Text => self.parser = ParserTypes::TextParser(TextParser::new(0)),
|
|
||||||
Protocol::Binary => self.parser = ParserTypes::BinaryParser(BinaryParser::new()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new(reader: R, writer: W, grids: Arc<[grid::Flut<u32>]>) -> FlutClient<R, W> {
|
|
||||||
FlutClient {
|
|
||||||
reader: BufReader::new(reader),
|
|
||||||
writer: BufWriter::new(writer),
|
|
||||||
grids,
|
|
||||||
parser: ParserTypes::TextParser(TextParser::new(0)),
|
|
||||||
counter: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn process_socket(&mut self) -> io::Result<()> {
|
|
||||||
loop {
|
|
||||||
match_parser!(parser: &self.parser.clone() => 'outer: loop {
|
|
||||||
for _ in 0..1000 {
|
|
||||||
let parsed = parser.parse(&mut self.reader).await;
|
|
||||||
match parsed {
|
|
||||||
Ok(Command::Help) => self.help_command().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::SetPixel(canvas, x, y, color)) => self.set_pixel_command(canvas, x, y, &color),
|
|
||||||
Ok(Command::ChangeCanvas(canvas)) => {
|
|
||||||
self.change_canvas_command(canvas)?;
|
|
||||||
break 'outer;
|
|
||||||
}
|
|
||||||
Ok(Command::ChangeProtocol(protocol)) => {
|
|
||||||
self.change_protocol(&protocol);
|
|
||||||
break 'outer;
|
|
||||||
}
|
|
||||||
Err(err) if err.kind() == ErrorKind::UnexpectedEof => return Ok(()),
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
increment_counter(self.counter);
|
|
||||||
self.counter = 0;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn save_image_frames(grids: Arc<[grid::Flut<u32>]>) -> io::Result<()> {
|
async fn save_image_frames(grids: Arc<[grid::Flut<u32>]>) -> io::Result<()> {
|
||||||
let base_dir = Path::new("./recordings");
|
let base_dir = Path::new("./recordings");
|
||||||
let mut timer = interval(Duration::from_secs(5));
|
let mut timer = interval(Duration::from_secs(5));
|
||||||
|
|
|
||||||
29
src/protocols.rs
Normal file
29
src/protocols.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
mod binary_protocol;
|
||||||
|
mod text_protocol;
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
pub use binary_protocol::BinaryParser;
|
||||||
|
pub use text_protocol::TextParser;
|
||||||
|
use tokio::io::AsyncWriteExt;
|
||||||
|
|
||||||
|
use crate::{Canvas, Command, Response};
|
||||||
|
|
||||||
|
pub trait Parser<R>
|
||||||
|
where
|
||||||
|
R: std::marker::Unpin + tokio::io::AsyncBufRead,
|
||||||
|
{
|
||||||
|
async fn parse(&self, reader: &mut R) -> io::Result<Command>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait IOProtocol {
|
||||||
|
fn change_canvas(&mut self, canvas: Canvas) -> io::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Responder<W>
|
||||||
|
where
|
||||||
|
W: AsyncWriteExt + std::marker::Unpin,
|
||||||
|
{
|
||||||
|
async fn unparse(&self, response: Response, writer: &mut W) -> io::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -2,7 +2,9 @@ use std::io::{self, Error, ErrorKind};
|
||||||
|
|
||||||
use tokio::io::{AsyncBufRead, AsyncBufReadExt, AsyncReadExt, AsyncWriteExt};
|
use tokio::io::{AsyncBufRead, AsyncBufReadExt, AsyncReadExt, AsyncWriteExt};
|
||||||
|
|
||||||
use crate::{Canvas, Color, Command, IOProtocol, Parser, Responder, Response};
|
use crate::{Canvas, Color, Command, Response};
|
||||||
|
|
||||||
|
use super::{IOProtocol, Parser, Responder};
|
||||||
|
|
||||||
const SIZE_BIN: u8 = 115;
|
const SIZE_BIN: u8 = 115;
|
||||||
const HELP_BIN: u8 = 104;
|
const HELP_BIN: u8 = 104;
|
||||||
|
|
@ -4,10 +4,12 @@ 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, IOProtocol, Parser, Protocol, Responder, Response,
|
config::{GRID_LENGTH, HELP_TEXT},
|
||||||
GRID_LENGTH, HELP_TEXT,
|
Canvas, Color, Command, Coordinate, Protocol, Response,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::{IOProtocol, Parser, Responder};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct TextParser {
|
pub struct TextParser {
|
||||||
canvas: Canvas,
|
canvas: Canvas,
|
||||||
62
src/utils.rs
Normal file
62
src/utils.rs
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
use std::task::Poll;
|
||||||
|
|
||||||
|
use tokio::io::{AsyncRead, AsyncWrite};
|
||||||
|
|
||||||
|
pub struct RepeatSome {
|
||||||
|
bytes: &'static [u8],
|
||||||
|
len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RepeatSome {
|
||||||
|
pub fn new(bytes: &'static [u8]) -> Self {
|
||||||
|
RepeatSome {
|
||||||
|
bytes,
|
||||||
|
len: bytes.len(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsyncRead for RepeatSome {
|
||||||
|
fn poll_read(
|
||||||
|
self: std::pin::Pin<&mut Self>,
|
||||||
|
cx: &mut std::task::Context<'_>,
|
||||||
|
buf: &mut tokio::io::ReadBuf<'_>,
|
||||||
|
) -> std::task::Poll<std::io::Result<()>> {
|
||||||
|
while buf.remaining() > self.len {
|
||||||
|
buf.put_slice(self.bytes)
|
||||||
|
}
|
||||||
|
Poll::Ready(Ok(()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Drain {}
|
||||||
|
|
||||||
|
impl Drain {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Drain {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsyncWrite for Drain {
|
||||||
|
fn poll_write(
|
||||||
|
self: std::pin::Pin<&mut Self>,
|
||||||
|
cx: &mut std::task::Context<'_>,
|
||||||
|
buf: &[u8],
|
||||||
|
) -> Poll<Result<usize, std::io::Error>> {
|
||||||
|
Poll::Ready(Ok(buf.len()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll_flush(
|
||||||
|
self: std::pin::Pin<&mut Self>,
|
||||||
|
cx: &mut std::task::Context<'_>,
|
||||||
|
) -> Poll<Result<(), std::io::Error>> {
|
||||||
|
Poll::Ready(Ok(()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll_shutdown(
|
||||||
|
self: std::pin::Pin<&mut Self>,
|
||||||
|
cx: &mut std::task::Context<'_>,
|
||||||
|
) -> Poll<Result<(), std::io::Error>> {
|
||||||
|
Poll::Ready(Ok(()))
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue