diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 23222a6..8691bb9 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -3,7 +3,7 @@ > **Version:** 1.1 > **Language:** Rust (Edition 2021) > **Engine:** Bevy (latest stable) -> **Last Updated:** 2026-04-20 +> **Last Updated:** 2026-04-29 --- @@ -67,18 +67,19 @@ solitaire_quest/ ├── Dockerfile # Multi-stage server build ├── docker-compose.yml # Server + Caddy reverse proxy │ -├── assets/ # Audio embedded at compile time via include_bytes!() -│ ├── cards/ # Reserved for future art pass (currently unused) -│ │ ├── faces/ -│ │ └── backs/ -│ ├── backgrounds/ # Reserved for future art pass (currently unused) -│ ├── fonts/ # Reserved for future art pass (currently unused) +├── assets/ # Assets embedded at compile time via include_bytes!() +│ ├── cards/ +│ │ ├── faces/face.png # placeholder (16×16 cream/ivory) +│ │ └── backs/back_0.png – back_4.png # placeholder patterns +│ ├── backgrounds/bg_0.png – bg_4.png # placeholder textures +│ ├── fonts/main.ttf # FiraMono-Medium (170K, OFL) │ └── audio/ │ ├── card_deal.wav │ ├── card_flip.wav │ ├── card_place.wav │ ├── card_invalid.wav -│ └── win_fanfare.wav +│ ├── win_fanfare.wav +│ └── ambient_loop.wav │ ├── solitaire_core/ # Pure Rust game logic — zero external deps beyond rand/serde ├── solitaire_sync/ # Shared API types — used by client and server @@ -143,6 +144,7 @@ Owns: - All Bevy UI screens (Home, Stats, Achievements, Settings, Profile) - Audio playback systems - Sync status display +- Card, background, and font asset loading (embedded via `include_bytes!()` — no `AssetServer` dependency) ### `solitaire_server` **Dependencies:** `solitaire_sync`, `axum`, `sqlx`, `jsonwebtoken`, `bcrypt`, `tower-governor`, `tracing`, `tokio`, `dotenvy`. @@ -237,6 +239,7 @@ Done |---|---|---| | `CardPlugin` | — | Card entity spawning, sprite management, drag-and-drop | | `TablePlugin` | — | Pile markers, background, layout calculation | +| `FontPlugin` | — | Embeds FiraMono-Medium font at compile time; exposes `FontResource` handle | | `AnimationPlugin` | — | Slide, flip, win cascade, toast animations | | `FeedbackAnimPlugin` | — | Shake, settle, and deal-stagger animations | | `AutoCompletePlugin` | Enter | Executes auto-complete when the HUD badge is lit | @@ -286,6 +289,20 @@ struct StatsResource(StatsSnapshot); struct ProgressResource(PlayerProgress); struct AchievementsResource(Vec); struct SettingsResource(Settings); + +// Pre-loaded card face and back PNG handles +struct CardImageSet { + face: Handle, // shared face image for all face-up cards + backs: [Handle; 5], // indexed by selected_card_back setting +} + +// Project-wide font handle (FiraMono-Medium embedded at compile time) +struct FontResource(Handle); + +// Pre-loaded background PNG handles +struct BackgroundImageSet { + handles: Vec>, // indices 0–4 match selected_background setting +} ``` ### Key Bevy Events @@ -743,7 +760,7 @@ Audio uses `bevy_kira_audio`. All sound files are `.wav`. | `card_place.wav` | Valid card placement | | `card_invalid.wav` | Invalid move attempt | | `win_fanfare.wav` | Game won | -| `ambient_loop` | Looping background music — uses `card_flip.wav` looped at very low volume as a placeholder until a dedicated track is added | +| `ambient_loop.wav` | Looping background music | Volume is controlled by two independent sliders in Settings (`sfx_volume`, `music_volume`), each stored in `Settings` and applied as `bevy_kira_audio` channel volumes. @@ -755,30 +772,49 @@ Audio systems listen for Bevy events and never block the game thread. ### Rendering approach -Cards, backgrounds, and UI are rendered **procedurally** — no image files are used. Cards are Bevy `Sprite` entities (colored rectangles) with `Text` children showing rank and suit symbols. Card back colors and background colors are selected by index from compile-time color tables in `card_plugin.rs` and `table_plugin.rs`. All UI text uses Bevy's built-in default font. +Cards are Bevy `Sprite` entities with `Handle` from `CardImageSet`. Face-up cards use `face.png` (a single shared image). Face-down cards use `backs/back_N.png` indexed by `settings.selected_card_back`. `Text2d` labels are still overlaid for rank and suit symbols. `CardImageSet` is populated at startup from `include_bytes!()` — no `AssetServer`. -This means the `assets/cards/`, `assets/backgrounds/`, and `assets/fonts/` directories are reserved for a future art pass and are currently empty (`.gitkeep` only). +Backgrounds are Bevy `Sprite` entities with `Handle` from `BackgroundImageSet`. `BackgroundImageSet` is populated at startup from `include_bytes!()`. + +The font `FiraMono-Medium` is embedded via `include_bytes!()` at startup by `FontPlugin` and exposed as `FontResource` for use by all UI and text systems. + +The `assets/` directory layout: + +``` +assets/ +├── cards/ +│ ├── faces/face.png # placeholder (16×16 cream/ivory) +│ └── backs/back_0.png – back_4.png # placeholder patterns +├── backgrounds/bg_0.png – bg_4.png # placeholder textures +├── fonts/main.ttf # FiraMono-Medium (170K, OFL) +└── audio/ + ├── card_deal.wav + ├── card_flip.wav + ├── card_place.wav + ├── card_invalid.wav + ├── win_fanfare.wav + └── ambient_loop.wav +``` ### Audio -All five sound effect WAV files are embedded at compile time via `include_bytes!()` in `audio_plugin.rs`. There is no runtime asset loading — the binary is fully self-contained. +All sound effect WAV files are embedded at compile time via `include_bytes!()` in `audio_plugin.rs`. There is no runtime asset loading — the binary is fully self-contained. -| File | Size | +| File | Trigger | |---|---| -| `card_deal.wav` | SFX | -| `card_flip.wav` | SFX | -| `card_place.wav` | SFX | -| `card_invalid.wav` | SFX | -| `win_fanfare.wav` | SFX | - -The ambient music loop reuses `card_flip.wav` at very low volume as a placeholder; a dedicated `ambient_loop.wav` can be dropped into `assets/audio/` and wired into `audio_plugin.rs` when ready. +| `card_deal.wav` | New game deal animation | +| `card_flip.wav` | Card flips face-up | +| `card_place.wav` | Valid card placement | +| `card_invalid.wav` | Invalid move attempt | +| `win_fanfare.wav` | Game won | +| `ambient_loop.wav` | Looping background music | ### Future art pass -When image-based card art is added, the recommended approach is: -- Embed assets via `bevy::asset::embedded_asset!()` macro (keeps the binary self-contained) +The placeholder PNG files can be replaced with real artwork without any code changes — just drop in new PNGs and rebuild. The texture atlas approach described below is still the recommended upgrade path for card faces: - Use a texture atlas (`assets/cards/atlas.png` + layout descriptor) for card faces - Individual PNGs for card backs and backgrounds (5 each) +- All assets remain embedded via `include_bytes!()` to keep the binary self-contained --- @@ -975,3 +1011,5 @@ Using `axum::test` and an in-memory SQLite database: | `SyncProvider` trait, not `SyncBackend` match arms | `SyncPlugin` stays backend-agnostic and testable; new backends can be added without touching the plugin | 2026-04-20 | | Dropped WebDAV backend | Redundant once the self-hosted server exists; removing it reduces surface area and simplifies settings UI | 2026-04-20 | | Dropped GPGS backend | Redundant with the self-hosted server; adds JNI complexity for no user-visible benefit on the target platforms | 2026-04-28 | +| PNG assets embedded via `include_bytes!()` | Using `Image::from_buffer()` in startup systems rather than `AssetServer::load()` keeps the binary self-contained and eliminates runtime file-not-found errors | 2026-04-29 | +| FiraMono-Medium font embedded via `include_bytes!()` | Exposed through `FontResource`; avoids runtime font loading errors on headless systems and ensures consistent text rendering across all platforms | 2026-04-29 | diff --git a/Cargo.lock b/Cargo.lock index a0b198c..a689f84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,6 +81,26 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aegis" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78412fa53e6da95324e8902c3641b3ff32ab45258582ea997eb9169c68ffa219" +dependencies = [ + "cc", + "softaes", +] + [[package]] name = "aes" version = "0.8.4" @@ -92,6 +112,20 @@ dependencies = [ "cpufeatures 0.2.17", ] +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "ahash" version = "0.8.12" @@ -174,6 +208,24 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "android-native-keyring-store" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c6349ddff23194f8fdce2ea8849380f5a4868c1648965b70e801e104cba9b3" +dependencies = [ + "base64", + "jni 0.21.1", + "keyring-core", + "log", + "ndk-context", + "regex", + "serde", + "serde_json", + "thiserror 2.0.18", + "tracing", +] + [[package]] name = "android-properties" version = "0.2.2" @@ -195,12 +247,89 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "antithesis_sdk" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18dbd97a5b6c21cc9176891cf715f7f0c273caf3959897f43b9bd1231939e675" +dependencies = [ + "libc", + "libloading", + "linkme", + "once_cell", + "rand 0.8.6", + "rustc_version_runtime", + "serde", + "serde_json", +] + [[package]] name = "anyhow" version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "apple-native-keyring-store" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7be2f067ccd8d4b4d4a66ddafe0f32a5dff31732f32dbff85fefc40929b1f72" +dependencies = [ + "keyring-core", + "log", + "security-framework", +] + [[package]] name = "approx" version = "0.5.1" @@ -210,6 +339,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "arc-swap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207" +dependencies = [ + "rustversion", +] + [[package]] name = "arrayref" version = "0.3.9" @@ -245,18 +383,14 @@ checksum = "f548ad2c4031f2902e3edc1f29c29e835829437de49562d8eb5dc5584d3a1043" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] -name = "async-broadcast" -version = "0.5.1" +name = "assoc" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b" -dependencies = [ - "event-listener 2.5.3", - "futures-core", -] +checksum = "bfdc70193dadb9d7287fa4b633f15f90c876915b31f6af17da307fc59c9859a8" [[package]] name = "async-broadcast" @@ -264,7 +398,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" dependencies = [ - "event-listener 5.4.1", + "event-listener", "event-listener-strategy", "futures-core", "pin-project-lite", @@ -290,53 +424,21 @@ checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" dependencies = [ "async-task", "concurrent-queue", - "fastrand 2.4.1", - "futures-lite 2.6.1", + "fastrand", + "futures-lite", "pin-project-lite", "slab", ] -[[package]] -name = "async-fs" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" -dependencies = [ - "async-lock 2.8.0", - "autocfg", - "blocking", - "futures-lite 1.13.0", -] - [[package]] name = "async-fs" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8034a681df4aed8b8edbd7fbe472401ecf009251c8b40556b304567052e294c5" dependencies = [ - "async-lock 3.4.2", + "async-lock", "blocking", - "futures-lite 2.6.1", -] - -[[package]] -name = "async-io" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" -dependencies = [ - "async-lock 2.8.0", - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-lite 1.13.0", - "log", - "parking", - "polling 2.8.0", - "rustix 0.37.28", - "slab", - "socket2 0.4.10", - "waker-fn", + "futures-lite", ] [[package]] @@ -349,49 +451,41 @@ dependencies = [ "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.6.1", + "futures-lite", "parking", - "polling 3.11.0", + "polling", "rustix 1.1.4", "slab", "windows-sys 0.61.2", ] -[[package]] -name = "async-lock" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" -dependencies = [ - "event-listener 2.5.3", -] - [[package]] name = "async-lock" version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ - "event-listener 5.4.1", + "event-listener", "event-listener-strategy", "pin-project-lite", ] [[package]] name = "async-process" -version = "1.8.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" dependencies = [ - "async-io 1.13.0", - "async-lock 2.8.0", + "async-channel", + "async-io", + "async-lock", "async-signal", + "async-task", "blocking", "cfg-if", - "event-listener 3.1.0", - "futures-lite 1.13.0", - "rustix 0.38.44", - "windows-sys 0.48.0", + "event-listener", + "futures-lite", + "rustix 1.1.4", ] [[package]] @@ -402,7 +496,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -411,8 +505,8 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485" dependencies = [ - "async-io 2.6.0", - "async-lock 3.4.2", + "async-io", + "async-lock", "atomic-waker", "cfg-if", "futures-core", @@ -440,7 +534,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -660,7 +754,7 @@ checksum = "7cf35516d0e7ac9ec25df533be1bf8cbaa20596a8e65f36838a3f7803a267d6d" dependencies = [ "bevy_macro_utils", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -714,11 +808,11 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29f86fed15972b9fb1a3f7b092cf0390e67131caaedab15a2707c043e3a3c886" dependencies = [ - "async-broadcast 0.7.2", + "async-broadcast", "async-channel", - "async-fs 2.2.0", - "async-io 2.6.0", - "async-lock 3.4.2", + "async-fs", + "async-io", + "async-lock", "atomicow", "bevy_android", "bevy_app", @@ -737,7 +831,7 @@ dependencies = [ "downcast-rs 2.0.2", "either", "futures-io", - "futures-lite 2.6.1", + "futures-lite", "futures-util", "js-sys", "ron", @@ -760,7 +854,7 @@ dependencies = [ "bevy_macro_utils", "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -861,7 +955,7 @@ checksum = "318ee0532c3da93749859d18f89a889c638fbc56aabac4d866583df7b951d103" dependencies = [ "bevy_macro_utils", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -948,7 +1042,7 @@ dependencies = [ "bevy_macro_utils", "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -1035,7 +1129,7 @@ checksum = "6960ea308d7e94adcac5c712553ff86614bba6b663511f3f3812f6bec028b51e" dependencies = [ "bevy_macro_utils", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -1069,7 +1163,7 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f37fb52655d0439656ca0a1db027d46926e463c81d893d4b1639668e5d7f1c1" dependencies = [ - "async-lock 3.4.2", + "async-lock", "base64", "bevy_animation", "bevy_app", @@ -1115,7 +1209,7 @@ dependencies = [ "bevy_utils", "bitflags 2.11.1", "bytemuck", - "futures-lite 2.6.1", + "futures-lite", "guillotiere", "half", "image", @@ -1264,7 +1358,7 @@ checksum = "3b147843b81a7ec548876ff97fa7bfdc646ef2567cb465566259237b39664438" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", "toml_edit 0.23.10+spec-1.0.0", ] @@ -1475,7 +1569,7 @@ dependencies = [ "indexmap", "proc-macro2", "quote", - "syn 2.0.117", + "syn", "uuid", ] @@ -1538,7 +1632,7 @@ dependencies = [ "bevy_macro_utils", "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -1661,7 +1755,7 @@ checksum = "73d32f90f9cfcef5a44401db7ce206770daaa1707b0fb95eb7a96a6933f54f1b" dependencies = [ "bevy_macro_utils", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -1678,7 +1772,7 @@ dependencies = [ "concurrent-queue", "crossbeam-queue", "derive_more", - "futures-lite 2.6.1", + "futures-lite", "heapless", "pin-project", ] @@ -1891,6 +1985,42 @@ dependencies = [ "winit", ] +[[package]] +name = "bigdecimal" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d6867f1565b3aad85681f1015055b087fcfd840d6aeee6eee7f2da317603695" +dependencies = [ + "autocfg", + "libm", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "bindgen" +version = "0.69.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +dependencies = [ + "bitflags 2.11.1", + "cexpr", + "clang-sys", + "itertools 0.12.1", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "syn", + "which", +] + [[package]] name = "bindgen" version = "0.72.1" @@ -1906,7 +2036,7 @@ dependencies = [ "regex", "rustc-hash 2.1.2", "shlex", - "syn 2.0.117", + "syn", ] [[package]] @@ -1940,6 +2070,27 @@ dependencies = [ "serde_core", ] +[[package]] +name = "bitpacking" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96a7139abd3d9cebf8cd6f920a389cf3dc9576172e32f4563f188cae3c3eb019" +dependencies = [ + "crunchy", +] + +[[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 = "blake3" version = "1.8.5" @@ -2005,7 +2156,7 @@ dependencies = [ "async-channel", "async-task", "futures-io", - "futures-lite 2.6.1", + "futures-lite", "piper", ] @@ -2019,6 +2170,40 @@ dependencies = [ "cipher", ] +[[package]] +name = "bon" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f47dbe92550676ee653353c310dfb9cf6ba17ee70396e1f7cf0a2020ad49b2fe" +dependencies = [ + "bon-macros", + "rustversion", +] + +[[package]] +name = "bon-macros" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "519bd3116aeeb42d5372c29d982d16d0170d3d4a5ed85fc7dd91642ffff3c67c" +dependencies = [ + "darling", + "ident_case", + "prettyplease", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "branches" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e426eb5cc1900033930ec955317b302e68f19f326cc7bb0c8a86865a826cdf0c" +dependencies = [ + "rustc_version", +] + [[package]] name = "bumpalo" version = "3.20.2" @@ -2042,7 +2227,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -2071,7 +2256,7 @@ checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ "bitflags 2.11.1", "log", - "polling 3.11.0", + "polling", "rustix 0.38.44", "slab", "thiserror 1.0.69", @@ -2110,6 +2295,12 @@ dependencies = [ "shlex", ] +[[package]] +name = "census" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f4c707c6a209cbe82d10abd08e1ea8995e9ea937d2550646e02798948992be0" + [[package]] name = "cesu8" version = "1.1.0" @@ -2137,6 +2328,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "cfg_block" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18758054972164c3264f7c8386f5fc6da6114cb46b619fd365d4e3b2dc3ae487" + [[package]] name = "chrono" version = "0.4.44" @@ -2172,6 +2369,46 @@ dependencies = [ "libloading", ] +[[package]] +name = "clap" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + [[package]] name = "cmake" version = "0.1.58" @@ -2192,6 +2429,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + [[package]] name = "combine" version = "4.6.7" @@ -2308,7 +2551,7 @@ dependencies = [ "bitflags 1.3.2", "core-foundation 0.9.4", "core-graphics-types 0.1.3", - "foreign-types", + "foreign-types 0.5.0", "libc", ] @@ -2374,7 +2617,7 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ceec7a6067e62d6f931a2baf6f3a751f4a892595bcec1461a3c94ef9949864b6" dependencies = [ - "bindgen", + "bindgen 0.72.1", ] [[package]] @@ -2487,6 +2730,15 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" +[[package]] +name = "crc32c" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a47af21622d091a8f0fb295b88bc886ac74efcc613efc19f5d0b21de5c89e47" +dependencies = [ + "rustc_version", +] + [[package]] name = "crc32fast" version = "1.5.0" @@ -2511,6 +2763,25 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-queue" version = "0.3.12" @@ -2520,6 +2791,16 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-skiplist" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df29de440c58ca2cc6e587ec3d22347551a32435fbde9d2bff64e78a9ffa151b" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -2551,9 +2832,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", + "rand_core 0.6.4", "typenum", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + [[package]] name = "ctrlc" version = "3.5.2" @@ -2595,7 +2886,41 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core", + "quote", + "syn", ] [[package]] @@ -2610,6 +2935,7 @@ dependencies = [ "lock_api", "once_cell", "parking_lot_core", + "serde", ] [[package]] @@ -2624,6 +2950,71 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" +[[package]] +name = "datasketches" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c286de4e81ea2590afc24d754e0f83810c566f50a1388fa75ebd57928c0d9745" + +[[package]] +name = "db-keystore" +version = "0.4.2-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6d682fd95a70cd0de8dd61a95cbd5fe16c9411cdd335864bcce58552f3df6c4" +dependencies = [ + "anyhow", + "clap", + "futures", + "keyring-core", + "log", + "regex", + "serde", + "serde_json", + "turso", + "uuid", + "zeroize", +] + +[[package]] +name = "dbus" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b942602992bb7acfd1f51c49811c58a610ef9181b6e66f3e519d79b540a3bf73" +dependencies = [ + "libc", + "libdbus-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "dbus-secret-service" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "708b509edf7889e53d7efb0ffadd994cc6c2345ccb62f55cfd6b0682165e4fa6" +dependencies = [ + "aes", + "block-padding", + "cbc", + "dbus", + "fastrand", + "hkdf", + "num", + "once_cell", + "openssl", + "sha2", + "zeroize", +] + +[[package]] +name = "dbus-secret-service-keyring-store" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21d8f54da401bb5eb2a4d873ac4b359f4a599df2ca8634bb5b8c045e5ee78757" +dependencies = [ + "dbus-secret-service", + "keyring-core", +] + [[package]] name = "der" version = "0.7.10" @@ -2636,14 +3027,13 @@ dependencies = [ ] [[package]] -name = "derivative" -version = "2.2.0" +name = "deranged" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "powerfmt", + "serde_core", ] [[package]] @@ -2665,7 +3055,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.117", + "syn", "unicode-xid", ] @@ -2728,7 +3118,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -2881,7 +3271,7 @@ checksum = "c8bad72d8308f7a382de2391ec978ddd736e0103846b965d7e2a63a75768af30" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -2893,6 +3283,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "endi" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" + [[package]] name = "enumflags2" version = "0.7.12" @@ -2911,7 +3307,26 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", +] + +[[package]] +name = "env_filter" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eef" +dependencies = [ + "log", +] + +[[package]] +name = "env_logger" +version = "0.11.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a" +dependencies = [ + "env_filter", + "log", ] [[package]] @@ -2961,23 +3376,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - -[[package]] -name = "event-listener" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - [[package]] name = "event-listener" version = "5.4.1" @@ -2995,7 +3393,7 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "event-listener 5.4.1", + "event-listener", "pin-project-lite", ] @@ -3006,14 +3404,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af9673d8203fcb076b19dfd17e38b3d4ae9f44959416ea532ce72415a6020365" [[package]] -name = "fastrand" -version = "1.9.0" +name = "fallible-iterator" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fastbloom" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7f34442dbe69c60fe8eaf58a8cafff81a1f278816d8ab4db255b3bef4ac3c4" dependencies = [ - "instant", + "getrandom 0.3.4", + "libm", + "siphasher", ] +[[package]] +name = "fastdivide" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afc2bd4d5a73106dd53d10d73d3401c2f32730ba2c0b93ddb888a8983680471" + [[package]] name = "fastrand" version = "2.4.1" @@ -3137,6 +3549,15 @@ dependencies = [ "ttf-parser", ] +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + [[package]] name = "foreign-types" version = "0.5.0" @@ -3144,7 +3565,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" dependencies = [ "foreign-types-macros", - "foreign-types-shared", + "foreign-types-shared 0.3.1", ] [[package]] @@ -3155,9 +3576,15 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "foreign-types-shared" version = "0.3.1" @@ -3183,12 +3610,43 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "fs4" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8640e34b88f7652208ce9e88b1a37a2ae95227d84abec377ccd3c5cfeb141ed4" +dependencies = [ + "rustix 1.1.4", + "windows-sys 0.59.0", +] + [[package]] name = "fs_extra" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.32" @@ -3233,28 +3691,13 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" -[[package]] -name = "futures-lite" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" -dependencies = [ - "fastrand 1.9.0", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - [[package]] name = "futures-lite" version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" dependencies = [ - "fastrand 2.4.1", + "fastrand", "futures-core", "futures-io", "parking", @@ -3269,7 +3712,7 @@ checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -3296,6 +3739,7 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ + "futures-channel", "futures-core", "futures-io", "futures-macro", @@ -3306,6 +3750,36 @@ dependencies = [ "slab", ] +[[package]] +name = "genawaiter" +version = "0.99.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c86bd0361bcbde39b13475e6e36cb24c329964aa2611be285289d1e4b751c1a0" +dependencies = [ + "genawaiter-macro", +] + +[[package]] +name = "genawaiter-macro" +version = "0.99.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b32dfe1fdfc0bbde1f22a5da25355514b5e450c33a6af6770884c8750aedfbc" + +[[package]] +name = "generator" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9" +dependencies = [ + "cc", + "cfg-if", + "libc", + "log", + "rustversion", + "windows-link 0.2.1", + "windows-result 0.4.1", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -3367,6 +3841,16 @@ dependencies = [ "wasip3", ] +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "gilrs" version = "0.11.1" @@ -3473,7 +3957,7 @@ dependencies = [ "inflections", "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -3713,12 +4197,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - [[package]] name = "hermit-abi" version = "0.5.2" @@ -3775,6 +4253,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "htmlescape" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163" + [[package]] name = "http" version = "1.4.0" @@ -3887,7 +4371,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.3", + "socket2", "tokio", "tower-service", "tracing", @@ -4005,6 +4489,12 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "1.1.0" @@ -4036,7 +4526,7 @@ dependencies = [ "byteorder-lite", "moxcms", "num-traits", - "png", + "png 0.18.1", ] [[package]] @@ -4088,12 +4578,12 @@ dependencies = [ ] [[package]] -name = "instant" -version = "0.1.13" +name = "intrusive-collections" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +checksum = "189d0897e4cbe8c75efedf3502c18c887b05046e59d28404d4d8e46cbc4d1e86" dependencies = [ - "cfg-if", + "memoffset", ] [[package]] @@ -4106,14 +4596,14 @@ dependencies = [ ] [[package]] -name = "io-lifetimes" -version = "1.0.11" +name = "io-uring" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +checksum = "4d09b98f7eace8982db770e4408e7470b028ce513ac28fecdc6bf4c30fe92b62" dependencies = [ - "hermit-abi 0.3.9", + "bitflags 2.11.1", + "cfg-if", "libc", - "windows-sys 0.48.0", ] [[package]] @@ -4132,6 +4622,21 @@ dependencies = [ "serde", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.13.0" @@ -4199,7 +4704,7 @@ dependencies = [ "quote", "rustc_version", "simd_cesu8", - "syn 2.0.117", + "syn", ] [[package]] @@ -4227,7 +4732,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" dependencies = [ "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -4275,16 +4780,37 @@ dependencies = [ [[package]] name = "keyring" -version = "2.3.3" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "363387f0019d714aa60cc30ab4fe501a747f4c08fc58f069dd14be971bd495a0" +checksum = "dc17b941cdab9063edc0f241dbe10ba9895a8b3f92aa908fd4b3533fea2ae841" dependencies = [ - "byteorder", - "lazy_static", - "linux-keyutils", - "secret-service", - "security-framework 2.11.1", - "windows-sys 0.52.0", + "android-native-keyring-store", + "apple-native-keyring-store", + "base64", + "clap", + "db-keystore", + "dbus-secret-service-keyring-store", + "keyring-core", + "linux-keyutils-keyring-store", + "rpassword", + "rprompt", + "windows-native-keyring-store", + "zbus-secret-service-keyring-store", +] + +[[package]] +name = "keyring-core" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb1e621458ca9c51aa110bd0339d4751a056b9576bf1253aee1aa560dda0fc9d" +dependencies = [ + "chrono", + "dashmap", + "log", + "regex", + "ron", + "serde", + "uuid", ] [[package]] @@ -4339,12 +4865,24 @@ dependencies = [ "spin 0.9.8", ] +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "leb128fmt" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" +[[package]] +name = "levenshtein_automata" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2cdeb66e45e9f36bfad5bbdb4d2384e70936afbee843c6f6543f0c551ebb25" + [[package]] name = "lewton" version = "0.10.2" @@ -4362,6 +4900,16 @@ version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +[[package]] +name = "libdbus-sys" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043" +dependencies = [ + "cc", + "pkg-config", +] + [[package]] name = "libloading" version = "0.8.9" @@ -4378,6 +4926,15 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" +[[package]] +name = "libmimalloc-sys" +version = "0.1.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d1eacfa31c33ec25e873c136ba5669f00f9866d0688bea7be4d3f7e43067df6" +dependencies = [ + "cc", +] + [[package]] name = "libredox" version = "0.1.16" @@ -4417,6 +4974,26 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4a5ff6bcca6c4867b1c4fd4ef63e4db7436ef363e0ad7531d1558856bae64f4" +[[package]] +name = "linkme" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83272d46373fb8decca684579ac3e7c8f3d71d4cc3aa693df8759e260ae41cf" +dependencies = [ + "linkme-impl", +] + +[[package]] +name = "linkme-impl" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d59e20403c7d08fe62b4376edfe5c7fb2ef1e6b1465379686d0f21c8df444b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "linux-keyutils" version = "0.2.5" @@ -4428,10 +5005,14 @@ dependencies = [ ] [[package]] -name = "linux-raw-sys" -version = "0.3.8" +name = "linux-keyutils-keyring-store" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +checksum = "39fbed79f71dc21eb21d3d07c0e908a3c58ff9a1fdbf5cf44230fb3deb6d994b" +dependencies = [ + "keyring-core", + "linux-keyutils", +] [[package]] name = "linux-raw-sys" @@ -4472,12 +5053,40 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +[[package]] +name = "loom" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "lru" +version = "0.16.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f66e8d5d03f609abc3a39e6f08e4164ebf1447a732906d39eb9b99b7919ef39" +dependencies = [ + "hashbrown 0.16.1", +] + [[package]] name = "lru-slab" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +[[package]] +name = "lz4_flex" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db9a0d582c2874f68138a16ce1867e0ffde6c0bb0a0df85e1f36d04146db488a" + [[package]] name = "mach2" version = "0.4.3" @@ -4530,6 +5139,15 @@ dependencies = [ "digest", ] +[[package]] +name = "measure_time" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51c55d61e72fc3ab704396c5fa16f4c184db37978ae4e94ca8959693a235fc0e" +dependencies = [ + "log", +] + [[package]] name = "memchr" version = "2.8.0" @@ -4545,15 +5163,6 @@ dependencies = [ "libc", ] -[[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" -dependencies = [ - "autocfg", -] - [[package]] name = "memoffset" version = "0.9.1" @@ -4572,12 +5181,43 @@ dependencies = [ "bitflags 2.11.1", "block", "core-graphics-types 0.2.0", - "foreign-types", + "foreign-types 0.5.0", "log", "objc", "paste", ] +[[package]] +name = "miette" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" +dependencies = [ + "cfg-if", + "miette-derive", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "mimalloc" +version = "0.1.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3627c4272df786b9260cabaa46aec1d59c93ede723d4c3ef646c503816b0640" +dependencies = [ + "libmimalloc-sys", +] + [[package]] name = "mime" version = "0.3.17" @@ -4627,6 +5267,12 @@ dependencies = [ "pxfm", ] +[[package]] +name = "murmurhash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2195bf6aa996a481483b29d62a7663eed3fe39600c460e323f8ff41e90bdd89b" + [[package]] name = "naga" version = "27.0.3" @@ -4724,18 +5370,6 @@ dependencies = [ "jni-sys 0.3.1", ] -[[package]] -name = "nix" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" -dependencies = [ - "bitflags 1.3.2", - "cfg-if", - "libc", - "memoffset 0.7.1", -] - [[package]] name = "nix" version = "0.30.1" @@ -4855,6 +5489,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" + [[package]] name = "num-derive" version = "0.4.2" @@ -4863,7 +5503,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -4923,10 +5563,10 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" dependencies = [ - "proc-macro-crate 3.5.0", + "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -5283,12 +5923,78 @@ version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "oneshot" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "269bca4c2591a28585d6bf10d9ed0332b7d76900a1b02bec41bdc3a2cdcda107" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openssl" +version = "0.10.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38c4372413cdaaf3cc79dd92d29d7d9f5ab09b51b10dded508fb90bb70b9222" +dependencies = [ + "bitflags 2.11.1", + "cfg-if", + "foreign-types 0.3.2", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "openssl-probe" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" +[[package]] +name = "openssl-src" +version = "300.6.0+3.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8e8cbfd3a4a8c8f089147fd7aaa33cf8c7450c4d09f8f80698a0cf093abeff4" +dependencies = [ + "cc", +] + +[[package]] +name = "openssl-sys" +version = "0.9.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13ce1245cd07fcc4cfdb438f7507b0c7e4f3849a69fd84d52374c66d83741bb6" +dependencies = [ + "cc", + "libc", + "openssl-src", + "pkg-config", + "vcpkg", +] + [[package]] name = "option-ext" version = "0.2.0" @@ -5314,6 +6020,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ordered-float" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7d950ca161dc355eaf28f82b11345ed76c6e1f6eb1f4f4479e0323b9e2fbd0e" +dependencies = [ + "num-traits", +] + [[package]] name = "ordered-stream" version = "0.2.0" @@ -5333,6 +6048,21 @@ dependencies = [ "ttf-parser", ] +[[package]] +name = "ownedbytes" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fbd56f7631767e61784dc43f8580f403f4475bd4aaa4da003e6295e1bab4a7e" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + [[package]] name = "p256" version = "0.13.2" @@ -5357,6 +6087,15 @@ dependencies = [ "sha2", ] +[[package]] +name = "pack1" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6e7cd9bd638dc2c831519a0caa1c006cab771a92b1303403a8322773c5b72d6" +dependencies = [ + "bytemuck", +] + [[package]] name = "parking" version = "2.2.1" @@ -5443,7 +6182,7 @@ checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -5459,7 +6198,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1" dependencies = [ "atomic-waker", - "fastrand 2.4.1", + "fastrand", "futures-io", ] @@ -5496,6 +6235,19 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + [[package]] name = "png" version = "0.18.1" @@ -5509,22 +6261,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "polling" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" -dependencies = [ - "autocfg", - "bitflags 1.3.2", - "cfg-if", - "concurrent-queue", - "libc", - "log", - "pin-project-lite", - "windows-sys 0.48.0", -] - [[package]] name = "polling" version = "3.11.0" @@ -5533,12 +6269,24 @@ checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" dependencies = [ "cfg-if", "concurrent-queue", - "hermit-abi 0.5.2", + "hermit-abi", "pin-project-lite", "rustix 1.1.4", "windows-sys 0.61.2", ] +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "opaque-debug", + "universal-hash", +] + [[package]] name = "portable-atomic" version = "1.13.1" @@ -5563,6 +6311,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "pp-rs" version = "0.2.1" @@ -5594,7 +6348,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.117", + "syn", ] [[package]] @@ -5606,16 +6360,6 @@ dependencies = [ "elliptic-curve", ] -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit 0.19.15", -] - [[package]] name = "proc-macro-crate" version = "3.5.0" @@ -5640,6 +6384,29 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" +[[package]] +name = "prost" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" +dependencies = [ + "anyhow", + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pxfm" version = "0.1.29" @@ -5683,7 +6450,7 @@ dependencies = [ "quinn-udp", "rustc-hash 2.1.2", "rustls", - "socket2 0.6.3", + "socket2", "thiserror 2.0.18", "tokio", "tracing", @@ -5721,7 +6488,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.3", + "socket2", "tracing", "windows-sys 0.60.2", ] @@ -5747,6 +6514,12 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "radsort" version = "0.1.1" @@ -5822,6 +6595,15 @@ dependencies = [ "rand 0.9.4", ] +[[package]] +name = "rand_pcg" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59cad018caf63deb318e5a4586d99a24424a364f40f1e5778c29aca23f4fc73e" +dependencies = [ + "rand_core 0.6.4", +] + [[package]] name = "range-alloc" version = "0.1.5" @@ -5834,6 +6616,15 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "973443cf09a9c8656b574a866ab68dfa19f0867d0340648c7d2f6a71b8a8ea68" +[[package]] +name = "rapidhash" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e48930979c155e2f33aa36ab3119b5ee81332beb6482199a8ecd6029b80b59" +dependencies = [ + "rustversion", +] + [[package]] name = "raw-cpuid" version = "11.6.0" @@ -5849,6 +6640,26 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "read-fonts" version = "0.36.0" @@ -6011,6 +6822,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "roaring" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dedc5658c6ecb3bdb5ef5f3295bb9253f42dcf3fd1402c03f6b1f7659c3c4a9" +dependencies = [ + "bytemuck", + "byteorder", +] + [[package]] name = "rodio" version = "0.20.1" @@ -6041,6 +6862,27 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" +[[package]] +name = "rpassword" +version = "7.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3bc4a3dd492cd6974dd3f32d6626ba9f36e5122e3df3b083474b104aebd139b" +dependencies = [ + "libc", + "rtoolbox", + "windows-sys 0.61.2", +] + +[[package]] +name = "rprompt" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69abf524bb9ccb7c071f7231441288d74b48d176cb309eb00e6f77d186c6e035" +dependencies = [ + "rtoolbox", + "windows-sys 0.59.0", +] + [[package]] name = "rsa" version = "0.9.10" @@ -6061,12 +6903,32 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rtoolbox" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50a0e551c1e27e1731aba276dbeaeac73f53c7cd34d1bda485d02bd1e0f36844" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "rtrb" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ade083ccbb4bf536df69d1f6432cc23deb7acccff86b183f3923a6fd56a1153" +[[package]] +name = "rust-stemmers" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e46a2036019fdb888131db7a4c847a1063a7493f971ed94ea82c67eada63ca54" +dependencies = [ + "serde", + "serde_derive", +] + [[package]] name = "rustc-hash" version = "1.1.0" @@ -6089,17 +6951,13 @@ dependencies = [ ] [[package]] -name = "rustix" -version = "0.37.28" +name = "rustc_version_runtime" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "519165d378b97752ca44bbe15047d5d3409e875f39327546b42ac81d7e18c1b6" +checksum = "2dd18cd2bae1820af0b6ad5e54f4a51d0f3fcc53b05f845675074efcc7af071d" dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", + "rustc_version", + "semver", ] [[package]] @@ -6152,7 +7010,7 @@ dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.7.0", + "security-framework", ] [[package]] @@ -6180,7 +7038,7 @@ dependencies = [ "rustls-native-certs", "rustls-platform-verifier-android", "rustls-webpki", - "security-framework 3.7.0", + "security-framework", "security-framework-sys", "webpki-root-certs", "windows-sys 0.61.2", @@ -6284,36 +7142,23 @@ dependencies = [ [[package]] name = "secret-service" -version = "3.1.0" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5204d39df37f06d1944935232fd2dfe05008def7ca599bf28c0800366c8a8f9" +checksum = "9a62d7f86047af0077255a29494136b9aaaf697c76ff70b8e49cded4e2623c14" dependencies = [ "aes", "cbc", "futures-util", "generic-array", + "getrandom 0.2.17", "hkdf", "num", "once_cell", - "rand 0.8.6", "serde", "sha2", "zbus", ] -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.11.1", - "core-foundation 0.9.4", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - [[package]] name = "security-framework" version = "3.7.0" @@ -6382,7 +7227,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -6417,7 +7262,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -6443,6 +7288,12 @@ dependencies = [ "digest", ] +[[package]] +name = "sha1_smol" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" + [[package]] name = "sha2" version = "0.10.9" @@ -6469,6 +7320,26 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "shuttle" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab17edba38d63047f46780cf7360acf7467fec2c048928689a5c1dd1c2b4e31" +dependencies = [ + "assoc", + "bitvec", + "cfg-if", + "generator", + "hex", + "owo-colors", + "rand 0.8.6", + "rand_core 0.6.4", + "rand_pcg", + "scoped-tls", + "smallvec", + "tracing", +] + [[package]] name = "signal-hook-registry" version = "1.4.8" @@ -6511,6 +7382,30 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" +[[package]] +name = "simsimd" +version = "6.5.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fb3bc3cdce07a7d7d4caa4c54f8aa967f6be41690482b54b24100a2253fa70" +dependencies = [ + "cc", +] + +[[package]] +name = "siphasher" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" + +[[package]] +name = "sketches-ddsketch" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e40b6cf54d988dc1a2223531b969c9a9e30906ad90ef64890c27b4bfbb46ea" +dependencies = [ + "serde", +] + [[package]] name = "skrifa" version = "0.39.0" @@ -6589,16 +7484,6 @@ dependencies = [ "serde", ] -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.6.3" @@ -6609,11 +7494,18 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "softaes" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fef461faaeb36c340b6c887167a9054a034f6acfc50a014ead26a02b4356b3de" + [[package]] name = "solitaire_app" version = "0.1.0" dependencies = [ "bevy", + "keyring", "solitaire_data", "solitaire_engine", ] @@ -6621,6 +7513,9 @@ dependencies = [ [[package]] name = "solitaire_assetgen" version = "0.1.0" +dependencies = [ + "png 0.17.16", +] [[package]] name = "solitaire_core" @@ -6639,7 +7534,7 @@ dependencies = [ "async-trait", "chrono", "dirs", - "keyring", + "keyring-core", "reqwest", "serde", "serde_json", @@ -6767,7 +7662,7 @@ dependencies = [ "crc", "crossbeam-queue", "either", - "event-listener 5.4.1", + "event-listener", "futures-core", "futures-intrusive", "futures-io", @@ -6802,7 +7697,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.117", + "syn", ] [[package]] @@ -6825,7 +7720,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.117", + "syn", "tokio", "url", ] @@ -6971,6 +7866,34 @@ dependencies = [ "unicode-properties", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "subtle" version = "2.6.1" @@ -6994,6 +7917,12 @@ dependencies = [ "zeno", ] +[[package]] +name = "symlink" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" + [[package]] name = "symphonia" version = "0.5.5" @@ -7115,17 +8044,6 @@ dependencies = [ "symphonia-metadata", ] -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.117" @@ -7154,7 +8072,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -7192,13 +8110,167 @@ dependencies = [ "slotmap", ] +[[package]] +name = "tantivy" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edde6a10743fff00a4e1a8c9ef020bf5f3cbad301b7d2d39f2b07f123c4eac07" +dependencies = [ + "aho-corasick", + "arc-swap", + "base64", + "bitpacking", + "bon", + "byteorder", + "census", + "crc32fast", + "crossbeam-channel", + "datasketches", + "downcast-rs 2.0.2", + "fastdivide", + "fnv", + "fs4", + "htmlescape", + "itertools 0.14.0", + "levenshtein_automata", + "log", + "lru", + "lz4_flex", + "measure_time", + "memmap2", + "once_cell", + "oneshot", + "rayon", + "regex", + "rust-stemmers", + "rustc-hash 2.1.2", + "serde", + "serde_json", + "sketches-ddsketch", + "smallvec", + "tantivy-bitpacker", + "tantivy-columnar", + "tantivy-common", + "tantivy-fst", + "tantivy-query-grammar", + "tantivy-stacker", + "tantivy-tokenizer-api", + "tempfile", + "thiserror 2.0.18", + "time", + "typetag", + "uuid", + "winapi", +] + +[[package]] +name = "tantivy-bitpacker" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fed3d674429bcd2de5d0a6d1aa5495fed8afd9c5ecce993019caf7615f53fa4" +dependencies = [ + "bitpacking", +] + +[[package]] +name = "tantivy-columnar" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c57166f5bcfd478f370ab8445afb4678dce44801fa5ce5c451aaf8595583c5dc" +dependencies = [ + "downcast-rs 2.0.2", + "fastdivide", + "itertools 0.14.0", + "serde", + "tantivy-bitpacker", + "tantivy-common", + "tantivy-sstable", + "tantivy-stacker", +] + +[[package]] +name = "tantivy-common" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbf10915aa75da3c3b0d58b58853d2e889efbaf32d4982a4c3715dde6bba23e5" +dependencies = [ + "async-trait", + "byteorder", + "ownedbytes", + "serde", + "time", +] + +[[package]] +name = "tantivy-fst" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d60769b80ad7953d8a7b2c70cdfe722bbcdcac6bccc8ac934c40c034d866fc18" +dependencies = [ + "byteorder", + "regex-syntax", + "utf8-ranges", +] + +[[package]] +name = "tantivy-query-grammar" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfadb8526b6da90704feb293b0701a6aae62ea14983143344be2dc5ce30f1d82" +dependencies = [ + "fnv", + "nom", + "ordered-float 5.3.0", + "serde", + "serde_json", +] + +[[package]] +name = "tantivy-sstable" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a2cfc3ac5164cbadc28965ffb145a8f47582a60ae5897859ad8d4316596c606" +dependencies = [ + "futures-util", + "itertools 0.14.0", + "tantivy-bitpacker", + "tantivy-common", + "tantivy-fst", + "zstd", +] + +[[package]] +name = "tantivy-stacker" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cbb051742da9d53ca9e8fff43a9b10e319338b24e2c0e15d0372df19ffeb951" +dependencies = [ + "murmurhash32", + "tantivy-common", +] + +[[package]] +name = "tantivy-tokenizer-api" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac258c2c6390673f2685813afeeafcb8c4e0ee7de8dd3fc46838dcc37263f98" +dependencies = [ + "serde", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "tempfile" version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ - "fastrand 2.4.1", + "fastrand", "getrandom 0.4.2", "once_cell", "rustix 1.1.4", @@ -7240,7 +8312,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -7251,7 +8323,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -7263,6 +8335,37 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tiny-skia" version = "0.11.4" @@ -7325,7 +8428,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.3", + "socket2", "tokio-macros", "windows-sys 0.61.2", ] @@ -7338,7 +8441,7 @@ checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -7375,12 +8478,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "toml_datetime" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" - [[package]] name = "toml_datetime" version = "0.7.5+spec-1.1.0" @@ -7399,17 +8496,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap", - "toml_datetime 0.6.11", - "winnow 0.5.40", -] - [[package]] name = "toml_edit" version = "0.23.10+spec-1.0.0" @@ -7462,7 +8548,7 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", - "socket2 0.6.3", + "socket2", "sync_wrapper", "tokio", "tokio-stream", @@ -7550,6 +8636,19 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "050686193eb999b4bb3bc2acfa891a13da00f79734704c4b8b4ef1a10b368a3c" +dependencies = [ + "crossbeam-channel", + "symlink", + "thiserror 2.0.18", + "time", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" version = "0.1.31" @@ -7558,7 +8657,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -7647,11 +8746,200 @@ dependencies = [ "core_maths", ] +[[package]] +name = "turso" +version = "0.6.0-pre.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c331e6a1f17f7864b71b2f3c009e9c2c2624bc549ff2025831fcb3be6fa2062f" +dependencies = [ + "mimalloc", + "thiserror 2.0.18", + "tracing", + "tracing-subscriber", + "turso_core", + "turso_sdk_kit", + "turso_sync_sdk_kit", +] + +[[package]] +name = "turso_core" +version = "0.6.0-pre.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4803a83babd2a8869f1c62468d32d4bc3300b9e4287e08a7d91cc5deea2bbf13" +dependencies = [ + "aegis", + "aes", + "aes-gcm", + "antithesis_sdk", + "arc-swap", + "bigdecimal", + "bitflags 2.11.1", + "branches", + "bumpalo", + "bytemuck", + "cfg_aliases", + "cfg_block", + "chrono", + "crc32c", + "crossbeam-skiplist", + "either", + "fallible-iterator", + "fastbloom", + "hex", + "intrusive-collections", + "io-uring", + "libc", + "libloading", + "libm", + "loom", + "miette", + "num-bigint", + "num-traits", + "pack1", + "parking_lot", + "pastey", + "polling", + "rand 0.9.4", + "rapidhash", + "regex", + "regex-syntax", + "roaring", + "rustc-hash 2.1.2", + "rustix 1.1.4", + "ryu", + "serde_json", + "shuttle", + "simsimd", + "smallvec", + "strum", + "strum_macros", + "tantivy", + "tempfile", + "thiserror 2.0.18", + "tracing", + "tracing-subscriber", + "turso_ext", + "turso_macros", + "turso_parser", + "twox-hash", + "uncased", + "uuid", + "windows-sys 0.61.2", +] + +[[package]] +name = "turso_ext" +version = "0.6.0-pre.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "823ee9910bc2f59e6ce9a045b9a11c812fa67e6b8242690ff7ae9e0ac42d1782" +dependencies = [ + "chrono", + "getrandom 0.3.4", + "turso_macros", +] + +[[package]] +name = "turso_macros" +version = "0.6.0-pre.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be58b0098c329a7a80d9684c896bab5c8e1bbf4e94ec0a45d5ce89b12e41a751" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "turso_parser" +version = "0.6.0-pre.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab02213f1e7115b7a657c886bf369bf84d4cffb7ca2ba219941b1d3bd60bd92" +dependencies = [ + "bitflags 2.11.1", + "memchr", + "miette", + "strum", + "strum_macros", + "thiserror 2.0.18", + "turso_macros", +] + +[[package]] +name = "turso_sdk_kit" +version = "0.6.0-pre.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b1563ab83a79ed936935e1f3d1ebb8775c16036fd58c3d99acdd4e777a6f61" +dependencies = [ + "bindgen 0.69.5", + "env_logger", + "parking_lot", + "tracing", + "tracing-appender", + "tracing-subscriber", + "turso_core", + "turso_sdk_kit_macros", +] + +[[package]] +name = "turso_sdk_kit_macros" +version = "0.6.0-pre.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "482301b24cf8d81e87bb83c6f4efc1efdc935a0489052c0d00e2f5b4e432c10a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "turso_sync_engine" +version = "0.6.0-pre.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f187919622f8ee861637bd5ce4d779b86becf18e7446f901c28d2a49399d2b7f" +dependencies = [ + "base64", + "bytes", + "genawaiter", + "http", + "libc", + "prost", + "roaring", + "serde", + "serde_json", + "thiserror 2.0.18", + "tracing", + "turso_core", + "turso_parser", + "uuid", +] + +[[package]] +name = "turso_sync_sdk_kit" +version = "0.6.0-pre.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5f0bf6f8ca34c9148e1d799b3750c9154627a40c357761250e1930c7212128b" +dependencies = [ + "bindgen 0.69.5", + "env_logger", + "genawaiter", + "parking_lot", + "tracing", + "tracing-appender", + "tracing-subscriber", + "turso_core", + "turso_sdk_kit", + "turso_sdk_kit_macros", + "turso_sync_engine", +] + [[package]] name = "twox-hash" version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" +dependencies = [ + "rand 0.9.4", +] [[package]] name = "typeid" @@ -7665,6 +8953,30 @@ version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" +[[package]] +name = "typetag" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be2212c8a9b9bcfca32024de14998494cf9a5dfa59ea1b829de98bac374b86bf" +dependencies = [ + "erased-serde", + "inventory", + "once_cell", + "serde", + "typetag-impl", +] + +[[package]] +name = "typetag-impl" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27a7a9b72ba121f6f1f6c3632b85604cac41aedb5ddc70accbebb6cac83de846" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "typewit" version = "1.15.2" @@ -7677,11 +8989,20 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" dependencies = [ - "memoffset 0.9.1", + "memoffset", "tempfile", "windows-sys 0.61.2", ] +[[package]] +name = "uncased" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.18" @@ -7739,6 +9060,16 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "untrusted" version = "0.9.0" @@ -7757,12 +9088,24 @@ dependencies = [ "serde", ] +[[package]] +name = "utf8-ranges" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba" + [[package]] name = "utf8_iter" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "uuid" version = "1.23.1" @@ -7772,6 +9115,7 @@ dependencies = [ "getrandom 0.4.2", "js-sys", "serde_core", + "sha1_smol", "wasm-bindgen", ] @@ -7789,7 +9133,7 @@ checksum = "41b6d82be61465f97d42bd1d15bf20f3b0a3a0905018f38f9d6f6962055b0b5c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -7810,12 +9154,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "waker-fn" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" - [[package]] name = "walkdir" version = "2.5.0" @@ -7907,7 +9245,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.117", + "syn", "wasm-bindgen-shared", ] @@ -8227,7 +9565,7 @@ dependencies = [ "ndk-sys 0.6.0+11769913", "objc", "once_cell", - "ordered-float", + "ordered-float 4.6.0", "parking_lot", "portable-atomic", "portable-atomic-util", @@ -8259,6 +9597,18 @@ dependencies = [ "web-sys", ] +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix 0.38.44", +] + [[package]] name = "whoami" version = "1.6.1" @@ -8442,7 +9792,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -8453,7 +9803,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -8464,7 +9814,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -8475,7 +9825,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -8490,6 +9840,19 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-native-keyring-store" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5fd986f648459dd29aa252ed3a5ad11a60c0b1251bf81625fb03a86c69d274e" +dependencies = [ + "byteorder", + "keyring-core", + "regex", + "windows-sys 0.61.2", + "zeroize", +] + [[package]] name = "windows-numerics" version = "0.2.0" @@ -8941,15 +10304,6 @@ dependencies = [ "xkbcommon-dl", ] -[[package]] -name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - [[package]] name = "winnow" version = "0.7.15" @@ -9004,7 +10358,7 @@ dependencies = [ "heck", "indexmap", "prettyplease", - "syn 2.0.117", + "syn", "wasm-metadata", "wit-bindgen-core", "wit-component", @@ -9020,7 +10374,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.117", + "syn", "wit-bindgen-core", "wit-bindgen-rust", ] @@ -9068,6 +10422,15 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "x11-dl" version = "2.21.0" @@ -9106,16 +10469,6 @@ version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b" -[[package]] -name = "xdg-home" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - [[package]] name = "xkbcommon-dl" version = "0.4.2" @@ -9166,73 +10519,79 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", "synstructure", ] [[package]] name = "zbus" -version = "3.15.2" +version = "5.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "675d170b632a6ad49804c8cf2105d7c31eddd3312555cffd4b740e08e97c25e6" +checksum = "c3bcbf15c8708d7fc1be0c993622e0a5cbd5e8b52bfa40afa4c3e0cd8d724ac1" dependencies = [ - "async-broadcast 0.5.1", + "async-broadcast", "async-executor", - "async-fs 1.6.0", - "async-io 1.13.0", - "async-lock 2.8.0", + "async-io", + "async-lock", "async-process", "async-recursion", "async-task", "async-trait", "blocking", - "byteorder", - "derivative", "enumflags2", - "event-listener 2.5.3", + "event-listener", "futures-core", - "futures-sink", - "futures-util", + "futures-lite", "hex", - "nix 0.26.4", - "once_cell", + "libc", "ordered-stream", - "rand 0.8.6", + "rustix 1.1.4", "serde", "serde_repr", - "sha1", - "static_assertions", "tracing", "uds_windows", - "winapi", - "xdg-home", + "uuid", + "windows-sys 0.61.2", + "winnow 1.0.2", "zbus_macros", "zbus_names", "zvariant", ] [[package]] -name = "zbus_macros" -version = "3.15.2" +name = "zbus-secret-service-keyring-store" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7131497b0f887e8061b430c530240063d33bf9455fa34438f388a245da69e0a5" +checksum = "4ccede190ba363386a24e8021c7f3848393976609ec9f5d1f8c6c09ef37075b4" dependencies = [ - "proc-macro-crate 1.3.1", + "keyring-core", + "secret-service", + "zbus", +] + +[[package]] +name = "zbus_macros" +version = "5.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51fa5406ad9175a8c825a931f8cf347116b531b3634fcb0b627c290f1f2516ff" +dependencies = [ + "proc-macro-crate", "proc-macro2", "quote", - "regex", - "syn 1.0.109", + "syn", + "zbus_names", + "zvariant", "zvariant_utils", ] [[package]] name = "zbus_names" -version = "2.6.1" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d" +checksum = "7074f3e50b894eac91750142016d30d0a89be8e67dbfd9704fb875825760e52d" dependencies = [ "serde", - "static_assertions", + "winnow 1.0.2", "zvariant", ] @@ -9259,7 +10618,7 @@ checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -9279,7 +10638,7 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", "synstructure", ] @@ -9288,6 +10647,20 @@ name = "zeroize" version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "zerotrie" @@ -9319,7 +10692,7 @@ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn", ] [[package]] @@ -9329,39 +10702,69 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] -name = "zvariant" -version = "3.15.2" +name = "zstd" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eef2be88ba09b358d3b58aca6e41cd853631d44787f319a1383ca83424fb2db" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" dependencies = [ - "byteorder", + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "zvariant" +version = "5.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db0ecb8987cf5e92653c57c098f7f0e39a03112edb796f4fe089fb7eaa14ff" +dependencies = [ + "endi", "enumflags2", - "libc", "serde", - "static_assertions", + "winnow 1.0.2", "zvariant_derive", + "zvariant_utils", ] [[package]] name = "zvariant_derive" -version = "3.15.2" +version = "5.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c24dc0bed72f5f90d1f8bb5b07228cbf63b3c6e9f82d82559d4bae666e7ed9" +checksum = "5b949b639ab1b4bed763aa7481ba0e368af68d8b55532f8ed4bec86a59f2ca98" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn", "zvariant_utils", ] [[package]] name = "zvariant_utils" -version = "1.0.1" +version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7234f0d811589db492d16893e3f21e8e2fd282e6d01b0cddee310322062cc200" +checksum = "6d464f5733ffa07a3164d656f18533caace9d0638596721355d73256a410d691" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "serde", + "syn", + "winnow 1.0.2", ] diff --git a/Cargo.toml b/Cargo.toml index d8003ff..762769f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,8 @@ rand = "0.8" async-trait = "0.1" tokio = { version = "1", features = ["full"] } dirs = "6" -keyring = "2" +keyring = "4" +keyring-core = "1" reqwest = { version = "0.13", features = ["json", "rustls", "rustls-native-certs"], default-features = false } solitaire_core = { path = "solitaire_core" } diff --git a/assets/backgrounds/bg_0.png b/assets/backgrounds/bg_0.png new file mode 100644 index 0000000..8848cb6 Binary files /dev/null and b/assets/backgrounds/bg_0.png differ diff --git a/assets/backgrounds/bg_1.png b/assets/backgrounds/bg_1.png new file mode 100644 index 0000000..c5d24dd Binary files /dev/null and b/assets/backgrounds/bg_1.png differ diff --git a/assets/backgrounds/bg_2.png b/assets/backgrounds/bg_2.png new file mode 100644 index 0000000..8501a49 Binary files /dev/null and b/assets/backgrounds/bg_2.png differ diff --git a/assets/backgrounds/bg_3.png b/assets/backgrounds/bg_3.png new file mode 100644 index 0000000..c61c299 Binary files /dev/null and b/assets/backgrounds/bg_3.png differ diff --git a/assets/backgrounds/bg_4.png b/assets/backgrounds/bg_4.png new file mode 100644 index 0000000..a0413dc Binary files /dev/null and b/assets/backgrounds/bg_4.png differ diff --git a/assets/cards/backs/back_0.png b/assets/cards/backs/back_0.png new file mode 100644 index 0000000..e49bed3 Binary files /dev/null and b/assets/cards/backs/back_0.png differ diff --git a/assets/cards/backs/back_1.png b/assets/cards/backs/back_1.png new file mode 100644 index 0000000..db1e94b Binary files /dev/null and b/assets/cards/backs/back_1.png differ diff --git a/assets/cards/backs/back_2.png b/assets/cards/backs/back_2.png new file mode 100644 index 0000000..253fd51 Binary files /dev/null and b/assets/cards/backs/back_2.png differ diff --git a/assets/cards/backs/back_3.png b/assets/cards/backs/back_3.png new file mode 100644 index 0000000..0532928 Binary files /dev/null and b/assets/cards/backs/back_3.png differ diff --git a/assets/cards/backs/back_4.png b/assets/cards/backs/back_4.png new file mode 100644 index 0000000..24d78fe Binary files /dev/null and b/assets/cards/backs/back_4.png differ diff --git a/assets/cards/faces/face.png b/assets/cards/faces/face.png new file mode 100644 index 0000000..8aa25cf Binary files /dev/null and b/assets/cards/faces/face.png differ diff --git a/assets/fonts/main.ttf b/assets/fonts/main.ttf new file mode 100644 index 0000000..1e95ced Binary files /dev/null and b/assets/fonts/main.ttf differ diff --git a/solitaire_app/Cargo.toml b/solitaire_app/Cargo.toml index a442a4b..5e1fb49 100644 --- a/solitaire_app/Cargo.toml +++ b/solitaire_app/Cargo.toml @@ -12,3 +12,4 @@ path = "src/main.rs" bevy = { workspace = true } solitaire_engine = { workspace = true } solitaire_data = { workspace = true } +keyring = { workspace = true } diff --git a/solitaire_app/src/main.rs b/solitaire_app/src/main.rs index fb2d4c9..992c934 100644 --- a/solitaire_app/src/main.rs +++ b/solitaire_app/src/main.rs @@ -3,12 +3,24 @@ use solitaire_data::{load_settings_from, provider_for_backend, settings_file_pat use solitaire_engine::{ AchievementPlugin, AnimationPlugin, AudioPlugin, AutoCompletePlugin, CardAnimationPlugin, CardPlugin, ChallengePlugin, CursorPlugin, DailyChallengePlugin, FeedbackAnimPlugin, - GamePlugin, HelpPlugin, HomePlugin, HudPlugin, InputPlugin, LeaderboardPlugin, + FontPlugin, GamePlugin, HelpPlugin, HomePlugin, HudPlugin, InputPlugin, LeaderboardPlugin, OnboardingPlugin, PausePlugin, ProfilePlugin, ProgressPlugin, SelectionPlugin, SettingsPlugin, StatsPlugin, SyncPlugin, TablePlugin, TimeAttackPlugin, WeeklyGoalsPlugin, WinSummaryPlugin, }; fn main() { + // Initialise the platform keyring store before any token operations. + // On Linux this uses the Secret Service (GNOME Keyring / KWallet); on + // macOS it uses the Keychain; on Windows it uses the Credential store. + // If the platform has no OS keyring (e.g. a headless CI box), keyring + // operations will fail gracefully with TokenError::KeychainUnavailable. + if let Err(e) = keyring::use_native_store(true) { + eprintln!( + "warn: could not initialise OS keyring ({e}); \ + server sync login will be unavailable" + ); + } + // Load settings before building the app so we can construct the right // sync provider. Falls back to defaults if no settings file exists yet. let settings: Settings = settings_file_path() @@ -32,6 +44,7 @@ fn main() { ..default() }), ) + .add_plugins(FontPlugin) .add_plugins(GamePlugin) .add_plugins(TablePlugin) .add_plugins(CardPlugin) diff --git a/solitaire_assetgen/Cargo.toml b/solitaire_assetgen/Cargo.toml index 1151841..2b69fd0 100644 --- a/solitaire_assetgen/Cargo.toml +++ b/solitaire_assetgen/Cargo.toml @@ -5,9 +5,17 @@ license.workspace = true edition.workspace = true publish = false -# Dev-only utility: synthesizes placeholder SFX WAV files into `assets/audio/`. +# Dev-only utility: synthesizes placeholder SFX WAV files into `assets/audio/` +# and placeholder PNG images into `assets/cards/` and `assets/backgrounds/`. # Not depended on by any other workspace crate. +[dependencies] +png = "0.17" + [[bin]] name = "gen_sfx" path = "src/bin/gen_sfx.rs" + +[[bin]] +name = "gen_art" +path = "src/bin/gen_art.rs" diff --git a/solitaire_assetgen/src/bin/gen_art.rs b/solitaire_assetgen/src/bin/gen_art.rs new file mode 100644 index 0000000..551e1a1 --- /dev/null +++ b/solitaire_assetgen/src/bin/gen_art.rs @@ -0,0 +1,229 @@ +//! Generates placeholder PNG assets for card faces, card backs, and table +//! backgrounds. All images are 16×16 pixels — Bevy's Sprite scales them via +//! `custom_size`, so small files keep the repository lightweight. +//! +//! Run with: +//! ``` +//! cargo run -p solitaire_assetgen --bin gen_art +//! ``` + +use std::fs::File; +use std::io::BufWriter; +use std::path::Path; + +// --------------------------------------------------------------------------- +// PNG helper +// --------------------------------------------------------------------------- + +/// Write a 16×16 RGBA image to `path`. `pixels` is a flat `[R,G,B,A, ...]` +/// byte array with exactly 16 * 16 * 4 = 1024 bytes. +fn save_png(path: &Path, pixels: &[u8; 1024]) { + let file = File::create(path) + .unwrap_or_else(|e| panic!("cannot create {}: {e}", path.display())); + let mut w = BufWriter::new(file); + let mut encoder = png::Encoder::new(&mut w, 16, 16); + encoder.set_color(png::ColorType::Rgba); + encoder.set_depth(png::BitDepth::Eight); + let mut writer = encoder + .write_header() + .unwrap_or_else(|e| panic!("png header error for {}: {e}", path.display())); + writer + .write_image_data(pixels) + .unwrap_or_else(|e| panic!("png data error for {}: {e}", path.display())); +} + +/// Build a flat 16×16 RGBA pixel array using a per-pixel closure. +fn make_image [u8; 4]>(f: F) -> [u8; 1024] { + let mut pixels = [0u8; 1024]; + for y in 0u32..16 { + for x in 0u32..16 { + let rgba = f(x, y); + let i = ((y * 16 + x) * 4) as usize; + pixels[i..i + 4].copy_from_slice(&rgba); + } + } + pixels +} + +// --------------------------------------------------------------------------- +// Card face +// --------------------------------------------------------------------------- + +/// Cream/ivory solid fill — represents a blank card face. +fn make_face() -> [u8; 1024] { + make_image(|_, _| [0xF8, 0xF8, 0xF0, 0xFF]) +} + +// --------------------------------------------------------------------------- +// Card backs (match the colours used in card_plugin.rs `card_back_colour()`) +// --------------------------------------------------------------------------- + +/// back_0 — blue base with semi-transparent white horizontal stripes every 4 px. +fn make_back_0() -> [u8; 1024] { + make_image(|_, y| { + if y % 4 < 2 { + [0xFF, 0xFF, 0xFF, 40] + } else { + [0x26, 0x4D, 0x8C, 0xFF] + } + }) +} + +/// back_1 — red base with semi-transparent white diagonal stripes. +fn make_back_1() -> [u8; 1024] { + make_image(|x, y| { + if (x + y) % 4 < 2 { + [0xFF, 0xFF, 0xFF, 40] + } else { + [0x8C, 0x1A, 0x1A, 0xFF] + } + }) +} + +/// back_2 — green base with white dots at every 4-px grid intersection. +fn make_back_2() -> [u8; 1024] { + make_image(|x, y| { + if x % 4 == 0 && y % 4 == 0 { + [0xFF, 0xFF, 0xFF, 0xFF] + } else { + [0x0D, 0x66, 0x1A, 0xFF] + } + }) +} + +/// back_3 — purple base with a white diamond centred at (8, 8). +fn make_back_3() -> [u8; 1024] { + make_image(|x, y| { + let dx = (x as i32 - 8).unsigned_abs(); + let dy = (y as i32 - 8).unsigned_abs(); + if dx + dy <= 4 { + [0xFF, 0xFF, 0xFF, 0xFF] + } else { + [0x59, 0x14, 0x85, 0xFF] + } + }) +} + +/// back_4 — teal base with a 1-px white border. +fn make_back_4() -> [u8; 1024] { + make_image(|x, y| { + if x == 0 || x == 15 || y == 0 || y == 15 { + [0xFF, 0xFF, 0xFF, 0xFF] + } else { + [0x0D, 0x66, 0x6B, 0xFF] + } + }) +} + +// --------------------------------------------------------------------------- +// Backgrounds +// --------------------------------------------------------------------------- + +/// bg_0 — dark green felt with very faint lighter grid lines every 8 px. +fn make_bg_0() -> [u8; 1024] { + make_image(|x, y| { + if x % 8 == 0 || y % 8 == 0 { + [0xFF, 0xFF, 0xFF, 30] + } else { + [0x1A, 0x4D, 0x1A, 0xFF] + } + }) +} + +/// bg_1 — dark wood brown with faint horizontal grain lines every 2 px. +fn make_bg_1() -> [u8; 1024] { + make_image(|_, y| { + if y % 2 == 0 { + [0xFF, 0xFF, 0xFF, 20] + } else { + [0x40, 0x2D, 0x1A, 0xFF] + } + }) +} + +/// bg_2 — navy with faint star/dot pattern (offset rows) every 8 px. +fn make_bg_2() -> [u8; 1024] { + make_image(|x, y| { + let row_offset: u32 = if (y / 4) % 2 == 0 { 0 } else { 4 }; + if (x + row_offset) % 8 == 0 && y % 8 == 0 { + [0xFF, 0xFF, 0xFF, 0xFF] + } else { + [0x0D, 0x14, 0x38, 0xFF] + } + }) +} + +/// bg_3 — burgundy with a faint diamond-grid pattern. +fn make_bg_3() -> [u8; 1024] { + make_image(|x, y| { + if (x + y) % 8 == 0 { + [0xFF, 0xFF, 0xFF, 30] + } else { + [0x4D, 0x0D, 0x14, 0xFF] + } + }) +} + +/// bg_4 — charcoal with faint pixel noise (alternating pixels every 3 columns). +fn make_bg_4() -> [u8; 1024] { + make_image(|x, y| { + if (x + y) % 2 == 0 && x % 3 == 0 { + [0xFF, 0xFF, 0xFF, 20] + } else { + [0x1F, 0x1F, 0x24, 0xFF] + } + }) +} + +// --------------------------------------------------------------------------- +// Entry point +// --------------------------------------------------------------------------- + +fn workspace_root() -> std::path::PathBuf { + let crate_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); + crate_dir.parent().unwrap().to_path_buf() +} + +fn main() { + let root = workspace_root(); + + // Ensure output directories exist. + std::fs::create_dir_all(root.join("assets/cards/faces")).unwrap(); + std::fs::create_dir_all(root.join("assets/cards/backs")).unwrap(); + std::fs::create_dir_all(root.join("assets/backgrounds")).unwrap(); + + // Card face. + let path = root.join("assets/cards/faces/face.png"); + save_png(&path, &make_face()); + println!("wrote {}", path.display()); + + // Card backs. + let backs = [ + make_back_0(), + make_back_1(), + make_back_2(), + make_back_3(), + make_back_4(), + ]; + for (i, pixels) in backs.iter().enumerate() { + let path = root.join(format!("assets/cards/backs/back_{i}.png")); + save_png(&path, pixels); + println!("wrote {}", path.display()); + } + + // Backgrounds. + let bgs = [ + make_bg_0(), + make_bg_1(), + make_bg_2(), + make_bg_3(), + make_bg_4(), + ]; + for (i, pixels) in bgs.iter().enumerate() { + let path = root.join(format!("assets/backgrounds/bg_{i}.png")); + save_png(&path, pixels); + println!("wrote {}", path.display()); + } + + println!("gen_art: all placeholder PNG assets generated successfully."); +} diff --git a/solitaire_data/Cargo.toml b/solitaire_data/Cargo.toml index de1d173..98eb690 100644 --- a/solitaire_data/Cargo.toml +++ b/solitaire_data/Cargo.toml @@ -13,6 +13,6 @@ chrono = { workspace = true } thiserror = { workspace = true } async-trait = { workspace = true } dirs = { workspace = true } -keyring = { workspace = true } +keyring-core = { workspace = true } reqwest = { workspace = true } tokio = { workspace = true } diff --git a/solitaire_data/src/auth_tokens.rs b/solitaire_data/src/auth_tokens.rs index fbfaee6..653f22a 100644 --- a/solitaire_data/src/auth_tokens.rs +++ b/solitaire_data/src/auth_tokens.rs @@ -8,9 +8,15 @@ //! [`TokenError::KeychainUnavailable`] — callers should fall back to prompting //! the user to log in again. //! +//! Before calling any function in this module the application must initialise +//! the default keyring store exactly once at startup by calling +//! `keyring::use_native_store` (e.g. in `solitaire_app::main` before building +//! the Bevy `App`). If no default store is set, all operations in this module +//! will return [`TokenError::KeychainUnavailable`]. +//! //! # Note: no unit tests — requires live OS keychain. -use keyring::Entry; +use keyring_core::Entry; use thiserror::Error; /// Errors that can occur when reading or writing tokens in the OS keychain. @@ -30,12 +36,13 @@ pub enum TokenError { /// Service name used to namespace all keychain entries for this application. const SERVICE: &str = "solitaire_quest_server"; -/// Map a `keyring::Error` to the appropriate `TokenError`. -fn map_keyring_err(err: keyring::Error, username: &str) -> TokenError { +/// Map a `keyring_core::Error` to the appropriate `TokenError`. +fn map_keyring_err(err: keyring_core::Error, username: &str) -> TokenError { let msg = err.to_string(); match err { - keyring::Error::NoStorageAccess(_) => TokenError::KeychainUnavailable(msg), - keyring::Error::NoEntry => TokenError::NotFound(username.to_string()), + keyring_core::Error::NoStorageAccess(_) => TokenError::KeychainUnavailable(msg), + keyring_core::Error::NoDefaultStore => TokenError::KeychainUnavailable(msg), + keyring_core::Error::NoEntry => TokenError::NotFound(username.to_string()), _ => TokenError::Keyring(msg), } } @@ -88,17 +95,17 @@ pub fn load_refresh_token(username: &str) -> Result { pub fn delete_tokens(username: &str) -> Result<(), TokenError> { match Entry::new(SERVICE, &format!("{username}_access")) .map_err(|e| map_keyring_err(e, username))? - .delete_password() + .delete_credential() { - Ok(()) | Err(keyring::Error::NoEntry) => {} + Ok(()) | Err(keyring_core::Error::NoEntry) => {} Err(e) => return Err(map_keyring_err(e, username)), } match Entry::new(SERVICE, &format!("{username}_refresh")) .map_err(|e| map_keyring_err(e, username))? - .delete_password() + .delete_credential() { - Ok(()) | Err(keyring::Error::NoEntry) => {} + Ok(()) | Err(keyring_core::Error::NoEntry) => {} Err(e) => return Err(map_keyring_err(e, username)), } diff --git a/solitaire_engine/src/card_plugin.rs b/solitaire_engine/src/card_plugin.rs index 1e02376..6be71d9 100644 --- a/solitaire_engine/src/card_plugin.rs +++ b/solitaire_engine/src/card_plugin.rs @@ -47,6 +47,19 @@ pub const CARD_FACE_COLOUR: Color = Color::srgb(0.98, 0.98, 0.95); pub const RED_SUIT_COLOUR: Color = Color::srgb(0.78, 0.12, 0.15); pub const BLACK_SUIT_COLOUR: Color = Color::srgb(0.08, 0.08, 0.08); +/// Pre-loaded [`Handle`]s for card face and back PNG textures. +/// +/// Loaded once at startup by [`load_card_images`]. When this resource is +/// present, card sprites use the PNG artwork; otherwise they fall back to +/// solid-colour sprites (used in tests with `MinimalPlugins`). +#[derive(Resource)] +pub struct CardImageSet { + /// Shared face image used for all face-up cards. + pub face: Handle, + /// One handle per unlockable card-back design (indices 0–4). + pub backs: [Handle; 5], +} + /// Alternative face tint for red-suit cards in color-blind mode — a subtle /// blue wash that distinguishes them from black-suit cards without colour alone. const CARD_FACE_COLOUR_RED_CBM: Color = Color::srgba(0.85, 0.92, 1.0, 1.0); @@ -160,6 +173,7 @@ impl Plugin for CardPlugin { .add_message::() .add_message::() .add_message::() + .add_systems(Startup, load_card_images) .add_systems(PostStartup, (sync_cards_startup, update_stock_empty_indicator_startup)) .add_systems( Update, @@ -180,6 +194,81 @@ impl Plugin for CardPlugin { } } +/// Loads card face and back PNGs at startup and inserts [`CardImageSet`]. +/// +/// The PNGs are embedded at compile time via `include_bytes!()`. Missing +/// files are compile errors, not runtime panics. Under `MinimalPlugins` +/// (tests) this system is still registered but `Assets` is unavailable, +/// so it does nothing and the plugin falls back to solid-colour sprites. +fn load_card_images(images: Option>>, mut commands: Commands) { + let Some(mut images) = images else { + // Assets is absent (e.g. MinimalPlugins in tests) — skip so + // tests can still run. The plugin falls back to solid-colour sprites. + return; + }; + use bevy::asset::RenderAssetUsages; + use bevy::image::{CompressedImageFormats, ImageSampler, ImageType}; + + let load = |bytes: &[u8]| { + Image::from_buffer( + bytes, + ImageType::Extension("png"), + CompressedImageFormats::NONE, + true, + ImageSampler::default(), + RenderAssetUsages::RENDER_WORLD, + ) + .expect("valid card PNG") + }; + + let face = images.add(load(include_bytes!("../../assets/cards/faces/face.png"))); + let backs = [ + images.add(load(include_bytes!("../../assets/cards/backs/back_0.png"))), + images.add(load(include_bytes!("../../assets/cards/backs/back_1.png"))), + images.add(load(include_bytes!("../../assets/cards/backs/back_2.png"))), + images.add(load(include_bytes!("../../assets/cards/backs/back_3.png"))), + images.add(load(include_bytes!("../../assets/cards/backs/back_4.png"))), + ]; + commands.insert_resource(CardImageSet { face, backs }); +} + +/// Builds the [`Sprite`] for a card, using PNG artwork when [`CardImageSet`] is +/// available and falling back to a solid-colour sprite in tests. +fn card_sprite( + card: &Card, + card_size: Vec2, + back_colour: Color, + color_blind: bool, + card_images: Option<&CardImageSet>, + selected_back: usize, +) -> Sprite { + if let Some(set) = card_images { + let image = if card.face_up { + set.face.clone() + } else { + let idx = selected_back.min(set.backs.len() - 1); + set.backs[idx].clone() + }; + Sprite { + image, + color: Color::WHITE, + custom_size: Some(card_size), + ..default() + } + } else { + let body_colour = if card.face_up { + face_colour(card, color_blind) + } else { + back_colour + }; + Sprite { + color: body_colour, + custom_size: Some(card_size), + ..default() + } + } +} + /// When card-back selection changes in Settings, re-render all cards so the /// new back colour is applied immediately (without waiting for a state change). fn resync_cards_on_settings_change( @@ -201,14 +290,14 @@ fn sync_cards_startup( slide_dur: Option>, settings: Option>, entities: Query<(Entity, &CardEntity, &Transform)>, + card_images: Option>, ) { if let Some(layout) = layout { let slide_secs = slide_dur.map_or(0.15, |d| d.slide_secs); - let back_colour = settings - .as_ref() - .map_or_else(|| card_back_colour(0), |s| card_back_colour(s.0.selected_card_back)); + let selected_back = settings.as_ref().map_or(0, |s| s.0.selected_card_back); + let back_colour = card_back_colour(selected_back); let color_blind = settings.as_ref().is_some_and(|s| s.0.color_blind_mode); - sync_cards(commands, &game.0, &layout.0, slide_secs, back_colour, color_blind, &entities); + sync_cards(commands, &game.0, &layout.0, slide_secs, back_colour, color_blind, &entities, card_images.as_deref(), selected_back); } } @@ -220,17 +309,17 @@ fn sync_cards_on_change( slide_dur: Option>, settings: Option>, entities: Query<(Entity, &CardEntity, &Transform)>, + card_images: Option>, ) { if events.read().next().is_none() { return; } if let Some(layout) = layout { let slide_secs = slide_dur.map_or(0.15, |d| d.slide_secs); - let back_colour = settings - .as_ref() - .map_or_else(|| card_back_colour(0), |s| card_back_colour(s.0.selected_card_back)); + let selected_back = settings.as_ref().map_or(0, |s| s.0.selected_card_back); + let back_colour = card_back_colour(selected_back); let color_blind = settings.as_ref().is_some_and(|s| s.0.color_blind_mode); - sync_cards(commands, &game.0, &layout.0, slide_secs, back_colour, color_blind, &entities); + sync_cards(commands, &game.0, &layout.0, slide_secs, back_colour, color_blind, &entities, card_images.as_deref(), selected_back); } } @@ -242,6 +331,8 @@ fn sync_cards( back_colour: Color, color_blind: bool, entities: &Query<(Entity, &CardEntity, &Transform)>, + card_images: Option<&CardImageSet>, + selected_back: usize, ) { let positions = card_positions(game, layout); @@ -266,10 +357,10 @@ fn sync_cards( Some(&(entity, cur)) => { update_card_entity( &mut commands, entity, card, position, z, layout, - slide_secs, back_colour, color_blind, cur, + slide_secs, back_colour, color_blind, cur, card_images, selected_back, ) } - None => spawn_card_entity(&mut commands, card, position, z, layout, back_colour, color_blind), + None => spawn_card_entity(&mut commands, card, position, z, layout, back_colour, color_blind, card_images, selected_back), } } } @@ -358,21 +449,23 @@ fn face_colour(card: &Card, color_blind: bool) -> Color { } } -fn spawn_card_entity(commands: &mut Commands, card: &Card, pos: Vec2, z: f32, layout: &Layout, back_colour: Color, color_blind: bool) { - let body_colour = if card.face_up { - face_colour(card, color_blind) - } else { - back_colour - }; +fn spawn_card_entity( + commands: &mut Commands, + card: &Card, + pos: Vec2, + z: f32, + layout: &Layout, + back_colour: Color, + color_blind: bool, + card_images: Option<&CardImageSet>, + selected_back: usize, +) { + let sprite = card_sprite(card, layout.card_size, back_colour, color_blind, card_images, selected_back); commands .spawn(( CardEntity { card_id: card.id }, - Sprite { - color: body_colour, - custom_size: Some(layout.card_size), - ..default() - }, + sprite, Transform::from_xyz(pos.x, pos.y, z), Visibility::default(), )) @@ -405,21 +498,13 @@ fn update_card_entity( back_colour: Color, color_blind: bool, cur: Vec3, + card_images: Option<&CardImageSet>, + selected_back: usize, ) { - let body_colour = if card.face_up { - face_colour(card, color_blind) - } else { - back_colour - }; - let target = Vec3::new(pos.x, pos.y, z); // Always refresh the visual appearance. - commands.entity(entity).insert(Sprite { - color: body_colour, - custom_size: Some(layout.card_size), - ..default() - }); + commands.entity(entity).insert(card_sprite(card, layout.card_size, back_colour, color_blind, card_images, selected_back)); // Slide to the new position when it differs meaningfully; snap otherwise. if (cur.truncate() - target.truncate()).length() > 1.0 && slide_secs > 0.0 { @@ -653,20 +738,24 @@ fn tick_hint_highlight( mut query: Query<(Entity, &mut HintHighlight, &mut Sprite, &CardEntity)>, game: Res, settings: Option>, + card_images: Option>, ) { let back_idx = settings.as_ref().map_or(0, |s| s.0.selected_card_back); + let use_images = card_images.is_some(); for (entity, mut hint, mut sprite, card_entity) in query.iter_mut() { hint.remaining -= time.delta_secs(); if hint.remaining <= 0.0 { - // Restore normal face-up colour. - let is_face_up = game.0.piles.values() - .flat_map(|p| p.cards.iter()) - .find(|c| c.id == card_entity.card_id) - .is_some_and(|c| c.face_up); - sprite.color = if is_face_up { - CARD_FACE_COLOUR + // Restore the normal sprite colour. + // When image-based rendering is active, WHITE is the neutral tint; + // otherwise restore the solid colour appropriate to the card state. + sprite.color = if use_images { + Color::WHITE } else { - card_back_colour(back_idx) + let is_face_up = game.0.piles.values() + .flat_map(|p| p.cards.iter()) + .find(|c| c.id == card_entity.card_id) + .is_some_and(|c| c.face_up); + if is_face_up { CARD_FACE_COLOUR } else { card_back_colour(back_idx) } }; commands .entity(entity) diff --git a/solitaire_engine/src/font_plugin.rs b/solitaire_engine/src/font_plugin.rs new file mode 100644 index 0000000..22e588b --- /dev/null +++ b/solitaire_engine/src/font_plugin.rs @@ -0,0 +1,36 @@ +// Register FontPlugin in solitaire_engine/src/lib.rs before use. + +//! Embeds FiraMono-Medium as the project font and exposes it via [`FontResource`]. + +use bevy::prelude::*; + +/// Holds the project-wide [`Handle`] loaded at startup. +#[derive(Resource)] +pub struct FontResource(pub Handle); + +/// Loads FiraMono-Medium at startup and inserts [`FontResource`]. +pub struct FontPlugin; + +impl Plugin for FontPlugin { + fn build(&self, app: &mut App) { + app.add_systems(Startup, load_font); + } +} + +fn load_font(fonts: Option>>, mut commands: Commands) { + let Some(mut fonts) = fonts else { + // Assets absent (e.g. MinimalPlugins in tests) — insert default. + commands.insert_resource(FontResource(Handle::default())); + return; + }; + let bytes: &'static [u8] = include_bytes!("../../assets/fonts/main.ttf"); + match Font::try_from_bytes(bytes.to_vec()) { + Ok(font) => { + commands.insert_resource(FontResource(fonts.add(font))); + } + Err(e) => { + warn!("failed to load main.ttf: {e}; falling back to Bevy default font"); + commands.insert_resource(FontResource(Handle::default())); + } + } +} diff --git a/solitaire_engine/src/hud_plugin.rs b/solitaire_engine/src/hud_plugin.rs index 4d0d54a..5996026 100644 --- a/solitaire_engine/src/hud_plugin.rs +++ b/solitaire_engine/src/hud_plugin.rs @@ -14,6 +14,7 @@ use solitaire_core::pile::PileType; use crate::auto_complete_plugin::AutoCompleteState; use crate::daily_challenge_plugin::DailyChallengeResource; use crate::events::InfoToastEvent; +use crate::font_plugin::FontResource; use crate::game_plugin::GameMutation; use crate::resources::GameStateResource; use crate::selection_plugin::SelectionState; @@ -98,9 +99,13 @@ impl Plugin for HudPlugin { } } -fn spawn_hud(mut commands: Commands) { +fn spawn_hud(font_res: Option>, mut commands: Commands) { let white = TextColor(Color::srgba(1.0, 1.0, 1.0, 0.80)); - let font = TextFont { font_size: 18.0, ..default() }; + let font = TextFont { + font: font_res.as_ref().map(|f| f.0.clone()).unwrap_or_default(), + font_size: 18.0, + ..default() + }; commands .spawn(( Node { diff --git a/solitaire_engine/src/input_plugin.rs b/solitaire_engine/src/input_plugin.rs index 390fe26..fa156b3 100644 --- a/solitaire_engine/src/input_plugin.rs +++ b/solitaire_engine/src/input_plugin.rs @@ -252,7 +252,7 @@ fn handle_keyboard_hint( mut confirm: ResMut, mut hint_cycle: ResMut, mut commands: Commands, - card_entities: Query<(Entity, &CardEntity, &Sprite)>, + mut card_entities: Query<(Entity, &CardEntity, &mut Sprite)>, mut info_toast: MessageWriter, mut hint_visual: MessageWriter, ) { @@ -308,16 +308,14 @@ fn handle_keyboard_hint( .and_then(|p| p.cards.last().filter(|c| c.face_up)) .map(|c| c.id); if let Some(card_id) = top_card_id { - for (entity, card_entity, _sprite) in card_entities.iter() { + for (entity, card_entity, mut sprite) in card_entities.iter_mut() { if card_entity.card_id == card_id { + // Tint the card gold without replacing the Sprite (which would + // discard the image handle set by CardImageSet). + sprite.color = Color::srgba(1.0, 1.0, 0.4, 1.0); commands.entity(entity) .insert(HintHighlight { remaining: 2.0 }) - .insert(HintHighlightTimer(2.0)) - .insert(Sprite { - color: Color::srgba(1.0, 1.0, 0.4, 1.0), - custom_size: Some(layout_res.0.card_size), - ..default() - }); + .insert(HintHighlightTimer(2.0)); break; } } diff --git a/solitaire_engine/src/lib.rs b/solitaire_engine/src/lib.rs index db39bf9..79859eb 100644 --- a/solitaire_engine/src/lib.rs +++ b/solitaire_engine/src/lib.rs @@ -6,6 +6,7 @@ pub mod animation_plugin; pub mod auto_complete_plugin; pub mod audio_plugin; pub mod card_plugin; +pub mod font_plugin; pub mod feedback_anim_plugin; pub mod challenge_plugin; pub mod cursor_plugin; @@ -59,9 +60,10 @@ pub use feedback_anim_plugin::{ pub use auto_complete_plugin::AutoCompletePlugin; pub use audio_plugin::{AudioPlugin, AudioState, SoundLibrary}; pub use card_plugin::{ - CardEntity, CardLabel, CardPlugin, HintHighlight, HintHighlightTimer, RightClickHighlight, - RightClickHighlightTimer, + CardEntity, CardImageSet, CardLabel, CardPlugin, HintHighlight, HintHighlightTimer, + RightClickHighlight, RightClickHighlightTimer, }; +pub use font_plugin::{FontPlugin, FontResource}; pub use cursor_plugin::CursorPlugin; pub use events::{ AchievementUnlockedEvent, CardFaceRevealedEvent, CardFlippedEvent, DrawRequestEvent, diff --git a/solitaire_engine/src/table_plugin.rs b/solitaire_engine/src/table_plugin.rs index 053c845..49ab16b 100644 --- a/solitaire_engine/src/table_plugin.rs +++ b/solitaire_engine/src/table_plugin.rs @@ -11,9 +11,21 @@ use solitaire_core::pile::PileType; use solitaire_data::settings::Theme; use crate::events::HintVisualEvent; -use crate::layout::{compute_layout, Layout, LayoutResource, TABLE_COLOUR}; +use crate::layout::{compute_layout, Layout, LayoutResource}; +#[cfg(test)] +use crate::layout::TABLE_COLOUR; use crate::settings_plugin::{SettingsChangedEvent, SettingsResource}; +/// Holds pre-loaded [`Handle`]s for the 5 selectable table backgrounds. +/// +/// Loaded once at startup by [`load_background_images`]. Index 0 is the +/// default; indices 1–4 are unlockable. +#[derive(Resource)] +pub struct BackgroundImageSet { + /// One handle per background slot (indices 0–4). + pub handles: Vec>, +} + /// Z-depth used for the background — below everything. const Z_BACKGROUND: f32 = -10.0; /// Z-depth used for pile markers — below cards (which start at 0) but above @@ -50,6 +62,7 @@ impl Plugin for TablePlugin { app.add_message::() .add_message::() .add_message::() + .add_systems(Startup, load_background_images.before(setup_table)) .add_systems(Startup, setup_table) .add_systems( Update, @@ -63,7 +76,50 @@ impl Plugin for TablePlugin { } } +/// Loads the 5 background PNG files at startup and stores their +/// [`Handle`]s in [`BackgroundImageSet`]. +/// +/// The PNGs are embedded at compile time via `include_bytes!()`. If a file +/// is missing the build will fail with a clear error rather than a runtime +/// panic. +fn load_background_images(images: Option>>, mut commands: Commands) { + let Some(mut images) = images else { + // Assets is absent (e.g. MinimalPlugins in tests) — insert an + // empty set so setup_table can proceed using a default handle. + commands.insert_resource(BackgroundImageSet { handles: Vec::new() }); + return; + }; + const BG_BYTES: [&[u8]; 5] = [ + include_bytes!("../../assets/backgrounds/bg_0.png"), + include_bytes!("../../assets/backgrounds/bg_1.png"), + include_bytes!("../../assets/backgrounds/bg_2.png"), + include_bytes!("../../assets/backgrounds/bg_3.png"), + include_bytes!("../../assets/backgrounds/bg_4.png"), + ]; + let handles = BG_BYTES + .iter() + .map(|bytes| { + use bevy::image::{CompressedImageFormats, ImageSampler, ImageType}; + let image = Image::from_buffer( + bytes, + ImageType::Extension("png"), + CompressedImageFormats::NONE, + true, + ImageSampler::default(), + bevy::asset::RenderAssetUsages::RENDER_WORLD, + ) + .expect("valid background PNG"); + images.add(image) + }) + .collect(); + commands.insert_resource(BackgroundImageSet { handles }); +} + /// Returns the felt colour for a given theme. +/// +/// Only used in tests — the runtime path now picks a PNG image via +/// [`BackgroundImageSet`] rather than a solid colour. +#[cfg(test)] fn theme_colour(theme: &Theme) -> Color { match theme { Theme::Green => Color::srgb(TABLE_COLOUR[0], TABLE_COLOUR[1], TABLE_COLOUR[2]), @@ -74,6 +130,10 @@ fn theme_colour(theme: &Theme) -> Color { /// Effective table background colour: unlocked background index overrides the /// Theme when `selected_background > 0`. +/// +/// Only used in tests — the runtime path now picks a PNG image via +/// [`BackgroundImageSet`] rather than a solid colour. +#[cfg(test)] fn effective_background_colour(theme: &Theme, selected_background: usize) -> Color { match selected_background { 0 => theme_colour(theme), @@ -93,6 +153,7 @@ fn setup_table( windows: Query<&Window>, existing_camera: Query<(), With>, settings: Option>, + bg_images: Option>, ) { // Only spawn a camera if one does not already exist (e.g. a parent app // may have added one in tests). @@ -107,23 +168,34 @@ fn setup_table( .unwrap_or(Vec2::new(1280.0, 800.0)); let layout = compute_layout(window_size); - let initial_colour = settings + let selected_bg = settings .as_ref() - .map(|s| effective_background_colour(&s.0.theme, s.0.selected_background)) - .unwrap_or_else(|| Color::srgb(TABLE_COLOUR[0], TABLE_COLOUR[1], TABLE_COLOUR[2])); + .map(|s| s.0.selected_background) + .unwrap_or(0); - spawn_background(&mut commands, window_size, initial_colour); + let image_handle = bg_images + .as_ref() + .and_then(|set| set.handles.get(selected_bg).cloned()) + .unwrap_or_default(); + + spawn_background(&mut commands, window_size, image_handle); spawn_pile_markers(&mut commands, &layout); commands.insert_resource(LayoutResource(layout)); } -fn spawn_background(commands: &mut Commands, window_size: Vec2, color: Color) { - // Spawn a felt-coloured rectangle that always covers the window. We give - // it the window size plus headroom so resizing up doesn't expose edges - // before the resize handler runs. +/// Spawns the felt background sprite using a PNG image handle. +/// +/// The sprite covers the window at twice the window size so brief resize gaps +/// are never visible. The image is tinted `Color::WHITE` (no tint) so the PNG +/// pixel data is rendered as-is. +fn spawn_background(commands: &mut Commands, window_size: Vec2, image: Handle) { + // Spawn a sprite covering the window. We give it the window size plus + // headroom so resizing up doesn't expose edges before the resize handler + // runs. commands.spawn(( Sprite { - color, + image, + color: Color::WHITE, custom_size: Some(window_size * 2.0), ..default() }, @@ -132,16 +204,30 @@ fn spawn_background(commands: &mut Commands, window_size: Vec2, color: Color) { )); } +/// Reacts to settings changes by updating the background sprite's image handle. +/// +/// When [`BackgroundImageSet`] is available the selected PNG handle is applied +/// directly (color is kept at `Color::WHITE` so the PNG pixel data shows +/// unmodified). If the resource is not yet ready the sprite is left unchanged. fn apply_theme_on_settings_change( mut events: MessageReader, mut backgrounds: Query<&mut Sprite, With>, + bg_images: Option>, ) { let Some(ev) = events.read().last() else { return; }; - let colour = effective_background_colour(&ev.0.theme, ev.0.selected_background); + let Some(set) = bg_images else { + // BackgroundImageSet not ready yet — leave sprite unchanged. + return; + }; + let selected = ev.0.selected_background; + let Some(handle) = set.handles.get(selected).cloned() else { + return; + }; for mut sprite in &mut backgrounds { - sprite.color = colour; + sprite.image = handle.clone(); + sprite.color = Color::WHITE; } }