diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 7701209c1..578b1a3c5 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -1,49 +1,38 @@ -name: github pages - +name: Deploy Nightly Docs on: - workflow_dispatch: - # push: - # paths: - # - docs/** - # - .github/workflows/docs.yml - # branches: - # - master - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true + push: + branches: + - master jobs: - build-deploy: + deploy: + name: Build & Deploy runs-on: ubuntu-latest - environment: docs + permissions: + contents: write + steps: - - # NOTE: Comment out when https://github.com/rust-lang/mdBook/pull/1306 is merged and released - # - name: Setup mdBook - # uses: peaceiris/actions-mdbook@v1 - # with: - # mdbook-version: "0.4.10" - - # NOTE: Delete when the previous one is enabled - - name: Setup mdBook - run: | - cargo install mdbook --git https://github.com/Demonthos/mdBook.git --branch master - uses: actions/checkout@v4 + - run: sudo apt-get update + - run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev libxdo-dev + - uses: dtolnay/rust-toolchain@nightly + with: + toolchain: nightly-2024-02-01 + - uses: Swatinem/rust-cache@v2 + with: + cache-all-crates: "true" + save-if: ${{ github.ref == 'refs/heads/master' }} + - uses: ilammy/setup-nasm@v1 - - name: Build - run: cd docs && - cd guide && mdbook build -d ../nightly/guide && cd .. && - cd router && mdbook build -d ../nightly/router && cd .. - # cd reference && mdbook build -d ../nightly/reference && cd .. && - # cd fermi && mdbook build -d ../nightly/fermi && cd .. + - name: cargo doc + run: cargo doc --no-deps --workspace --all-features - - name: Deploy 🚀 + - name: Deploy uses: JamesIves/github-pages-deploy-action@v4.5.0 with: - branch: gh-pages # The branch the action should deploy to. - folder: docs/nightly # The folder the action should deploy. - target-folder: docs/nightly + branch: gh-pages + folder: target/doc + target-folder: api-docs/nightly repository-name: dioxuslabs/docsite clean: false - token: ${{ secrets.DEPLOY_KEY }} # let's pretend I don't need it for now + token: ${{ secrets.DEPLOY_KEY }} diff --git a/Cargo.lock b/Cargo.lock index 8969db311..4f920a0fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -168,9 +168,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2faccea4cc4ab4a667ce676a30e8ec13922a692c99bb8f5b11f1502c72e04220" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anstyle-parse" @@ -326,13 +326,13 @@ dependencies = [ [[package]] name = "async-channel" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca33f4bc4ed1babef42cad36cc1f51fa88be00420404e5b1e80ab1b18f7678c" +checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3" dependencies = [ "concurrent-queue", - "event-listener 4.0.3", - "event-listener-strategy", + "event-listener 5.0.0", + "event-listener-strategy 0.5.0", "futures-core", "pin-project-lite", ] @@ -422,7 +422,7 @@ dependencies = [ "futures-io", "futures-lite 2.2.0", "parking", - "polling 3.3.2", + "polling 3.4.0", "rustix 0.38.31", "slab", "tracing", @@ -445,7 +445,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" dependencies = [ "event-listener 4.0.3", - "event-listener-strategy", + "event-listener-strategy 0.4.0", "pin-project-lite", ] @@ -907,16 +907,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base64" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" -dependencies = [ - "byteorder", - "safemem", -] - [[package]] name = "base64" version = "0.13.1" @@ -1158,9 +1148,9 @@ checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "bytecheck" -version = "0.6.11" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6372023ac861f6e6dc89c8344a8f398fb42aaba2b5dbc649ca0c0e9dbcb627" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" dependencies = [ "bytecheck_derive", "ptr_meta", @@ -1169,9 +1159,9 @@ dependencies = [ [[package]] name = "bytecheck_derive" -version = "0.6.11" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7ec4c6f261935ad534c0c22dbef2201b45918860eb1c574b972bd213a76af61" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" dependencies = [ "proc-macro2", "quote", @@ -1180,9 +1170,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.14.1" +version = "1.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2490600f404f2b94c167e31d3ed1d5f3c225a0f3b80230053b3e0b7b962bd9" +checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f" [[package]] name = "byteorder" @@ -1287,7 +1277,7 @@ dependencies = [ "serde", "tempfile", "thiserror", - "toml 0.8.9", + "toml 0.8.10", "walkdir", ] @@ -1318,9 +1308,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceed8ef69d8518a5dda55c07425450b58a4e1946f4951eab6d7191ee86c2443d" +checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f" dependencies = [ "serde", ] @@ -1374,7 +1364,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3f9629bc6c4388ea699781dc988c2b99766d7679b151c81990b4fa1208fafd3" dependencies = [ "serde", - "toml 0.8.9", + "toml 0.8.10", ] [[package]] @@ -1384,7 +1374,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "802b755090e39835a4b0440fb0bbee0df7495a8b337f63db21e616f7821c7e8c" dependencies = [ "serde", - "toml 0.8.9", + "toml 0.8.10", ] [[package]] @@ -1437,9 +1427,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.15.6" +version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6100bc57b6209840798d95cb2775684849d332f7bd788db2a8c8caf7ef82a41a" +checksum = "fa50868b64a9a6fda9d593ce778849ea8715cd2a3d2cc17ffdb4a2f2f2f1961d" dependencies = [ "smallvec", "target-lexicon", @@ -2415,11 +2405,11 @@ dependencies = [ "flate2", "fs_extra", "futures-util", - "gitignore", "headers 0.3.9", "html_parser", "hyper 0.14.28", "hyper-rustls 0.23.2", + "ignore", "indicatif", "interprocess-docfix", "lazy_static", @@ -2428,17 +2418,20 @@ dependencies = [ "mlua", "notify", "open", + "prettier-please", + "rayon", "reqwest", "rsx-rosetta", "serde", "serde_json", "subprocess", + "syn 2.0.48", "tar", "tauri-bundler", "tempfile", "thiserror", "tokio", - "toml 0.8.9", + "toml 0.8.10", "toml_edit 0.21.1", "tower", "tower-http 0.2.5", @@ -2886,7 +2879,7 @@ version = "0.4.3" dependencies = [ "dioxus", "dioxus-core", - "flume 0.11.0", + "flume", "futures-channel", "futures-util", "generational-box", @@ -3245,6 +3238,17 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "event-listener" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b72557800024fabbaa2449dd4bf24e37b93702d457a4d4f2b0dd1f0f039f20c1" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + [[package]] name = "event-listener-strategy" version = "0.4.0" @@ -3255,6 +3259,16 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "event-listener-strategy" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291" +dependencies = [ + "event-listener 5.0.0", + "pin-project-lite", +] + [[package]] name = "execute" version = "0.2.13" @@ -3300,12 +3314,12 @@ checksum = "de853764b47027c2e862a995c34978ffa63c1501f2e15f987ba11bd4f9bba193" [[package]] name = "exr" -version = "1.6.4" +version = "1.72.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "279d3efcc55e19917fff7ab3ddd6c14afb6a90881a0078465196fe2f99d08c56" +checksum = "887d93f60543e9a9362ef8a21beedd0a833c5d9610e18c67abe15a5963dcb1a4" dependencies = [ "bit_field", - "flume 0.10.14", + "flume", "half 2.3.1", "lebe", "miniz_oxide", @@ -3382,7 +3396,7 @@ dependencies = [ "atomic 0.6.0", "pear", "serde", - "toml 0.8.9", + "toml 0.8.10", "uncased", "version_check", ] @@ -3421,19 +3435,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "flume" -version = "0.10.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" -dependencies = [ - "futures-core", - "futures-sink", - "nanorand", - "pin-project", - "spin 0.9.8", -] - [[package]] name = "flume" version = "0.11.0" @@ -3928,9 +3929,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf97ba92db08df386e10c8ede66a2a0369bd277090afd8710e19e38de9ec0cd" +checksum = "1b3ba52851e73b46a4c3df1d89343741112003f0f6f13beb0dfac9e457c3fdcd" dependencies = [ "bitflags 2.4.2", "libc", @@ -3941,15 +3942,6 @@ dependencies = [ "url", ] -[[package]] -name = "gitignore" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d051488d9a601181a9b90c9ad8ae7e8251d642ddd2463008f2f5019d255bd89" -dependencies = [ - "glob", -] - [[package]] name = "gix-actor" version = "0.28.1" @@ -4688,9 +4680,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" +checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3" [[package]] name = "hex" @@ -4725,6 +4717,29 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "hoot" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df22a4d90f1b0e65fe3e0d6ee6a4608cc4d81f4b2eb3e670f44bb6bde711e452" +dependencies = [ + "httparse", + "log", +] + +[[package]] +name = "hootbin" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "354e60868e49ea1a39c44b9562ad207c4259dc6eabf9863bf3b0f058c55cfdb2" +dependencies = [ + "fastrand 2.0.1", + "hoot", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "hostname" version = "0.3.1" @@ -4955,9 +4970,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.59" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -5226,7 +5241,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.4", + "hermit-abi 0.3.5", "libc", "windows-sys 0.48.0", ] @@ -5278,12 +5293,12 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" +checksum = "fe8f25ce1159c7740ff0b9b2f5cdf4a8428742ba7c112b9f20f22cd5219c7dab" dependencies = [ - "hermit-abi 0.3.4", - "rustix 0.38.31", + "hermit-abi 0.3.5", + "libc", "windows-sys 0.52.0", ] @@ -5299,9 +5314,9 @@ dependencies = [ [[package]] name = "is_ci" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb" +checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" [[package]] name = "itertools" @@ -5389,9 +5404,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" dependencies = [ "libc", ] @@ -5407,9 +5422,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" dependencies = [ "wasm-bindgen", ] @@ -5562,9 +5577,9 @@ dependencies = [ [[package]] name = "libgit2-sys" -version = "0.16.1+1.7.1" +version = "0.16.2+1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2a2bb3680b094add03bb3732ec520ece34da31a8cd2d633d1389d0f0fb60d0c" +checksum = "ee4126d8b4ee5c9d9ea891dd875cfdc1e9d0950437179104b183d7d8a74d24e8" dependencies = [ "cc", "libc", @@ -5820,15 +5835,6 @@ dependencies = [ "imgref", ] -[[package]] -name = "lru" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6e8aaa3f231bb4bd57b84b2d5dc3ae7f350265df8aa96492e0bc394a1571909" -dependencies = [ - "hashbrown 0.12.3", -] - [[package]] name = "lru" version = "0.10.1" @@ -6121,9 +6127,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", "simd-adler32", @@ -6274,15 +6280,6 @@ dependencies = [ "rand 0.8.5", ] -[[package]] -name = "nanorand" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" -dependencies = [ - "getrandom 0.2.12", -] - [[package]] name = "nasm-rs" version = "0.2.5" @@ -6488,9 +6485,9 @@ dependencies = [ [[package]] name = "num-derive" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", @@ -6499,19 +6496,18 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" dependencies = [ "autocfg", "num-integer", @@ -6532,9 +6528,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", "libm", @@ -6546,7 +6542,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.4", + "hermit-abi 0.3.5", "libc", ] @@ -6969,9 +6965,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.6" +version = "2.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f200d8d83c44a45b21764d1916299752ca035d15ecd46faca3e9a2a2bf6ad06" +checksum = "219c0dcc30b6a27553f9cc242972b67f75b60eb0db71f0b5462f38b058c41546" dependencies = [ "memchr", "thiserror", @@ -6980,9 +6976,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.6" +version = "2.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcd6ab1236bbdb3a49027e920e693192ebfe8913f6d60e294de57463a493cfde" +checksum = "22e1288dbd7786462961e69bfd4df7848c1e37e8b74303dbdab82c3a9cdd2809" dependencies = [ "pest", "pest_generator", @@ -6990,9 +6986,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.6" +version = "2.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a31940305ffc96863a735bef7c7994a00b325a7138fdbc5bda0f1a0476d3275" +checksum = "1381c29a877c6d34b8c176e734f35d7f7f5b3adaefe940cb4d1bb7af94678e2e" dependencies = [ "pest", "pest_meta", @@ -7003,9 +6999,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.7.6" +version = "2.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7ff62f5259e53b78d1af898941cdcdccfae7385cf7d793a6e55de5d05bb4b7d" +checksum = "d0934d6907f148c22a3acbda520c7eed243ad7487a30f51f6ce52b58b7077a8a" dependencies = [ "once_cell", "pest", @@ -7321,9 +7317,9 @@ dependencies = [ [[package]] name = "polling" -version = "3.3.2" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "545c980a3880efd47b2e262f6a4bb6daad6555cf3367aa9c4e52895f69537a41" +checksum = "30054e72317ab98eddd8561db0f6524df3367636884b7b21b703e4b280a84a14" dependencies = [ "cfg-if", "concurrent-queue", @@ -7755,7 +7751,7 @@ dependencies = [ "nasm-rs", "new_debug_unreachable", "noop_proc_macro", - "num-derive 0.4.1", + "num-derive 0.4.2", "num-traits", "once_cell", "paste", @@ -7918,9 +7914,9 @@ dependencies = [ [[package]] name = "rend" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2571463863a6bd50c32f94402933f03457a3fbaf697a707c5be741e459f08fd" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" dependencies = [ "bytecheck", ] @@ -7968,7 +7964,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots", + "webpki-roots 0.25.4", "winreg", ] @@ -8072,9 +8068,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.7.43" +version = "0.7.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527a97cdfef66f65998b5f3b637c26f5a5ec09cc52a3f9932313ac645f4190f5" +checksum = "5cba464629b3394fc4dbc6f940ff8f5b4ff5c7aef40f29166fd4ad12acbc99c0" dependencies = [ "bitvec", "bytecheck", @@ -8090,9 +8086,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.43" +version = "0.7.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5c462a1328c8e67e4d6dbad1eb0355dd43e8ab432c6e227a43657f16ade5033" +checksum = "a7dddfff8de25e6f62b9d64e6e432bf1c6736c57d20323e15ee10435fbda7c65" dependencies = [ "proc-macro2", "quote", @@ -8384,10 +8380,24 @@ checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", "ring 0.17.7", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" +dependencies = [ + "log", + "ring 0.17.7", + "rustls-pki-types", + "rustls-webpki 0.102.2", + "subtle", + "zeroize", +] + [[package]] name = "rustls-native-certs" version = "0.6.3" @@ -8409,6 +8419,12 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pki-types" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a716eb65e3158e90e17cd93d855216e27bde02745ab842f2cab4a39dba1bacf" + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -8419,6 +8435,17 @@ dependencies = [ "untrusted 0.9.0", ] +[[package]] +name = "rustls-webpki" +version = "0.102.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" +dependencies = [ + "ring 0.17.7", + "rustls-pki-types", + "untrusted 0.9.0", +] + [[package]] name = "rustversion" version = "1.0.14" @@ -8835,9 +8862,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.6.0" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b0ed1662c5a68664f45b76d18deb0e234aff37207086803165c961eb695e981" +checksum = "15d167997bd841ec232f5b2b8e0e26606df2e7caa4c31b95ea9ca52b200bd270" dependencies = [ "base64 0.21.7", "chrono", @@ -8845,6 +8872,7 @@ dependencies = [ "indexmap 1.9.3", "indexmap 2.2.2", "serde", + "serde_derive", "serde_json", "serde_with_macros", "time", @@ -8852,9 +8880,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.6.0" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "568577ff0ef47b879f736cd66740e022f3672788cdf002a05a4e609ea5a6fb15" +checksum = "865f9743393e638991566a8b7a479043c2c8da94a33e0a31f18214c9cae0a64d" dependencies = [ "darling", "proc-macro2", @@ -9108,11 +9136,11 @@ dependencies = [ [[package]] name = "sledgehammer_utils" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cd16550f1dd7866c7580dbf80c892dc1bef106737eeb850d42c62ec61896059" +checksum = "f20798defa0e9d4eff9ca451c7f84774c7378a9c3b5a40112cfa2b3eadb97ae2" dependencies = [ - "lru 0.8.1", + "lru 0.12.2", "once_cell", "rustc-hash", ] @@ -9295,7 +9323,7 @@ dependencies = [ "tracing", "url", "uuid", - "webpki-roots", + "webpki-roots 0.25.4", ] [[package]] @@ -9441,7 +9469,7 @@ checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490" dependencies = [ "atoi", "chrono", - "flume 0.11.0", + "flume", "futures-channel", "futures-core", "futures-executor", @@ -9665,10 +9693,10 @@ version = "6.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a2d580ff6a20c55dfb86be5f9c238f67835d0e81cbdea8bf5680e0897320331" dependencies = [ - "cfg-expr 0.15.6", + "cfg-expr 0.15.7", "heck 0.4.1", "pkg-config", - "toml 0.8.9", + "toml 0.8.10", "version-compare", ] @@ -9940,9 +9968,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe80ced77cbfb4cb91a94bf72b378b4b6791a0d9b7f09d0be747d1bdff4e68bd" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" dependencies = [ "deranged", "itoa 1.0.10", @@ -10159,15 +10187,15 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6a4b9e8023eb94392d3dca65d717c53abc5dad49c07cb65bb8fcd87115fa325" +checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290" dependencies = [ "indexmap 2.2.2", "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.21.1", + "toml_edit 0.22.4", ] [[package]] @@ -10208,6 +10236,17 @@ name = "toml_edit" version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap 2.2.2", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ffdf896f8daaabf9b66ba8e77ea1ed5ed0f72821b398aba62352e95062951" dependencies = [ "indexmap 2.2.2", "serde", @@ -10404,9 +10443,9 @@ dependencies = [ [[package]] name = "treediff" -version = "4.0.2" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52984d277bdf2a751072b5df30ec0377febdb02f7696d64c2d7d54630bac4303" +checksum = "4d127780145176e2b5d16611cc25a900150e86e9fd79d3bde6ff3a37359c9cb5" dependencies = [ "serde_json", ] @@ -10565,9 +10604,9 @@ dependencies = [ [[package]] name = "ulid" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3c3b4dcec1e4729aab50688a1a0631483d79e65b194851425e7748287715a6" +checksum = "34778c17965aa2a08913b57e1f34db9b4a63f5de31768b55bf20d2795f921259" dependencies = [ "getrandom 0.2.12", "rand 0.8.5", @@ -10622,9 +10661,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" @@ -10668,18 +10707,20 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "2.9.1" +version = "2.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cdd25c339e200129fe4de81451814e5228c9b771d57378817d6117cc2b3f97" +checksum = "0b52731d03d6bb2fd18289d4028aee361d6c28d44977846793b994b13cdcc64d" dependencies = [ "base64 0.21.7", + "hootbin", "log", "native-tls", "once_cell", - "rustls 0.21.10", - "rustls-webpki", + "rustls 0.22.2", + "rustls-pki-types", + "rustls-webpki 0.102.2", "url", - "webpki-roots", + "webpki-roots 0.26.1", ] [[package]] @@ -10731,7 +10772,7 @@ checksum = "c372e4e6fad129795fb86fda6021b258948560b39883b80ed00510a7d19846b0" dependencies = [ "cfg-if", "noop_proc_macro", - "num-derive 0.4.1", + "num-derive 0.4.2", "num-traits", "profiling", ] @@ -10883,9 +10924,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -10893,9 +10934,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" dependencies = [ "bumpalo", "log", @@ -10908,12 +10949,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-cli-support" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a875870b7b39024cbca8f61a0e1fc8edfe7ac02b484e5a9bcea64374050a850e" +checksum = "806a045c4ec4ef7c3ad86dc27bcb641b84d9eeb3846200f56d7ab0885241d654" dependencies = [ "anyhow", - "base64 0.9.3", + "base64 0.21.7", "log", "rustc-demangle", "serde_json", @@ -10930,9 +10971,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-externref-xform" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04c5d468dc79cfd824d181c386f34c2e7ea521ea5855ddd95af8f4cf3fa676f4" +checksum = "12b6ac5fca1d0992d2328147488169ea166bfe899c88f8ad06cf583f4c492fcf" dependencies = [ "anyhow", "walrus", @@ -10940,9 +10981,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" +checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97" dependencies = [ "cfg-if", "js-sys", @@ -10952,9 +10993,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -10962,9 +11003,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", @@ -10975,9 +11016,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-multi-value-xform" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65f10c037dad45759d53b598d4737acdced90a0945023c8c6cd8d67b4b3e4eaf" +checksum = "d1e019acde479e2f090fb7f14a51fa0077ec3a7bb12a56e0e888a82be7b5bd3f" dependencies = [ "anyhow", "walrus", @@ -10985,15 +11026,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" +checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" [[package]] name = "wasm-bindgen-test" -version = "0.3.40" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139bd73305d50e1c1c4333210c0db43d989395b64a237bd35c10ef3832a7f70c" +checksum = "143ddeb4f833e2ed0d252e618986e18bfc7b0e52f2d28d77d05b2f045dd8eb61" dependencies = [ "console_error_panic_hook", "js-sys", @@ -11005,9 +11046,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.40" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70072aebfe5da66d2716002c729a14e4aec4da0e23cc2ea66323dac541c93928" +checksum = "a5211b7550606857312bba1d978a8ec75692eae187becc5e680444fffc5e6f89" dependencies = [ "proc-macro2", "quote", @@ -11016,9 +11057,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-threads-xform" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ddf1a4beb1bceb2b73c2325581901ca2cd92af628f24389a678854dcd65b24" +checksum = "90a2e577034352f9aa9352730fcf2562c68957f2e9b9ee70ab6379510e49e2fe" dependencies = [ "anyhow", "walrus", @@ -11027,9 +11068,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-wasm-conventions" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f13ed8ccdac31eadcfd4c9b2ec7bd43e77454b14acb1f43189f2875a9b0391" +checksum = "4e6b653f6820409609bda0f176e6949302307af7a7b9479cd4d4b1bdc31eb9cd" dependencies = [ "anyhow", "walrus", @@ -11037,9 +11078,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-wasm-interpreter" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4282a271772a3063d4057c1144e118254f207fbbc1381b8d50b23c25585d893" +checksum = "682940195a701dbf887f20017418b8cac916a37b3f91ededec33226619e973c1" dependencies = [ "anyhow", "log", @@ -11088,9 +11129,9 @@ checksum = "449167e2832691a1bff24cde28d2804e90e09586a448c8e76984792c44334a6b" [[package]] name = "web-sys" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" +checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446" dependencies = [ "js-sys", "wasm-bindgen", @@ -11192,6 +11233,15 @@ version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +[[package]] +name = "webpki-roots" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webview2-com" version = "0.28.0" @@ -11550,9 +11600,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.37" +version = "0.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7cad8365489051ae9f054164e459304af2e7e9bb407c958076c8bf4aef52da5" +checksum = "5389a154b01683d28c77f8f68f49dea75f0a4da32557a58f68ee51ebba472d29" dependencies = [ "memchr", ] @@ -11655,11 +11705,11 @@ dependencies = [ [[package]] name = "xdg-home" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2769203cd13a0c6015d515be729c526d041e9cf2c0cc478d57faee85f40c6dcd" +checksum = "21e5a325c3cb8398ad6cf859c1135b25dd29e186679cf2da7581d9679f63b38e" dependencies = [ - "nix 0.26.4", + "libc", "winapi", ] @@ -11692,9 +11742,9 @@ dependencies = [ [[package]] name = "zbus" -version = "3.14.1" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31de390a2d872e4cd04edd71b425e29853f786dc99317ed72d73d6fcf5ebb948" +checksum = "c45d06ae3b0f9ba1fb2671268b975557d8f5a84bb5ec6e43964f87e763d8bca8" dependencies = [ "async-broadcast", "async-executor", @@ -11733,9 +11783,9 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "3.14.1" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d1794a946878c0e807f55a397187c11fc7a038ba5d868e7db4f3bd7760bc9d" +checksum = "b4a1ba45ed0ad344b85a2bb5a1fe9830aed23d67812ea39a586e7d0136439c7d" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index ab16daeb3..748eb89a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,7 +84,7 @@ dioxus-signals = { path = "packages/signals" } dioxus-cli-config = { path = "packages/cli-config", version = "0.4.1" } generational-box = { path = "packages/generational-box", version = "0.4.3" } dioxus-hot-reload = { path = "packages/hot-reload", version = "0.4.0" } -dioxus-fullstack = { path = "packages/fullstack", version = "0.4.1" } +dioxus-fullstack = { path = "packages/fullstack", version = "0.4.1" } dioxus_server_macro = { path = "packages/server-macro", version = "0.4.1" } tracing = "0.1.37" tracing-futures = "0.2.5" @@ -128,7 +128,7 @@ http-range = {version = "0.1.5", optional = true } warp = { version = "0.3.0", optional = true } [dev-dependencies] -dioxus = { workspace = true, features = ["router"]} +dioxus = { workspace = true, features = ["router"] } dioxus-ssr = { workspace = true } futures-util = "0.3.21" separator = "0.4.1" diff --git a/packages/cli/Cargo.toml b/packages/cli/Cargo.toml index fd8b4e2de..657c70e0f 100644 --- a/packages/cli/Cargo.toml +++ b/packages/cli/Cargo.toml @@ -26,7 +26,7 @@ fs_extra = "1.2.0" cargo_toml = "0.18.0" futures-util = { workspace = true } notify = { version = "5.0.0-pre.16", features = ["serde"] } -html_parser = { workspace = true } +html_parser = { workspace = true } cargo_metadata = "0.18.1" tokio = { version = "1.16.1", features = ["fs", "sync", "rt", "macros"] } atty = "0.2.14" @@ -36,6 +36,7 @@ hyper = "0.14.17" hyper-rustls = "0.23.2" indicatif = "0.17.5" subprocess = "0.2.9" +rayon = "1.8.0" axum = { version = "0.5.1", features = ["ws", "headers"] } axum-server = { version = "0.5.1", features = ["tls-rustls"] } @@ -74,6 +75,10 @@ toml_edit = "0.21.0" # bundling tauri-bundler = { version = "=1.4.*", features = ["native-tls-vendored"] } +# formatting +syn = { version = "2.0" } +prettyplease = { workspace = true } + manganis-cli-support = { workspace = true, features = ["webp", "html"] } dioxus-autofmt = { workspace = true } @@ -84,7 +89,7 @@ dioxus-html = { workspace = true, features = ["hot-reload-context"] } dioxus-core = { workspace = true, features = ["serialize"] } dioxus-hot-reload = { workspace = true } interprocess-docfix = { version = "1.2.2" } -gitignore = "1.0.8" +ignore = "0.4.22" [features] default = [] diff --git a/packages/cli/src/cli/autoformat.rs b/packages/cli/src/cli/autoformat.rs index 7eb631dc6..b3d6cedf9 100644 --- a/packages/cli/src/cli/autoformat.rs +++ b/packages/cli/src/cli/autoformat.rs @@ -1,5 +1,5 @@ use dioxus_autofmt::{IndentOptions, IndentType}; -use futures_util::{stream::FuturesUnordered, StreamExt}; +use rayon::prelude::*; use std::{fs, path::Path, process::exit}; use super::*; @@ -10,6 +10,10 @@ use super::*; /// Format some rsx #[derive(Clone, Debug, Parser)] pub struct Autoformat { + /// Format rust code before the formatting the rsx macros + #[clap(long)] + pub all_code: bool, + /// Run in 'check' mode. Exits with 0 if input is formatted correctly. Exits /// with 1 and prints a diff if formatting is required. #[clap(short, long)] @@ -29,19 +33,19 @@ pub struct Autoformat { } impl Autoformat { - // Todo: autoformat the entire crate - pub async fn autoformat(self) -> Result<()> { + pub fn autoformat(self) -> Result<()> { let Autoformat { check, raw, file, split_line_attributes, + all_code: format_rust_code, .. } = self; // Default to formatting the project if raw.is_none() && file.is_none() { - if let Err(e) = autoformat_project(check, split_line_attributes).await { + if let Err(e) = autoformat_project(check, split_line_attributes, format_rust_code) { eprintln!("error formatting project: {}", e); exit(1); } @@ -60,14 +64,18 @@ impl Autoformat { // Format single file if let Some(file) = file { - refactor_file(file, split_line_attributes)?; + refactor_file(file, split_line_attributes, format_rust_code)?; } Ok(()) } } -fn refactor_file(file: String, split_line_attributes: bool) -> Result<(), Error> { +fn refactor_file( + file: String, + split_line_attributes: bool, + format_rust_code: bool, +) -> Result<(), Error> { let indent = indentation_for(".", split_line_attributes)?; let file_content = if file == "-" { let mut contents = String::new(); @@ -76,10 +84,15 @@ fn refactor_file(file: String, split_line_attributes: bool) -> Result<(), Error> } else { fs::read_to_string(&file) }; - let Ok(s) = file_content else { + let Ok(mut s) = file_content else { eprintln!("failed to open file: {}", file_content.unwrap_err()); exit(1); }; + + if format_rust_code { + s = format_rust(&s)?; + } + let edits = dioxus_autofmt::fmt_file(&s, indent); let out = dioxus_autofmt::apply_formats(&s, edits); @@ -94,50 +107,46 @@ fn refactor_file(file: String, split_line_attributes: bool) -> Result<(), Error> Ok(()) } -fn get_project_files(config: &CrateConfig) -> Vec { - let mut files = vec![]; - - let gitignore_path = config.crate_dir.join(".gitignore"); - if gitignore_path.is_file() { - let gitigno = gitignore::File::new(gitignore_path.as_path()).unwrap(); - if let Ok(git_files) = gitigno.included_files() { - let git_files = git_files - .into_iter() - .filter(|f| f.ends_with(".rs") && !is_target_dir(f)); - files.extend(git_files) - }; - } else { - collect_rs_files(&config.crate_dir, &mut files); +use std::ffi::OsStr; +fn get_project_files() -> Vec { + let mut files = Vec::new(); + for result in ignore::Walk::new("./") { + let path = result.unwrap().into_path(); + if let Some(ext) = path.extension() { + if ext == OsStr::new("rs") { + files.push(path); + } + } } - files } -fn is_target_dir(file: &Path) -> bool { - let stripped = if let Ok(cwd) = std::env::current_dir() { - file.strip_prefix(cwd).unwrap_or(file) - } else { - file - }; - if let Some(first) = stripped.components().next() { - first.as_os_str() == "target" - } else { - false - } -} - -async fn format_file( +fn format_file( path: impl AsRef, indent: IndentOptions, -) -> Result { - let contents = tokio::fs::read_to_string(&path).await?; + format_rust_code: bool, +) -> Result { + let mut contents = fs::read_to_string(&path)?; + let mut if_write = false; + if format_rust_code { + let formatted = format_rust(&contents) + .map_err(|err| Error::ParseError(format!("Syntax Error:\n{}", err)))?; + if contents != formatted { + if_write = true; + contents = formatted; + } + } let edits = dioxus_autofmt::fmt_file(&contents, indent); let len = edits.len(); if !edits.is_empty() { + if_write = true; + } + + if if_write { let out = dioxus_autofmt::apply_formats(&contents, edits); - tokio::fs::write(path, out).await?; + fs::write(path, out)?; } Ok(len) @@ -145,13 +154,15 @@ async fn format_file( /// Read every .rs file accessible when considering the .gitignore and try to format it /// -/// Runs using Tokio for multithreading, so it should be really really fast +/// Runs using rayon for multithreading, so it should be really really fast /// /// Doesn't do mod-descending, so it will still try to format unreachable files. TODO. -async fn autoformat_project(check: bool, split_line_attributes: bool) -> Result<()> { - let crate_config = dioxus_cli_config::CrateConfig::new(None)?; - - let files_to_format = get_project_files(&crate_config); +fn autoformat_project( + check: bool, + split_line_attributes: bool, + format_rust_code: bool, +) -> Result<()> { + let files_to_format = get_project_files(); if files_to_format.is_empty() { return Ok(()); @@ -164,26 +175,18 @@ async fn autoformat_project(check: bool, split_line_attributes: bool) -> Result< let indent = indentation_for(&files_to_format[0], split_line_attributes)?; let counts = files_to_format - .into_iter() - .map(|path| async { - let path_clone = path.clone(); - let res = tokio::spawn(format_file(path, indent.clone())).await; - + .into_par_iter() + .map(|path| { + let res = format_file(&path, indent.clone(), format_rust_code); match res { + Ok(cnt) => Some(cnt), Err(err) => { - eprintln!("error formatting file: {}\n{err}", path_clone.display()); + eprintln!("error formatting file : {}\n{:#?}", path.display(), err); None } - Ok(Err(err)) => { - eprintln!("error formatting file: {}\n{err}", path_clone.display()); - None - } - Ok(Ok(res)) => Some(res), } }) - .collect::>() - .collect::>() - .await; + .collect::>(); let files_formatted: usize = counts.into_iter().flatten().sum(); @@ -242,28 +245,21 @@ fn indentation_for( )) } -fn collect_rs_files(folder: &impl AsRef, files: &mut Vec) { - if is_target_dir(folder.as_ref()) { - return; - } - let Ok(folder) = folder.as_ref().read_dir() else { - return; - }; - // load the gitignore - for entry in folder { - let Ok(entry) = entry else { - continue; - }; - let path = entry.path(); - if path.is_dir() { - collect_rs_files(&path, files); - } - if let Some(ext) = path.extension() { - if ext == "rs" && !is_target_dir(&path) { - files.push(path); - } - } - } +/// Format rust code using prettyplease +fn format_rust(input: &str) -> Result { + let syntax_tree = syn::parse_file(input).map_err(format_syn_error)?; + let output = prettyplease::unparse(&syntax_tree); + Ok(output) +} + +fn format_syn_error(err: syn::Error) -> Error { + let start = err.span().start(); + let line = start.line; + let column = start.column; + Error::ParseError(format!( + "Syntax Error in line {} column {}:\n{}", + line, column, err + )) } #[tokio::test] @@ -284,13 +280,14 @@ async fn test_auto_fmt() { .to_string(); let fmt = Autoformat { + all_code: false, check: false, raw: Some(test_rsx), file: None, split_line_attributes: false, }; - fmt.autoformat().await.unwrap(); + fmt.autoformat().unwrap(); } /*#[test] diff --git a/packages/cli/src/main.rs b/packages/cli/src/main.rs index 0a57735db..dae2deb2c 100644 --- a/packages/cli/src/main.rs +++ b/packages/cli/src/main.rs @@ -70,7 +70,6 @@ async fn main() -> anyhow::Result<()> { Autoformat(opts) => opts .autoformat() - .await .context(error_wrapper("Error autoformatting RSX")), Check(opts) => opts diff --git a/packages/cli/src/server/mod.rs b/packages/cli/src/server/mod.rs index bd1cafdd8..3f9510839 100644 --- a/packages/cli/src/server/mod.rs +++ b/packages/cli/src/server/mod.rs @@ -112,12 +112,6 @@ async fn setup_file_watcher Result + Send + 'static>( }, web_info.clone(), ); - - #[cfg(feature = "plugin")] - let _ = PluginManager::on_serve_rebuild( - chrono::Local::now().timestamp(), - e.paths, - ); } Err(e) => { last_update_time = chrono::Local::now().timestamp(); diff --git a/packages/core/src/error_boundary.rs b/packages/core/src/error_boundary.rs index 7fa1d2591..6e1055c6e 100644 --- a/packages/core/src/error_boundary.rs +++ b/packages/core/src/error_boundary.rs @@ -140,12 +140,12 @@ impl ErrorBoundary { /// /// ```rust, ignore /// #[component] -/// fn app( count: String) -> Element { +/// fn app(count: String) -> Element { /// let id: i32 = count.parse().throw()?; /// /// rsx! { /// div { "Count {}" } -/// }) +/// } /// } /// ``` pub trait Throw: Sized { @@ -170,7 +170,7 @@ pub trait Throw: Sized { /// /// rsx! { /// div { "Count {}" } - /// }) + /// } /// } /// ``` fn throw(self) -> Option; @@ -193,7 +193,7 @@ pub trait Throw: Sized { /// /// rsx! { /// div { "Count {}" } - /// }) + /// } /// } /// ``` fn throw_with(self, e: impl FnOnce() -> D) -> Option { diff --git a/packages/core/src/events.rs b/packages/core/src/events.rs index 2c0c92d14..7581d0bb6 100644 --- a/packages/core/src/events.rs +++ b/packages/core/src/events.rs @@ -159,7 +159,7 @@ impl std::fmt::Debug for Event { /// button { /// onclick: move |evt| cx.onclick.call(evt), /// } -/// }) +/// } /// } /// /// ``` diff --git a/packages/core/src/lib.rs b/packages/core/src/lib.rs index a55ce4be7..afa80eb84 100644 --- a/packages/core/src/lib.rs +++ b/packages/core/src/lib.rs @@ -42,7 +42,7 @@ pub(crate) mod innerlude { /// An Errored [`Element`] will propagate the error to the nearest error boundary. pub type Element = Option; - /// A [`Component`] is a function that takes a [`Scope`] and returns an [`Element`]. + /// A [`Component`] is a function that takes [`Properties`] and returns an [`Element`]. /// /// Components can be used in other components with two syntax options: /// - lowercase as a function call with named arguments (rust style) @@ -84,7 +84,7 @@ pub use crate::innerlude::{ /// The purpose of this module is to alleviate imports of many common types /// -/// This includes types like [`Scope`], [`Element`], and [`Component`]. +/// This includes types like [`Element`], and [`Component`]. pub mod prelude { pub use crate::innerlude::{ consume_context, consume_context_from_scope, current_scope_id, fc_to_builder, flush_sync, diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index 75ce4ffc7..2de7f0514 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -24,7 +24,7 @@ use std::{any::Any, collections::BTreeSet, rc::Rc}; /// /// ## Guide /// -/// Components are defined as simple functions that take [`Scope`] and return an [`Element`]. +/// Components are defined as simple functions that take [`crate::properties::Properties`] and return an [`Element`]. /// /// ```rust /// # use dioxus::prelude::*; @@ -218,7 +218,7 @@ impl VirtualDom { /// # Example /// ```rust, ignore /// fn Example() -> Element { - /// rsx!( div { "hello world" } )) + /// rsx!( div { "hello world" } ) /// } /// /// let dom = VirtualDom::new(Example); @@ -439,7 +439,7 @@ impl VirtualDom { self.process_events(); // Now that we have collected all queued work, we should check if we have any dirty scopes. If there are not, then we can poll any queued futures - if !self.dirty_scopes.is_empty() || !self.suspended_scopes.is_empty() { + if !self.dirty_scopes.is_empty() { return; } @@ -526,7 +526,7 @@ impl VirtualDom { /// /// # Example /// ```rust, ignore - /// static app: Component = |cx| rsx!{ "hello world" }); + /// static app: Component = |cx| rsx!{ "hello world" }; /// /// let mut dom = VirtualDom::new(); /// let edits = dom.rebuild(); diff --git a/packages/dioxus/Cargo.toml b/packages/dioxus/Cargo.toml index fa1d2a4f6..b808bdc85 100644 --- a/packages/dioxus/Cargo.toml +++ b/packages/dioxus/Cargo.toml @@ -55,6 +55,9 @@ warp = ["dioxus-fullstack?/warp", "ssr", "dioxus-liveview?/warp"] rocket = ["dioxus-liveview?/rocket"] tui = ["dioxus-tui", "dioxus-config-macro/tui"] +# This feature enables some nightly flags that make it more clear what structs/methods are available in each feature +nightly-doc = [] + [dev-dependencies] futures-util = { workspace = true } tracing = { workspace = true } diff --git a/packages/dioxus/README.md b/packages/dioxus/README.md index 210ea77c3..ebd2cdb90 100644 --- a/packages/dioxus/README.md +++ b/packages/dioxus/README.md @@ -50,7 +50,7 @@ fn main() { // It's not required, but highly recommended. For example, UpperCamelCase components will not generate a warning. #[component] fn App() -> Element { - rsx!("hello world!")) + rsx!("hello world!") } ``` @@ -97,13 +97,12 @@ If we want to omit the boilerplate of `cx.render`, we can simply pass in render nodes in match statements. ```rust, ignore -#[component[ +#[component] fn Example() -> Element { - // both of these are equivalent - rsx!("hello world")) + rsx!("hello world"); - rsx!("hello world!") + rsx!("hello world!"); } ``` @@ -127,7 +126,7 @@ fn App() -> Element { )) } - )) + ) } ``` @@ -147,7 +146,7 @@ fn App() -> Element { title: "My App", color: "red", } - )) + ) } ``` @@ -169,7 +168,7 @@ fn Header(cx: Scope) -> Element { background_color: "{cx.props.color}" h1 { "{cx.props.title}" } } - )) + ) } ``` @@ -184,7 +183,7 @@ fn Header(title: String, color: String) -> Element { background_color: "{color}" h1 { "{title}" } } - )) + ) } ``` @@ -201,13 +200,13 @@ struct HeaderProps<'a> { } #[component] -fn Header(props: HeaderProps -> Element { +fn Header(props: HeaderProps) -> Element { rsx!( div { background_color: "{cx.props.color}" h1 { "{cx.props.title}" } } - )) + ) } ``` @@ -299,7 +298,7 @@ fn App() -> Element { div { "Count: {count}" } button { onclick: move |_| count.set(count + 1), "Increment" } button { onclick: move |_| count.set(count - 1), "Decrement" } - )) + ) } ``` diff --git a/packages/dioxus/src/launch.rs b/packages/dioxus/src/launch.rs index 3b49eb97a..63b2183e2 100644 --- a/packages/dioxus/src/launch.rs +++ b/packages/dioxus/src/launch.rs @@ -38,6 +38,7 @@ impl LaunchBuilder { /// Launch your web application. #[cfg(feature = "web")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "web")))] pub fn web() -> LaunchBuilder { LaunchBuilder { launch_fn: dioxus_web::launch::launch, @@ -48,6 +49,7 @@ impl LaunchBuilder { /// Launch your desktop application. #[cfg(feature = "desktop")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "desktop")))] pub fn desktop() -> LaunchBuilder { LaunchBuilder { launch_fn: dioxus_desktop::launch::launch, @@ -58,6 +60,7 @@ impl LaunchBuilder { /// Launch your fullstack application. #[cfg(feature = "fullstack")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "fullstack")))] pub fn fullstack() -> LaunchBuilder { LaunchBuilder { launch_fn: dioxus_fullstack::launch::launch, @@ -68,6 +71,7 @@ impl LaunchBuilder { /// Launch your fullstack application. #[cfg(feature = "mobile")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "mobile")))] pub fn mobile() -> LaunchBuilder { LaunchBuilder { launch_fn: dioxus_mobile::launch::launch, @@ -77,6 +81,7 @@ impl LaunchBuilder { } #[cfg(feature = "tui")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "tui")))] /// Launch your tui application pub fn tui() -> LaunchBuilder { LaunchBuilder { @@ -209,24 +214,28 @@ pub fn launch(app: fn() -> Element) { } #[cfg(feature = "web")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "web")))] /// Launch your web application without any additional configuration. See [`LaunchBuilder`] for more options. pub fn launch_web(app: fn() -> Element) { LaunchBuilder::web().launch(app) } #[cfg(feature = "desktop")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "desktop")))] /// Launch your desktop application without any additional configuration. See [`LaunchBuilder`] for more options. pub fn launch_desktop(app: fn() -> Element) { LaunchBuilder::desktop().launch(app) } #[cfg(feature = "fullstack")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "fullstack")))] /// Launch your fullstack application without any additional configuration. See [`LaunchBuilder`] for more options. pub fn launch_fullstack(app: fn() -> Element) { LaunchBuilder::fullstack().launch(app) } #[cfg(feature = "tui")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "tui")))] /// Launch your tui application without any additional configuration. See [`LaunchBuilder`] for more options. pub fn launch_tui(app: fn() -> Element) { LaunchBuilder::tui().launch(app) diff --git a/packages/dioxus/src/lib.rs b/packages/dioxus/src/lib.rs index fd052dfc2..d843cfd56 100644 --- a/packages/dioxus/src/lib.rs +++ b/packages/dioxus/src/lib.rs @@ -1,88 +1,114 @@ #![doc = include_str!("../README.md")] #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")] #![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")] +#![cfg_attr(any(docsrs, feature = "nightly-doc"), feature(doc_cfg))] pub use dioxus_core; #[cfg(feature = "launch")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "launch")))] mod launch; #[cfg(feature = "hooks")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "hooks")))] pub use dioxus_hooks as hooks; #[cfg(feature = "signals")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "signals")))] pub use dioxus_signals as signals; pub mod events { #[cfg(feature = "html")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "html")))] pub use dioxus_html::prelude::*; } #[cfg(feature = "html")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "html")))] pub use dioxus_html as html; #[cfg(feature = "macro")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "macro")))] pub use dioxus_core_macro as core_macro; pub mod prelude { #[cfg(feature = "launch")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "launch")))] pub use crate::launch::*; #[cfg(feature = "hooks")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "hooks")))] pub use crate::hooks::*; #[cfg(feature = "signals")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "signals")))] pub use dioxus_signals::*; pub use dioxus_core::prelude::*; #[cfg(feature = "macro")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "macro")))] #[allow(deprecated)] pub use dioxus_core_macro::{component, format_args_f, inline_props, render, rsx, Props}; #[cfg(feature = "launch")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "launch")))] pub use dioxus_config_macro::*; #[cfg(feature = "html")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "html")))] pub use dioxus_html as dioxus_elements; #[cfg(feature = "html")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "html")))] pub use dioxus_elements::{prelude::*, GlobalAttributes, SvgAttributes}; #[cfg(all(not(target_arch = "wasm32"), feature = "hot-reload"))] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "hot-reload")))] pub use dioxus_hot_reload::{self, hot_reload_init}; pub use dioxus_core; #[cfg(feature = "fullstack")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "fullstack")))] pub use dioxus_fullstack::prelude::*; #[cfg(feature = "router")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "router")))] pub use dioxus_router; #[cfg(feature = "router")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "router")))] pub use dioxus_router::prelude::*; } #[cfg(feature = "web")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "web")))] pub use dioxus_web as web; #[cfg(feature = "router")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "router")))] pub use dioxus_router as router; #[cfg(feature = "fullstack")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "fullstack")))] pub use dioxus_fullstack as fullstack; #[cfg(feature = "desktop")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "desktop")))] pub use dioxus_desktop as desktop; #[cfg(feature = "mobile")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "mobile")))] pub use dioxus_desktop as mobile; #[cfg(feature = "liveview")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "liveview")))] pub use dioxus_liveview as liveview; #[cfg(feature = "tui")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "tui")))] pub use dioxus_tui as tui; #[cfg(feature = "ssr")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "ssr")))] pub use dioxus_ssr as ssr; diff --git a/packages/fullstack/Cargo.toml b/packages/fullstack/Cargo.toml index 8e77e84fe..63fde221c 100644 --- a/packages/fullstack/Cargo.toml +++ b/packages/fullstack/Cargo.toml @@ -81,3 +81,5 @@ salvo = ["dep:salvo", "server", "http-body-util"] server = ["server_fn/ssr", "dioxus_server_macro/server", "tokio", "tokio-util", "tokio-stream", "dioxus-ssr", "dioxus-ssr/incremental", "tower", "hyper", "http", "tower-layer", "anymap", "tracing-futures", "pin-project", "thiserror", "dioxus-cli-config"] default-tls = ["server_fn/default-tls"] rustls = ["server_fn/rustls"] +# This feature enables some nightly flags that make it more clear what structs/methods are available in each feature +nightly-doc = [] diff --git a/packages/fullstack/examples/axum-desktop/src/client.rs b/packages/fullstack/examples/axum-desktop/src/client.rs index da11fda25..247f2e8f2 100644 --- a/packages/fullstack/examples/axum-desktop/src/client.rs +++ b/packages/fullstack/examples/axum-desktop/src/client.rs @@ -4,10 +4,10 @@ // ``` use axum_desktop::*; -use dioxus_fullstack::prelude::server_fn::set_server_url; fn main() { // Set the url of the server where server functions are hosted. - set_server_url("http://127.0.0.1:8080"); + #[cfg(not(feature = "server"))] + dioxus::fullstack::prelude::server_fn::set_server_url("http://127.0.0.1:8080"); dioxus::desktop::launch(app) } diff --git a/packages/fullstack/examples/axum-desktop/src/server.rs b/packages/fullstack/examples/axum-desktop/src/server.rs index 0781db5fb..759d5799b 100644 --- a/packages/fullstack/examples/axum-desktop/src/server.rs +++ b/packages/fullstack/examples/axum-desktop/src/server.rs @@ -4,7 +4,7 @@ // ``` use axum_desktop::*; -use dioxus_fullstack::prelude::*; +use dioxus::prelude::*; #[tokio::main] async fn main() { diff --git a/packages/fullstack/examples/static-hydrated/src/main.rs b/packages/fullstack/examples/static-hydrated/src/main.rs index 72bd6894b..69c81b40e 100644 --- a/packages/fullstack/examples/static-hydrated/src/main.rs +++ b/packages/fullstack/examples/static-hydrated/src/main.rs @@ -27,7 +27,7 @@ async fn main() { } // Hydrate the page -#[cfg(feature = "web")] +#[cfg(all(feature = "web", not(feature = "server")))] fn main() { dioxus_web::launch_with_props( dioxus_fullstack::router::RouteWithCfg::, diff --git a/packages/fullstack/src/adapters/axum_adapter.rs b/packages/fullstack/src/adapters/axum_adapter.rs index 731b3f13e..d73edeb88 100644 --- a/packages/fullstack/src/adapters/axum_adapter.rs +++ b/packages/fullstack/src/adapters/axum_adapter.rs @@ -332,7 +332,7 @@ where } fn connect_hot_reload(self) -> Self { - #[cfg(all(debug_assertions, feature = "hot-reload", feature = "server"))] + #[cfg(all(debug_assertions, feature = "hot-reload"))] { self.nest( "/_dioxus", @@ -354,7 +354,7 @@ where .route("/hot_reload", get(hot_reload_handler)), ) } - #[cfg(not(all(debug_assertions, feature = "hot-reload", feature = "server")))] + #[cfg(not(all(debug_assertions, feature = "hot-reload")))] { self } @@ -476,7 +476,7 @@ fn report_err(e: E) -> Response { } /// A handler for Dioxus web hot reload websocket. This will send the updated static parts of the RSX to the client when they change. -#[cfg(all(debug_assertions, feature = "hot-reload", feature = "server"))] +#[cfg(all(debug_assertions, feature = "hot-reload"))] pub async fn hot_reload_handler(ws: axum::extract::WebSocketUpgrade) -> impl IntoResponse { use axum::extract::ws::Message; use futures_util::StreamExt; diff --git a/packages/fullstack/src/adapters/mod.rs b/packages/fullstack/src/adapters/mod.rs index d368b9c73..61f24bf3c 100644 --- a/packages/fullstack/src/adapters/mod.rs +++ b/packages/fullstack/src/adapters/mod.rs @@ -12,8 +12,8 @@ #[cfg(feature = "axum")] pub mod axum_adapter; -#[cfg(feature = "salvo")] -pub mod salvo_adapter; +// #[cfg(feature = "salvo")] +// pub mod salvo_adapter; #[cfg(feature = "warp")] pub mod warp_adapter; diff --git a/packages/fullstack/src/adapters/salvo_adapter.rs b/packages/fullstack/src/adapters/salvo_adapter.rs index 4c41fc4a4..a30097c9a 100644 --- a/packages/fullstack/src/adapters/salvo_adapter.rs +++ b/packages/fullstack/src/adapters/salvo_adapter.rs @@ -291,17 +291,20 @@ impl DioxusRouterExt for Router { ) -> Self { let cfg = cfg.into(); - self.serve_static_assets(cfg.assets_path) + self.serve_static_assets(cfg.assets_path.clone()) .connect_hot_reload() .register_server_fns(server_fn_path) - .push(Router::with_path("/<**any_path>").get(SSRHandler { cfg })) + .push(Router::with_path("/<**any_path>").get(SSRHandler { + config: cfg, + virtual_dom: virtual_dom_factory, + })) } fn connect_hot_reload(self) -> Self { let mut _dioxus_router = Router::with_path("_dioxus"); _dioxus_router = _dioxus_router.push(Router::with_path("hot_reload").handle(HotReloadHandler)); - #[cfg(all(debug_assertions, feature = "hot-reload", feature = "server"))] + #[cfg(all(debug_assertions, feature = "hot-reload"))] { _dioxus_router = _dioxus_router.push(Router::with_path("disconnect").handle(ignore_ws)); } @@ -485,11 +488,11 @@ fn handle_error(error: impl Error + Send + Sync, res: &mut Response) { } /// A handler for Dioxus web hot reload websocket. This will send the updated static parts of the RSX to the client when they change. -#[cfg(not(all(debug_assertions, feature = "hot-reload", feature = "server")))] +#[cfg(not(all(debug_assertions, feature = "hot-reload")))] #[derive(Default)] pub struct HotReloadHandler; -#[cfg(not(all(debug_assertions, feature = "hot-reload", feature = "server")))] +#[cfg(not(all(debug_assertions, feature = "hot-reload")))] #[handler] impl HotReloadHandler { async fn handle( @@ -503,11 +506,11 @@ impl HotReloadHandler { } /// A handler for Dioxus web hot reload websocket. This will send the updated static parts of the RSX to the client when they change. -#[cfg(all(debug_assertions, feature = "hot-reload", feature = "server"))] +#[cfg(all(debug_assertions, feature = "hot-reload"))] #[derive(Default)] pub struct HotReloadHandler; -#[cfg(all(debug_assertions, feature = "hot-reload", feature = "server"))] +#[cfg(all(debug_assertions, feature = "hot-reload"))] #[handler] impl HotReloadHandler { async fn handle( @@ -561,7 +564,7 @@ impl HotReloadHandler { } } -#[cfg(all(debug_assertions, feature = "hot-reload", feature = "server"))] +#[cfg(all(debug_assertions, feature = "hot-reload"))] #[handler] async fn ignore_ws(req: &mut Request, res: &mut Response) -> Result<(), salvo::http::StatusError> { use salvo::websocket::WebSocketUpgrade; diff --git a/packages/fullstack/src/adapters/warp_adapter.rs b/packages/fullstack/src/adapters/warp_adapter.rs index 462fce1f6..711980ec8 100644 --- a/packages/fullstack/src/adapters/warp_adapter.rs +++ b/packages/fullstack/src/adapters/warp_adapter.rs @@ -187,7 +187,7 @@ pub fn serve_dioxus_application( ) -> BoxedFilter<(impl Reply,)> { let cfg = cfg.into(); // Serve the dist folder and the index.html file - let serve_dir = warp::fs::dir(cfg.assets_path); + let serve_dir = warp::fs::dir(cfg.assets_path.clone()); let virtual_dom_factory = Arc::new(virtual_dom_factory) as Arc VirtualDom + Send + Sync + 'static>; @@ -332,13 +332,13 @@ impl warp::reject::Reject for RecieveFailed {} /// ``` pub fn connect_hot_reload() -> impl Filter + Clone { - #[cfg(not(all(debug_assertions, feature = "hot-reload", feature = "server")))] + #[cfg(not(all(debug_assertions, feature = "hot-reload")))] { warp::path!("_dioxus" / "hot_reload") .map(warp::reply) .map(|reply| warp::reply::with_status(reply, warp::http::StatusCode::NOT_FOUND)) } - #[cfg(all(debug_assertions, feature = "hot-reload", feature = "server"))] + #[cfg(all(debug_assertions, feature = "hot-reload"))] { use crate::hot_reload::HotReloadState; use futures_util::sink::SinkExt; @@ -349,7 +349,7 @@ pub fn connect_hot_reload() -> impl Filter impl Filter); impl Drop for DisconnectOnDrop { diff --git a/packages/fullstack/src/config.rs b/packages/fullstack/src/config.rs index 765108e5f..f4416b8df 100644 --- a/packages/fullstack/src/config.rs +++ b/packages/fullstack/src/config.rs @@ -53,6 +53,7 @@ impl Config { /// Set the address to serve the app on. #[cfg(feature = "server")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] pub fn addr(self, addr: impl Into) -> Self { let addr = addr.into(); Self { addr, ..self } @@ -60,6 +61,7 @@ impl Config { /// Set the route to the server functions. #[cfg(feature = "server")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] pub fn server_fn_route(self, server_fn_route: &'static str) -> Self { Self { server_fn_route, @@ -69,6 +71,7 @@ impl Config { /// Set the incremental renderer config. #[cfg(feature = "server")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] pub fn incremental(self, cfg: IncrementalRendererConfig) -> Self { Self { server_cfg: self.server_cfg.incremental(cfg), @@ -78,18 +81,21 @@ impl Config { /// Set the server config. #[cfg(feature = "server")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] pub fn server_cfg(self, server_cfg: ServeConfigBuilder) -> Self { Self { server_cfg, ..self } } /// Set the web config. #[cfg(feature = "web")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "web")))] pub fn web_cfg(self, web_cfg: dioxus_web::Config) -> Self { Self { web_cfg, ..self } } /// Set the desktop config. #[cfg(feature = "desktop")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "desktop")))] pub fn desktop_cfg(self, desktop_cfg: dioxus_desktop::Config) -> Self { Self { desktop_cfg, @@ -99,11 +105,13 @@ impl Config { /// Set the mobile config. #[cfg(feature = "mobile")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "mobile")))] pub fn mobile_cfg(self, mobile_cfg: dioxus_mobile::Config) -> Self { Self { mobile_cfg, ..self } } #[cfg(feature = "server")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] /// Launch a server application pub async fn launch_server( self, diff --git a/packages/fullstack/src/lib.rs b/packages/fullstack/src/lib.rs index b04a3cbc9..270cbc801 100644 --- a/packages/fullstack/src/lib.rs +++ b/packages/fullstack/src/lib.rs @@ -2,6 +2,7 @@ #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")] #![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")] #![deny(missing_docs)] +#![cfg_attr(any(docsrs, feature = "nightly-doc"), feature(doc_cfg))] pub use once_cell; @@ -9,8 +10,20 @@ mod html_storage; #[cfg(feature = "server")] mod adapters; +// Splitting up the glob export lets us document features required for each adapter +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "axum")))] +#[cfg(feature = "axum")] +pub use adapters::axum_adapter; +// TODO: Compilation seems to be broken with the salvo feature enabled. Fix and add more features to checks in CI +// #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "salvo")))] +// #[cfg(feature = "salvo")] +// pub use adapters::salvo_adapter; +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "warp")))] +#[cfg(feature = "warp")] +pub use adapters::warp_adapter; +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] #[cfg(feature = "server")] -pub use adapters::*; +pub use adapters::{server_fn_service, ServerFnHandler}; mod config; mod hooks; #[cfg(all(debug_assertions, feature = "hot-reload", feature = "server"))] @@ -30,35 +43,57 @@ mod server_fn; /// A prelude of commonly used items in dioxus-fullstack. pub mod prelude { #[cfg(feature = "axum")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "axum")))] pub use crate::adapters::axum_adapter::*; - #[cfg(feature = "salvo")] - pub use crate::adapters::salvo_adapter::*; + // #[cfg(feature = "salvo")] + // #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "salvo")))] + // pub use crate::adapters::salvo_adapter::*; #[cfg(feature = "warp")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "warp")))] pub use crate::adapters::warp_adapter::*; use crate::hooks; #[cfg(not(feature = "server"))] + #[cfg_attr( + any(docsrs, feature = "nightly-doc"), + doc(cfg(not(feature = "server"))) + )] pub use crate::html_storage::deserialize::get_root_props_from_document; #[cfg(feature = "server")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] pub use crate::layer::{Layer, Service}; #[cfg(all(feature = "server", feature = "router"))] + #[cfg_attr( + any(docsrs, feature = "nightly-doc"), + doc(cfg(all(feature = "server", feature = "router"))) + )] pub use crate::render::pre_cache_static_routes_with_props; #[cfg(feature = "server")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] pub use crate::render::SSRState; #[cfg(feature = "router")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "router")))] pub use crate::router::FullstackRouterConfig; #[cfg(feature = "server")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] pub use crate::serve_config::{ServeConfig, ServeConfigBuilder}; #[cfg(all(feature = "server", feature = "axum"))] + #[cfg_attr( + any(docsrs, feature = "nightly-doc"), + doc(cfg(all(feature = "server", feature = "axum"))) + )] pub use crate::server_context::Axum; #[cfg(feature = "server")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] pub use crate::server_context::{ extract, server_context, DioxusServerContext, FromServerContext, ProvideServerContext, }; pub use crate::server_fn::DioxusServerFn; #[cfg(feature = "server")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] pub use crate::server_fn::{ServerFnMiddleware, ServerFnTraitObj, ServerFunction}; pub use dioxus_server_macro::*; #[cfg(feature = "server")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] pub use dioxus_ssr::incremental::IncrementalRendererConfig; pub use server_fn::{self, ServerFn as _, ServerFnError}; @@ -66,11 +101,26 @@ pub mod prelude { } // Warn users about overlapping features -#[cfg(all(feature = "server", feature = "web", not(doc)))] +#[cfg(all( + feature = "server", + feature = "web", + not(doc), + not(feature = "nightly-doc") +))] compile_error!("The `ssr` feature (enabled by `warp`, `axum`, or `salvo`) and `web` feature are overlapping. Please choose one or the other."); -#[cfg(all(feature = "server", feature = "desktop", not(doc)))] +#[cfg(all( + feature = "server", + feature = "desktop", + not(doc), + not(feature = "nightly-doc") +))] compile_error!("The `ssr` feature (enabled by `warp`, `axum`, or `salvo`) and `desktop` feature are overlapping. Please choose one or the other."); -#[cfg(all(feature = "server", feature = "mobile", not(doc)))] +#[cfg(all( + feature = "server", + feature = "mobile", + not(doc), + not(feature = "nightly-doc") +))] compile_error!("The `ssr` feature (enabled by `warp`, `axum`, or `salvo`) and `mobile` feature are overlapping. Please choose one or the other."); diff --git a/packages/fullstack/src/server_context.rs b/packages/fullstack/src/server_context.rs index 6f3b4b6c9..8d5966a7c 100644 --- a/packages/fullstack/src/server_context.rs +++ b/packages/fullstack/src/server_context.rs @@ -228,6 +228,7 @@ impl FromServerContext for FromContext { } #[cfg(feature = "axum")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "axum")))] /// An adapter for axum extractors for the server context pub struct Axum; diff --git a/packages/fullstack/src/server_fn.rs b/packages/fullstack/src/server_fn.rs index e71994b92..d51e4beec 100644 --- a/packages/fullstack/src/server_fn.rs +++ b/packages/fullstack/src/server_fn.rs @@ -1,9 +1,10 @@ -#[cfg(any(feature = "server", doc))] +#[cfg(feature = "server")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] #[derive(Clone)] /// A trait object for a function that be called on serializable arguments and returns a serializable result. pub struct ServerFnTraitObj(server_fn::ServerFnTraitObj<()>); -#[cfg(any(feature = "server", doc))] +#[cfg(feature = "server")] impl std::ops::Deref for ServerFnTraitObj { type Target = server_fn::ServerFnTraitObj<()>; @@ -12,14 +13,14 @@ impl std::ops::Deref for ServerFnTraitObj { } } -#[cfg(any(feature = "server", doc))] +#[cfg(feature = "server")] impl std::ops::DerefMut for ServerFnTraitObj { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } -#[cfg(any(feature = "server", doc))] +#[cfg(feature = "server")] impl ServerFnTraitObj { fn new( prefix: &'static str, @@ -40,6 +41,7 @@ impl ServerFnTraitObj { server_fn::inventory::collect!(ServerFnTraitObj); #[cfg(feature = "server")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] /// Middleware for a server function pub struct ServerFnMiddleware { /// The prefix of the server function. @@ -72,7 +74,8 @@ pub(crate) static MIDDLEWARE: once_cell::sync::Lazy< #[cfg(feature = "server")] server_fn::inventory::collect!(ServerFnMiddleware); -#[cfg(any(feature = "server", doc))] +#[cfg(feature = "server")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] /// A server function that can be called on serializable arguments and returns a serializable result. pub type ServerFunction = server_fn::SerializedFnTraitObj<()>; @@ -88,7 +91,8 @@ static REGISTERED_SERVER_FUNCTIONS: once_cell::sync::Lazy< std::sync::Arc::new(std::sync::RwLock::new(map)) }); -#[cfg(any(feature = "server", doc))] +#[cfg(feature = "server")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] /// The registry of all Dioxus server functions. pub struct DioxusServerFnRegistry; @@ -155,7 +159,8 @@ impl server_fn::ServerFunctionRegistry<()> for DioxusServerFnRegistry { } } -#[cfg(any(feature = "server", doc))] +#[cfg(feature = "server")] +#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] /// Errors that can occur when registering a server function. #[derive(thiserror::Error, Debug, Clone, serde::Serialize, serde::Deserialize)] pub enum ServerRegistrationFnError { @@ -178,7 +183,8 @@ pub enum ServerRegistrationFnError { /// Technically, the trait is implemented on a type that describes the server function's arguments, not the function itself. pub trait DioxusServerFn: server_fn::ServerFn<()> { /// Registers the server function, allowing the client to query it by URL. - #[cfg(any(feature = "server", doc))] + #[cfg(feature = "server")] + #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] fn register_explicit() -> Result<(), server_fn::ServerFnError> { Self::register_in_explicit::() } diff --git a/packages/generational-box/src/lib.rs b/packages/generational-box/src/lib.rs index 052f95a37..341ef89bf 100644 --- a/packages/generational-box/src/lib.rs +++ b/packages/generational-box/src/lib.rs @@ -228,9 +228,9 @@ pub trait Storage: AnyStorage + 'static { /// A trait for any storage backing type. pub trait AnyStorage: Default { /// The reference this storage type returns. - type Ref: Deref; + type Ref: Deref + 'static; /// The mutable reference this storage type returns. - type Mut: DerefMut; + type Mut: DerefMut + 'static; /// Try to map the mutable ref. fn try_map_mut( @@ -247,13 +247,16 @@ pub trait AnyStorage: Default { } /// Try to map the ref. - fn try_map( + fn try_map( ref_: Self::Ref, f: impl FnOnce(&T) -> Option<&U>, ) -> Option>; /// Map the ref. - fn map(ref_: Self::Ref, f: impl FnOnce(&T) -> &U) -> Self::Ref { + fn map( + ref_: Self::Ref, + f: impl FnOnce(&T) -> &U, + ) -> Self::Ref { Self::try_map(ref_, |v| Some(f(v))).unwrap() } diff --git a/packages/generational-box/src/sync.rs b/packages/generational-box/src/sync.rs index 5241fb22e..1edd9a12e 100644 --- a/packages/generational-box/src/sync.rs +++ b/packages/generational-box/src/sync.rs @@ -23,7 +23,7 @@ impl AnyStorage for SyncStorage { type Ref = GenerationalRef>; type Mut = GenerationalRefMut>; - fn try_map( + fn try_map( ref_: Self::Ref, f: impl FnOnce(&I) -> Option<&U>, ) -> Option> { diff --git a/packages/generational-box/src/unsync.rs b/packages/generational-box/src/unsync.rs index e1f5f9df9..da08cf4c4 100644 --- a/packages/generational-box/src/unsync.rs +++ b/packages/generational-box/src/unsync.rs @@ -92,7 +92,7 @@ impl AnyStorage for UnsyncStorage { type Ref = GenerationalRef>; type Mut = GenerationalRefMut>; - fn try_map( + fn try_map( _self: Self::Ref, f: impl FnOnce(&I) -> Option<&U>, ) -> Option> { diff --git a/packages/hooks/src/lib.rs b/packages/hooks/src/lib.rs index 1c937ff8e..5d842b5ff 100644 --- a/packages/hooks/src/lib.rs +++ b/packages/hooks/src/lib.rs @@ -1,7 +1,6 @@ #![doc = include_str!("../README.md")] #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")] #![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")] -#![cfg_attr(feature = "nightly-features", feature(debug_refcell))] #[macro_export] /// A helper macro for using hooks and properties in async environments. diff --git a/packages/liveview/src/launch.rs b/packages/liveview/src/launch.rs index 2b2d294a8..d008e38cd 100644 --- a/packages/liveview/src/launch.rs +++ b/packages/liveview/src/launch.rs @@ -3,9 +3,9 @@ use std::any::Any; #[cfg(feature = "axum")] pub type Config = crate::Config; -#[cfg(feature = "salvo")] +#[cfg(all(feature = "salvo", not(feature = "axum")))] pub type Config = crate::Config; -#[cfg(feature = "rocket")] +#[cfg(all(feature = "rocket", not(any(feature = "axum", feature = "salvo"))))] pub type Config = crate::Config>; /// Launches the WebView and runs the event loop, with configuration and root props. diff --git a/packages/router/Cargo.toml b/packages/router/Cargo.toml index e4f68d27f..3343f1886 100644 --- a/packages/router/Cargo.toml +++ b/packages/router/Cargo.toml @@ -35,7 +35,6 @@ default = [] ssr = ["dioxus-ssr/incremental", "tokio", "dioxus-fullstack?/server"] liveview = ["dioxus-liveview", "tokio", "dep:serde", "serde_json"] wasm_test = [] -serde = ["dep:serde", "gloo-utils?/serde"] web = ["gloo", "web-sys", "wasm-bindgen", "gloo-utils", "js-sys"] fullstack = ["dioxus-fullstack"] diff --git a/packages/router/src/components/router.rs b/packages/router/src/components/router.rs index af04fdacb..88aa349ce 100644 --- a/packages/router/src/components/router.rs +++ b/packages/router/src/components/router.rs @@ -11,18 +11,6 @@ pub struct RouterConfigFactory { config: Rc RouterConfig>>>>, } -#[cfg(feature = "serde")] -impl Default for RouterConfigFactory -where - ::Err: std::fmt::Display, - R: serde::Serialize + serde::de::DeserializeOwned, -{ - fn default() -> Self { - Self::from(RouterConfig::default) - } -} - -#[cfg(not(feature = "serde"))] impl Default for RouterConfigFactory where ::Err: std::fmt::Display, @@ -40,19 +28,6 @@ impl RouterConfig + 'static> From for RouterCo } } -#[cfg(feature = "serde")] -/// The props for [`Router`]. -#[derive(Props)] -pub struct RouterProps -where - ::Err: std::fmt::Display, - R: serde::Serialize + serde::de::DeserializeOwned, -{ - #[props(default, into)] - config: RouterConfigFactory, -} - -#[cfg(not(feature = "serde"))] /// The props for [`Router`]. #[derive(Props)] pub struct RouterProps @@ -74,7 +49,6 @@ where } } -#[cfg(not(feature = "serde"))] impl Default for RouterProps where ::Err: std::fmt::Display, @@ -86,20 +60,6 @@ where } } -#[cfg(feature = "serde")] -impl Default for RouterProps -where - ::Err: std::fmt::Display, - R: serde::Serialize + serde::de::DeserializeOwned, -{ - fn default() -> Self { - Self { - config: RouterConfigFactory::default(), - } - } -} - -#[cfg(not(feature = "serde"))] impl PartialEq for RouterProps where ::Err: std::fmt::Display, @@ -110,19 +70,6 @@ where } } -#[cfg(feature = "serde")] -impl PartialEq for RouterProps -where - ::Err: std::fmt::Display, - R: serde::Serialize + serde::de::DeserializeOwned, -{ - fn eq(&self, _: &Self) -> bool { - // prevent the router from re-rendering when the initial url or config changes - true - } -} - -#[cfg(not(feature = "serde"))] /// A component that renders the current route. pub fn Router(props: RouterProps) -> Element where @@ -148,28 +95,3 @@ where rsx! { Outlet:: {} } } - -#[cfg(feature = "serde")] -/// A component that renders the current route. -pub fn Router(cx: ScopeState>) -> Element -where - ::Err: std::fmt::Display, - R: serde::Serialize + serde::de::DeserializeOwned, -{ - use_context_provider(|| { - RouterContext::new( - (cx.props - .config - .config - .take() - .expect("use_context_provider ran twice"))(), - cx.schedule_update_any(), - ) - }); - use_context_provider(|| OutletContext:: { - current_level: 0, - _marker: std::marker::PhantomData, - }); - - rsx! { Outlet:: {} } -} diff --git a/packages/router/src/history/web.rs b/packages/router/src/history/web.rs index a0f677e24..180840d2d 100644 --- a/packages/router/src/history/web.rs +++ b/packages/router/src/history/web.rs @@ -23,7 +23,6 @@ fn base_path() -> Option<&'static str> { base_path } -#[cfg(not(feature = "serde"))] #[allow(clippy::extra_unused_type_parameters)] fn update_scroll(window: &Window, history: &History) { let scroll = ScrollPosition::of_window(window); @@ -32,27 +31,6 @@ fn update_scroll(window: &Window, history: &History) { } } -#[cfg(feature = "serde")] -fn update_scroll( - window: &Window, - history: &History, -) { - if let Some(WebHistoryState { state, .. }) = get_current::>(history) { - let scroll = ScrollPosition::of_window(window); - let state = WebHistoryState { state, scroll }; - if let Err(err) = replace_state_with_url(history, &state, None) { - error!(err); - } - } -} - -#[cfg(feature = "serde")] -#[derive(serde::Deserialize, serde::Serialize)] -struct WebHistoryState { - state: R, - scroll: ScrollPosition, -} - /// A [`HistoryProvider`] that integrates with a browser via the [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API). /// /// # Prefix @@ -75,7 +53,6 @@ pub struct WebHistory { phantom: std::marker::PhantomData, } -#[cfg(not(feature = "serde"))] impl Default for WebHistory where ::Err: std::fmt::Display, @@ -85,19 +62,7 @@ where } } -#[cfg(feature = "serde")] -impl Default for WebHistory -where - ::Err: std::fmt::Display, - R: serde::Serialize + serde::de::DeserializeOwned, -{ - fn default() -> Self { - Self::new(None, true) - } -} - impl WebHistory { - #[cfg(not(feature = "serde"))] /// Create a new [`WebHistory`]. /// /// If `do_scroll_restoration` is [`true`], [`WebHistory`] will take control of the history @@ -116,47 +81,6 @@ impl WebHistory { myself } - #[cfg(feature = "serde")] - /// Create a new [`WebHistory`]. - /// - /// If `do_scroll_restoration` is [`true`], [`WebHistory`] will take control of the history - /// state. It'll also set the browsers scroll restoration to `manual`. - pub fn new(prefix: Option, do_scroll_restoration: bool) -> Self - where - ::Err: std::fmt::Display, - R: serde::Serialize + serde::de::DeserializeOwned, - { - let w = window().expect("access to `window`"); - let h = w.history().expect("`window` has access to `history`"); - let document = w.document().expect("`window` has access to `document`"); - - let myself = Self::new_inner( - prefix, - do_scroll_restoration, - EventListener::new(&document, "scroll", { - let mut last_updated = 0.0; - move |evt| { - // the time stamp in milliseconds - let time_stamp = evt.time_stamp(); - // throttle the scroll event to 100ms - if (time_stamp - last_updated) < 100.0 { - return; - } - update_scroll::(&w, &h); - last_updated = time_stamp; - } - }), - ); - - let current_route = myself.current_route(); - tracing::trace!("initial route: {:?}", current_route); - let current_url = current_route.to_string(); - let state = myself.create_state(current_route); - let _ = replace_state_with_url(&myself.history, &state, Some(¤t_url)); - - myself - } - fn new_inner(prefix: Option, do_scroll_restoration: bool) -> Self where ::Err: std::fmt::Display, @@ -191,17 +115,10 @@ impl WebHistory { .unwrap_or_default() } - #[cfg(not(feature = "serde"))] fn create_state(&self, _state: R) -> [f64; 2] { let scroll = self.scroll_pos(); [scroll.x, scroll.y] } - - #[cfg(feature = "serde")] - fn create_state(&self, state: R) -> WebHistoryState { - let scroll = self.scroll_pos(); - WebHistoryState { state, scroll } - } } impl WebHistory @@ -254,91 +171,6 @@ where } } -#[cfg(feature = "serde")] -impl HistoryProvider - for WebHistory -where - ::Err: std::fmt::Display, -{ - fn current_route(&self) -> R { - match get_current::>(&self.history) { - // Try to get the route from the history state - Some(route) => route.state, - // If that fails, get the route from the current URL - None => self.route_from_location(), - } - } - - fn current_prefix(&self) -> Option { - self.prefix.clone() - } - - fn go_back(&mut self) { - if let Err(e) = self.history.back() { - error!("failed to go back: ", e) - } - } - - fn go_forward(&mut self) { - if let Err(e) = self.history.forward() { - error!("failed to go forward: ", e) - } - } - - fn push(&mut self, state: R) { - use gloo_utils::format::JsValueSerdeExt; - if JsValue::from_serde(&state) != JsValue::from_serde(&self.current_route()) { - // don't push the same state twice - return; - } - - let w = window().expect("access to `window`"); - let h = w.history().expect("`window` has access to `history`"); - - // update the scroll position before pushing the new state - update_scroll::(&w, &h); - - let path = self.full_path(&state); - - let state = self.create_state(state); - - self.handle_nav(push_state_and_url(&self.history, &state, path)); - } - - fn replace(&mut self, state: R) { - let path = match &self.prefix { - None => format!("{state}"), - Some(prefix) => format!("{prefix}{state}"), - }; - - let state = self.create_state(state); - - self.handle_nav(replace_state_with_url(&self.history, &state, Some(&path))); - } - - fn external(&mut self, url: String) -> bool { - self.navigate_external(url) - } - - fn updater(&mut self, callback: std::sync::Arc) { - let w = self.window.clone(); - let h = self.history.clone(); - let s = self.listener_animation_frame.clone(); - let d = self.do_scroll_restoration; - - self.listener_navigation = Some(EventListener::new(&self.window, "popstate", move |_| { - (*callback)(); - if d { - let mut s = s.lock().expect("unpoisoned scroll mutex"); - if let Some(current_state) = get_current::>(&h) { - *s = Some(current_state.scroll.scroll_to(w.clone())); - } - } - })); - } -} - -#[cfg(not(feature = "serde"))] impl HistoryProvider for WebHistory where ::Err: std::fmt::Display, diff --git a/packages/router/src/history/web_history.rs b/packages/router/src/history/web_history.rs index 25a7063b4..df5219874 100644 --- a/packages/router/src/history/web_history.rs +++ b/packages/router/src/history/web_history.rs @@ -1,10 +1,7 @@ use gloo::console::error; -#[cfg(feature = "serde")] -use gloo_utils::format::JsValueSerdeExt; use wasm_bindgen::JsValue; use web_sys::History; -#[cfg(not(feature = "serde"))] pub(crate) fn replace_state_with_url( history: &History, value: &[f64; 2], @@ -17,18 +14,6 @@ pub(crate) fn replace_state_with_url( history.replace_state_with_url(&position, "", url) } -#[cfg(feature = "serde")] -pub(crate) fn replace_state_with_url( - history: &History, - value: &V, - url: Option<&str>, -) -> Result<(), JsValue> { - let position = JsValue::from_serde(value).unwrap(); - - history.replace_state_with_url(&position, "", url) -} - -#[cfg(not(feature = "serde"))] pub(crate) fn push_state_and_url( history: &History, value: &[f64; 2], @@ -41,33 +26,6 @@ pub(crate) fn push_state_and_url( history.push_state_with_url(&position, "", Some(&url)) } -#[cfg(feature = "serde")] -pub(crate) fn push_state_and_url( - history: &History, - value: &V, - url: String, -) -> Result<(), JsValue> { - let position = JsValue::from_serde(value).unwrap(); - - history.push_state_with_url(&position, "", Some(&url)) -} - -#[cfg(feature = "serde")] -pub(crate) fn get_current(history: &History) -> Option { - let state = history.state(); - if let Err(err) = &state { - error!(err); - } - state.ok().and_then(|state| { - let deserialized = state.into_serde(); - if let Err(err) = &deserialized { - error!(format!("{}", err)); - } - deserialized.ok() - }) -} - -#[cfg(not(feature = "serde"))] pub(crate) fn get_current(history: &History) -> Option<[f64; 2]> { use wasm_bindgen::JsCast; diff --git a/packages/router/src/router_cfg.rs b/packages/router/src/router_cfg.rs index 0c81faae1..30dcac10f 100644 --- a/packages/router/src/router_cfg.rs +++ b/packages/router/src/router_cfg.rs @@ -31,21 +31,6 @@ pub struct RouterConfig { pub(crate) initial_route: Option, } -#[cfg(feature = "serde")] -impl Default for RouterConfig -where - ::Err: std::fmt::Display, - R: serde::Serialize + serde::de::DeserializeOwned, -{ - fn default() -> Self { - Self { - failure_external_navigation: FailureExternalNavigation::, - history: None, - on_update: None, - } - } -} - macro_rules! default_history { ($initial_route:ident) => { { @@ -83,24 +68,6 @@ macro_rules! default_history { }; } -#[cfg(feature = "serde")] -impl RouterConfig -where - ::Err: std::fmt::Display, - R: serde::Serialize + serde::de::DeserializeOwned, -{ - pub(crate) fn get_history(self) -> Box> { - #[allow(unused)] - let initial_route = self.initial_route.clone().unwrap_or("/".parse().unwrap_or_else(|err| - panic!("index route does not exist:\n{}\n use MemoryHistory::with_initial_path or RouterConfig::initial_route to set a custom path", err) - )); - self.history - .take() - .unwrap_or_else(|| default_history!(initial_route)) - } -} - -#[cfg(not(feature = "serde"))] impl Default for RouterConfig where ::Err: std::fmt::Display, diff --git a/packages/signals/Cargo.toml b/packages/signals/Cargo.toml index 8dc9da3af..d5ed4494d 100644 --- a/packages/signals/Cargo.toml +++ b/packages/signals/Cargo.toml @@ -26,7 +26,6 @@ flume = { version = "0.11.0", default-features = false, features = ["async"] } [dev-dependencies] dioxus = { workspace = true } -# dioxus-desktop = { workspace = true } tokio = { version = "1", features = ["full"] } tracing-subscriber = "0.3.17" simple_logger = "4.2.0" diff --git a/packages/signals/examples/map_signal.rs b/packages/signals/examples/map_signal.rs new file mode 100644 index 000000000..71d882638 --- /dev/null +++ b/packages/signals/examples/map_signal.rs @@ -0,0 +1,50 @@ +#![allow(non_snake_case)] + +use dioxus::prelude::*; + +fn main() { + launch(app); +} + +fn app() -> Element { + let mut vec = use_signal(|| vec![0]); + + rsx! { + button { + onclick: move |_| { + let mut write = vec.write(); + let len = write.len() as i32; + write.push(len); + }, + "Create" + } + + button { + onclick: move |_| { + vec.write().pop(); + }, + "Destroy" + } + + for i in 0..vec.len() { + Child { count: vec.map(move |v| &v[i]) } + } + } +} + +#[component] +fn Child(count: MappedSignal) -> Element { + use_memo({ + to_owned![count]; + move || { + let value = count.read(); + println!("Child value: {value}"); + } + }); + + rsx! { + div { + "Child: {count}" + } + } +} diff --git a/packages/signals/src/copy_value.rs b/packages/signals/src/copy_value.rs index 142e6d800..4961fb2b8 100644 --- a/packages/signals/src/copy_value.rs +++ b/packages/signals/src/copy_value.rs @@ -13,6 +13,7 @@ use dioxus_core::ScopeId; use generational_box::{GenerationalBox, Owner, Storage}; +use crate::ReadableRef; use crate::Writable; use crate::{ReactiveContext, Readable}; @@ -204,40 +205,30 @@ impl> CopyValue { } } -impl> Readable for CopyValue { - type Ref = S::Ref; +impl> Readable for CopyValue { + type Target = T; + type Storage = S; - fn map_ref &U>(ref_: Self::Ref, f: F) -> Self::Ref { - S::map(ref_, f) - } - - fn try_map_ref Option<&U>>( - ref_: Self::Ref, - f: F, - ) -> Option> { - S::try_map(ref_, f) - } - - fn try_read(&self) -> Result, generational_box::BorrowError> { + fn try_read(&self) -> Result, generational_box::BorrowError> { self.value.try_read() } - fn peek(&self) -> Self::Ref { + fn peek(&self) -> ReadableRef { self.value.read() } } -impl> Writable for CopyValue { +impl> Writable for CopyValue { type Mut = S::Mut; - fn map_mut &mut U>( + fn map_mut &mut U>( mut_: Self::Mut, f: F, ) -> Self::Mut { S::map_mut(mut_, f) } - fn try_map_mut Option<&mut U>>( + fn try_map_mut Option<&mut U>>( mut_: Self::Mut, f: F, ) -> Option> { diff --git a/packages/signals/src/global/memo.rs b/packages/signals/src/global/memo.rs index d48d4ffa5..9bea70da1 100644 --- a/packages/signals/src/global/memo.rs +++ b/packages/signals/src/global/memo.rs @@ -1,6 +1,6 @@ -use crate::read::Readable; +use crate::{read::Readable, ReadableRef}; use dioxus_core::prelude::{IntoAttributeValue, ScopeId}; -use generational_box::{AnyStorage, UnsyncStorage}; +use generational_box::UnsyncStorage; use std::{mem::MaybeUninit, ops::Deref}; use crate::{ReadOnlySignal, Signal}; @@ -51,27 +51,17 @@ impl GlobalMemo { } } -impl Readable for GlobalMemo { - type Ref = generational_box::GenerationalRef>; - - fn map_ref &U>(ref_: Self::Ref, f: F) -> Self::Ref { - ::map(ref_, f) - } - - fn try_map_ref Option<&U>>( - ref_: Self::Ref, - f: F, - ) -> Option> { - ::try_map(ref_, f) - } +impl Readable for GlobalMemo { + type Target = T; + type Storage = UnsyncStorage; #[track_caller] - fn try_read(&self) -> Result, generational_box::BorrowError> { + fn try_read(&self) -> Result, generational_box::BorrowError> { self.signal().try_read() } #[track_caller] - fn peek(&self) -> Self::Ref { + fn peek(&self) -> ReadableRef { self.signal().peek() } } diff --git a/packages/signals/src/global/signal.rs b/packages/signals/src/global/signal.rs index 96db09cca..dda337232 100644 --- a/packages/signals/src/global/signal.rs +++ b/packages/signals/src/global/signal.rs @@ -1,12 +1,12 @@ -use crate::read::Readable; use crate::write::Writable; use crate::Write; +use crate::{read::Readable, ReadableRef}; use dioxus_core::prelude::{IntoAttributeValue, ScopeId}; -use generational_box::{AnyStorage, GenerationalRef, UnsyncStorage}; -use std::{cell::Ref, mem::MaybeUninit, ops::Deref}; +use generational_box::UnsyncStorage; +use std::{mem::MaybeUninit, ops::Deref}; use super::get_global_context; -use crate::{MappedSignal, Signal}; +use crate::Signal; /// A signal that can be accessed from anywhere in the application and created in a static pub struct GlobalSignal { @@ -60,56 +60,42 @@ impl GlobalSignal { self.signal().with_mut(f) } - /// Map the signal to a new type. - pub fn map( - &self, - f: impl Fn(&T) -> &O + 'static, - ) -> MappedSignal>> { - MappedSignal::new(self.signal(), f) - } - /// Get the generational id of the signal. pub fn id(&self) -> generational_box::GenerationalBoxId { self.signal().id() } } -impl Readable for GlobalSignal { - type Ref = generational_box::GenerationalRef>; - - fn map_ref &U>(ref_: Self::Ref, f: F) -> Self::Ref { - ::map(ref_, f) - } - - fn try_map_ref Option<&U>>( - ref_: Self::Ref, - f: F, - ) -> Option> { - ::try_map(ref_, f) - } +impl Readable for GlobalSignal { + type Target = T; + type Storage = UnsyncStorage; #[track_caller] - fn try_read(&self) -> Result, generational_box::BorrowError> { + fn try_read(&self) -> Result, generational_box::BorrowError> { self.signal().try_read() } #[track_caller] - fn peek(&self) -> Self::Ref { + fn peek(&self) -> ReadableRef { self.signal().peek() } } -impl Writable for GlobalSignal { +impl Writable for GlobalSignal { type Mut = Write; - fn map_mut &mut U>( + fn map_mut &mut U>( ref_: Self::Mut, f: F, ) -> Self::Mut { Write::map(ref_, f) } - fn try_map_mut Option<&mut U>>( + fn try_map_mut< + I: ?Sized + 'static, + U: ?Sized + 'static, + F: FnOnce(&mut I) -> Option<&mut U>, + >( ref_: Self::Mut, f: F, ) -> Option> { @@ -151,7 +137,7 @@ impl Deref for GlobalSignal { // Then move that value into the closure. We assume that the closure now has a in memory layout of Self. let uninit_closure = move || { - as Readable>::read(unsafe { &*uninit_callable.as_ptr() }).clone() + as Readable>::read(unsafe { &*uninit_callable.as_ptr() }).clone() }; // Check that the size of the closure is the same as the size of Self in case the compiler changed the layout of the closure. diff --git a/packages/signals/src/impls.rs b/packages/signals/src/impls.rs index 7f5f2b8f6..3d120b54e 100644 --- a/packages/signals/src/impls.rs +++ b/packages/signals/src/impls.rs @@ -2,15 +2,15 @@ use crate::copy_value::CopyValue; use crate::read::Readable; use crate::signal::Signal; use crate::write::Writable; -use crate::{GlobalMemo, GlobalSignal, ReadOnlySignal, SignalData}; -use generational_box::Storage; +use crate::{GlobalMemo, GlobalSignal, MappedSignal, ReadOnlySignal, SignalData}; +use generational_box::{AnyStorage, Storage}; use std::{ fmt::{Debug, Display}, ops::{Add, Div, Mul, Sub}, }; -macro_rules! read_impls { +macro_rules! default_impl { ($ty:ident $(: $extra_bounds:path)? $(, $bound_ty:ident : $bound:path, $vec_bound_ty:ident : $vec_bound:path)?) => { $( impl Default for $ty { @@ -20,7 +20,11 @@ macro_rules! read_impls { } } )? + } +} +macro_rules! read_impls { + ($ty:ident $(: $extra_bounds:path)? $(, $bound_ty:ident : $bound:path, $vec_bound_ty:ident : $vec_bound:path)?) => { impl Display for $ty { #[track_caller] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -113,6 +117,7 @@ macro_rules! write_impls { } read_impls!(CopyValue, S: Storage, S: Storage>); +default_impl!(CopyValue, S: Storage, S: Storage>); write_impls!(CopyValue, Storage, Storage>); impl> Clone for CopyValue { @@ -124,6 +129,7 @@ impl> Clone for CopyValue { impl> Copy for CopyValue {} read_impls!(Signal, S: Storage>, S: Storage>>); +default_impl!(Signal, S: Storage>, S: Storage>>); write_impls!(Signal, Storage>, Storage>>); impl>> Clone for Signal { @@ -139,6 +145,11 @@ read_impls!( S: Storage>, S: Storage>> ); +default_impl!( + ReadOnlySignal, + S: Storage>, + S: Storage>> +); impl>> Clone for ReadOnlySignal { fn clone(&self) -> Self { @@ -149,5 +160,8 @@ impl>> Clone for ReadOnlySignal { impl>> Copy for ReadOnlySignal {} read_impls!(GlobalSignal); +default_impl!(GlobalSignal); read_impls!(GlobalMemo: PartialEq); + +read_impls!(MappedSignal, S: AnyStorage, S: AnyStorage); diff --git a/packages/signals/src/map.rs b/packages/signals/src/map.rs index 640ca9604..e203a6d0e 100644 --- a/packages/signals/src/map.rs +++ b/packages/signals/src/map.rs @@ -1,114 +1,86 @@ -use crate::read::Readable; -use crate::CopyValue; -use crate::Signal; -use crate::SignalData; -use dioxus_core::ScopeId; -use generational_box::Storage; -use std::fmt::Debug; -use std::fmt::Display; +use std::{ops::Deref, rc::Rc}; + +use crate::{read::Readable, ReadableRef}; +use dioxus_core::prelude::*; +use generational_box::{AnyStorage, UnsyncStorage}; /// A read only signal that has been mapped to a new type. -pub struct MappedSignal { - origin_scope: ScopeId, - mapping: CopyValue U>>, +pub struct MappedSignal { + try_read: Rc Result, generational_box::BorrowError> + 'static>, + peek: Rc S::Ref + 'static>, } -impl MappedSignal<()> { - /// Create a new mapped signal. - pub fn new( - signal: Signal, - mapping: impl Fn(&T) -> &U + 'static, - ) -> MappedSignal> - where - S: Storage>, - U: ?Sized, - { +impl Clone for MappedSignal { + fn clone(&self) -> Self { MappedSignal { - origin_scope: signal.origin_scope(), - mapping: CopyValue::new(Box::new(move || S::map(signal.read(), &mapping))), + try_read: self.try_read.clone(), + peek: self.peek.clone(), } } } -impl MappedSignal { - /// Get the scope that the signal was created in. - pub fn origin_scope(&self) -> ScopeId { - self.origin_scope - } - - /// Get the current value of the signal. This will subscribe the current scope to the signal. - pub fn read(&self) -> U { - (self.mapping.read())() - } - - /// Run a closure with a reference to the signal's value. - pub fn with(&self, f: impl FnOnce(U) -> O) -> O { - f(self.read()) +impl MappedSignal +where + O: ?Sized, + S: AnyStorage, +{ + /// Create a new mapped signal. + pub(crate) fn new( + try_read: Rc Result, generational_box::BorrowError> + 'static>, + peek: Rc S::Ref + 'static>, + ) -> Self { + MappedSignal { try_read, peek } } } -impl MappedSignal { - /// Get the current value of the signal. This will subscribe the current scope to the signal. - pub fn value(&self) -> U { - self.read().clone() +impl Readable for MappedSignal +where + O: ?Sized, + S: AnyStorage, +{ + type Target = O; + type Storage = S; + + fn try_read(&self) -> Result, generational_box::BorrowError> { + (self.try_read)() + } + + fn peek(&self) -> ReadableRef { + (self.peek)() } } -impl PartialEq for MappedSignal { +impl IntoAttributeValue for MappedSignal +where + O: Clone + IntoAttributeValue, + S: AnyStorage, +{ + fn into_value(self) -> dioxus_core::AttributeValue { + self.with(|f| f.clone().into_value()) + } +} + +impl PartialEq for MappedSignal +where + O: ?Sized, + S: AnyStorage, +{ fn eq(&self, other: &Self) -> bool { - self.mapping == other.mapping + std::ptr::eq(&self.peek, &other.peek) && std::ptr::eq(&self.try_read, &other.try_read) } } -impl std::clone::Clone for MappedSignal { - fn clone(&self) -> Self { - *self - } -} - -impl Copy for MappedSignal {} - -impl Display for MappedSignal { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.with(|v| Display::fmt(&v, f)) - } -} - -impl Debug for MappedSignal { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.with(|v| Debug::fmt(&v, f)) - } -} - -impl std::ops::Deref for MappedSignal { - type Target = dyn Fn() -> T; +/// Allow calling a signal with signal() syntax +/// +/// Currently only limited to copy types, though could probably specialize for string/arc/rc +impl Deref for MappedSignal +where + O: Clone, + S: AnyStorage + 'static, +{ + type Target = dyn Fn() -> O; fn deref(&self) -> &Self::Target { - // https://github.com/dtolnay/case-studies/tree/master/callable-types - - // First we create a closure that captures something with the Same in memory layout as Self (MaybeUninit). - let uninit_callable = std::mem::MaybeUninit::::uninit(); - // Then move that value into the closure. We assume that the closure now has a in memory layout of Self. - let uninit_closure = move || Self::read(unsafe { &*uninit_callable.as_ptr() }); - - // Check that the size of the closure is the same as the size of Self in case the compiler changed the layout of the closure. - let size_of_closure = std::mem::size_of_val(&uninit_closure); - assert_eq!(size_of_closure, std::mem::size_of::()); - - // Then cast the lifetime of the closure to the lifetime of &self. - fn cast_lifetime<'a, T>(_a: &T, b: &'a T) -> &'a T { - b - } - let reference_to_closure = cast_lifetime( - { - // The real closure that we will never use. - &uninit_closure - }, - // We transmute self into a reference to the closure. This is safe because we know that the closure has the same memory layout as Self so &Closure == &Self. - unsafe { std::mem::transmute(self) }, - ); - - // Cast the closure to a trait object. - reference_to_closure as &Self::Target + Readable::deref_impl(self) } } diff --git a/packages/signals/src/read.rs b/packages/signals/src/read.rs index 14bf14580..63de45047 100644 --- a/packages/signals/src/read.rs +++ b/packages/signals/src/read.rs @@ -1,66 +1,92 @@ -use std::{mem::MaybeUninit, ops::Deref}; +use std::{mem::MaybeUninit, ops::Index, rc::Rc}; + +use generational_box::AnyStorage; + +use crate::MappedSignal; + +/// A reference to a value that can be read from. +#[allow(type_alias_bounds)] +pub type ReadableRef::Target> = ::Ref; /// A trait for states that can be read from like [`crate::Signal`], [`crate::GlobalSignal`], or [`crate::ReadOnlySignal`]. You may choose to accept this trait as a parameter instead of the concrete type to allow for more flexibility in your API. For example, instead of creating two functions, one that accepts a [`crate::Signal`] and one that accepts a [`crate::GlobalSignal`], you can create one function that accepts a [`Readable`] type. -pub trait Readable { - /// The type of the reference. - type Ref: Deref; +pub trait Readable { + /// The target type of the reference. + type Target: ?Sized + 'static; - /// Map the reference to a new type. - fn map_ref &U>(ref_: Self::Ref, f: F) -> Self::Ref; + /// The type of the storage this readable uses. + type Storage: AnyStorage; - /// Try to map the reference to a new type. - fn try_map_ref Option<&U>>( - ref_: Self::Ref, - f: F, - ) -> Option>; - - /// Try to get the current value of the state. If this is a signal, this will subscribe the current scope to the signal. If the value has been dropped, this will panic. - fn try_read(&self) -> Result, generational_box::BorrowError>; + /// Map the readable type to a new type. + fn map(self, f: impl Fn(&Self::Target) -> &O + 'static) -> MappedSignal + where + Self: Clone + Sized + 'static, + { + let mapping = Rc::new(f); + let try_read = Rc::new({ + let self_ = self.clone(); + let mapping = mapping.clone(); + move || { + self_ + .try_read() + .map(|ref_| ::map(ref_, |r| mapping(r))) + } + }) + as Rc< + dyn Fn() -> Result, generational_box::BorrowError> + 'static, + >; + let peek = Rc::new(move || ::map(self.peek(), |r| mapping(r))) + as Rc ReadableRef + 'static>; + MappedSignal::new(try_read, peek) + } /// Get the current value of the state. If this is a signal, this will subscribe the current scope to the signal. If the value has been dropped, this will panic. #[track_caller] - fn read(&self) -> Self::Ref { + fn read(&self) -> ReadableRef { self.try_read().unwrap() } + /// Try to get the current value of the state. If this is a signal, this will subscribe the current scope to the signal. If the value has been dropped, this will panic. + #[track_caller] + fn try_read(&self) -> Result, generational_box::BorrowError>; + /// Get the current value of the state without subscribing to updates. If the value has been dropped, this will panic. - fn peek(&self) -> Self::Ref; + fn peek(&self) -> ReadableRef; /// Clone the inner value and return it. If the value has been dropped, this will panic. #[track_caller] - fn cloned(&self) -> T + fn cloned(&self) -> Self::Target where - T: Clone, + Self::Target: Clone, { self.read().clone() } /// Run a function with a reference to the value. If the value has been dropped, this will panic. #[track_caller] - fn with(&self, f: impl FnOnce(&T) -> O) -> O { + fn with(&self, f: impl FnOnce(&Self::Target) -> O) -> O { f(&*self.read()) } /// Run a function with a reference to the value. If the value has been dropped, this will panic. #[track_caller] - fn with_peek(&self, f: impl FnOnce(&T) -> O) -> O { + fn with_peek(&self, f: impl FnOnce(&Self::Target) -> O) -> O { f(&*self.peek()) } /// Index into the inner value and return a reference to the result. If the value has been dropped or the index is invalid, this will panic. #[track_caller] - fn index(&self, index: I) -> Self::Ref + fn index(&self, index: I) -> ReadableRef>::Output> where - T: std::ops::Index, + Self::Target: std::ops::Index, { - Self::map_ref(self.read(), |v| v.index(index)) + ::map(self.read(), |v| v.index(index)) } #[doc(hidden)] - fn deref_impl<'a>(&self) -> &'a dyn Fn() -> T + fn deref_impl<'a>(&self) -> &'a dyn Fn() -> Self::Target where Self: Sized + 'a, - T: Clone, + Self::Target: Clone, { // https://github.com/dtolnay/case-studies/tree/master/callable-types @@ -92,7 +118,7 @@ pub trait Readable { } /// An extension trait for Readable> that provides some convenience methods. -pub trait ReadableVecExt: Readable> { +pub trait ReadableVecExt: Readable> { /// Returns the length of the inner vector. #[track_caller] fn len(&self) -> usize { @@ -107,45 +133,43 @@ pub trait ReadableVecExt: Readable> { /// Get the first element of the inner vector. #[track_caller] - fn first(&self) -> Option> { - Self::try_map_ref(self.read(), |v| v.first()) + fn first(&self) -> Option> { + ::try_map(self.read(), |v| v.first()) } /// Get the last element of the inner vector. #[track_caller] - fn last(&self) -> Option> { - Self::try_map_ref(self.read(), |v| v.last()) + fn last(&self) -> Option> { + ::try_map(self.read(), |v| v.last()) } /// Get the element at the given index of the inner vector. #[track_caller] - fn get(&self, index: usize) -> Option> { - Self::try_map_ref(self.read(), |v| v.get(index)) + fn get(&self, index: usize) -> Option> { + ::try_map(self.read(), |v| v.get(index)) } /// Get an iterator over the values of the inner vector. #[track_caller] - fn iter(&self) -> ReadableValueIterator<'_, T, Self> + fn iter(&self) -> ReadableValueIterator<'_, Self> where Self: Sized, { ReadableValueIterator { index: 0, value: self, - phantom: std::marker::PhantomData, } } } /// An iterator over the values of a `Readable>`. -pub struct ReadableValueIterator<'a, T, R> { +pub struct ReadableValueIterator<'a, R> { index: usize, value: &'a R, - phantom: std::marker::PhantomData, } -impl<'a, T: 'static, R: Readable>> Iterator for ReadableValueIterator<'a, T, R> { - type Item = R::Ref; +impl<'a, T: 'static, R: Readable>> Iterator for ReadableValueIterator<'a, R> { + type Item = ReadableRef; fn next(&mut self) -> Option { let index = self.index; @@ -157,12 +181,12 @@ impl<'a, T: 'static, R: Readable>> Iterator for ReadableValueIterator<'a, impl ReadableVecExt for R where T: 'static, - R: Readable>, + R: Readable>, { } /// An extension trait for Readable> that provides some convenience methods. -pub trait ReadableOptionExt: Readable> { +pub trait ReadableOptionExt: Readable> { /// Unwraps the inner value and clones it. #[track_caller] fn unwrap(&self) -> T @@ -174,14 +198,14 @@ pub trait ReadableOptionExt: Readable> { /// Attempts to read the inner value of the Option. #[track_caller] - fn as_ref(&self) -> Option> { - Self::try_map_ref(self.read(), |v| v.as_ref()) + fn as_ref(&self) -> Option> { + ::try_map(self.read(), |v| v.as_ref()) } } impl ReadableOptionExt for R where T: 'static, - R: Readable>, + R: Readable>, { } diff --git a/packages/signals/src/read_only_signal.rs b/packages/signals/src/read_only_signal.rs index 8b75d095b..54106be31 100644 --- a/packages/signals/src/read_only_signal.rs +++ b/packages/signals/src/read_only_signal.rs @@ -1,4 +1,4 @@ -use crate::{read::Readable, Signal, SignalData}; +use crate::{read::Readable, ReadableRef, Signal, SignalData}; use std::ops::Deref; use dioxus_core::{prelude::IntoAttributeValue, ScopeId}; @@ -54,22 +54,12 @@ impl>> ReadOnlySignal { } } -impl>> Readable for ReadOnlySignal { - type Ref = S::Ref; - - fn map_ref &U>(ref_: Self::Ref, f: F) -> Self::Ref { - S::map(ref_, f) - } - - fn try_map_ref Option<&U>>( - ref_: Self::Ref, - f: F, - ) -> Option> { - S::try_map(ref_, f) - } +impl>> Readable for ReadOnlySignal { + type Target = T; + type Storage = S; #[track_caller] - fn try_read(&self) -> Result, generational_box::BorrowError> { + fn try_read(&self) -> Result, generational_box::BorrowError> { self.inner.try_read() } diff --git a/packages/signals/src/signal.rs b/packages/signals/src/signal.rs index a35360695..0b11051b1 100644 --- a/packages/signals/src/signal.rs +++ b/packages/signals/src/signal.rs @@ -1,6 +1,6 @@ use crate::{ - read::Readable, write::Writable, CopyValue, GlobalMemo, GlobalSignal, MappedSignal, - ReactiveContext, ReadOnlySignal, + read::Readable, write::Writable, CopyValue, GlobalMemo, GlobalSignal, ReactiveContext, + ReadOnlySignal, ReadableRef, }; use dioxus_core::{ prelude::{flush_sync, spawn, IntoAttributeValue}, @@ -187,33 +187,18 @@ impl>> Signal { } } - /// Map the signal to a new type. - pub fn map(self, f: impl Fn(&T) -> &O + 'static) -> MappedSignal> { - MappedSignal::new(self, f) - } - /// Get the generational id of the signal. pub fn id(&self) -> generational_box::GenerationalBoxId { self.inner.id() } } -impl>> Readable for Signal { - type Ref = S::Ref; - - fn map_ref &U>(ref_: Self::Ref, f: F) -> Self::Ref { - S::map(ref_, f) - } - - fn try_map_ref Option<&U>>( - ref_: Self::Ref, - f: F, - ) -> Option> { - S::try_map(ref_, f) - } +impl>> Readable for Signal { + type Target = T; + type Storage = S; #[track_caller] - fn try_read(&self) -> Result, generational_box::BorrowError> { + fn try_read(&self) -> Result, generational_box::BorrowError> { let inner = self.inner.try_read()?; let reactive_context = ReactiveContext::current(); @@ -225,23 +210,27 @@ impl>> Readable for Signal { /// Get the current value of the signal. **Unlike read, this will not subscribe the current scope to the signal which can cause parts of your UI to not update.** /// /// If the signal has been dropped, this will panic. - fn peek(&self) -> S::Ref { + fn peek(&self) -> ReadableRef { let inner = self.inner.read(); S::map(inner, |v| &v.value) } } -impl>> Writable for Signal { +impl>> Writable for Signal { type Mut = Write; - fn map_mut &mut U>( + fn map_mut &mut U>( ref_: Self::Mut, f: F, ) -> Self::Mut { Write::map(ref_, f) } - fn try_map_mut Option<&mut U>>( + fn try_map_mut< + I: ?Sized + 'static, + U: ?Sized + 'static, + F: FnOnce(&mut I) -> Option<&mut U>, + >( ref_: Self::Mut, f: F, ) -> Option> { diff --git a/packages/signals/src/write.rs b/packages/signals/src/write.rs index 02ab44c82..4cba48c62 100644 --- a/packages/signals/src/write.rs +++ b/packages/signals/src/write.rs @@ -1,40 +1,46 @@ use std::ops::DerefMut; +use std::ops::IndexMut; use crate::read::Readable; /// A trait for states that can be read from like [`crate::Signal`], or [`crate::GlobalSignal`]. You may choose to accept this trait as a parameter instead of the concrete type to allow for more flexibility in your API. For example, instead of creating two functions, one that accepts a [`crate::Signal`] and one that accepts a [`crate::GlobalSignal`], you can create one function that accepts a [`Writable`] type. -pub trait Writable: Readable { +pub trait Writable: Readable { /// The type of the reference. - type Mut: DerefMut; + type Mut: DerefMut + 'static; /// Map the reference to a new type. - fn map_mut &mut U>(ref_: Self::Mut, f: F) - -> Self::Mut; + fn map_mut &mut U>( + ref_: Self::Mut, + f: F, + ) -> Self::Mut; /// Try to map the reference to a new type. - fn try_map_mut Option<&mut U>>( + fn try_map_mut Option<&mut U>>( ref_: Self::Mut, f: F, ) -> Option>; /// Get a mutable reference to the value. If the value has been dropped, this will panic. #[track_caller] - fn write(&mut self) -> Self::Mut { + fn write(&mut self) -> Self::Mut { self.try_write().unwrap() } /// Try to get a mutable reference to the value. If the value has been dropped, this will panic. - fn try_write(&self) -> Result, generational_box::BorrowMutError>; + fn try_write(&self) -> Result, generational_box::BorrowMutError>; /// Run a function with a mutable reference to the value. If the value has been dropped, this will panic. #[track_caller] - fn with_mut(&mut self, f: impl FnOnce(&mut T) -> O) -> O { + fn with_mut(&mut self, f: impl FnOnce(&mut Self::Target) -> O) -> O { f(&mut *self.write()) } /// Set the value of the signal. This will trigger an update on all subscribers. #[track_caller] - fn set(&mut self, value: T) { + fn set(&mut self, value: Self::Target) + where + Self::Target: Sized, + { *self.write() = value; } @@ -42,38 +48,41 @@ pub trait Writable: Readable { #[track_caller] fn toggle(&mut self) where - T: std::ops::Not + Clone, + Self::Target: std::ops::Not + Clone, { self.set(!self.cloned()); } /// Index into the inner value and return a reference to the result. #[track_caller] - fn index_mut(&mut self, index: I) -> Self::Mut + fn index_mut(&mut self, index: I) -> Self::Mut<>::Output> where - T: std::ops::IndexMut, + Self::Target: std::ops::IndexMut, { Self::map_mut(self.write(), |v| v.index_mut(index)) } /// Takes the value out of the Signal, leaving a Default in its place. #[track_caller] - fn take(&mut self) -> T + fn take(&mut self) -> Self::Target where - T: Default, + Self::Target: Default, { - self.with_mut(|v| std::mem::take(v)) + self.with_mut(std::mem::take) } /// Replace the value in the Signal, returning the old value. #[track_caller] - fn replace(&mut self, value: T) -> T { + fn replace(&mut self, value: Self::Target) -> Self::Target + where + Self::Target: Sized, + { self.with_mut(|v| std::mem::replace(v, value)) } } /// An extension trait for Writable> that provides some convenience methods. -pub trait WritableOptionExt: Writable> { +pub trait WritableOptionExt: Writable> { /// Gets the value out of the Option, or inserts the given value if the Option is empty. fn get_or_insert(&mut self, default: T) -> Self::Mut { self.get_or_insert_with(|| default) @@ -101,12 +110,12 @@ pub trait WritableOptionExt: Writable> { impl WritableOptionExt for W where T: 'static, - W: Writable>, + W: Writable>, { } /// An extension trait for Writable> that provides some convenience methods. -pub trait WritableVecExt: Writable> { +pub trait WritableVecExt: Writable> { /// Pushes a new value to the end of the vector. #[track_caller] fn push(&mut self, value: T) { @@ -175,26 +184,24 @@ pub trait WritableVecExt: Writable> { /// Gets an iterator over the values of the vector. #[track_caller] - fn iter_mut(&self) -> WritableValueIterator + fn iter_mut(&self) -> WritableValueIterator where Self: Sized + Clone, { WritableValueIterator { index: 0, value: self.clone(), - phantom: std::marker::PhantomData, } } } /// An iterator over the values of a `Writable>`. -pub struct WritableValueIterator { +pub struct WritableValueIterator { index: usize, value: R, - phantom: std::marker::PhantomData, } -impl>> Iterator for WritableValueIterator { +impl>> Iterator for WritableValueIterator { type Item = R::Mut; fn next(&mut self) -> Option { @@ -207,6 +214,6 @@ impl>> Iterator for WritableValueIterator { impl WritableVecExt for W where T: 'static, - W: Writable>, + W: Writable>, { } diff --git a/packages/web/src/event.rs b/packages/web/src/event.rs index e79b55fe8..8fa2b1aea 100644 --- a/packages/web/src/event.rs +++ b/packages/web/src/event.rs @@ -10,7 +10,7 @@ use dioxus_html::{ }; use js_sys::Array; use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue}; -use web_sys::{Document, Element, Event, MouseEvent}; +use web_sys::{Document, DragEvent, Element, Event, MouseEvent}; pub(crate) struct WebEventConverter; @@ -49,10 +49,7 @@ impl HtmlEventConverter for WebEventConverter { #[inline(always)] fn convert_drag_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::DragData { let event = downcast_event(event); - DragData::new(WebDragData::new( - event.element.clone(), - event.raw.clone().unchecked_into(), - )) + DragData::new(WebDragData::new(event.raw.clone().unchecked_into())) } #[inline(always)] @@ -462,13 +459,12 @@ impl HasFileData for WebFormData { } struct WebDragData { - element: Element, raw: MouseEvent, } impl WebDragData { - fn new(element: Element, raw: MouseEvent) -> Self { - Self { element, raw } + fn new(raw: MouseEvent) -> Self { + Self { raw } } } @@ -529,17 +525,16 @@ impl HasFileData for WebDragData { #[cfg(not(feature = "file_engine"))] let files = None; #[cfg(feature = "file_engine")] - let files = self - .element - .dyn_ref() - .and_then(|input: &web_sys::HtmlInputElement| { - input.files().and_then(|files| { + let files = self.raw.dyn_ref::().and_then(|drag_event| { + drag_event.data_transfer().and_then(|dt| { + dt.files().and_then(|files| { #[allow(clippy::arc_with_non_send_sync)] crate::file_engine::WebFileEngine::new(files).map(|f| { std::sync::Arc::new(f) as std::sync::Arc }) }) - }); + }) + }); files } diff --git a/packages/web/src/lib.rs b/packages/web/src/lib.rs index 7e365d89b..e106a9dc3 100644 --- a/packages/web/src/lib.rs +++ b/packages/web/src/lib.rs @@ -61,10 +61,7 @@ pub use crate::cfg::Config; #[cfg(feature = "file_engine")] pub use crate::file_engine::WebFileEngineExt; use dioxus_core::VirtualDom; -use futures_util::{ - future::{select, Either}, - pin_mut, FutureExt, StreamExt, -}; +use futures_util::{pin_mut, select, FutureExt, StreamExt}; mod cfg; mod dom; @@ -159,17 +156,21 @@ pub async fn run(virtual_dom: VirtualDom, web_config: Config) { let (mut res, template) = { let work = dom.wait_for_work().fuse(); pin_mut!(work); + let mut rx_next = rx.select_next_some(); #[cfg(all(feature = "hot_reload", debug_assertions))] - match select(work, select(hotreload_rx.next(), rx.next())).await { - Either::Left((_, _)) => (None, None), - Either::Right((Either::Left((new_template, _)), _)) => (None, new_template), - Either::Right((Either::Right((evt, _)), _)) => (evt, None), + { + let mut hot_reload_next = hotreload_rx.select_next_some(); + select! { + _ = work => (None, None), + new_template = hot_reload_next => (None, Some(new_template)), + evt = rx_next => (Some(evt), None), + } } #[cfg(not(all(feature = "hot_reload", debug_assertions)))] - match select(work, rx.next()).await { - Either::Left((_, _)) => (None, None), - Either::Right((evt, _)) => (evt, None), + select! { + _ = work => (None, None), + evt = rx_next => (Some(evt), None), } };