diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 1ae7df0..153029d 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,5 +1,5 @@ name: CI -on: +on: pull_request: push: branches: @@ -20,8 +20,7 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - - run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev libwayland-dev - - run: cargo check --workspace --all-features --all-targets + - run: cargo check --all-features --all-targets check-no-defaults: runs-on: ubuntu-latest @@ -29,8 +28,7 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - - run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev - - run: cargo check --workspace --no-default-features + - run: cargo check --no-default-features clippy: runs-on: ubuntu-latest @@ -38,9 +36,8 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - - run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev libwayland-dev - run: rustup component add clippy - - run: cargo clippy --workspace --all-features --all-targets -- -D warnings + - run: cargo clippy --all-features --all-targets -- -D warnings doc: runs-on: ubuntu-latest @@ -48,19 +45,17 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - - run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev - - run: cargo doc --workspace --all-features --no-deps --document-private-items + - run: cargo doc --all-features --no-deps --document-private-items env: RUSTDOCFLAGS: -D warnings - + test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - - run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev libwayland-dev - - run: cargo test --workspace --all-features --all-targets + - run: cargo test --all-features --all-targets # Note: cargo test --all-targets disables doc tests, so we have to add this to test docs doctest: @@ -69,5 +64,4 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - - run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev libwayland-dev - - run: cargo test --workspace --all-features --doc + - run: cargo test --all-features --doc diff --git a/Cargo.lock b/Cargo.lock index 507cd8d..5b1425a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,23 +39,21 @@ dependencies = [ [[package]] name = "android-activity" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" +checksum = "0f2a1bb052857d5dd49572219344a7332b31b76405648eabac5bc68978251bcd" dependencies = [ "android-properties", - "bitflags 2.10.0", + "bitflags 2.13.0", "cc", - "cesu8", "jni", - "jni-sys", "libc", "log", "ndk", "ndk-context", "ndk-sys", "num_enum", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -108,9 +106,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "bit-set" @@ -135,9 +133,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" [[package]] name = "block" @@ -156,9 +154,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.1" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "bytemuck" @@ -182,9 +180,9 @@ dependencies = [ [[package]] name = "bytes" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "calloop" @@ -192,7 +190,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "log", "polling", "rustix 0.38.44", @@ -214,9 +212,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.51" +version = "1.2.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" +checksum = "dad887fd958be91b5098c0248def011f4523ab786cd411be668777e55063501f" dependencies = [ "find-msvc-tools", "jobserver", @@ -224,12 +222,6 @@ dependencies = [ "shlex", ] -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - [[package]] name = "cfg-if" version = "1.0.4" @@ -334,7 +326,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "core-foundation 0.10.1", "libc", ] @@ -374,9 +366,9 @@ checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" [[package]] name = "dlib" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +checksum = "ab8ecd87370524b461f8557c119c405552c396ed91fc0a8eec68679eab26f94a" dependencies = [ "libloading", ] @@ -438,15 +430,15 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "flate2" -version = "1.1.5" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", @@ -541,7 +533,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" dependencies = [ - "rustix 1.1.3", + "rustix 1.1.4", "windows-link", ] @@ -595,7 +587,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "gpu-alloc-types", ] @@ -605,7 +597,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", ] [[package]] @@ -626,7 +618,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "gpu-descriptor-types", "hashbrown 0.15.5", ] @@ -637,7 +629,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", ] [[package]] @@ -680,6 +672,12 @@ dependencies = [ "foldhash 0.2.0", ] +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + [[package]] name = "hermit-abi" version = "0.5.2" @@ -694,35 +692,71 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" [[package]] name = "indexmap" -version = "2.12.1" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.1", ] [[package]] name = "jni" -version = "0.21.1" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" dependencies = [ - "cesu8", "cfg-if", "combine", - "jni-sys", + "jni-macros", + "jni-sys 0.4.1", "log", - "thiserror 1.0.69", + "simd_cesu8", + "thiserror 2.0.18", "walkdir", - "windows-sys 0.45.0", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn", ] [[package]] name = "jni-sys" -version = "0.3.0" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn", +] [[package]] name = "jobserver" @@ -736,13 +770,12 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.99" +version = "0.3.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11" +checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31" dependencies = [ "cfg-if", "futures-util", - "once_cell", "wasm-bindgen", ] @@ -771,16 +804,15 @@ checksum = "4b60dfc32f652b926df6192e55525b16d186c69d47876c3ead4da5cc9f8450e2" dependencies = [ "arrayvec", "euclid", - "libm", "polycool", "smallvec", ] [[package]] name = "libc" -version = "0.2.178" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libloading" @@ -800,13 +832,14 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.12" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "libc", - "redox_syscall 0.7.0", + "plain", + "redox_syscall 0.8.1", ] [[package]] @@ -823,9 +856,9 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litrs" @@ -844,9 +877,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a" [[package]] name = "malloc_buf" @@ -859,15 +892,15 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" [[package]] name = "memmap2" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" dependencies = [ "libc", ] @@ -878,7 +911,7 @@ version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00c15a6f673ff72ddcc22394663290f870fb224c1bfce55734a75c414150e605" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "block", "core-graphics-types 0.2.0", "foreign-types", @@ -905,7 +938,7 @@ checksum = "066cf25f0e8b11ee0df221219010f213ad429855f57c494f995590c861a9a7d8" dependencies = [ "arrayvec", "bit-set", - "bitflags 2.10.0", + "bitflags 2.13.0", "cfg-if", "cfg_aliases", "codespan-reporting", @@ -929,8 +962,8 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.10.0", - "jni-sys", + "bitflags 2.13.0", + "jni-sys 0.3.1", "log", "ndk-sys", "num_enum", @@ -950,7 +983,7 @@ version = "0.6.0+11769913" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" dependencies = [ - "jni-sys", + "jni-sys 0.3.1", ] [[package]] @@ -965,9 +998,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" dependencies = [ "num_enum_derive", "rustversion", @@ -975,9 +1008,9 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1016,7 +1049,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "block2", "libc", "objc2", @@ -1032,7 +1065,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "block2", "objc2", "objc2-core-location", @@ -1056,7 +1089,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "block2", "objc2", "objc2-foundation", @@ -1098,7 +1131,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "block2", "dispatch", "libc", @@ -1123,7 +1156,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "block2", "objc2", "objc2-foundation", @@ -1135,7 +1168,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "block2", "objc2", "objc2-foundation", @@ -1158,7 +1191,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "block2", "objc2", "objc2-cloud-kit", @@ -1190,7 +1223,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "block2", "objc2", "objc2-core-location", @@ -1199,24 +1232,25 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "orbclient" -version = "0.3.49" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "247ad146e19b9437f8604c21f8652423595cf710ad108af40e77d3ae6e96b827" +checksum = "5df339f526ea9a60e371768d50efc2f2508c7203290731565d1f7a6f71d21747" dependencies = [ + "libc", "libredox", ] [[package]] name = "ordered-float" -version = "5.0.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2c1f9f56e534ac6a9b8a4600bdf0f530fb393b5f393e7b4d03489c3cf0c3f01" +checksum = "b7d950ca161dc355eaf28f82b11345ed76c6e1f6eb1f4f4479e0323b9e2fbd0e" dependencies = [ "num-traits", ] @@ -1279,18 +1313,18 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pin-project" -version = "1.1.10" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.10" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", "quote", @@ -1299,15 +1333,21 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pkg-config" -version = "0.3.32" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "plain" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "png" @@ -1332,7 +1372,7 @@ dependencies = [ "concurrent-queue", "hermit-abi", "pin-project-lite", - "rustix 1.1.3", + "rustix 1.1.4", "windows-sys 0.61.2", ] @@ -1349,20 +1389,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50596ddc09eb5ad5f75cacd40209568e66df71baf86e1499a0e99c4cff12a5a6" dependencies = [ "arrayvec", - "libm", ] [[package]] name = "portable-atomic" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "portable-atomic-util" -version = "0.2.4" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" dependencies = [ "portable-atomic", ] @@ -1375,42 +1414,42 @@ checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" [[package]] name = "proc-macro-crate" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.104" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9695f8df41bb4f3d222c95a67532365f569318332d03d5f3f67f37b20e6ebdf0" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "profiling" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" +checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5" [[package]] name = "quick-xml" -version = "0.37.5" +version = "0.39.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" +checksum = "cdcc8dd4e2f670d309a5f0e83fe36dfdc05af317008fea29144da1a2ac858e5e" dependencies = [ "memchr", ] [[package]] name = "quote" -version = "1.0.42" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -1423,9 +1462,9 @@ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "range-alloc" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d6831663a5098ea164f89cff59c6284e95f4e3c76ce9848d4529f5ccca9bde" +checksum = "ca45419789ae5a7899559e9512e58ca889e41f04f1f2445e9f4b290ceccd1d08" [[package]] name = "raw-window-handle" @@ -1447,7 +1486,12 @@ dependencies = [ name = "rectree" version = "0.1.0" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", + "hashbrown 0.16.1", + "kurbo", + "pollster", + "vello", + "winit", ] [[package]] @@ -1465,16 +1509,16 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", ] [[package]] name = "redox_syscall" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" +checksum = "5b44b894f2a6e36457d665d1e08c3866add6ed5e70050c1b4ba8a8ddedb02ce7" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", ] [[package]] @@ -1489,13 +1533,22 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "errno", "libc", "linux-raw-sys 0.4.15", @@ -1504,14 +1557,14 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "errno", "libc", - "linux-raw-sys 0.11.0", + "linux-raw-sys 0.12.1", "windows-sys 0.61.2", ] @@ -1555,6 +1608,12 @@ dependencies = [ "tiny-skia", ] +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + [[package]] name = "serde" version = "1.0.228" @@ -1587,15 +1646,31 @@ dependencies = [ [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "simd-adler32" -version = "0.3.8" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[package]] +name = "simd_cesu8" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "skrifa" @@ -1609,9 +1684,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "slotmap" @@ -1624,9 +1699,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.15.1" +version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" [[package]] name = "smithay-client-toolkit" @@ -1634,7 +1709,7 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "calloop", "calloop-wayland-source", "cursor-icon", @@ -1662,20 +1737,13 @@ dependencies = [ "serde", ] -[[package]] -name = "spatree" -version = "0.1.0" -dependencies = [ - "kurbo", -] - [[package]] name = "spirv" version = "0.3.0+sdk-1.3.268.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", ] [[package]] @@ -1698,9 +1766,9 @@ checksum = "0193cc4331cfd2f3d2011ef287590868599a2f33c3e69bc22c1a3d3acf9e02fb" [[package]] name = "syn" -version = "2.0.111" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -1783,18 +1851,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.5+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" -version = "0.23.10+spec-1.0.0" +version = "0.25.12+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" dependencies = [ "indexmap", "toml_datetime", @@ -1804,9 +1872,9 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.0.6+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ "winnow", ] @@ -1835,15 +1903,15 @@ checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-segmentation" -version = "1.12.0" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] name = "unicode-width" @@ -1896,18 +1964,6 @@ dependencies = [ "vello_encoding", ] -[[package]] -name = "vello_winit_examples" -version = "0.1.0" -dependencies = [ - "hashbrown 0.16.1", - "kurbo", - "pollster", - "rectree", - "vello", - "winit", -] - [[package]] name = "version_check" version = "0.9.5" @@ -1926,18 +1982,18 @@ dependencies = [ [[package]] name = "wasip2" -version = "1.0.1+wasi-0.2.4" +version = "1.0.4+wasi-0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.122" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409" +checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a" dependencies = [ "cfg-if", "once_cell", @@ -1948,9 +2004,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.72" +version = "0.4.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9473dbd2991ae90b6291c3c32c30c6187ac49aa32f9905d1cce280ec1e110b0f" +checksum = "503b14d284f2c8dac03b819967e155ea753f573586193b2b2c95990cb5d69280" dependencies = [ "js-sys", "wasm-bindgen", @@ -1958,9 +2014,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.122" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6" +checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1968,9 +2024,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.122" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e" +checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd" dependencies = [ "bumpalo", "proc-macro2", @@ -1981,22 +2037,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.122" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437" +checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f" dependencies = [ "unicode-ident", ] [[package]] name = "wayland-backend" -version = "0.3.11" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673a33c33048a5ade91a6b139580fa174e19fb0d23f396dca9fa15f2e1e49b35" +checksum = "2857dd20b54e916ec7253b3d6b4d5c4d7d4ca2c33c2e11c6c76a99bd8744755d" dependencies = [ "cc", "downcast-rs", - "rustix 1.1.3", + "rustix 1.1.4", "scoped-tls", "smallvec", "wayland-sys", @@ -2004,12 +2060,12 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.11" +version = "0.31.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d" +checksum = "645c7c96bb74690c3189b5c9cb4ca1627062bb23693a4fad9d8c3de958260144" dependencies = [ - "bitflags 2.10.0", - "rustix 1.1.3", + "bitflags 2.13.0", + "rustix 1.1.4", "wayland-backend", "wayland-scanner", ] @@ -2020,29 +2076,29 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "cursor-icon", "wayland-backend", ] [[package]] name = "wayland-cursor" -version = "0.31.11" +version = "0.31.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447ccc440a881271b19e9989f75726d60faa09b95b0200a9b7eb5cc47c3eeb29" +checksum = "4a52d18780be9b1314328a3de5f930b73d2200112e3849ca6cb11822793fb34d" dependencies = [ - "rustix 1.1.3", + "rustix 1.1.4", "wayland-client", "xcursor", ] [[package]] name = "wayland-protocols" -version = "0.32.9" +version = "0.32.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efa790ed75fbfd71283bd2521a1cfdc022aabcc28bdcff00851f9e4ae88d9901" +checksum = "563a85523cade2429938e790815fd7319062103b9f4a2dc806e9b53b95982d8f" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "wayland-backend", "wayland-client", "wayland-scanner", @@ -2050,11 +2106,11 @@ dependencies = [ [[package]] name = "wayland-protocols-plasma" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a07a14257c077ab3279987c4f8bb987851bf57081b93710381daea94f2c2c032" +checksum = "2b6d8cf1eb2c1c31ed1f5643c88a6e53538129d4af80030c8cabd1f9fa884d91" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -2063,11 +2119,11 @@ dependencies = [ [[package]] name = "wayland-protocols-wlr" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd94963ed43cf9938a090ca4f7da58eb55325ec8200c3848963e98dc25b78ec" +checksum = "eb04e52f7836d7c7976c78ca0250d61e33873c34156a2a1fc9474828ec268234" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -2076,9 +2132,9 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.7" +version = "0.31.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54cb1e9dc49da91950bdfd8b848c49330536d9d1fb03d4bfec8cae50caa50ae3" +checksum = "9c324a910fd86ebdc364a3e61ec1f11737d3b1d6c273c0239ee8ff4bc0d24b4a" dependencies = [ "proc-macro2", "quick-xml", @@ -2087,9 +2143,9 @@ dependencies = [ [[package]] name = "wayland-sys" -version = "0.31.7" +version = "0.31.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34949b42822155826b41db8e5d0c1be3a2bd296c747577a43a3e6daefc296142" +checksum = "d8eab23fefc9e41f8e841df4a9c707e8a8c4ed26e944ef69297184de2785e3be" dependencies = [ "dlib", "log", @@ -2099,9 +2155,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.99" +version = "0.3.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436" +checksum = "a6430a72df5eb332242960fe84b3002a241163998241eb596d4f739b9757061d" dependencies = [ "js-sys", "wasm-bindgen", @@ -2124,7 +2180,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfe68bac7cde125de7a731c3400723cadaaf1703795ad3f4805f187459cd7a77" dependencies = [ "arrayvec", - "bitflags 2.10.0", + "bitflags 2.13.0", "cfg-if", "cfg_aliases", "document-features", @@ -2155,7 +2211,7 @@ dependencies = [ "arrayvec", "bit-set", "bit-vec", - "bitflags 2.10.0", + "bitflags 2.13.0", "bytemuck", "cfg_aliases", "document-features", @@ -2215,7 +2271,7 @@ dependencies = [ "arrayvec", "ash", "bit-set", - "bitflags 2.10.0", + "bitflags 2.13.0", "block", "bytemuck", "cfg-if", @@ -2260,7 +2316,7 @@ version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afdcf84c395990db737f2dd91628706cb31e86d72e53482320d368e52b5da5eb" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "bytemuck", "js-sys", "log", @@ -2284,7 +2340,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ "windows-core", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -2297,7 +2353,7 @@ dependencies = [ "windows-interface", "windows-result", "windows-strings", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -2334,7 +2390,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -2344,16 +2400,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ "windows-result", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", + "windows-targets", ] [[package]] @@ -2362,7 +2409,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -2371,7 +2418,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -2383,67 +2430,34 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -2456,48 +2470,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -2506,14 +2496,14 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winit" -version = "0.30.12" +version = "0.30.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66d4b9ed69c4009f6321f762d6e61ad8a2389cd431b97cb1e146812e9e6c732" +checksum = "a6755fa58a9f8350bd1e472d4c3fcc25f824ec358933bba33306d0b63df5978d" dependencies = [ "ahash", "android-activity", "atomic-waker", - "bitflags 2.10.0", + "bitflags 2.13.0", "block2", "bytemuck", "calloop", @@ -2558,18 +2548,18 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.14" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" dependencies = [ "memchr", ] [[package]] name = "wit-bindgen" -version = "0.46.0" +version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" [[package]] name = "x11-dl" @@ -2593,7 +2583,7 @@ dependencies = [ "libc", "libloading", "once_cell", - "rustix 1.1.3", + "rustix 1.1.4", "x11rb-protocol", ] @@ -2615,7 +2605,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.13.0", "dlib", "log", "once_cell", @@ -2636,18 +2626,18 @@ checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" [[package]] name = "zerocopy" -version = "0.8.31" +version = "0.8.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" +checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.31" +version = "0.8.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" +checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 93184be..8df0d90 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,16 +1,20 @@ -[workspace] -resolver = "2" -members = ["crates/*", "examples/*", ] - -[workspace.package] +[package] +name = "rectree" version = "0.1.0" edition = "2024" license = "MIT OR Apache-2.0" repository = "https://github.com/voxell-tech/rectree" +description = "Representing user interfaces using a rectangle tree." +keywords = ["rectangle", "layout", "user-interface", "hierarchy", "box"] +categories = ["gui", "data-structures", "no-std"] +readme = "README.md" -[workspace.dependencies] -rectree = { version = "0.1.0", path = "crates/rectree" } -sparse_map = "0.1.2" -hashbrown = { version = "0.16.1", default-features = false, features = ["default-hasher", "inline-more"] } -kurbo = { version = "0.13.1", default-features = false } +[dependencies] bitflags = { version = "2", default-features = false } + +[dev-dependencies] +hashbrown = { version = "0.16.1", default-features = false, features = ["default-hasher", "inline-more"] } +kurbo = { version = "0.13.1", default-features = false, features = ["std"] } +vello = "0.7" +winit = "0.30.12" +pollster = "0.4.0" diff --git a/README.md b/README.md deleted file mode 120000 index 079e7c5..0000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -crates/rectree/README.md \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..fb37933 --- /dev/null +++ b/README.md @@ -0,0 +1,165 @@ +# Rectree + +[![License](https://img.shields.io/badge/license-MIT%2FApache-blue.svg)](https://github.com/voxell-tech/rectree#license) +[![Crates.io](https://img.shields.io/crates/v/rectree.svg)](https://crates.io/crates/rectree) +[![Downloads](https://img.shields.io/crates/d/rectree.svg)](https://crates.io/crates/rectree) +[![Docs](https://docs.rs/rectree/badge.svg)](https://docs.rs/rectree/latest/rectree/) +[![CI](https://github.com/voxell-tech/rectree/workflows/CI/badge.svg)](https://github.com/voxell-tech/rectree/actions) +[![Discord](https://img.shields.io/discord/442334985471655946.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/Mhnyp6VYEQ) + +**Rectree** proposes a simple concept towards user interfaces, that +everything can be represented as a tree of axis-aligned bounding +boxes (AABB). In **Rectree**, these are represented as rectangles, +hence the name "rect-tree". + +Rectree is designed to be: +- **Deterministic**: identical inputs always produce identical + layouts. +- **Incremental**: only affected subtrees are recomputed. +- **Policy-free**: layout behavior is defined by user-provided + algorithms. + +![layout_basic](/.github/assets/layout_basic.png) + +## Core Concepts + +| Type / Trait | Role | +| ----------------- | ---------------------------------------------- | +| [`Rectree`] | tree structure and per-node layout logic | +| [`RectNodes`] | flat mutable storage for per-node numbers | +| [`NodeContext`] | restricted build-time view of `RectNodes` | +| [`RectNode`] | per-node data (size, constraint, translation) | +| [`NodeState`] | bitflags that short-circuit incremental passes | +| [`Constraint`] | min/max size bounds, flowing top-down | +| [`Size`] | resolved dimensions, flowing bottom-up | + +Rectree itself does not impose a specific layout style (e.g. flexbox, +grid). Instead, it provides a strict data-flow model on top of which +layout algorithms can be built. + +## Three-Pass Layout + +Each call to `layout` runs three passes in order: + +1. **constrain** (top-down): each node derives the constraint it + passes to its children via `Rectree::constrain`. +2. **build** (bottom-up): each node measures itself given its + constraint and child sizes via `Rectree::build`. +3. **propagate_translation** (top-down): local translations set + during build are accumulated into world-space positions. + +Each pass is short-circuited by `NodeState` flags so only nodes +that actually changed are reprocessed. + +### Layout Rules + +1. Constraints flow strictly top-down (parent to child). +2. Sizes flow strictly bottom-up (child to parent). +3. A parent may pass a different constraint to each child. +4. Given the same constraint, an unmodified node must always + produce the same size. +5. The build pass must not write child sizes, only child + translations. This is enforced by `NodeContext`. + +## Example + +```rust +use std::collections::HashMap; +use rectree::{ + Constraint, NodeContext, RectNode, RectNodes, + Rectree, Size, layout, +}; + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +struct Id(u32); + +// Flat node storage backed by a HashMap. +struct Store(HashMap>); + +impl RectNodes for Store { + type Id = Id; + + fn get_node(&self, id: &Id) -> Option<&RectNode> { + self.0.get(id) + } + + fn get_node_mut(&mut self, id: &Id) + -> Option<&mut RectNode> + { + self.0.get_mut(id) + } +} + +// Tree with one root and one child. The root fills its +// constraint; the child has a fixed 100x50 size. +struct Tree { root: Id, child: Id } + +impl Rectree for Tree { + type Id = Id; + type Nodes = Store; + + fn for_each_child( + &self, + id: &Id, + _nodes: &mut Store, + mut f: impl FnMut(&Id, &mut Store), + ) { + if *id == self.root { + f(&self.child, _nodes); + } + } + + // Pass the parent constraint to children unchanged. + fn constrain(&self, _: &Id, _nodes: &Store, parent: Constraint) + -> Constraint + { + parent + } + + fn build( + &self, + id: &Id, + constraint: Constraint, + _nodes: &mut Self::Nodes, + ) -> Size { + if *id == self.child { + Size::new(100.0, 50.0) + } else { + constraint.max + } + } +} + +let root = Id(0); +let child = Id(1); +let tree = Tree { root, child }; + +let mut store = Store(HashMap::new()); +store.0.insert(root, RectNode::new(None)); +store.0.insert(child, RectNode::new(Some(root))); + +// Constrain the root to an 800x600 window. +store.0.get_mut(&root).unwrap().constraint = + Constraint::tight(Size::new(800.0, 600.0)); + +layout(&tree, &mut store, &root); + +// Child is placed at the origin by default. +assert_eq!(store.0[&child].world_translation.x, 0.0); +assert_eq!(store.0[&child].world_translation.y, 0.0); +assert_eq!(store.0[&child].size, Size::new(100.0, 50.0)); +``` + +## Join the community! + +You can join us on the [Voxell discord server](https://discord.gg/Mhnyp6VYEQ). + +## License + +`rectree` is dual-licensed under either: + +- MIT License ([LICENSE-MIT](/LICENSE-MIT) or [http://opensource.org/licenses/MIT](http://opensource.org/licenses/MIT)) +- Apache License, Version 2.0 ([LICENSE-APACHE](/LICENSE-APACHE) or [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)) + +This means you can select the license you prefer! +This dual-licensing approach is the de-facto standard in the Rust ecosystem and there are [very good reasons](https://github.com/bevyengine/bevy/issues/2373) to include both. diff --git a/crates/rectree/Cargo.toml b/crates/rectree/Cargo.toml deleted file mode 100644 index 7088ee0..0000000 --- a/crates/rectree/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "rectree" -version.workspace = true -edition.workspace = true -license.workspace = true -repository.workspace = true -description = "Representing user interfaces using a rectangle tree." -keywords = ["rectangle", "layout", "user-interface", "hierarchy", "box"] -categories = ["gui", "data-structures", "no-std"] -readme = "README.md" - -[dependencies] -bitflags.workspace = true diff --git a/crates/rectree/README.md b/crates/rectree/README.md deleted file mode 100644 index fb37933..0000000 --- a/crates/rectree/README.md +++ /dev/null @@ -1,165 +0,0 @@ -# Rectree - -[![License](https://img.shields.io/badge/license-MIT%2FApache-blue.svg)](https://github.com/voxell-tech/rectree#license) -[![Crates.io](https://img.shields.io/crates/v/rectree.svg)](https://crates.io/crates/rectree) -[![Downloads](https://img.shields.io/crates/d/rectree.svg)](https://crates.io/crates/rectree) -[![Docs](https://docs.rs/rectree/badge.svg)](https://docs.rs/rectree/latest/rectree/) -[![CI](https://github.com/voxell-tech/rectree/workflows/CI/badge.svg)](https://github.com/voxell-tech/rectree/actions) -[![Discord](https://img.shields.io/discord/442334985471655946.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/Mhnyp6VYEQ) - -**Rectree** proposes a simple concept towards user interfaces, that -everything can be represented as a tree of axis-aligned bounding -boxes (AABB). In **Rectree**, these are represented as rectangles, -hence the name "rect-tree". - -Rectree is designed to be: -- **Deterministic**: identical inputs always produce identical - layouts. -- **Incremental**: only affected subtrees are recomputed. -- **Policy-free**: layout behavior is defined by user-provided - algorithms. - -![layout_basic](/.github/assets/layout_basic.png) - -## Core Concepts - -| Type / Trait | Role | -| ----------------- | ---------------------------------------------- | -| [`Rectree`] | tree structure and per-node layout logic | -| [`RectNodes`] | flat mutable storage for per-node numbers | -| [`NodeContext`] | restricted build-time view of `RectNodes` | -| [`RectNode`] | per-node data (size, constraint, translation) | -| [`NodeState`] | bitflags that short-circuit incremental passes | -| [`Constraint`] | min/max size bounds, flowing top-down | -| [`Size`] | resolved dimensions, flowing bottom-up | - -Rectree itself does not impose a specific layout style (e.g. flexbox, -grid). Instead, it provides a strict data-flow model on top of which -layout algorithms can be built. - -## Three-Pass Layout - -Each call to `layout` runs three passes in order: - -1. **constrain** (top-down): each node derives the constraint it - passes to its children via `Rectree::constrain`. -2. **build** (bottom-up): each node measures itself given its - constraint and child sizes via `Rectree::build`. -3. **propagate_translation** (top-down): local translations set - during build are accumulated into world-space positions. - -Each pass is short-circuited by `NodeState` flags so only nodes -that actually changed are reprocessed. - -### Layout Rules - -1. Constraints flow strictly top-down (parent to child). -2. Sizes flow strictly bottom-up (child to parent). -3. A parent may pass a different constraint to each child. -4. Given the same constraint, an unmodified node must always - produce the same size. -5. The build pass must not write child sizes, only child - translations. This is enforced by `NodeContext`. - -## Example - -```rust -use std::collections::HashMap; -use rectree::{ - Constraint, NodeContext, RectNode, RectNodes, - Rectree, Size, layout, -}; - -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -struct Id(u32); - -// Flat node storage backed by a HashMap. -struct Store(HashMap>); - -impl RectNodes for Store { - type Id = Id; - - fn get_node(&self, id: &Id) -> Option<&RectNode> { - self.0.get(id) - } - - fn get_node_mut(&mut self, id: &Id) - -> Option<&mut RectNode> - { - self.0.get_mut(id) - } -} - -// Tree with one root and one child. The root fills its -// constraint; the child has a fixed 100x50 size. -struct Tree { root: Id, child: Id } - -impl Rectree for Tree { - type Id = Id; - type Nodes = Store; - - fn for_each_child( - &self, - id: &Id, - _nodes: &mut Store, - mut f: impl FnMut(&Id, &mut Store), - ) { - if *id == self.root { - f(&self.child, _nodes); - } - } - - // Pass the parent constraint to children unchanged. - fn constrain(&self, _: &Id, _nodes: &Store, parent: Constraint) - -> Constraint - { - parent - } - - fn build( - &self, - id: &Id, - constraint: Constraint, - _nodes: &mut Self::Nodes, - ) -> Size { - if *id == self.child { - Size::new(100.0, 50.0) - } else { - constraint.max - } - } -} - -let root = Id(0); -let child = Id(1); -let tree = Tree { root, child }; - -let mut store = Store(HashMap::new()); -store.0.insert(root, RectNode::new(None)); -store.0.insert(child, RectNode::new(Some(root))); - -// Constrain the root to an 800x600 window. -store.0.get_mut(&root).unwrap().constraint = - Constraint::tight(Size::new(800.0, 600.0)); - -layout(&tree, &mut store, &root); - -// Child is placed at the origin by default. -assert_eq!(store.0[&child].world_translation.x, 0.0); -assert_eq!(store.0[&child].world_translation.y, 0.0); -assert_eq!(store.0[&child].size, Size::new(100.0, 50.0)); -``` - -## Join the community! - -You can join us on the [Voxell discord server](https://discord.gg/Mhnyp6VYEQ). - -## License - -`rectree` is dual-licensed under either: - -- MIT License ([LICENSE-MIT](/LICENSE-MIT) or [http://opensource.org/licenses/MIT](http://opensource.org/licenses/MIT)) -- Apache License, Version 2.0 ([LICENSE-APACHE](/LICENSE-APACHE) or [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)) - -This means you can select the license you prefer! -This dual-licensing approach is the de-facto standard in the Rust ecosystem and there are [very good reasons](https://github.com/bevyengine/bevy/issues/2373) to include both. diff --git a/crates/spatree/Cargo.toml b/crates/spatree/Cargo.toml deleted file mode 100644 index 8c59863..0000000 --- a/crates/spatree/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "spatree" -version.workspace = true -edition.workspace = true -license.workspace = true -repository.workspace = true -description = "Fast 2D spatial indexing using Morton codes." -keywords = ["bvh", "spatial", "hash", "morton", "rectangle"] -categories = ["gui", "data-structures", "no-std"] -readme = "README.md" - -[dependencies] -kurbo.workspace = true - -[features] -default = ["std"] -std = ["kurbo/std"] -libm = ["kurbo/libm"] diff --git a/crates/spatree/README.md b/crates/spatree/README.md deleted file mode 100644 index 6c92108..0000000 --- a/crates/spatree/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# Spatree - -[![License](https://img.shields.io/badge/license-MIT%2FApache-blue.svg)](https://github.com/voxell-tech/rectree#license) -[![Crates.io](https://img.shields.io/crates/v/spatree.svg)](https://crates.io/crates/spatree) -[![Downloads](https://img.shields.io/crates/d/spatree.svg)](https://crates.io/crates/spatree) -[![Docs](https://docs.rs/spatree/badge.svg)](https://docs.rs/spatree/latest/spatree/) -[![CI](https://github.com/voxell-tech/rectree/workflows/CI/badge.svg)](https://github.com/voxell-tech/rectree/actions) -[![Discord](https://img.shields.io/discord/442334985471655946.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/Mhnyp6VYEQ) - -**Spatree** provides a simple, fast 2D spatial indexing solution using -Morton codes to generate a Linear Bounding Volume Hierarchy (LBVH). - -## Join the community! - -You can join us on the [Voxell discord server](https://discord.gg/Mhnyp6VYEQ). - -## License - -`spatree` is dual-licensed under either: - -- MIT License ([LICENSE-MIT](/LICENSE-MIT) or [http://opensource.org/licenses/MIT](http://opensource.org/licenses/MIT)) -- Apache License, Version 2.0 ([LICENSE-APACHE](/LICENSE-APACHE) or [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)) - -This means you can select the license you prefer! -This dual-licensing approach is the de-facto standard in the Rust ecosystem and there are [very good reasons](https://github.com/bevyengine/bevy/issues/2373) to include both. - -## Reference - -- [Maximizing Parallelism in the Construction of BVHs, Octrees, and k-d Trees](https://research.nvidia.com/sites/default/files/pubs/2012-06_Maximizing-Parallelism-in/karras2012hpg_paper.pdf) diff --git a/crates/spatree/src/lib.rs b/crates/spatree/src/lib.rs deleted file mode 100644 index 71490bb..0000000 --- a/crates/spatree/src/lib.rs +++ /dev/null @@ -1,658 +0,0 @@ -#![doc = include_str!("../README.md")] -#![no_std] - -extern crate alloc; - -use core::ops::Deref; - -use alloc::boxed::Box; -use alloc::vec; -use alloc::vec::Vec; -use kurbo::{Point, Rect}; - -use crate::morton::{MortonCode, find_split, morton_2d_f64}; - -pub use kurbo; - -pub mod morton; - -/// **Spatree** implements a Linear Bounding Volume Hierarchy (LBVH). -/// -/// It uses _Morton encoding_ to map 2D spaital coordinates onto a 1D -/// Z-order curve. Sorting these codes ensures spatially close objects -/// are adjacent in memory, allowing for efficient top-down hierarchy -/// generation. -#[derive(Default)] -pub struct Spatree { - global_bound: Rect, - rects: Vec, - nodes: Vec, -} - -// Builders. -impl Spatree { - /// Creates a new empty [`Spatree`]. - pub fn new() -> Self { - Self::default() - } - - /// Push a new [`Rect`] into the spatial tree. - /// - /// If this is performed after [`Self::build()`], a rebuild will - /// be required to cater for the change! - pub fn push_rect(&mut self, rect: Rect) -> RectId { - let index = self.rects.len(); - self.rects.push(rect); - // Fit the global bound to the new rect. - self.global_bound = self.global_bound.union(rect); - RectId(index) - } - - /// Get a specific [`Rect`] for a given [`RectId`]. - pub fn get_rect(&self, id: RectId) -> Option<&Rect> { - self.rects.get(*id) - } - - /// Obtain the global bounding box of the spatial tree. - /// Thi global bound is accumulated during - /// [`Self::push_rect()`] calls. - pub fn global_bound(&self) -> &Rect { - &self.global_bound - } - - /// Constructs a spatial hierarchy (LBVH) from the current set of rectangles. - /// - /// ### Arguments - /// - /// - `point_from_rect`: A closure that determines the stable - /// representative point (e.g., center or top-left) of a `Rect` - /// used for Morton encoding. - /// - /// After construction, all internal node bounding boxes are computed. - /// - /// If [`Self::global_bound()`] has zero area, the tree is left - /// empty since no meaningful spatial ordering can be derived. - pub fn build(&mut self, point_from_rect: F) - where - F: Fn(&Rect) -> Point, - { - let bound_size = self.global_bound.size(); - // There is point in building a spatial tree when there is no - // space within the max bound. - if bound_size.is_zero_area() { - return; - } - - let mut morton_codes = self - .rects - .iter() - .enumerate() - .map(|(index, rect)| { - let point = point_from_rect(rect); - let x = point.x / bound_size.width; - let y = point.y / bound_size.height; - - let code = morton_2d_f64(x, y); - MortonCode { code, index } - }) - .collect::>(); - - morton_codes.sort_unstable(); - - // Build internal nodes. - self.nodes = generate_hierarchy(&morton_codes); - self.calculate_internal_bounds(); - } - - /// Calculate the bounds of all the internal nodes. - fn calculate_internal_bounds(&mut self) { - if self.nodes.is_empty() { - return; - } - - // Because internal nodes were allocated top-down, children - // always have a higher index than their parents. By iterating - // backwards, we process the tree bottom-up. - for i in (0..self.nodes.len()).rev() { - let mut combined_rect = None; - - // Check both children to compute the unioned bounding box - for child_id in self.nodes[i].children { - let child_rect = match child_id { - NodeId::Leaf(rect_id) => { - // Leaf bounds are already known from the input rects - self.rects[rect_id] - } - NodeId::Internal(idx) => { - // Because idx > i, this child's rect was - // already calculated in a previous iteration of this loop. - self.nodes[idx].rect - } - NodeId::Invalid => Rect::ZERO, - }; - - // Union the child's rect into the parent's rect - combined_rect = Some(match combined_rect { - None => child_rect, - Some(existing) => child_rect.union(existing), - }); - } - - if let Some(final_rect) = combined_rect { - self.nodes[i].rect = final_rect; - } - } - } -} - -/// Queries. -impl Spatree { - /// Query for all hits for an arbitrary target. - pub fn query( - &self, - target: T, - hit_condition: F, - ) -> Vec - where - F: Fn(&Rect, &T) -> bool, - { - let mut hits = Vec::new(); - - if self.nodes.is_empty() { - // There's no tree, if there's just one rect, do a hit - // test for it. - if let Some(rect) = self.rects.first() - && hit_condition(rect, &target) - { - hits.push(RectId(0)); - } - } else { - // Traverse the tree. - let mut stack = vec![0]; - - while let Some(node_idx) = stack.pop() { - let node = self.nodes[node_idx]; - - // Skip the tree if it's not a hit. - if !hit_condition(&node.rect, &target) { - continue; - } - - for child in node.children.iter() { - match child { - NodeId::Internal(child_idx) => { - stack.push(*child_idx) - } - NodeId::Leaf(leaf_idx) => { - if hit_condition( - &self.rects[*leaf_idx], - &target, - ) { - hits.push(RectId(*leaf_idx)); - } - } - NodeId::Invalid => continue, - } - } - } - } - - hits - } - - /// Query for a singles hit for an arbitrary target. - pub fn query_single( - &self, - target: T, - hit_condition: H, - conflict_resolution: C, - ) -> Option - where - H: Fn(&Rect, &T) -> bool, - C: Fn(RectId, RectId) -> RectId, - { - let mut hit = None; - // let mut hits = Vec::new(); - - if self.nodes.is_empty() { - // There's no tree, if there's just one rect, do a hit - // test for it. - if let Some(rect) = self.rects.first() - && hit_condition(rect, &target) - { - hit = Some(RectId(0)); - } - } else { - // Traverse the tree. - let mut stack = vec![0]; - - while let Some(node_idx) = stack.pop() { - let node = self.nodes[node_idx]; - - // Skip the tree if it's not a hit. - if !hit_condition(&node.rect, &target) { - continue; - } - - for child in node.children.iter() { - match child { - NodeId::Internal(child_idx) => { - stack.push(*child_idx) - } - NodeId::Leaf(leaf_idx) => { - if hit_condition( - &self.rects[*leaf_idx], - &target, - ) { - let new_hit = RectId(*leaf_idx); - match &mut hit { - Some(hit) => { - *hit = conflict_resolution( - *hit, new_hit, - ); - } - None => hit = Some(new_hit), - } - } - } - NodeId::Invalid => continue, - } - } - } - } - - hit - } - - /// Query for all rects that contains the given [`Point`]. - pub fn query_point(&self, point: Point) -> Vec { - self.query( - point, - #[inline(always)] - |rect, point| rect.contains(*point), - ) - } - - /// Query for all rects that overlaps the given [`Rect`]. - pub fn query_rect(&self, rect: Rect) -> Vec { - self.query( - rect, - #[inline(always)] - |rect, target_rect| rect.overlaps(*target_rect), - ) - } - - /// Query for a single rects that contains the given [`Point`]. - pub fn query_point_single( - &self, - point: Point, - conflict_resolution: C, - ) -> Option - where - C: Fn(RectId, RectId) -> RectId, - { - self.query_single( - point, - #[inline(always)] - |rect, point| rect.contains(*point), - conflict_resolution, - ) - } - - /// Query for a single rects that contains the given [`Point`]. - pub fn query_rect_single( - &self, - rect: Rect, - conflict_resolution: C, - ) -> Option - where - C: Fn(RectId, RectId) -> RectId, - { - self.query_single( - rect, - #[inline(always)] - |rect, target_rect| rect.overlaps(*target_rect), - conflict_resolution, - ) - } -} - -/// An internal node within the [`Spatree`]. -#[derive(Debug, Clone, Copy)] -pub struct Node { - pub rect: Rect, - pub parent: Option, - pub children: [NodeId; 2], -} - -impl Node { - /// Empty node with zero area, no children, and no parent. - pub const EMPTY: Self = Self { - rect: Rect::ZERO, - parent: None, - children: [NodeId::Invalid; 2], - }; -} - -#[derive( - Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, -)] -pub enum NodeId { - Internal(usize), - Leaf(usize), - Invalid, -} - -#[derive( - Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, -)] -pub struct RectId(usize); - -impl RectId { - pub fn into_inner(self) -> usize { - self.0 - } -} - -impl Deref for RectId { - type Target = usize; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -/// Top down hierarchy building for single threaded algorithm. -pub fn generate_hierarchy(codes: &[MortonCode]) -> Vec { - let len = codes.len(); - if len <= 1 { - return Vec::new(); - } - - // A binary tree with N leaves has exactly N - 1 internal nodes. - let mut internal_nodes = vec![Node::EMPTY; len - 1]; - - /// Represents a range to be split and its connection to the tree. - struct BuildStack { - first: usize, - last: usize, - parent_idx: Option, - /// `0` for left, `1` for right. - child_slot: usize, - } - - let mut stack = Vec::with_capacity(len); - let mut node_idx = 0; - - // First build stakc will have the full range. - stack.push(BuildStack { - first: 0, - last: internal_nodes.len(), - parent_idx: None, - child_slot: 0, - }); - - while let Some(task) = stack.pop() { - let BuildStack { - first, - last, - parent_idx, - child_slot, - } = task; - - let curr_node_id = if first == last { - // Single element range represents a leaf node. - NodeId::Leaf(codes[first].index) - } else { - // Internal node case. - let node_id = NodeId::Internal(node_idx); - let split = find_split(codes, first, last); - - // Push right sub-range then left sub-range (LIFO). - stack.push(BuildStack { - first, - last: split, - parent_idx: Some(node_idx), - child_slot: 0, - }); - stack.push(BuildStack { - first: split + 1, - last, - parent_idx: Some(node_idx), - child_slot: 1, - }); - - node_idx += 1; - node_id - }; - - // Link the current node to its parent if it's not the root. - if let Some(parent_idx) = parent_idx { - internal_nodes[parent_idx].children[child_slot] = - curr_node_id; - - // If the current node is internal, set its parent index. - if let NodeId::Internal(curr_idx) = curr_node_id { - internal_nodes[curr_idx].parent = Some(parent_idx); - } - } - } - - internal_nodes -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_empty_tree() { - let mut tree = Spatree::new(); - tree.build(|r| r.center()); - - assert!(tree.rects.is_empty()); - assert!(tree.nodes.is_empty()); - assert_eq!(tree.global_bound().area(), 0.0); - - let hits = tree.query_point(Point::new(10.0, 10.0)); - assert!(hits.is_empty()); - } - - #[test] - fn test_single_item_tree() { - let mut tree = Spatree::new(); - let r1 = Rect::new(0.0, 0.0, 10.0, 10.0); - let id = tree.push_rect(r1); - - tree.build(|r| r.center()); - - // Single item means N-1 = 0 internal nodes. - assert!(tree.nodes.is_empty()); - - let hits = tree.query_point(Point::new(5.0, 5.0)); - assert_eq!(hits.len(), 1); - assert_eq!(hits[0], id); - } - - #[test] - fn test_hierarchy_structure_and_bounds() { - let mut tree = Spatree::new(); - - // 4 corners of a 100x100 area. - // Top left. - let r1 = Rect::new(0.0, 0.0, 10.0, 10.0); - // Top right. - let r2 = Rect::new(90.0, 0.0, 100.0, 10.0); - // Bottom left. - let r3 = Rect::new(0.0, 90.0, 10.0, 100.0); - // Bottom right. - let r4 = Rect::new(90.0, 90.0, 100.0, 100.0); - - tree.push_rect(r1); - tree.push_rect(r2); - tree.push_rect(r3); - tree.push_rect(r4); - - tree.build(|r| r.center()); - - // N items = N-1 internal nodes. - assert_eq!(tree.nodes.len(), 3); - - // Root is the first node generated in top-down. - let root = &tree.nodes[0]; - let expected_union = r1.union(r2).union(r3).union(r4); - - assert_eq!(root.rect.x0, expected_union.x0); - assert_eq!(root.rect.y0, expected_union.y0); - assert_eq!(root.rect.x1, expected_union.x1); - assert_eq!(root.rect.y1, expected_union.y1); - } - - #[test] - fn test_query_point() { - let mut tree = Spatree::new(); - let r1 = Rect::new(10.0, 10.0, 30.0, 30.0); - let r2 = Rect::new(20.0, 20.0, 40.0, 40.0); - - let id1 = tree.push_rect(r1); - let id2 = tree.push_rect(r2); - - tree.build(|r| r.center()); - - // Point inside intersection. - let hits = tree.query_point(Point::new(25.0, 25.0)); - assert_eq!(hits.len(), 2); - assert!(hits.contains(&id1)); - assert!(hits.contains(&id2)); - } - - #[test] - fn test_query_rect() { - let mut tree = Spatree::new(); - - // Define 3 distinct areas. - // Top left. - let r1 = Rect::new(0.0, 0.0, 10.0, 10.0); - // Top right. - let r2 = Rect::new(20.0, 0.0, 30.0, 10.0); - // Bottom wide strip. - let r3 = Rect::new(0.0, 20.0, 30.0, 30.0); - - let id1 = tree.push_rect(r1); - let id2 = tree.push_rect(r2); - let id3 = tree.push_rect(r3); - - tree.build(|r| r.center()); - - // 1. Overlaps only `r1`. - let q1 = Rect::new(-5.0, -5.0, 5.0, 5.0); - let hits = tree.query_rect(q1); - assert_eq!(hits.len(), 1); - assert!(hits.contains(&id1)); - - // 2. Overlaps `r1` and `r2` but not `r3`. - let q2 = Rect::new(5.0, 2.0, 25.0, 8.0); - let hits = tree.query_rect(q2); - assert_eq!(hits.len(), 2); - assert!(hits.contains(&id1)); - assert!(hits.contains(&id2)); - assert!(!hits.contains(&id3)); - - // 3. Overlaps all 3. - let q3 = Rect::new(5.0, 5.0, 25.0, 25.0); - let hits = tree.query_rect(q3); - assert_eq!(hits.len(), 3); - assert!(hits.contains(&id1)); - assert!(hits.contains(&id2)); - assert!(hits.contains(&id3)); - - // 4. Complete miss - let q4 = Rect::new(100.0, 100.0, 110.0, 110.0); - let hits = tree.query_rect(q4); - assert!(hits.is_empty()); - } - - /// Largest index win (simulating a stack/z-order). - #[inline(always)] - fn stack_conflict_resolution(a: RectId, b: RectId) -> RectId { - if a > b { a } else { b } - } - - #[test] - fn test_query_point_single() { - let mut tree = Spatree::new(); - - // Largest (lowest). - let id0 = tree.push_rect(Rect::new(0.0, 0.0, 100.0, 100.0)); - // Middle (center). - let id1 = tree.push_rect(Rect::new(0.0, 0.0, 50.0, 50.0)); - // Smallest (top). - let id2 = tree.push_rect(Rect::new(0.0, 0.0, 10.0, 10.0)); - - assert!(id0 < id1 && id1 < id2, "Ids should be incremented!"); - - tree.build(|r| r.center()); - - // 1. Point hits all 3. - let p1 = Point::new(5.0, 5.0); - let hit = - tree.query_point_single(p1, stack_conflict_resolution); - assert_eq!(hit, Some(id2)); - - // 2. Point hits `id0` and `id1`, but misses the tiny `id2`. - let p2 = Point::new(20.0, 20.0); - let hit = - tree.query_point_single(p2, stack_conflict_resolution); - assert_eq!(hit, Some(id1)); - - // 3. Point hits only the large base `id0`. - let p3 = Point::new(75.0, 75.0); - let hit = - tree.query_point_single(p3, stack_conflict_resolution); - assert_eq!(hit, Some(id0)); - - // 4. Complete miss. - let p4 = Point::new(150.0, 150.0); - let hit = - tree.query_point_single(p4, stack_conflict_resolution); - assert!(hit.is_none()); - } - - #[test] - fn test_query_rect_single() { - let mut tree = Spatree::new(); - - // Largest (lowest). - let id0 = tree.push_rect(Rect::new(0.0, 0.0, 100.0, 100.0)); - // Middle (center). - let id1 = tree.push_rect(Rect::new(0.0, 0.0, 50.0, 50.0)); - // Smallest (top). - let id2 = tree.push_rect(Rect::new(0.0, 0.0, 10.0, 10.0)); - - tree.build(|r| r.center()); - - // 1. Overlaps all 3. - let q1 = Rect::new(2.0, 2.0, 8.0, 8.0); - let hit = - tree.query_rect_single(q1, stack_conflict_resolution); - assert_eq!(hit, Some(id2)); - - // 2. Overlaps `id0` and `id1`, but misses `id2`. - let q2 = Rect::new(15.0, 15.0, 25.0, 25.0); - let hit = - tree.query_rect_single(q2, stack_conflict_resolution); - assert_eq!(hit, Some(id1)); - - // 3. Overlaps only the largest base `id0`. - let q3 = Rect::new(60.0, 60.0, 70.0, 70.0); - let hit = - tree.query_rect_single(q3, stack_conflict_resolution); - assert_eq!(hit, Some(id0)); - - // 4. Complete miss. - let q4 = Rect::new(200.0, 200.0, 210.0, 210.0); - let hit = - tree.query_rect_single(q4, stack_conflict_resolution); - assert!(hit.is_none()); - } -} diff --git a/crates/spatree/src/morton.rs b/crates/spatree/src/morton.rs deleted file mode 100644 index a94ec7b..0000000 --- a/crates/spatree/src/morton.rs +++ /dev/null @@ -1,114 +0,0 @@ -/// Stores the Morton code alongside their associated leaf index. -/// -/// This struct is optimized for ordering based only on -/// [`Self::code`] without any consideration for [`Self::index`]. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct MortonCode { - pub code: u32, - pub index: usize, -} - -impl Ord for MortonCode { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - self.code.cmp(&other.code) - } -} - -impl PartialOrd for MortonCode { - fn partial_cmp( - &self, - other: &Self, - ) -> Option { - Some(self.cmp(other)) - } -} - -/// `x` & `y` must be within (and will be clamped into) -/// the `0..=1` range. -pub fn morton_2d_f64(x: f64, y: f64) -> u32 { - const MAX: f64 = 65535.0; - let x = (x.clamp(0.0, 1.0) * MAX) as u16; - let y = (y.clamp(0.0, 1.0) * MAX) as u16; - - morton_2d(x, y) -} - -/// Combine 2 [`u16`] integers into a [`u32`] morton code. -pub fn morton_2d(x: u16, y: u16) -> u32 { - fn expand(mut v: u32) -> u32 { - v = (v | (v << 8)) & 0x00FF00FF; - v = (v | (v << 4)) & 0x0F0F0F0F; - v = (v | (v << 2)) & 0x33333333; - v = (v | (v << 1)) & 0x55555555; - v - } - expand(x as u32) | (expand(y as u32) << 1) -} - -/// Find the split point for a range of sorted Morton codes. -/// -/// Locate the position where the shared bit prefix changes and -/// return the index used to divide the range into two clusters. -pub const fn find_split( - morton_codes: &[MortonCode], - first: usize, - last: usize, -) -> usize { - let first_code = morton_codes[first].code; - let last_code = morton_codes[last].code; - // Split the range in the middle for identical Morton codes. - if first_code == last_code { - return (first + last) >> 1; - }; - - let common_prefix = calc_common_prefix(first_code, last_code); - - // Use binary search to find where the next bit differs. - // Specifically, we are looking for the highest object that - // shares more than `common_prefix` bits with the first one. - - // Initial guess. - let mut split = first; - let mut step = last - first; - while step > 1 { - // Exponential decrease. - step = (step + 1) >> 1; - // Proposed new position. - let new_split = split + step; - - if new_split < last { - let split_code = morton_codes[new_split].code; - let split_prefix = - calc_common_prefix(first_code, split_code); - - if split_prefix > common_prefix { - // Accept proposal. - split = new_split - }; - } - } - - split -} - -/// Measures the common prefix of two morton codes. -#[inline] -pub const fn calc_common_prefix(code_a: u32, code_b: u32) -> u32 { - (code_a ^ code_b).leading_zeros() -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_morton_logic_consistency() { - // Ensure x and y bits are interleaved correctly. - // x=1 (01), y=0 (00) -> 01 - assert_eq!(morton_2d(1, 0), 1); - // x=0 (00), y=1 (01) -> 10 (binary) -> 2 - assert_eq!(morton_2d(0, 1), 2); - // x=1 (01), y=1 (01) -> 11 (binary) -> 3 - assert_eq!(morton_2d(1, 1), 3); - } -} diff --git a/examples/vello_winit_examples/examples/layout_basic.rs b/examples/layout_basic/main.rs similarity index 99% rename from examples/vello_winit_examples/examples/layout_basic.rs rename to examples/layout_basic/main.rs index 1a0de45..5c33d57 100644 --- a/examples/vello_winit_examples/examples/layout_basic.rs +++ b/examples/layout_basic/main.rs @@ -46,7 +46,8 @@ use rectree::{ use vello::Scene; use vello::peniko::Color; use vello::peniko::color::palette::css; -use vello_winit_examples::{VelloDemo, VelloWinitApp}; +mod vello_winit; +use vello_winit::{VelloDemo, VelloWinitApp}; use winit::event_loop::EventLoop; fn main() { diff --git a/examples/vello_winit_examples/src/lib.rs b/examples/layout_basic/vello_winit.rs similarity index 100% rename from examples/vello_winit_examples/src/lib.rs rename to examples/layout_basic/vello_winit.rs diff --git a/examples/vello_winit_examples/Cargo.toml b/examples/vello_winit_examples/Cargo.toml deleted file mode 100644 index 5665017..0000000 --- a/examples/vello_winit_examples/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "vello_winit_examples" -version.workspace = true -edition.workspace = true -license.workspace = true -repository.workspace = true -publish = false - -[dependencies] -rectree.workspace = true -hashbrown.workspace = true -kurbo.workspace = true -vello = "0.7" -winit = "0.30.12" -pollster = "0.4.0" diff --git a/crates/rectree/src/geom.rs b/src/geom.rs similarity index 100% rename from crates/rectree/src/geom.rs rename to src/geom.rs diff --git a/crates/rectree/src/lib.rs b/src/lib.rs similarity index 100% rename from crates/rectree/src/lib.rs rename to src/lib.rs diff --git a/crates/rectree/src/node.rs b/src/node.rs similarity index 100% rename from crates/rectree/src/node.rs rename to src/node.rs