From e97bfd22e99fb73dd587574c936989878a66e261 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Fri, 2 May 2025 12:55:18 +0200 Subject: [PATCH 1/9] remove shell.nix, add flake.nix --- .envrc | 2 +- flake.lock | 64 +++++++++++++++++++++++++++++++++ flake.nix | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++ shell.nix | 4 --- 4 files changed, 168 insertions(+), 5 deletions(-) create mode 100644 flake.lock create mode 100644 flake.nix delete mode 100644 shell.nix diff --git a/.envrc b/.envrc index 1d953f4..3550a30 100644 --- a/.envrc +++ b/.envrc @@ -1 +1 @@ -use nix +use flake diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..8c4b6bb --- /dev/null +++ b/flake.lock @@ -0,0 +1,64 @@ +{ + "nodes": { + "naersk": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1745925850, + "narHash": "sha256-cyAAMal0aPrlb1NgzMxZqeN1mAJ2pJseDhm2m6Um8T0=", + "owner": "nix-community", + "repo": "naersk", + "rev": "38bc60bbc157ae266d4a0c96671c6c742ee17a5f", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "naersk", + "type": "github" + } + }, + "nix-filter": { + "locked": { + "lastModified": 1731533336, + "narHash": "sha256-oRam5PS1vcrr5UPgALW0eo1m/5/pls27Z/pabHNy2Ms=", + "owner": "numtide", + "repo": "nix-filter", + "rev": "f7653272fd234696ae94229839a99b73c9ab7de0", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "nix-filter", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1746055187, + "narHash": "sha256-3dqArYSMP9hM7Qpy5YWhnSjiqniSaT2uc5h2Po7tmg0=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "3e362ce63e16b9572d8c2297c04f7c19ab6725a5", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-24.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "naersk": "naersk", + "nix-filter": "nix-filter", + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..043b61f --- /dev/null +++ b/flake.nix @@ -0,0 +1,103 @@ +{ + description = "Flake for command line interface of the ServicePoint display."; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11"; + nix-filter.url = "github:numtide/nix-filter"; + naersk = { + url = "github:nix-community/naersk"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = + inputs@{ + self, + nixpkgs, + naersk, + nix-filter, + }: + let + lib = nixpkgs.lib; + supported-systems = [ + "x86_64-linux" + "aarch64-linux" + "aarch64-darwin" + "x86_64-darwin" + ]; + forAllSystems = + f: + lib.genAttrs supported-systems ( + system: + f rec { + pkgs = nixpkgs.legacyPackages.${system}; + naersk' = pkgs.callPackage naersk { }; + selfPkgs = self.packages."${system}"; + inherit system; + } + ); + in + rec { + packages = forAllSystems ( + { pkgs, naersk', ... }: + rec { + servicepoint-life = naersk'.buildPackage rec { + strictDeps = true; + nativeBuildInputs = with pkgs; [ pkg-config ]; + buildInputs = with pkgs; [ + xe + xz + ]; + src = nix-filter.lib.filter { + root = ./.; + include = [ + ./Cargo.toml + ./Cargo.lock + ./src + ./README.md + ./LICENSE + ]; + }; + }; + + default = servicepoint-life; + } + ); + + legacyPackages = packages; + + apps = forAllSystems ( + { selfPkgs, ... }: + rec { + servicepoint-life = { + type = "app"; + program = "${selfPkgs.servicepoint-life}/out/servicepoint-life"; + }; + default = servicepoint-life; + } + ); + + devShells = forAllSystems ( + { pkgs, selfPkgs, ... }: + { + default = pkgs.mkShell rec { + inputsFrom = [ selfPkgs.default ]; + packages = [ + pkgs.gdb + (pkgs.symlinkJoin { + name = "rust-toolchain"; + paths = with pkgs; [ + rustc + cargo + rustfmt + clippy + ]; + }) + ]; + }; + } + ); + + formatter = forAllSystems ({ pkgs, ... }: pkgs.nixfmt-rfc-style); + }; +} diff --git a/shell.nix b/shell.nix deleted file mode 100644 index 0bf2bcc..0000000 --- a/shell.nix +++ /dev/null @@ -1,4 +0,0 @@ -{ pkgs ? import {} }: - pkgs.mkShell { - nativeBuildInputs = with pkgs.buildPackages; [ rustup cargo pkg-config xe lzma ]; -} -- 2.47.0 From ce194993be192233e82889c2d1542e5ebcaaed95 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Fri, 2 May 2025 13:15:02 +0200 Subject: [PATCH 2/9] update to new (unreleased) servicepoint version --- Cargo.lock | 146 +++++++++++++++++++++++++++++++++++++-------------- Cargo.toml | 12 +++-- src/game.rs | 21 +++----- src/main.rs | 46 +++++++--------- src/rules.rs | 2 - 5 files changed, 143 insertions(+), 84 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a397605..c7227be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -72,6 +72,18 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -172,6 +184,12 @@ dependencies = [ "log", ] +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "getrandom" version = "0.2.15" @@ -241,6 +259,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + [[package]] name = "parking_lot" version = "0.12.2" @@ -264,6 +288,12 @@ dependencies = [ "windows-targets 0.52.5", ] +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -272,9 +302,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -289,21 +319,27 @@ dependencies = [ ] [[package]] -name = "rand" -version = "0.9.0-alpha.1" +name = "radium" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d31e63ea85be51c423e52ba8f2e68a3efd53eed30203ee029dd09947333693e" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ + "libc", "rand_chacha", "rand_core", - "zerocopy", ] [[package]] name = "rand_chacha" -version = "0.9.0-alpha.1" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78674ef918c19451dbd250f8201f8619b494f64c9aa6f3adb28fd8a0f1f6da46" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", @@ -311,12 +347,11 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.9.0-alpha.1" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc89dffba8377c5ec847d12bb41492bda235dba31a25e8b695cd0fe6589eb8c9" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", - "zerocopy", ] [[package]] @@ -357,12 +392,35 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +[[package]] +name = "rust-lzma" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d62915608f6cee1d7f2fc00f28b4f058ff79d6e4ec3c2fe0006b09b52437c84" +dependencies = [ + "pkg-config", + "vcpkg", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "servicepoint" +version = "0.14.0" +source = "git+https://git.berlin.ccc.de/servicepoint/servicepoint/?branch=next#8ddbaeaaa64a4abb8ffb8b08a3a84cc1135e312f" +dependencies = [ + "bitvec", + "log", + "once_cell", + "rand", + "rust-lzma", + "thiserror", +] + [[package]] name = "servicepoint-life" version = "0.1.0" @@ -372,16 +430,7 @@ dependencies = [ "env_logger", "log", "rand", - "servicepoint2", -] - -[[package]] -name = "servicepoint2" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d9aecc4d31a71578481de6c6d64383d374126c38469c9689067579c1d910fd" -dependencies = [ - "log", + "servicepoint", ] [[package]] @@ -428,15 +477,41 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.64" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ad3dee41f36859875573074334c200d1add8e4a87bb37113ebd31d926b7b11f" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "unicode-ident" version = "1.0.12" @@ -449,6 +524,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -617,21 +698,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] -name = "zerocopy" -version = "0.8.0-alpha.6" +name = "wyz" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db678a6ee512bd06adf35c35be471cae2f9c82a5aed2b5d15e03628c98bddd57" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.0-alpha.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201585ea96d37ee69f2ac769925ca57160cef31acb137c16f38b02b76f4c1e62" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "tap", ] diff --git a/Cargo.toml b/Cargo.toml index 9b88435..a2dc836 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,9 +4,15 @@ version = "0.1.0" edition = "2021" [dependencies] -clap = { version = "4.5.4", features = ["derive"] } -rand = "0.9.0-alpha.1" +clap = { version = "4.5", features = ["derive"] } +rand = "0.8" env_logger = "0.11.3" -servicepoint2 = { version = "0.4.2", default-features = false } crossterm = "0.27.0" log = "0.4.21" + +[dependencies.servicepoint] +package = "servicepoint" +version = "0.14.0" +features = ["rand"] +git = "https://git.berlin.ccc.de/servicepoint/servicepoint/" +branch = "next" diff --git a/src/game.rs b/src/game.rs index 308440d..7dd344c 100644 --- a/src/game.rs +++ b/src/game.rs @@ -1,29 +1,24 @@ -use servicepoint2::Grid; +use servicepoint::{Grid, Value, ValueGrid}; use crate::rules::Rules; -pub(crate) struct Game +pub(crate) struct Game where - TGrid: Grid, - TState: Copy + PartialEq, - TKernel: Copy, + TState: Value + PartialEq, + TKernel: Value, { - pub field: TGrid, + pub field: ValueGrid, pub rules: Rules, } -impl Game -where - TGrid: Grid, - TState: Copy + PartialEq, - TKernel: Copy, +impl Game { pub fn step(&mut self) { self.field = self.field_iteration(); } - fn field_iteration(&self) -> TGrid { - let mut next = TGrid::new(self.field.width(), self.field.height()); + fn field_iteration(&self) -> ValueGrid { + let mut next = ValueGrid::new(self.field.width(), self.field.height()); for x in 0..self.field.width() { for y in 0..self.field.height() { let old_state = self.field.get(x, y); diff --git a/src/main.rs b/src/main.rs index 02e8bda..3ce1c2e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ use std::io::stdout; +use std::net::UdpSocket; use std::num::Wrapping; use std::thread; use std::time::{Duration, Instant}; @@ -12,12 +13,7 @@ use crossterm::terminal::{ use log::LevelFilter; use rand::distributions::{Distribution, Standard}; use rand::Rng; -use servicepoint2::{ - ByteGrid, CompressionCode, Connection, FRAME_PACING, Grid, Origin, PixelGrid, TILE_HEIGHT, - TILE_WIDTH, -}; -use servicepoint2::Command::{BitmapLinearWin, CharBrightness}; - +use servicepoint::{FRAME_PACING, Grid, TILE_HEIGHT, TILE_WIDTH, Bitmap, UdpSocketExt, BitmapCommand, SendCommandExt, BrightnessGridCommand, BrightnessGrid, Brightness, ValueGrid, PIXEL_WIDTH, PIXEL_HEIGHT, ByteGrid}; use crate::game::Game; use crate::print::{println_debug, println_info, println_warning}; use crate::rules::{generate_bb3, generate_u8b3}; @@ -37,11 +33,11 @@ fn main() { let mut left_pixels = Game { rules: generate_bb3(), - field: PixelGrid::max_sized(), + field: ValueGrid::new(PIXEL_WIDTH, PIXEL_HEIGHT), }; let mut right_pixels = Game { rules: generate_bb3(), - field: PixelGrid::max_sized(), + field: ValueGrid::new(PIXEL_WIDTH, PIXEL_HEIGHT), }; let mut left_luma = Game { rules: generate_u8b3(), @@ -57,8 +53,8 @@ fn main() { randomize(&mut right_luma.field); randomize(&mut right_pixels.field); - let mut pixels = PixelGrid::max_sized(); - let mut luma = ByteGrid::new(TILE_WIDTH, TILE_HEIGHT); + let mut pixels = Bitmap::max_sized(); + let mut luma = BrightnessGrid::new(TILE_WIDTH, TILE_HEIGHT); let mut split_pixel = 0; let mut split_speed: i32 = 1; @@ -222,7 +218,7 @@ impl TryFrom for AppEvent { } } -fn draw_pixels(pixels: &mut PixelGrid, left: &PixelGrid, right: &PixelGrid, split_index: usize) { +fn draw_pixels(pixels: &mut Bitmap, left: &ValueGrid, right: &ValueGrid, split_index: usize) { for x in 0..pixels.width() { let left_or_right = if x < split_index { left } else { right }; for y in 0..pixels.height() { @@ -232,28 +228,22 @@ fn draw_pixels(pixels: &mut PixelGrid, left: &PixelGrid, right: &PixelGrid, spli } } -fn draw_luma(luma: &mut ByteGrid, left: &ByteGrid, right: &ByteGrid, split_tile: usize) { +fn draw_luma(luma: &mut BrightnessGrid, left: &ByteGrid, right: &ByteGrid, split_tile: usize) { for x in 0..luma.width() { let left_or_right = if x < split_tile { left } else { right }; for y in 0..luma.height() { - let set = u8::max(48, left_or_right.get(x, y)); - - let set = set as f32 / u8::MAX as f32 * 12f32; - - luma.set(x, y, set as u8); + let set: u8 = left_or_right.get(x, y) / u8::MAX * u8::from(Brightness::MAX); + let set = Brightness::try_from(set).unwrap(); + luma.set(x, y, set); } } } -fn send_to_screen(connection: &Connection, pixels: &PixelGrid, luma: &ByteGrid) { - let pixel_cmd = BitmapLinearWin(Origin(0, 0), pixels.clone(), CompressionCode::Uncompressed); - connection - .send(pixel_cmd.into()) - .expect("could not send pixels"); - - connection - .send(CharBrightness(Origin(0, 0), luma.clone()).into()) - .expect("could not send brightness"); +fn send_to_screen(connection: &UdpSocket, pixels: &Bitmap, luma: &BrightnessGrid) { + let cmd: BitmapCommand = pixels.clone().try_into().unwrap(); + _ = connection.send_command(cmd); + let cmd: BrightnessGridCommand = luma.clone().try_into().unwrap(); + _ = connection.send_command(cmd); } fn randomize(field: &mut TGrid) @@ -270,7 +260,7 @@ fn randomize(field: &mut TGrid) } } -fn init() -> Connection { +fn init() -> UdpSocket { env_logger::builder() .filter_level(LevelFilter::Info) .parse_default_env() @@ -280,7 +270,7 @@ fn init() -> Connection { .expect("could not enter alternate screen"); enable_raw_mode().expect("could not enable raw terminal mode"); - Connection::open(Cli::parse().destination) + UdpSocket::bind_connect(Cli::parse().destination) .expect("Could not connect. Did you forget `--destination`?") } diff --git a/src/rules.rs b/src/rules.rs index 6156a5d..e506fad 100644 --- a/src/rules.rs +++ b/src/rules.rs @@ -3,8 +3,6 @@ use rand::{thread_rng, Rng}; use crate::print::println_info; -const MAX_BRIGHTNESS: u8 = 12; - pub struct Rules where TState: Copy + PartialEq, -- 2.47.0 From fdca264ef99ecd41b23701c7e85273da193c4754 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Fri, 2 May 2025 13:17:23 +0200 Subject: [PATCH 3/9] fix div zero --- src/rules.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rules.rs b/src/rules.rs index e506fad..bd06cdd 100644 --- a/src/rules.rs +++ b/src/rules.rs @@ -86,7 +86,7 @@ pub fn generate_u8b3() -> Rules { _ => panic!(), }; - let alive_threshold = rng.gen(); + let alive_threshold = u8::max(1, rng.gen()); let birth = generate_neighbor_counts(rng.gen_range(1..=9), &mut rng, &[0]); let survive = generate_neighbor_counts( -- 2.47.0 From 1c9ac90b824b2b93dffad67c550f0abae87c0a64 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Fri, 2 May 2025 13:43:02 +0200 Subject: [PATCH 4/9] update dependencies, clippy fixes, metadata --- Cargo.lock | 198 ++++++++++++++++++++++++++++------------------------ Cargo.toml | 25 +++++-- README.md | 10 ++- flake.nix | 4 +- src/game.rs | 3 +- src/main.rs | 76 +++++++++++++------- 6 files changed, 191 insertions(+), 125 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c7227be..b68b5aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,7 +47,7 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" dependencies = [ - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -57,7 +57,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -68,9 +68,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "bitvec" @@ -137,16 +137,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] -name = "crossterm" -version = "0.27.0" +name = "convert_case" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" +checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "crossterm" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ "bitflags", "crossterm_winapi", - "libc", + "derive_more", + "document-features", "mio", "parking_lot", + "rustix", "signal-hook", "signal-hook-mio", "winapi", @@ -161,6 +172,36 @@ dependencies = [ "winapi", ] +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "document-features" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +dependencies = [ + "litrs", +] + [[package]] name = "env_filter" version = "0.1.0" @@ -184,6 +225,16 @@ dependencies = [ "log", ] +[[package]] +name = "errno" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +dependencies = [ + "libc", + "windows-sys", +] + [[package]] name = "funty" version = "2.0.0" @@ -221,9 +272,21 @@ checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" [[package]] name = "lock_api" @@ -249,14 +312,14 @@ checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "mio" -version = "0.8.11" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", "log", "wasi", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -285,7 +348,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.5", + "windows-targets", ] [[package]] @@ -402,6 +465,19 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "rustix" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -423,7 +499,7 @@ dependencies = [ [[package]] name = "servicepoint-life" -version = "0.1.0" +version = "0.2.0" dependencies = [ "clap", "crossterm", @@ -445,9 +521,9 @@ dependencies = [ [[package]] name = "signal-hook-mio" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" dependencies = [ "libc", "mio", @@ -518,6 +594,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + [[package]] name = "utf8parse" version = "0.2.1" @@ -558,37 +640,13 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[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.5", -] - -[[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", + "windows-targets", ] [[package]] @@ -597,46 +655,28 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[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.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" -[[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.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" -[[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.5" @@ -649,48 +689,24 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" -[[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.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" -[[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.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" -[[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.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" -[[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.5" diff --git a/Cargo.toml b/Cargo.toml index a2dc836..9b1cb68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,20 @@ [package] name = "servicepoint-life" -version = "0.1.0" +version = "0.2.0" edition = "2021" +license = "GPL-3.0-or-later" +description = "Small terminal app that generates conways game of life rules and simulates them on the servicepoint display." +repository = "https://git.berlin.ccc.de/vinzenz/servicepoint-life" +readme = "README.md" +keywords = ["cccb", "cccb-servicepoint", "conway", "game-of-life", "simulation"] +rust-version = "1.70.0" [dependencies] clap = { version = "4.5", features = ["derive"] } rand = "0.8" -env_logger = "0.11.3" -crossterm = "0.27.0" -log = "0.4.21" +env_logger = "0.11" +crossterm = "0.29" +log = "0.4" [dependencies.servicepoint] package = "servicepoint" @@ -16,3 +22,14 @@ version = "0.14.0" features = ["rand"] git = "https://git.berlin.ccc.de/servicepoint/servicepoint/" branch = "next" + +[lints.clippy] +incompatible_msrv = "forbid" + +[profile.size-optimized] +inherits = "release" +opt-level = 'z' # Optimize for size +lto = true # Enable link-time optimization +codegen-units = 1 # Reduce number of codegen units to increase optimizations +panic = 'abort' # Abort on panic +strip = true # Strip symbols from binary diff --git a/README.md b/README.md index 8fada83..c262679 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,13 @@ # servicepoint-life -More fully featured game of life for the servicepoint display based on the example in the repo. +This is a small terminal app that generates conways game of life rules and simulates them on the servicepoint display. +It uses the [servicepoint](https://git.berlin.ccc.de/servicepoint/servicepoint/) library for the display commands. +## Running + +With Nix flakes, you can just `nix run git+https://git.berlin.ccc.de/vinzenz/servicepoint-life`. + +Otherwise, you can `cargo install --git https://git.berlin.ccc.de/vinzenz/servicepoint-life` and then run `servicepoint-life`. + +If you want to poke at the code you can always check out the repo and `cargo run` it. diff --git a/flake.nix b/flake.nix index 043b61f..ed140f1 100644 --- a/flake.nix +++ b/flake.nix @@ -1,5 +1,5 @@ { - description = "Flake for command line interface of the ServicePoint display."; + description = "Flake for servicepoint-life"; inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11"; @@ -71,7 +71,7 @@ rec { servicepoint-life = { type = "app"; - program = "${selfPkgs.servicepoint-life}/out/servicepoint-life"; + program = "${selfPkgs.servicepoint-life}/bin/servicepoint-life"; }; default = servicepoint-life; } diff --git a/src/game.rs b/src/game.rs index 7dd344c..9caa85b 100644 --- a/src/game.rs +++ b/src/game.rs @@ -11,7 +11,8 @@ where pub rules: Rules, } -impl Game +impl + Game { pub fn step(&mut self) { self.field = self.field_iteration(); diff --git a/src/main.rs b/src/main.rs index 3ce1c2e..0679ef0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,22 +1,35 @@ -use std::io::stdout; -use std::net::UdpSocket; -use std::num::Wrapping; -use std::thread; -use std::time::{Duration, Instant}; - +use std::{ + io::stdout, + net::UdpSocket, + num::Wrapping, + thread, + time::{Duration, Instant}, +}; +use crate::{ + game::Game, + print::{println_debug, println_info, println_warning}, + rules::{generate_bb3, generate_u8b3}, +}; use clap::Parser; -use crossterm::{event, execute}; -use crossterm::event::{Event, KeyCode, KeyEventKind}; -use crossterm::terminal::{ - disable_raw_mode, enable_raw_mode, EnableLineWrap, EnterAlternateScreen, LeaveAlternateScreen, +use crossterm::{ + event, + event::{Event, KeyCode, KeyEventKind}, + execute, + terminal::{ + disable_raw_mode, enable_raw_mode, EnableLineWrap, EnterAlternateScreen, + LeaveAlternateScreen, + }, }; use log::LevelFilter; -use rand::distributions::{Distribution, Standard}; -use rand::Rng; -use servicepoint::{FRAME_PACING, Grid, TILE_HEIGHT, TILE_WIDTH, Bitmap, UdpSocketExt, BitmapCommand, SendCommandExt, BrightnessGridCommand, BrightnessGrid, Brightness, ValueGrid, PIXEL_WIDTH, PIXEL_HEIGHT, ByteGrid}; -use crate::game::Game; -use crate::print::{println_debug, println_info, println_warning}; -use crate::rules::{generate_bb3, generate_u8b3}; +use rand::{ + distributions::{Distribution, Standard}, + Rng, +}; +use servicepoint::{ + Bitmap, BitmapCommand, Brightness, BrightnessGrid, BrightnessGridCommand, ByteGrid, Grid, + SendCommandExt, UdpSocketExt, ValueGrid, FRAME_PACING, PIXEL_HEIGHT, PIXEL_WIDTH, TILE_HEIGHT, + TILE_WIDTH, +}; mod game; mod print; @@ -149,11 +162,17 @@ fn main() { } Ok(AppEvent::SimulationSpeedUp) => { target_duration = target_duration.saturating_sub(Duration::from_millis(1)); - println_info(format!("increased simulation speed to {} ups", 1f64 / target_duration.as_secs_f64())); + println_info(format!( + "increased simulation speed to {} ups", + 1f64 / target_duration.as_secs_f64() + )); } Ok(AppEvent::SimulationSpeedDown) => { target_duration = target_duration.saturating_add(Duration::from_millis(1)); - println_info(format!("decreased simulation speed to {} ups", 1f64 / target_duration.as_secs_f64())); + println_info(format!( + "decreased simulation speed to {} ups", + 1f64 / target_duration.as_secs_f64() + )); } } } @@ -218,7 +237,12 @@ impl TryFrom for AppEvent { } } -fn draw_pixels(pixels: &mut Bitmap, left: &ValueGrid, right: &ValueGrid, split_index: usize) { +fn draw_pixels( + pixels: &mut Bitmap, + left: &ValueGrid, + right: &ValueGrid, + split_index: usize, +) { for x in 0..pixels.width() { let left_or_right = if x < split_index { left } else { right }; for y in 0..pixels.height() { @@ -240,16 +264,16 @@ fn draw_luma(luma: &mut BrightnessGrid, left: &ByteGrid, right: &ByteGrid, split } fn send_to_screen(connection: &UdpSocket, pixels: &Bitmap, luma: &BrightnessGrid) { - let cmd: BitmapCommand = pixels.clone().try_into().unwrap(); - _ = connection.send_command(cmd); - let cmd: BrightnessGridCommand = luma.clone().try_into().unwrap(); - _ = connection.send_command(cmd); + let cmd: BitmapCommand = pixels.clone().into(); + connection.send_command(cmd).unwrap(); + let cmd: BrightnessGridCommand = luma.clone().into(); + connection.send_command(cmd).unwrap(); } fn randomize(field: &mut TGrid) - where - TGrid: Grid, - Standard: Distribution, +where + TGrid: Grid, + Standard: Distribution, { let mut rng = rand::thread_rng(); -- 2.47.0 From 4144db2d210a434701cb4ec33856ebb1d70f4152 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Fri, 2 May 2025 15:24:05 +0200 Subject: [PATCH 5/9] split main also: - update dependencies - clippy fixes - metadata --- Cargo.lock | 75 ------------ Cargo.toml | 2 - src/app.rs | 153 ++++++++++++++++++++++++ src/main.rs | 295 +--------------------------------------------- src/simulation.rs | 180 ++++++++++++++++++++++++++++ 5 files changed, 339 insertions(+), 366 deletions(-) create mode 100644 src/app.rs create mode 100644 src/simulation.rs diff --git a/Cargo.lock b/Cargo.lock index b68b5aa..2cb5d30 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - [[package]] name = "anstream" version = "0.6.14" @@ -202,29 +193,6 @@ dependencies = [ "litrs", ] -[[package]] -name = "env_filter" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "humantime", - "log", -] - [[package]] name = "errno" version = "0.3.11" @@ -258,12 +226,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "is_terminal_polyfill" version = "1.70.0" @@ -304,12 +266,6 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" -[[package]] -name = "memchr" -version = "2.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" - [[package]] name = "mio" version = "1.0.3" @@ -426,35 +382,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "regex" -version = "1.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" - [[package]] name = "rust-lzma" version = "0.6.0" @@ -503,8 +430,6 @@ version = "0.2.0" dependencies = [ "clap", "crossterm", - "env_logger", - "log", "rand", "servicepoint", ] diff --git a/Cargo.toml b/Cargo.toml index 9b1cb68..feec40c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,9 +12,7 @@ rust-version = "1.70.0" [dependencies] clap = { version = "4.5", features = ["derive"] } rand = "0.8" -env_logger = "0.11" crossterm = "0.29" -log = "0.4" [dependencies.servicepoint] package = "servicepoint" diff --git a/src/app.rs b/src/app.rs new file mode 100644 index 0000000..1b5ee67 --- /dev/null +++ b/src/app.rs @@ -0,0 +1,153 @@ +use crate::{ + print::{println_debug, println_info, println_warning}, + simulation::{Simulation, SimulationEvent}, + Cli, +}; +use crossterm::{ + event, + event::{Event, KeyCode, KeyEvent, KeyEventKind}, + execute, + terminal::{ + disable_raw_mode, enable_raw_mode, EnableLineWrap, EnterAlternateScreen, + LeaveAlternateScreen, + }, +}; +use servicepoint::{ + Bitmap, BitmapCommand, BrightnessGrid, BrightnessGridCommand, SendCommandExt, UdpSocketExt, + FRAME_PACING, TILE_HEIGHT, TILE_WIDTH, +}; +use std::{ + io::stdout, + net::UdpSocket, + thread, + time::{Duration, Instant}, +}; + +pub(crate) struct App { + connection: UdpSocket, + sim: Simulation, + target_duration: Duration, + pixels: Bitmap, + luma: BrightnessGrid, + terminated: bool, +} + +impl App { + pub fn new(cli: Cli) -> Self { + let connection = UdpSocket::bind_connect(cli.destination) + .expect("Could not connect. Did you forget `--destination`?"); + + execute!(stdout(), EnterAlternateScreen, EnableLineWrap) + .expect("could not enter alternate screen"); + enable_raw_mode().expect("could not enable raw terminal mode"); + + Self { + connection, + sim: Simulation::new(), + terminated: false, + target_duration: FRAME_PACING, + pixels: Bitmap::max_sized(), + luma: BrightnessGrid::new(TILE_WIDTH, TILE_HEIGHT), + } + } + + pub(crate) fn run_iteration(&mut self) { + let start = Instant::now(); + self.sim.run_iteration(); + + self.sim.draw_state(&mut self.pixels, &mut self.luma); + let cmd: BitmapCommand = self.pixels.clone().into(); + self.connection.send_command(cmd).unwrap(); + let cmd: BrightnessGridCommand = self.luma.clone().into(); + self.connection.send_command(cmd).unwrap(); + + self.poll_events(); + + let tick_time = start.elapsed(); + if tick_time < self.target_duration { + thread::sleep(self.target_duration - tick_time); + } + } + + pub(crate) fn terminated(&self) -> bool { + self.terminated + } + + fn poll_events(&mut self) -> bool { + while event::poll(Duration::from_secs(0)).expect("could not poll") { + let event = event::read().expect("could not read event"); + + if let Event::Key(KeyEvent { + kind: KeyEventKind::Press, + code, + .. + }) = event + { + if let Some(sim_event) = self.handle_key(code) { + self.sim.handle_event(sim_event); + }; + } else { + println_debug(format!("unhandled event {event:?}")); + } + } + false + } + + fn handle_key(&mut self, code: KeyCode) -> Option { + match code { + KeyCode::Char('d') => Some(SimulationEvent::RandomizeLeftPixels), + KeyCode::Char('e') => Some(SimulationEvent::RandomizeLeftLuma), + KeyCode::Char('f') => Some(SimulationEvent::RandomizeRightPixels), + KeyCode::Char('r') => Some(SimulationEvent::RandomizeRightLuma), + KeyCode::Right => Some(SimulationEvent::SeparatorAccelerate), + KeyCode::Left => Some(SimulationEvent::SeparatorDecelerate), + KeyCode::Char('h') => { + println_info("[h] help"); + println_info("[q] quit"); + println_info("[d] randomize left pixels"); + println_info("[e] randomize left luma"); + println_info("[r] randomize right pixels"); + println_info("[f] randomize right luma"); + println_info("[→] accelerate divider right"); + println_info("[←] accelerate divider left"); + None + } + KeyCode::Char('q') => { + println_warning("terminating"); + self.terminated = true; + None + } + KeyCode::Up => { + self.target_duration = self + .target_duration + .saturating_sub(Duration::from_millis(1)); + println_info(format!( + "increased simulation speed to {} ups", + 1f64 / self.target_duration.as_secs_f64() + )); + None + } + KeyCode::Down => { + self.target_duration = self + .target_duration + .saturating_add(Duration::from_millis(1)); + println_info(format!( + "decreased simulation speed to {} ups", + 1f64 / self.target_duration.as_secs_f64() + )); + None + } + key_code => { + println_debug(format!("unhandled KeyCode {key_code:?}")); + None + } + } + } +} + +impl Drop for App { + fn drop(&mut self) { + disable_raw_mode().expect("could not disable raw terminal mode"); + execute!(stdout(), LeaveAlternateScreen).expect("could not leave alternate screen"); + } +} diff --git a/src/main.rs b/src/main.rs index 0679ef0..324ed38 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,39 +1,11 @@ -use std::{ - io::stdout, - net::UdpSocket, - num::Wrapping, - thread, - time::{Duration, Instant}, -}; -use crate::{ - game::Game, - print::{println_debug, println_info, println_warning}, - rules::{generate_bb3, generate_u8b3}, -}; +use crate::app::App; use clap::Parser; -use crossterm::{ - event, - event::{Event, KeyCode, KeyEventKind}, - execute, - terminal::{ - disable_raw_mode, enable_raw_mode, EnableLineWrap, EnterAlternateScreen, - LeaveAlternateScreen, - }, -}; -use log::LevelFilter; -use rand::{ - distributions::{Distribution, Standard}, - Rng, -}; -use servicepoint::{ - Bitmap, BitmapCommand, Brightness, BrightnessGrid, BrightnessGridCommand, ByteGrid, Grid, - SendCommandExt, UdpSocketExt, ValueGrid, FRAME_PACING, PIXEL_HEIGHT, PIXEL_WIDTH, TILE_HEIGHT, - TILE_WIDTH, -}; +mod app; mod game; mod print; mod rules; +mod simulation; #[derive(Parser, Debug)] struct Cli { @@ -42,263 +14,8 @@ struct Cli { } fn main() { - let connection = init(); - - let mut left_pixels = Game { - rules: generate_bb3(), - field: ValueGrid::new(PIXEL_WIDTH, PIXEL_HEIGHT), - }; - let mut right_pixels = Game { - rules: generate_bb3(), - field: ValueGrid::new(PIXEL_WIDTH, PIXEL_HEIGHT), - }; - let mut left_luma = Game { - rules: generate_u8b3(), - field: ByteGrid::new(TILE_WIDTH, TILE_HEIGHT), - }; - let mut right_luma = Game { - rules: generate_u8b3(), - field: ByteGrid::new(TILE_WIDTH, TILE_HEIGHT), - }; - - randomize(&mut left_luma.field); - randomize(&mut left_pixels.field); - randomize(&mut right_luma.field); - randomize(&mut right_pixels.field); - - let mut pixels = Bitmap::max_sized(); - let mut luma = BrightnessGrid::new(TILE_WIDTH, TILE_HEIGHT); - - let mut split_pixel = 0; - let mut split_speed: i32 = 1; - - let mut iteration = Wrapping(0u8); - - let mut target_duration = FRAME_PACING; - - loop { - let start = Instant::now(); - - left_pixels.step(); - right_pixels.step(); - - if iteration % Wrapping(10) == Wrapping(0) { - left_luma.step(); - right_luma.step(); - } - - iteration += Wrapping(1u8); - - if split_speed > 0 && split_pixel == pixels.width() { - split_pixel = 0; - - (left_luma, right_luma) = (right_luma, left_luma); - (left_pixels, right_pixels) = (right_pixels, left_pixels); - - randomize(&mut left_pixels.field); - randomize(&mut left_luma.field); - left_pixels.rules = generate_bb3(); - left_luma.rules = generate_u8b3(); - } else if split_speed < 0 && split_pixel == 0 { - split_pixel = pixels.width(); - - (left_luma, right_luma) = (right_luma, left_luma); - (left_pixels, right_pixels) = (right_pixels, left_pixels); - - randomize(&mut right_pixels.field); - randomize(&mut right_luma.field); - right_pixels.rules = generate_bb3(); - right_luma.rules = generate_u8b3(); - } - - split_pixel = - i32::clamp(split_pixel as i32 + split_speed, 0, pixels.width() as i32) as usize; - - draw_pixels( - &mut pixels, - &left_pixels.field, - &right_pixels.field, - split_pixel, - ); - draw_luma( - &mut luma, - &left_luma.field, - &right_luma.field, - split_pixel / 8, - ); - send_to_screen(&connection, &pixels, &luma); - - while event::poll(Duration::from_secs(0)).expect("could not poll") { - match event::read().expect("could not read event").try_into() { - Err(_) => {} - Ok(AppEvent::RandomizeLeftPixels) => { - randomize(&mut left_pixels.field); - println_debug("randomized left pixels"); - } - Ok(AppEvent::RandomizeRightPixels) => { - randomize(&mut right_pixels.field); - println_info("randomized right pixels"); - } - Ok(AppEvent::RandomizeLeftLuma) => { - randomize(&mut left_luma.field); - println_info("randomized left luma"); - } - Ok(AppEvent::RandomizeRightLuma) => { - randomize(&mut right_luma.field); - println_info("randomized right luma"); - } - Ok(AppEvent::SeparatorAccelerate) => { - split_speed += 1; - println_info(format!("increased separator speed to {split_speed}")); - } - Ok(AppEvent::SeparatorDecelerate) => { - split_speed -= 1; - println_info(format!("decreased separator speed to {split_speed}")); - } - Ok(AppEvent::Close) => { - println_warning("terminating"); - de_init(); - return; - } - Ok(AppEvent::SimulationSpeedUp) => { - target_duration = target_duration.saturating_sub(Duration::from_millis(1)); - println_info(format!( - "increased simulation speed to {} ups", - 1f64 / target_duration.as_secs_f64() - )); - } - Ok(AppEvent::SimulationSpeedDown) => { - target_duration = target_duration.saturating_add(Duration::from_millis(1)); - println_info(format!( - "decreased simulation speed to {} ups", - 1f64 / target_duration.as_secs_f64() - )); - } - } - } - - let tick_time = start.elapsed(); - if tick_time < target_duration { - thread::sleep(target_duration - tick_time); - } + let mut app = App::new(Cli::parse()); + while !app.terminated() { + app.run_iteration(); } } - -enum AppEvent { - Close, - RandomizeLeftPixels, - RandomizeRightPixels, - RandomizeLeftLuma, - RandomizeRightLuma, - SeparatorAccelerate, - SeparatorDecelerate, - SimulationSpeedUp, - SimulationSpeedDown, -} - -impl TryFrom for AppEvent { - type Error = (); - - fn try_from(event: Event) -> Result { - match event { - Event::Key(key_event) if key_event.kind == KeyEventKind::Press => { - match key_event.code { - KeyCode::Char('h') => { - println_info("[h] help"); - println_info("[q] quit"); - println_info("[d] randomize left pixels"); - println_info("[e] randomize left luma"); - println_info("[r] randomize right pixels"); - println_info("[f] randomize right luma"); - println_info("[→] accelerate divider right"); - println_info("[←] accelerate divider left"); - Err(()) - } - KeyCode::Char('q') => Ok(AppEvent::Close), - KeyCode::Char('d') => Ok(AppEvent::RandomizeLeftPixels), - KeyCode::Char('e') => Ok(AppEvent::RandomizeLeftLuma), - KeyCode::Char('f') => Ok(AppEvent::RandomizeRightPixels), - KeyCode::Char('r') => Ok(AppEvent::RandomizeRightLuma), - KeyCode::Right => Ok(AppEvent::SeparatorAccelerate), - KeyCode::Left => Ok(AppEvent::SeparatorDecelerate), - KeyCode::Up => Ok(AppEvent::SimulationSpeedUp), - KeyCode::Down => Ok(AppEvent::SimulationSpeedDown), - key_code => { - println_debug(format!("unhandled KeyCode {key_code:?}")); - Err(()) - } - } - } - event => { - println_debug(format!("unhandled event {event:?}")); - Err(()) - } - } - } -} - -fn draw_pixels( - pixels: &mut Bitmap, - left: &ValueGrid, - right: &ValueGrid, - split_index: usize, -) { - for x in 0..pixels.width() { - let left_or_right = if x < split_index { left } else { right }; - for y in 0..pixels.height() { - let set = x == split_index || left_or_right.get(x, y); - pixels.set(x, y, set); - } - } -} - -fn draw_luma(luma: &mut BrightnessGrid, left: &ByteGrid, right: &ByteGrid, split_tile: usize) { - for x in 0..luma.width() { - let left_or_right = if x < split_tile { left } else { right }; - for y in 0..luma.height() { - let set: u8 = left_or_right.get(x, y) / u8::MAX * u8::from(Brightness::MAX); - let set = Brightness::try_from(set).unwrap(); - luma.set(x, y, set); - } - } -} - -fn send_to_screen(connection: &UdpSocket, pixels: &Bitmap, luma: &BrightnessGrid) { - let cmd: BitmapCommand = pixels.clone().into(); - connection.send_command(cmd).unwrap(); - let cmd: BrightnessGridCommand = luma.clone().into(); - connection.send_command(cmd).unwrap(); -} - -fn randomize(field: &mut TGrid) -where - TGrid: Grid, - Standard: Distribution, -{ - let mut rng = rand::thread_rng(); - - for y in 0..field.height() { - for x in 0..field.width() { - field.set(x, y, rng.gen()); - } - } -} - -fn init() -> UdpSocket { - env_logger::builder() - .filter_level(LevelFilter::Info) - .parse_default_env() - .init(); - - execute!(stdout(), EnterAlternateScreen, EnableLineWrap) - .expect("could not enter alternate screen"); - enable_raw_mode().expect("could not enable raw terminal mode"); - - UdpSocket::bind_connect(Cli::parse().destination) - .expect("Could not connect. Did you forget `--destination`?") -} - -fn de_init() { - disable_raw_mode().expect("could not disable raw terminal mode"); - execute!(stdout(), LeaveAlternateScreen).expect("could not leave alternate screen"); -} diff --git a/src/simulation.rs b/src/simulation.rs new file mode 100644 index 0000000..579f645 --- /dev/null +++ b/src/simulation.rs @@ -0,0 +1,180 @@ +use crate::{ + game::Game, + print::{println_debug, println_info}, + rules::{generate_bb3, generate_u8b3}, +}; +use rand::{distributions::Standard, prelude::Distribution, Rng}; +use servicepoint::{ + Bitmap, Brightness, BrightnessGrid, Grid, Value, ValueGrid, PIXEL_HEIGHT, PIXEL_WIDTH, + TILE_HEIGHT, TILE_SIZE, TILE_WIDTH, +}; +use std::num::Wrapping; + +pub(crate) struct Simulation { + pub(crate) left_pixels: Game, + pub(crate) right_pixels: Game, + pub(crate) left_luma: Game, + pub(crate) right_luma: Game, + split_pixel: usize, + pub(crate) split_speed: i32, + iteration: Wrapping, +} + +pub enum SimulationEvent { + RandomizeLeftPixels, + RandomizeRightPixels, + RandomizeLeftLuma, + RandomizeRightLuma, + SeparatorAccelerate, + SeparatorDecelerate, +} + +impl Simulation { + pub fn new() -> Simulation { + let left_pixels = Game { + rules: generate_bb3(), + field: make_randomized(PIXEL_WIDTH, PIXEL_HEIGHT), + }; + let right_pixels = Game { + rules: generate_bb3(), + field: make_randomized(PIXEL_WIDTH, PIXEL_HEIGHT), + }; + let left_luma = Game { + rules: generate_u8b3(), + field: make_randomized(TILE_WIDTH, TILE_HEIGHT), + }; + let right_luma = Game { + rules: generate_u8b3(), + field: make_randomized(TILE_WIDTH, TILE_HEIGHT), + }; + + Self { + left_pixels, + right_pixels, + left_luma, + right_luma, + split_pixel: 0, + split_speed: 1, + iteration: Wrapping(0u8), + } + } + + fn swap_left_right(&mut self) { + std::mem::swap(&mut self.left_luma, &mut self.right_luma); + std::mem::swap(&mut self.left_pixels, &mut self.right_pixels); + } + + fn regenerate(pixels: &mut Game, luma: &mut Game) { + randomize(&mut pixels.field); + randomize(&mut luma.field); + pixels.rules = generate_bb3(); + luma.rules = generate_u8b3(); + } + + pub(crate) fn run_iteration(&mut self) { + self.left_pixels.step(); + self.right_pixels.step(); + + if self.iteration % Wrapping(10) == Wrapping(0) { + self.left_luma.step(); + self.right_luma.step(); + } + + self.iteration += Wrapping(1u8); + + if self.split_speed > 0 && self.split_pixel == self.left_pixels.field.width() { + self.split_pixel = 0; + self.swap_left_right(); + Self::regenerate(&mut self.left_pixels, &mut self.left_luma); + } else if self.split_speed < 0 && self.split_pixel == 0 { + self.split_pixel = self.left_pixels.field.width(); + self.swap_left_right(); + Self::regenerate(&mut self.right_pixels, &mut self.right_luma); + } + + self.split_pixel = i32::clamp( + self.split_pixel as i32 + self.split_speed, + 0, + self.left_pixels.field.width() as i32, + ) as usize; + } + + pub(crate) fn draw_state(&self, pixels: &mut Bitmap, luma: &mut BrightnessGrid) { + for x in 0..pixels.width() { + let left_or_right = if x < self.split_pixel { + &self.left_pixels.field + } else { + &self.right_pixels.field + }; + for y in 0..pixels.height() { + let set = x == self.split_pixel || left_or_right.get(x, y); + pixels.set(x, y, set); + } + } + + let split_tile = self.split_pixel / TILE_SIZE; + for x in 0..luma.width() { + let left_or_right = if x < split_tile { + &self.left_luma.field + } else { + &self.right_luma.field + }; + for y in 0..luma.height() { + let set: u8 = left_or_right.get(x, y) / u8::MAX * u8::from(Brightness::MAX); + let set = Brightness::try_from(set).unwrap(); + luma.set(x, y, set); + } + } + } + + pub(crate) fn handle_event(&mut self, event: SimulationEvent) { + match event { + SimulationEvent::RandomizeLeftPixels => { + randomize(&mut self.left_pixels.field); + println_debug("randomized left pixels"); + } + SimulationEvent::RandomizeRightPixels => { + randomize(&mut self.right_pixels.field); + println_info("randomized right pixels"); + } + SimulationEvent::RandomizeLeftLuma => { + randomize(&mut self.left_luma.field); + println_info("randomized left luma"); + } + SimulationEvent::RandomizeRightLuma => { + randomize(&mut self.right_luma.field); + println_info("randomized right luma"); + } + SimulationEvent::SeparatorAccelerate => { + self.split_speed += 1; + println_info(format!("increased separator speed to {}", self.split_speed)); + } + SimulationEvent::SeparatorDecelerate => { + self.split_speed -= 1; + println_info(format!("decreased separator speed to {}", self.split_speed)); + } + } + } +} + +fn make_randomized(width: usize, height: usize) -> ValueGrid +where + Standard: Distribution, +{ + let mut pixels = ValueGrid::new(width, height); + randomize(&mut pixels); + pixels +} + +fn randomize(field: &mut ValueGrid) +where + Standard: Distribution, +{ + let mut rng = rand::thread_rng(); + + for y in 0..field.height() { + for x in 0..field.width() { + field.set(x, y, rng.gen()); + } + } +} -- 2.47.0 From 558964bfb19def29a696fa09ad1d9d1c8f7fdf2f Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Fri, 2 May 2025 15:27:31 +0200 Subject: [PATCH 6/9] enable lto for release --- Cargo.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index feec40c..5f6e7b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,10 +24,12 @@ branch = "next" [lints.clippy] incompatible_msrv = "forbid" +[profile.release] +lto = true # Enable link-time optimization +codegen-units = 1 # Reduce number of codegen units to increase optimizations + [profile.size-optimized] inherits = "release" opt-level = 'z' # Optimize for size -lto = true # Enable link-time optimization -codegen-units = 1 # Reduce number of codegen units to increase optimizations panic = 'abort' # Abort on panic strip = true # Strip symbols from binary -- 2.47.0 From 3b5872c8ea68544611bd7fcf5f5ea5b1207e3718 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Fri, 2 May 2025 15:53:39 +0200 Subject: [PATCH 7/9] remove unused generics --- src/game.rs | 20 ++++++--------- src/rules.rs | 63 +++++++++++++++++++++++++++-------------------- src/simulation.rs | 20 +++++++-------- 3 files changed, 53 insertions(+), 50 deletions(-) diff --git a/src/game.rs b/src/game.rs index 9caa85b..9bf39f4 100644 --- a/src/game.rs +++ b/src/game.rs @@ -2,23 +2,19 @@ use servicepoint::{Grid, Value, ValueGrid}; use crate::rules::Rules; -pub(crate) struct Game -where - TState: Value + PartialEq, - TKernel: Value, +pub(crate) struct Game { - pub field: ValueGrid, - pub rules: Rules, + pub field: ValueGrid, + pub rules: Rules, } -impl - Game +impl Game { pub fn step(&mut self) { self.field = self.field_iteration(); } - fn field_iteration(&self) -> ValueGrid { + fn field_iteration(&self) -> ValueGrid { let mut next = ValueGrid::new(self.field.width(), self.field.height()); for x in 0..self.field.width() { for y in 0..self.field.height() { @@ -37,14 +33,12 @@ impl let mut count = 0; let kernel = &self.rules.kernel; - assert_eq!(KERNEL_SIZE % 2, 1); - let offset = KERNEL_SIZE as i32 / 2; for (kernel_y, kernel_row) in kernel.iter().enumerate() { - let offset_y = kernel_y as i32 - offset; + let offset_y = kernel_y as i32 - 1; for (kernel_x, kernel_value) in kernel_row.iter().enumerate() { - let offset_x = kernel_x as i32 - offset; + let offset_x = kernel_x as i32 - 1; let neighbor_x = x + offset_x; let neighbor_y = y + offset_y; diff --git a/src/rules.rs b/src/rules.rs index bd06cdd..b7432d7 100644 --- a/src/rules.rs +++ b/src/rules.rs @@ -1,28 +1,27 @@ use rand::rngs::ThreadRng; use rand::{thread_rng, Rng}; - +use servicepoint::Value; use crate::print::println_info; -pub struct Rules -where - TState: Copy + PartialEq, - TKernel: Copy, +pub struct Rules { - pub kernel: [[TKernel; KERNEL_SIZE]; KERNEL_SIZE], - pub count_neighbor: Box i32>, - pub next_state: Box TState>, + pub kernel: Kernel3x3, + pub count_neighbor: Box i32>, + pub next_state: Box T>, } -pub const MOORE_NEIGHBORHOOD: [[bool; 3]; 3] = +type Kernel3x3 = [[bool; 3]; 3]; + +pub const MOORE_NEIGHBORHOOD: Kernel3x3 = [[true, true, true], [true, false, true], [true, true, true]]; -pub const NEUMANN_NEIGHBORHOOD: [[bool; 3]; 3] = [ +pub const NEUMANN_NEIGHBORHOOD: Kernel3x3 = [ [false, true, false], [true, false, true], [false, true, false], ]; -pub const DIAGONALS_NEIGHBORHOOD: [[bool; 3]; 3] = [ +pub const DIAGONALS_NEIGHBORHOOD: Kernel3x3 = [ [true, false, true], [false, false, false], [true, false, true], @@ -37,16 +36,11 @@ pub fn count_true_neighbor(neighbor_state: bool, kernel_value: bool) -> i32 { } #[must_use] -pub fn generate_bb3() -> Rules { +pub fn generate_bb3() -> Rules { let mut rng = thread_rng(); - let is_moore = rng.gen_bool(1.0 / 2.0); - let kernel = if is_moore { - MOORE_NEIGHBORHOOD - } else { - NEUMANN_NEIGHBORHOOD - }; - let max_neighbors = if is_moore { 8 } else { 4 }; + let kernel = choose_neighborhood(&mut rng); + let max_neighbors = count_max_neighbors(kernel); let birth = generate_neighbor_counts(rng.gen_range(1..=max_neighbors), &mut rng, &[0]); let survive = generate_neighbor_counts(rng.gen_range(1..=max_neighbors), &mut rng, &[]); @@ -76,16 +70,10 @@ fn generate_neighbor_counts(count: u8, rng: &mut ThreadRng, exclude: &[i32]) -> } #[must_use] -pub fn generate_u8b3() -> Rules { +pub fn generate_u8b3() -> Rules { let mut rng = thread_rng(); - let kernel = match rng.gen_range(0..3) { - 0 => MOORE_NEIGHBORHOOD, - 1 => NEUMANN_NEIGHBORHOOD, - 2 => DIAGONALS_NEIGHBORHOOD, - _ => panic!(), - }; - + let kernel = choose_neighborhood(&mut rng); let alive_threshold = u8::max(1, rng.gen()); let birth = generate_neighbor_counts(rng.gen_range(1..=9), &mut rng, &[0]); @@ -113,3 +101,24 @@ pub fn generate_u8b3() -> Rules { }), } } + +fn choose_neighborhood(rng: &mut ThreadRng) -> Kernel3x3 { + match rng.gen_range(0..3) { + 0 => MOORE_NEIGHBORHOOD, + 1 => NEUMANN_NEIGHBORHOOD, + 2 => DIAGONALS_NEIGHBORHOOD, + _ => unreachable!(), + } +} + +fn count_max_neighbors(kernel: [[bool; SIZE]; SIZE]) -> u8 { + let mut result = 0; + for row in kernel { + for cell in row { + if cell { + result += 1; + } + } + } + result +} diff --git a/src/simulation.rs b/src/simulation.rs index 579f645..a3a8e51 100644 --- a/src/simulation.rs +++ b/src/simulation.rs @@ -11,10 +11,10 @@ use servicepoint::{ use std::num::Wrapping; pub(crate) struct Simulation { - pub(crate) left_pixels: Game, - pub(crate) right_pixels: Game, - pub(crate) left_luma: Game, - pub(crate) right_luma: Game, + pub(crate) left_pixels: Game, + pub(crate) right_pixels: Game, + pub(crate) left_luma: Game, + pub(crate) right_luma: Game, split_pixel: usize, pub(crate) split_speed: i32, iteration: Wrapping, @@ -64,7 +64,7 @@ impl Simulation { std::mem::swap(&mut self.left_pixels, &mut self.right_pixels); } - fn regenerate(pixels: &mut Game, luma: &mut Game) { + fn regenerate(pixels: &mut Game, luma: &mut Game) { randomize(&mut pixels.field); randomize(&mut luma.field); pixels.rules = generate_bb3(); @@ -120,8 +120,8 @@ impl Simulation { &self.right_luma.field }; for y in 0..luma.height() { - let set: u8 = left_or_right.get(x, y) / u8::MAX * u8::from(Brightness::MAX); - let set = Brightness::try_from(set).unwrap(); + let set = left_or_right.get(x, y) as f32 / u8::MAX as f32 * u8::from(Brightness::MAX) as f32; + let set = Brightness::try_from(set as u8).unwrap(); luma.set(x, y, set); } } @@ -161,9 +161,9 @@ fn make_randomized(width: usize, height: usize) -> ValueGrid where Standard: Distribution, { - let mut pixels = ValueGrid::new(width, height); - randomize(&mut pixels); - pixels + let mut grid = ValueGrid::new(width, height); + randomize(&mut grid); + grid } fn randomize(field: &mut ValueGrid) -- 2.47.0 From fa8118bb781d2311e77e2bc86fafe55f5f328e49 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Fri, 2 May 2025 16:12:54 +0200 Subject: [PATCH 8/9] tweak visuals --- src/app.rs | 2 +- src/rules.rs | 11 +++++++---- src/simulation.rs | 9 ++++----- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/app.rs b/src/app.rs index 1b5ee67..78a0474 100644 --- a/src/app.rs +++ b/src/app.rs @@ -45,7 +45,7 @@ impl App { connection, sim: Simulation::new(), terminated: false, - target_duration: FRAME_PACING, + target_duration: FRAME_PACING * 4, pixels: Bitmap::max_sized(), luma: BrightnessGrid::new(TILE_WIDTH, TILE_HEIGHT), } diff --git a/src/rules.rs b/src/rules.rs index b7432d7..40b984f 100644 --- a/src/rules.rs +++ b/src/rules.rs @@ -12,8 +12,11 @@ pub struct Rules type Kernel3x3 = [[bool; 3]; 3]; -pub const MOORE_NEIGHBORHOOD: Kernel3x3 = - [[true, true, true], [true, false, true], [true, true, true]]; +pub const MOORE_NEIGHBORHOOD: Kernel3x3 = [ + [true, true, true], + [true, false, true], + [true, true, true] +]; pub const NEUMANN_NEIGHBORHOOD: Kernel3x3 = [ [false, true, false], @@ -83,8 +86,8 @@ pub fn generate_u8b3() -> Rules { &[], ); - let add = rng.gen_range(5..40); - let sub = rng.gen_range(5..40); + let add = rng.gen_range(1..15); + let sub = rng.gen_range(1..15); println_info(format!("generated u8b3: Birth {birth:?} Survival {survive:?}, kernel: {kernel:?}, alive_thresh: {alive_threshold}, delta: {add}/{sub}")); diff --git a/src/simulation.rs b/src/simulation.rs index a3a8e51..03e03d2 100644 --- a/src/simulation.rs +++ b/src/simulation.rs @@ -75,10 +75,8 @@ impl Simulation { self.left_pixels.step(); self.right_pixels.step(); - if self.iteration % Wrapping(10) == Wrapping(0) { - self.left_luma.step(); - self.right_luma.step(); - } + self.left_luma.step(); + self.right_luma.step(); self.iteration += Wrapping(1u8); @@ -121,7 +119,8 @@ impl Simulation { }; for y in 0..luma.height() { let set = left_or_right.get(x, y) as f32 / u8::MAX as f32 * u8::from(Brightness::MAX) as f32; - let set = Brightness::try_from(set as u8).unwrap(); + let set = (set as u8).max(1); + let set = Brightness::try_from(set).unwrap(); luma.set(x, y, set); } } -- 2.47.0 From 16a54ca747644c19d1700edbd794fad7fa69ab86 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Sat, 3 May 2025 11:51:42 +0200 Subject: [PATCH 9/9] update to released servicepoint version --- Cargo.lock | 196 ++++++++++++++++++++++++++++------------------------- Cargo.toml | 3 +- flake.lock | 6 +- src/app.rs | 2 +- 4 files changed, 108 insertions(+), 99 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2cb5d30..441a416 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -19,43 +19,44 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.3" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", - "windows-sys", + "once_cell", + "windows-sys 0.59.0", ] [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "bitflags" @@ -83,9 +84,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.5.4" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" dependencies = [ "clap_builder", "clap_derive", @@ -93,9 +94,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" dependencies = [ "anstream", "anstyle", @@ -105,9 +106,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" dependencies = [ "heck", "proc-macro2", @@ -117,15 +118,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "convert_case" @@ -200,7 +201,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -211,9 +212,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", @@ -228,9 +229,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "libc" @@ -262,9 +263,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "mio" @@ -275,7 +276,7 @@ dependencies = [ "libc", "log", "wasi", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -286,9 +287,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -307,17 +308,14 @@ dependencies = [ "windows-targets", ] -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro2" @@ -330,9 +328,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.36" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -375,23 +373,13 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" dependencies = [ "bitflags", ] -[[package]] -name = "rust-lzma" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d62915608f6cee1d7f2fc00f28b4f058ff79d6e4ec3c2fe0006b09b52437c84" -dependencies = [ - "pkg-config", - "vcpkg", -] - [[package]] name = "rustix" version = "1.0.7" @@ -402,7 +390,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -414,13 +402,12 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "servicepoint" version = "0.14.0" -source = "git+https://git.berlin.ccc.de/servicepoint/servicepoint/?branch=next#8ddbaeaaa64a4abb8ffb8b08a3a84cc1135e312f" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce70bae3641ccafdeb9832ac367efd51243e0708ef35151ad8c2c4ee578aa4a" dependencies = [ "bitvec", "log", - "once_cell", "rand", - "rust-lzma", "thiserror", ] @@ -457,18 +444,18 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" dependencies = [ "libc", ] [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" [[package]] name = "strsim" @@ -515,9 +502,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-segmentation" @@ -527,15 +514,9 @@ checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "wasi" @@ -575,10 +556,19 @@ dependencies = [ ] [[package]] -name = "windows-targets" -version = "0.52.5" +name = "windows-sys" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -592,51 +582,51 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "wyz" @@ -646,3 +636,23 @@ checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" dependencies = [ "tap", ] + +[[package]] +name = "zerocopy" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index 5f6e7b6..0845ce6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,8 +18,7 @@ crossterm = "0.29" package = "servicepoint" version = "0.14.0" features = ["rand"] -git = "https://git.berlin.ccc.de/servicepoint/servicepoint/" -branch = "next" +default-features = false [lints.clippy] incompatible_msrv = "forbid" diff --git a/flake.lock b/flake.lock index 8c4b6bb..578e72d 100644 --- a/flake.lock +++ b/flake.lock @@ -37,11 +37,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1746055187, - "narHash": "sha256-3dqArYSMP9hM7Qpy5YWhnSjiqniSaT2uc5h2Po7tmg0=", + "lastModified": 1746183838, + "narHash": "sha256-kwaaguGkAqTZ1oK0yXeQ3ayYjs8u/W7eEfrFpFfIDFA=", "owner": "nixos", "repo": "nixpkgs", - "rev": "3e362ce63e16b9572d8c2297c04f7c19ab6725a5", + "rev": "bf3287dac860542719fe7554e21e686108716879", "type": "github" }, "original": { diff --git a/src/app.rs b/src/app.rs index 78a0474..7ded9b1 100644 --- a/src/app.rs +++ b/src/app.rs @@ -13,7 +13,7 @@ use crossterm::{ }, }; use servicepoint::{ - Bitmap, BitmapCommand, BrightnessGrid, BrightnessGridCommand, SendCommandExt, UdpSocketExt, + Bitmap, BitmapCommand, BrightnessGrid, BrightnessGridCommand, UdpSocketExt, FRAME_PACING, TILE_HEIGHT, TILE_WIDTH, }; use std::{ -- 2.47.0