[
  {
    "path": ".gitattributes",
    "content": "* text=auto\n\n*.rs text eol=lf\n*.toml text eol=lf\n*.wgsl text eol=lf\n*.txt text eol=lf\n\n*.png binary\n*.ttf binary\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "github: actuate-rs\nopen_collective: actuateui\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\non:\n  push:\n    branches: [\"main\"]\n  pull_request:\n    branches: [\"main\"]\n\nenv:\n  CARGO_TERM_COLOR: always\n\njobs:\n  # Build core features\n  core:\n    name: Build core\n    runs-on: ubuntu-latest\n    timeout-minutes: 30\n    steps:\n      - name: Checkout sources\n        uses: actions/checkout@v4\n      - name: Cache\n        uses: actions/cache@v4\n        with:\n          path: |\n            ~/.cargo/bin/\n            ~/.cargo/registry/index/\n            ~/.cargo/registry/cache/\n            ~/.cargo/git/db/\n            target/\n          key: ${{ runner.os }}-cargo-test-${{ hashFiles('**/Cargo.toml') }}\n      - name: Install stable toolchain\n        uses: dtolnay/rust-toolchain@stable\n      - name: Run cargo build\n        run: cargo build --verbose\n\n  # Run cargo fmt --all -- --check\n  format:\n    name: Format\n    runs-on: ubuntu-latest\n    timeout-minutes: 30\n    steps:\n      - name: Checkout sources\n        uses: actions/checkout@v4\n      - name: Install stable toolchain\n        uses: dtolnay/rust-toolchain@stable\n        with:\n          components: rustfmt\n      - name: Run cargo fmt\n        run: cargo fmt --all -- --check\n\n  # Run cargo clippy\n  clippy:\n    name: Clippy\n    runs-on: ubuntu-latest\n    timeout-minutes: 30\n    steps:\n      - name: Checkout sources\n        uses: actions/checkout@v4\n      - name: Cache\n        uses: actions/cache@v4\n        with:\n          path: |\n            ~/.cargo/bin/\n            ~/.cargo/registry/index/\n            ~/.cargo/registry/cache/\n            ~/.cargo/git/db/\n            target/\n          key: ${{ runner.os }}-cargo-clippy-${{ hashFiles('**/Cargo.toml') }}\n      - name: Install stable toolchain\n        uses: dtolnay/rust-toolchain@stable\n        with:\n          components: clippy\n      - name: Install Dependencies\n        run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev\n      - name: Run clippy\n        run: cargo clippy -- -D warnings\n\n  # Run cargo test\n  test:\n    name: Tests\n    runs-on: ubuntu-latest\n    timeout-minutes: 30\n    steps:\n      - name: Checkout sources\n        uses: actions/checkout@v4\n      - name: Cache\n        uses: actions/cache@v4\n        with:\n          path: |\n            ~/.cargo/bin/\n            ~/.cargo/registry/index/\n            ~/.cargo/registry/cache/\n            ~/.cargo/git/db/\n            target/\n          key: ${{ runner.os }}-cargo-test-${{ hashFiles('**/Cargo.toml') }}\n      - name: Install stable toolchain\n        uses: dtolnay/rust-toolchain@stable\n      - name: Install Dependencies\n        run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev\n      - name: Run cargo test\n        run: cargo test --features full --verbose\n\n  # Run cargo test\n  miri:\n    name: Miri\n    runs-on: ubuntu-latest\n    timeout-minutes: 30\n    steps:\n      - name: Checkout sources\n        uses: actions/checkout@v4\n      - name: Cache\n        uses: actions/cache@v4\n        with:\n          path: |\n            ~/.cargo/bin/\n            ~/.cargo/registry/index/\n            ~/.cargo/registry/cache/\n            ~/.cargo/git/db/\n            target/\n          key: ${{ runner.os }}-cargo-test-${{ hashFiles('**/Cargo.toml') }}\n      - name: Install stable toolchain\n        uses: dtolnay/rust-toolchain@stable\n      - name: Install Dependencies\n        run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev\n      - name: Install Miri\n        run: |\n          rustup toolchain install nightly --component miri\n          rustup override set nightly\n          cargo miri setup\n      - name: Test with Miri\n        run: cargo miri test --workspace --features full --verbose\n"
  },
  {
    "path": ".gitignore",
    "content": "/target\ndist/"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## [0.21.0](https://github.com/actuate-rs/actuate/compare/actuate-v0.20.1...actuate-v0.21.0) - 2025-12-18\n\n## Breaking changes\n\n- Update to Bevy v0.17.3\n\n## [0.20.1](https://github.com/actuate-rs/actuate/compare/actuate-v0.20.0...actuate-v0.20.1) - 2024-12-13\n\n## Documentation\n\n- Fix formatting in crate example\n\n## [0.20.0](https://github.com/actuate-rs/actuate/compare/actuate-v0.19.1...actuate-v0.20.0) - 2024-12-13\n\n## Breaking changes\n\n- Fix `Data` impl for `&T` (63d89ed)\n- Remove Data from root exports (677b160)\n- Replace `Memoize` trait with more specific `Generational` trait (febe238)\n\n## Features\n\n- Impl `Data` for Rc<dyn Fn(..)> and derive `Clone` for `Catch` composable (e038307)\n- Impl `Clone` for `from_fn`, `from_iter`, and `memo` composables (21c016f)\n- Add `material_ui` composable (5dad9a3)\n\n## Fixes\n\n- Replace `std` deps with `core` (68d44a2)\n- Simplify styling in `scroll_view` composable and update `http` example (f90e4c4)\n- Check for removed entities in Spawn composable (c23e158)\n\n## Documentation\n\n- Add docs to `use_local_task` (63d89ed)\n- Add docs to `use_task` (7ddbe84)\n- Update counter example (3b79bb1)\n- Update borrowing docs (efcdfe3)\n\n## [0.19.1](https://github.com/actuate-rs/actuate/compare/actuate-v0.19.0...actuate-v0.19.1) - 2024-12-09\n\n## Features\n\n- Add `use_effect` hook (5ae0a51)\n  - `fn use_effect<D, T>(cx: ScopeState<'_>, dependency: D, effect: impl FnOnce(&D))`\n\n## Fixes\n\n- Remove `AnyItemState` in `from_iter` composable to pass stacked borrows check in miri (2360814)\n\n## Documentation\n\n- Add docs for `from_fn` and `from_iter` composables (5c379e1)\n\n## [0.19.0](https://github.com/actuate-rs/actuate/compare/actuate-v0.18.1...actuate-v0.19.0) - 2024-12-08\n\n## Breaking changes\n\n- Require `'static` items in `from_iter` composable\n  - This prevents edge cases where an item may have been removed from a collection, but references still exist down the tree.\n\n## Documentation\n\n- Add logo to rustdocs (702b1e0)\n- Update material docs (3084286)\n- Update link to `core::error::Error` in `Catch` composable (b664206)\n\n## [0.18.1](https://github.com/actuate-rs/actuate/compare/actuate-v0.18.0...actuate-v0.18.1) - 2024-12-07\n\n## Fixes\n\n- Specify `winit` backend for `docs.rs` (62bec2d)\n\n## [0.18.0](https://github.com/actuate-rs/actuate/compare/actuate-v0.17.2...actuate-v0.18.0) - 2024-12-07\n\n## Breaking changes\n\n- Create `ScrollView` composable and new `ui` module (28628f4, ebb17b0)\n  - The `material` is now located under `ui`\n\n## Features\n\n- Add support for reactive Bevy desktop apps (7c65ba9, 6918000)\n- Add more picking handler methods to `Modify` (64404b3)\n- More advanced typography with new Text composable (825e007)\n- Derive `Clone` for `Spawn` and refactor (6c4e457)\n- Add methods to modify all Node fields\n\n## [0.17.2](https://github.com/actuate-rs/actuate/compare/actuate-v0.17.1...actuate-v0.17.2) - 2024-12-07\n\n## Fixes\n\n- Update pending composable ordering and track child index in `Spawn` composable (fdf89ed)\n- Reverse node IDs and refactor internals (42e1971)\n\n## Documentation\n\n- Add docs to `spawn` constructor and split up ecs module (9c06bfe)\n- Move examples for `catch` and `dyn_compose` to rustdocs (9502a4b)\n- Move traits example to data module and add docs, reorganize examples (67ec922)\n- Update Data docs (829c6d9)\n\n## [0.17.1](https://github.com/actuate-rs/actuate/compare/actuate-v0.17.0...actuate-v0.17.1) - 2024-12-06\n\n## Features\n\n- Create `FromFn` composable\n\n  - You can now create a composable without input using `from_fn` (433ab1d)\n  - ```rs\n     fn from_fn<F, C>(f: F) -> FromFn<F, C>\n     where\n         F: Fn(ScopeState) -> C,\n         C: Compose\n    ```\n\n- Derive `Clone` and `Debug` for `Button`, `Container`, and `RadioButton` (4f337ed)\n\n## Documentation\n\n- Update docs for feature flags (869aa89)\n\n## [0.17.0](https://github.com/actuate-rs/actuate/compare/actuate-v0.16.1...actuate-v0.17.0) - 2024-12-06\n\n## Breaking changes\n\n- Move `Modifier` and `Modify` to ecs module (behind new picking feature) (35b10ea)\n  - These items can be useful for other design systems than Material 3\n- Call `on_insert` on every insertion of a spawned bundle (this now requires `Fn` instead of `FnOnce`) (533da07)\n\n## Fixes\n\n- Revert from breadth-first traversal of the composition to depth-first (8b3acd2)\n- Update styling for `Container` (9cca3a7)\n\n## [0.16.1](https://github.com/actuate-rs/actuate/compare/actuate-v0.16.0...actuate-v0.16.1) - 2024-12-05\n\n## Features\n\n- Material UI components\n\n  - `Button`\n  - `Container`\n  - `RadioButton`\n  - `text`\n    - `label`\n    - `heading`\n\n- New scheduling algorithm based on `BTreeSet` (2a457a9)\n\n## [0.16.0](https://github.com/actuate-rs/actuate/compare/actuate-v0.15.0...actuate-v0.16.0) - 2024-12-05\n\n### Breaking changes\n\n- Major internal rewrite! (9ef73eb) The new internals allow for more dynamic control over the composition\n  , enabling features like pause and resume of a composition.\n  `Composer::try_compose` will now also skip directly to changed composables, rather than setting change flags.\n  - Removes exported methods for `ScopeData`\n  - The `Runtime` struct is now private to ensure safety\n\n## Features\n\n- `Composer` is now an iterator! This allows for stepping through each composable in the composition.\n- `Composer` also implements `fmt::Debug`:\n\n  ```rs\n  use actuate::prelude::*;\n  use actuate::composer::Composer;\n\n  #[derive(Data)]\n  struct A;\n\n  impl Compose for A {\n      fn compose(cx: Scope<Self>) -> impl Compose {\n          (B, C)\n      }\n  }\n\n  #[derive(Data)]\n  struct B;\n\n  impl Compose for B {\n      fn compose(cx: Scope<Self>) -> impl Compose {}\n  }\n\n  #[derive(Data)]\n  struct C;\n\n  impl Compose for C {\n      fn compose(cx: Scope<Self>) -> impl Compose {}\n  }\n\n  let mut composer = Composer::new(A);\n  composer.try_compose().unwrap();\n\n  assert_eq!(format!(\"{:?}\", composer), \"Composer(A(B, C))\")\n  ```\n\n## [0.15.0](https://github.com/actuate-rs/actuate/compare/actuate-v0.14.2...actuate-v0.15.0) - 2024-12-03\n\n### Breaking changes\n\n- Add `#[actuate(path = \"..\")]` attribute to `Data` macro and use fully-qualified path to Actuate by default (b159478).\n  - This allows for use of the `Data` macro without importing the full `prelude`.\n- Replace `DynCompose::new` with `dyn_compose` constructor fn (9d65ec8).\n- Return `Rc` from use_context\n  - `fn use_context<T: 'static>(cx: ScopeState<'_>) -> Result<&Rc<T>, ContextError<T>> { .. }`\n  - This allows for cloning context into `'static` environments.\n\n### Refactors\n\n- Use explicit imports internally to speed up compile times and exclude hidden `Data` traits from prelude (07bfd96).\n\n## [0.14.2](https://github.com/actuate-rs/actuate/compare/actuate-v0.14.1...actuate-v0.14.2) - 2024-12-03\n\n### Features\n\n- Optimize empty composables by skipping creation of ScopeData\n\n### Fixes\n\n- Enable Tokio dependency with animation and ecs features (5263fe4)\n\n## [0.14.1](https://github.com/actuate-rs/actuate/compare/actuate-v0.14.0...actuate-v0.14.1) - 2024-12-03\n\n### Fixes\n\n- Remove unused tokio read lock guard (0ad962f)\n\n## [0.14.0](https://github.com/actuate-rs/actuate/compare/actuate-v0.13.0...actuate-v0.14.0) - 2024-12-03\n\n### Breaking Changes\n\n- Remove unsound `Compose` impl for `Map` and create `MapUnchecked` struct\n  - The original `Compose` impl for `Map` would cause undefined behavior if multiple references to the same composable were used. The new unsafe `MapUnchecked` keeps this functionality for low-level components, where the documented safety contract can be checked. However, for most composables I now see `Compose + Clone` being a typical pattern (which I think is fine given some composables only copy references when cloned, and references to composables can still be passed around).\n\n### Fixes\n\n- Impl re-composition when the type has changed in `DynCompose` (7d41100)\n\n### Documentation\n\n- Update docs for `Spawn` composable (205b88a)\n- Add example to showcase `DynCompose` (7d41100)\n\n## [0.13.0](https://github.com/actuate-rs/actuate/compare/actuate-v0.12.0...actuate-v0.13.0) - 2024-12-02\n\n### Breaking Changes\n\n- Use `PartialEq` in `use_memo` instead of the `Memoize` trait (6539c95)\n  - This is to memoize tuples and other groups of data.\n    To use pointer equality, you can still use `Signal::generation` or `Memoize::memoize` to get the current generation.\n- Remove unused UseWorld struct (81615cd)\n\n### Documentation\n\n- Add more documentation to the `Catch` composable\n  - Adds a quick explanation of using `Result` + `Catch`, and links to the `catch` constructor function for more info.\n- Add explanation to `compose::from_iter` (dc6715d)\n\n### Other\n\n- Change release procedure and update CI (dd4be8d, fe23aad, 723fe6c)\n\n## [0.12.0](https://github.com/actuate-rs/actuate/compare/actuate-v0.11.0...actuate-v0.12.0) - 2024-12-02\n\n### Other\n\n- `#![no_std]` support ([#100](https://github.com/actuate-rs/actuate/pull/100))\n- Clean up and add internal docs\n- Remove Sized bound in Compose trait\n- Create `Catch` composable and impl `Compose` for `Result` ([#99](https://github.com/actuate-rs/actuate/pull/99))\n- Add getter and setter methods to ScopeData\n- Update docs\n- Remove is_empty from ScopeState in favor of checking for empty types\n- Create README.md\n\n## [0.11.0](https://github.com/actuate-rs/actuate/compare/actuate-v0.10.2...actuate-v0.11.0) - 2024-11-29\n\n### Other\n\n- Update to Bevy 0.15.0\n- Disable observers after drop\n- Add support for standard references in RefMap and Cow\n- Fix formatting in README\n\n## [0.10.2](https://github.com/actuate-rs/actuate/compare/actuate-v0.10.1...actuate-v0.10.2) - 2024-11-28\n\n### Other\n\n- Add specialized impl of SystemParamFunction for Triggers\n- Export animation channel\n- Impl Data for UseAnimated\n- Impl Data for Pin\n- Impl Data for Box<dyn Future<Output = ()>>\n- Allow return values for Data fns\n- Create `use_animated` hook ([#88](https://github.com/actuate-rs/actuate/pull/88))\n- Fix tasks not running on the ecs\n\n## [0.10.1](https://github.com/actuate-rs/actuate/compare/actuate-v0.10.0...actuate-v0.10.1) - 2024-11-26\n\n### Other\n\n- Apply system params in use_world_once\n- Apply deferred system param updates\n- Add SignalMut::set_if_neq and generation methods\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[package]\nname = \"actuate\"\nversion = \"0.21.0\"\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\ndescription = \"A reactive user-interface framework\"\nrepository = \"https://github.com/actuate-rs/actuate\"\n\n[features]\nanimation = [\"ecs\", \"dep:bevy_math\", \"dep:bevy_time\", \"dep:tokio\"]\necs = [\"std\", \"dep:bevy_app\", \"dep:bevy_ecs\", \"dep:bevy_utils\", \"dep:bevy_winit\"]\nexecutor = [\"std\", \"dep:tokio\"]\nmaterial = [\"ecs\", \"ui\", \"picking\", \"dep:bevy_color\", \"dep:bevy_input\", \"dep:bevy_text\"]\npicking = [\"dep:bevy_picking\"]\nrt = [\"executor\", \"tokio/rt-multi-thread\"]\nstd = []\ntracing = [\"dep:tracing\"]\nui = [\"dep:bevy_ui\"]\nfull = [\"animation\", \"ecs\", \"material\", \"rt\", \"tracing\"]\ndefault = [\"std\"]\n\n[workspace]\nmembers = [\n    \".\",\n    \"macros\"\n]\n\n[dependencies]\nactuate-macros = { version = \"0.2.0\", path = \"macros\" }\nahash = { version = \"0.8.11\", default-features = false }\nbevy_app = { version = \"0.17.3\", optional = true }\nbevy_color = { version = \"0.17.3\", optional = true }\nbevy_ecs = { version = \"0.17.3\", optional = true }\nbevy_input = { version = \"0.17.3\", optional = true }\nbevy_math = { version = \"0.17.3\", optional = true }\nbevy_picking = { version = \"0.17.3\", optional = true }\nbevy_text = { version = \"0.17.3\", optional = true }\nbevy_time = { version = \"0.17.3\", optional = true }\nbevy_ui = { version = \"0.17.3\", optional = true }\nbevy_utils = { version = \"0.17.3\", optional = true }\nbevy_winit = { version = \"0.17.3\", optional = true }\ncrossbeam-queue = { version = \"0.3.11\", default-features = false, features = [\"alloc\"] }\nfutures = \"0.3.31\"\nhashbrown = \"0.15.2\"\nslotmap = \"1.0.7\"\nthiserror = \"2.0.3\"\ntracing = { version = \"0.1.40\", optional = true }\ntokio = { version = \"1.41.1\", features = [\"sync\"], optional = true }\ntypeid = \"1.0.2\"\n\n[dev-dependencies]\nbevy = { version = \"0.17.3\" }\nreqwest = { version = \"0.12.9\", features = [\"json\"] }\nserde = { version = \"1.0.215\", features = [\"derive\"] }\ntracing-subscriber = \"0.3.18\"\n\n[package.metadata.docs.rs]\nall-features = true\nfeatures = [\"bevy_winit/x11\"]\nrustdoc-args = [\"--cfg\", \"docsrs\"]\n\n[[example]]\nname = \"counter\"\nrequired-features = [\"material\"]\n\n[[example]]\nname = \"http\"\nrequired-features = [\"material\", \"rt\"]\n\n[[example]]\nname = \"radio_button\"\nrequired-features = [\"material\"]\n\n[[example]]\nname = \"timer\"\nrequired-features = [\"ecs\"]\n"
  },
  {
    "path": "LICENSE-APACHE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "LICENSE-MIT",
    "content": "MIT License\n\nCopyright (c) 2023 Matthew Hunzinger\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<div align=\"center\">\n  <h1>Actuate</h1>\n  <a href=\"https://crates.io/crates/actuate\">\n    <img src=\"https://img.shields.io/crates/v/actuate?style=flat-square\"\n      alt=\"Crates.io version\" />\n  </a>\n  <a href=\"https://docs.rs/actuate\">\n    <img src=\"https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square\"\n      alt=\"docs.rs docs\" />\n  </a>\n  <a href=\"https://github.com/actuate-rs/actuate/actions\">\n    <img src=\"https://github.com/actuate-rs/actuate/actions/workflows/ci.yml/badge.svg\"\n      alt=\"CI status\" />\n  </a>\n</div>\n\n<div align=\"center\">\n <a href=\"https://github.com/actuate-rs/actuate/tree/main/examples\">Examples</a>\n</div>\n\n<br />\n\nA high-performance and borrow-checker friendly framework for declarative programming in Rust.\nThis crate provides a generic library that lets you define reactive components (also known as composables).\n\n## Features\n- Declarative scenes and UI for [Bevy](https://github.com/bevyengine/bevy)\n- Efficient and borrow-checker friendly state management: Manage state with components and hooks, all using zero-cost smart pointers\n- Generic core for custom backends\n\n```rust\nuse actuate::prelude::*;\n\n#[derive(Data)]\nstruct Counter {\n    start: i32,\n}\n\nimpl Compose for Counter {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        let count = use_mut(&cx, || cx.me().start);\n\n        material_ui((\n            text::headline(format!(\"High five count: {}\", count)),\n            button(text::label(\"Up high\")).on_click(move || SignalMut::update(count, |x| *x += 1)),\n            button(text::label(\"Down low\")).on_click(move || SignalMut::update(count, |x| *x -= 1)),\n            if *count == 0 {\n                Some(text::label(\"Gimme five!\"))\n            } else {\n                None\n            },\n        ))\n        .align_items(AlignItems::Center)\n        .justify_content(JustifyContent::Center)\n    }\n}\n```\n\n## Borrowing\nComposables can borrow from their ancestors, as well as state.\n```rs\nuse actuate::prelude::*;\n\n#[derive(Data)]\nstruct User<'a> {\n    // `actuate::Cow` allows for either a borrowed or owned value.\n    name: Cow<'a, String>,\n}\n\nimpl Compose for User<'_> {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        text::headline(cx.me().name.to_string())\n    }\n}\n\n#[derive(Data)]\nstruct App {\n    name: String\n}\n\nimpl Compose for App {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        // Get a mapped reference to the app's `name` field.\n        let name = Signal::map(cx.me(), |me| &me.name).into();\n\n        User { name }\n    }\n}\n```\n\n## Installation\nTo add this crate to your project:\n```\ncargo add actuate --features full\n```\nFor more feature flags, see the crate documentation for [features](https://docs.rs/actuate/latest/actuate/#features).\n\n## Inspiration\nThis crate is inspired by [Xilem](https://github.com/linebender/xilem) and uses a similar approach to type-safe reactivity. The main difference with this crate is the concept of scopes, components store their state in their own scope and updates to that scope re-render the component.\n\nState management is inspired by React and [Dioxus](https://github.com/DioxusLabs/dioxus).\n\nPrevious implementations were in [Concoct](https://github.com/concoct-rs/concoct) but were never very compatible with lifetimes.\n"
  },
  {
    "path": "examples/README.md",
    "content": "## Examples\n\nExamples combining Actuate and [Bevy](https://github.com/bevyengine/bevy)\n\nYou can run these examples with:\n\n```\ncargo run --features full --example {EXAMPLE}\n```\n"
  },
  {
    "path": "examples/counter.rs",
    "content": "// Counter UI example.\n\nuse actuate::prelude::*;\nuse bevy::{prelude::*, winit::WinitSettings};\n\n// Counter composable.\n#[derive(Data)]\nstruct Counter {\n    start: i32,\n}\n\nimpl Compose for Counter {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        let count = use_mut(&cx, || cx.me().start);\n\n        material_ui((\n            text::headline(format!(\"High five count: {}\", count)),\n            button(text::label(\"Up high\")).on_click(move || SignalMut::update(count, |x| *x += 1)),\n            button(text::label(\"Down low\")).on_click(move || SignalMut::update(count, |x| *x -= 1)),\n            if *count == 0 {\n                Some(text::label(\"Gimme five!\"))\n            } else {\n                None\n            },\n        ))\n        .align_items(AlignItems::Center)\n        .justify_content(JustifyContent::Center)\n    }\n}\n\nfn setup(mut commands: Commands) {\n    commands.spawn(Camera2d::default());\n\n    // Spawn a composition with a `Counter`, adding it to the Actuate runtime.\n    commands.spawn((\n        Node {\n            width: Val::Percent(100.),\n            height: Val::Percent(100.),\n            ..default()\n        },\n        Composition::new(Counter { start: 0 }),\n    ));\n}\n\nfn main() {\n    App::new()\n        .add_plugins((DefaultPlugins, ActuatePlugin))\n        .insert_resource(WinitSettings::desktop_app())\n        .add_systems(Startup, setup)\n        .run();\n}\n"
  },
  {
    "path": "examples/http.rs",
    "content": "// HTTP UI example\n\nuse actuate::{executor::ExecutorContext, prelude::*};\nuse bevy::{prelude::*, winit::WinitSettings};\nuse serde::Deserialize;\nuse std::collections::HashMap;\n\n// Dog breed composable.\n#[derive(Data)]\nstruct Breed {\n    name: String,\n    families: Vec<String>,\n}\n\nimpl Compose for Breed {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        container((\n            text::headline(cx.me().name.to_owned()),\n            compose::from_iter(cx.me().families.clone(), |family| {\n                text::label(family.to_string())\n            }),\n        ))\n    }\n}\n\n#[derive(Deserialize)]\nstruct Response {\n    message: HashMap<String, Vec<String>>,\n}\n\n// Dog breed list composable.\n#[derive(Data)]\nstruct BreedList;\n\nimpl Compose for BreedList {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        let breeds = use_mut(&cx, HashMap::new);\n\n        // Spawn a task that loads dog breeds from an HTTP API.\n        use_task(&cx, move || async move {\n            let json: Response = reqwest::get(\"https://dog.ceo/api/breeds/list/all\")\n                .await\n                .unwrap()\n                .json()\n                .await\n                .unwrap();\n\n            SignalMut::set(breeds, json.message);\n        });\n\n        material_ui(\n            // Render the currently loaded breeds.\n            scroll_view(compose::from_iter((*breeds).clone(), |breed| Breed {\n                name: breed.0.clone(),\n                families: breed.1.clone(),\n            }))\n            .max_width(Val::Px(400.))\n            .flex_gap(Val::Px(30.)),\n        )\n        .align_items(AlignItems::Center)\n    }\n}\n\n#[derive(Data)]\nstruct Example;\n\nimpl Compose for Example {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        // Setup the Tokio executor.\n        use_provider(&cx, ExecutorContext::default);\n\n        BreedList\n    }\n}\n\nfn main() {\n    App::new()\n        .add_plugins((DefaultPlugins, ActuatePlugin))\n        .insert_resource(WinitSettings::desktop_app())\n        .add_systems(Startup, setup)\n        .run();\n}\n\nfn setup(mut commands: Commands) {\n    commands.spawn(Camera2d::default());\n\n    // Spawn a composition with a `BreedList`, adding it to the Actuate runtime.\n    commands.spawn((\n        Node {\n            width: Val::Percent(100.),\n            height: Val::Percent(100.),\n            ..default()\n        },\n        Composition::new(Example),\n    ));\n}\n"
  },
  {
    "path": "examples/radio_button.rs",
    "content": "// Counter UI example.\n\nuse actuate::prelude::*;\nuse bevy::prelude::*;\n\n// Counter composable.\n#[derive(Data)]\nstruct Example;\n\nimpl Compose for Example {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        let is_shown = use_mut(&cx, || true);\n\n        radio_button()\n            .is_enabled(*is_shown)\n            .on_click(move || SignalMut::update(is_shown, |x| *x = !*x))\n    }\n}\n\nfn setup(mut commands: Commands) {\n    commands.spawn(Camera2d::default());\n\n    // Spawn a composition with a `Counter`, adding it to the Actuate runtime.\n    commands.spawn((\n        Node {\n            flex_direction: FlexDirection::Column,\n            align_items: AlignItems::Center,\n            row_gap: Val::Px(10.),\n            ..default()\n        },\n        Composition::new(Example),\n    ));\n}\n\nfn main() {\n    App::new()\n        .add_plugins((DefaultPlugins, ActuatePlugin))\n        .add_systems(Startup, setup)\n        .run();\n}\n"
  },
  {
    "path": "examples/timer.rs",
    "content": "// Timer UI example.\n\nuse actuate::prelude::*;\nuse bevy::prelude::*;\n\n// Timer composable.\n#[derive(Data)]\nstruct Timer;\n\nimpl Compose for Timer {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        let current_time = use_mut(&cx, Time::default);\n\n        // Use the `Time` resource from the ECS world, updating the `current_time`.\n        use_world(&cx, move |time: Res<Time>| {\n            SignalMut::set(current_time, *time)\n        });\n\n        // Spawn a `Text` component, updating it when this scope is re-composed.\n        spawn(Text::new(format!(\"Elapsed: {:?}\", current_time.elapsed())))\n    }\n}\n\nfn main() {\n    App::new()\n        .add_plugins((DefaultPlugins, ActuatePlugin))\n        .add_systems(Startup, setup)\n        .run();\n}\n\nfn setup(mut commands: Commands) {\n    commands.spawn(Camera2d::default());\n\n    // Spawn a composition with a `Timer`, adding it to the Actuate runtime.\n    commands.spawn((Node::default(), Composition::new(Timer)));\n}\n"
  },
  {
    "path": "macros/CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## [0.2.0](https://github.com/actuate-rs/actuate/compare/actuate-macros-v0.1.6...actuate-macros-v0.2.0) - 2024-12-3\n\n### Breaking changes\n\n- Add `#[actuate(path = \"..\")]` attribute to `Data` macro and use fully-qualified path to Actuate by default (b159478)\n\n## [0.1.6](https://github.com/actuate-rs/actuate/compare/actuate-macros-v0.1.5...actuate-macros-v0.1.6) - 2024-11-25\n\n### Other\n\n- Add basic support for borrowed trait objects\n\n## [0.1.5](https://github.com/actuate-rs/actuate/compare/actuate-macros-v0.1.4...actuate-macros-v0.1.5) - 2024-11-21\n\n### Other\n\n- Remove Data::Id in favor of typeid crate ([#65](https://github.com/actuate-rs/actuate/pull/65))\n\n## [0.1.4](https://github.com/actuate-rs/actuate/compare/actuate-macros-v0.1.3...actuate-macros-v0.1.4) - 2024-11-18\n\n### Other\n\n- Move macros crate to root and refactor Mut to use NonNull\n\n## [0.1.3](https://github.com/actuate-rs/actuate/compare/actuate-macros-v0.1.2...actuate-macros-v0.1.3) - 2024-11-16\n\n### Other\n\n- Test Memo composable\n- Safely impl Compose for Map<C>\n- Use Data macro in more places\n- Refactor macro\n\n## [0.1.2](https://github.com/actuate-rs/actuate/compare/actuate-macros-v0.1.1...actuate-macros-v0.1.2) - 2024-11-13\n\n### Other\n\n- Create Handler struct\n- Create actuate-winit crate and refactor\n\n## [0.1.1](https://github.com/actuate-rs/actuate/compare/actuate-macros-v0.1.0...actuate-macros-v0.1.1) - 2024-11-12\n\n### Other\n\n- Create core crate and refactor\n"
  },
  {
    "path": "macros/Cargo.toml",
    "content": "[package]\nname = \"actuate-macros\"\ndescription = \"Macros for Actuate\"\nversion = \"0.2.0\"\nedition = \"2021\"\nlicense = \"MIT OR Apache-2.0\"\nrepository = \"https://github.com/actuate-rs/actuate\"\n\n[lib]\nproc-macro = true\n\n[dependencies]\nquote = \"1.0.37\"\nsyn = { version = \"2.0.87\", features = [\"full\"] }\n"
  },
  {
    "path": "macros/src/lib.rs",
    "content": "use proc_macro::TokenStream;\nuse quote::{format_ident, quote, ToTokens};\nuse syn::{\n    parse_macro_input, parse_quote, punctuated::Punctuated, token::Comma, Data, DeriveInput,\n    GenericParam, ItemTrait, MetaNameValue, TypeParamBound,\n};\n\n#[proc_macro_derive(Data, attributes(actuate))]\npub fn derive_data(input: TokenStream) -> TokenStream {\n    let input = parse_macro_input!(input as DeriveInput);\n    let ident = &input.ident;\n\n    let generics = &input.generics;\n\n    let mut cell = None;\n    if let Some(attr) = input\n        .attrs\n        .iter()\n        .find(|attr| attr.path().is_ident(\"actuate\"))\n    {\n        let args: MetaNameValue = attr.parse_args().unwrap();\n        if args.path.get_ident().unwrap() == \"path\" {\n            let value = args.value.to_token_stream().to_string();\n            cell = Some(format_ident!(\"{}\", &value[1..value.len() - 1]));\n        }\n    }\n    let actuate = cell.unwrap_or(format_ident!(\"actuate\"));\n\n    let generic_params: Punctuated<_, Comma> = generics\n        .params\n        .iter()\n        .map(|param| match param {\n            GenericParam::Lifetime(lifetime_param) => lifetime_param.to_token_stream(),\n            GenericParam::Type(type_param) => {\n                let ident = &type_param.ident;\n\n                let mut bounds = type_param.bounds.clone();\n                bounds.push(parse_quote!(#actuate::data::Data));\n\n                quote! {\n                    #ident: #bounds\n                }\n            }\n            GenericParam::Const(const_param) => const_param.to_token_stream(),\n        })\n        .collect();\n\n    let generic_ty_params: Punctuated<_, Comma> = generics\n        .params\n        .iter()\n        .map(|param| match param {\n            GenericParam::Lifetime(lifetime_param) => lifetime_param.to_token_stream(),\n            GenericParam::Type(type_param) => type_param.ident.to_token_stream(),\n            GenericParam::Const(const_param) => const_param.to_token_stream(),\n        })\n        .collect();\n\n    let Data::Struct(input_struct) = input.data else {\n        todo!()\n    };\n\n    let checks = input_struct.fields.iter().map(|field| {\n        let field_ident = field.ident.as_ref().unwrap();\n        let check_ident = format_ident!(\"__check_{}_{}\", ident, field_ident);\n        quote! {\n           #[doc(hidden)]\n           #[allow(non_snake_case)]\n           fn #check_ident <#generic_params> (t: #ident <#generic_ty_params>) {\n                use #actuate::data::{FieldWrap, DataField, FnField, StaticField};\n\n                (&&FieldWrap(t.#field_ident)).check()\n           }\n        }\n    });\n\n    let gen = quote! {\n        #( #checks )*\n\n        #[doc(hidden)]\n        unsafe impl <#generic_params> #actuate::data::Data for #ident <#generic_ty_params> {}\n    };\n    gen.into()\n}\n\n#[proc_macro_attribute]\npub fn data(_attrs: TokenStream, input: TokenStream) -> TokenStream {\n    let item = parse_macro_input!(input as ItemTrait);\n\n    let contains_data = item.supertraits.iter().any(|x| {\n        if let TypeParamBound::Trait(trait_bound) = x {\n            if trait_bound.path.is_ident(\"Data\") {\n                return true;\n            }\n        }\n\n        false\n    });\n\n    if !contains_data {\n        return quote! {\n            compile_error!(\"\\\n                Traits used as `Data` must require all implementations to be `Data`. \\\n                To fix this, add `Data` as a supertrait to your trait (i.e trait MyTrait: Data {}).\\\n            \");\n        }\n        .into();\n    }\n\n    let ident = &item.ident;\n\n    quote! {\n        #item\n\n        unsafe impl actuate::data::Data for Box<dyn #ident + '_> {}\n    }\n    .into()\n}\n"
  },
  {
    "path": "src/animation.rs",
    "content": "use crate::{\n    data::Data,\n    ecs::{use_world, use_world_once},\n    use_local_task, use_mut, use_ref, ScopeState, Signal, SignalMut,\n};\nuse bevy_ecs::prelude::*;\nuse bevy_math::VectorSpace;\nuse bevy_time::Time;\nuse std::{\n    cell::{Cell, RefCell},\n    ops::Deref,\n    time::Duration,\n};\nuse tokio::sync::{mpsc, oneshot};\n\nstruct State<T> {\n    from: T,\n    to: T,\n    duration: Duration,\n    tx: Option<oneshot::Sender<()>>,\n}\n\n/// Use an animated value.\npub fn use_animated<T>(cx: ScopeState<'_>, make_initial: impl FnOnce() -> T) -> UseAnimated<'_, T>\nwhere\n    T: VectorSpace + Send + 'static,\n    T::Scalar: From<f32>,\n{\n    let start_cell = use_world_once(cx, |time: Res<Time>| Cell::new(Some(time.elapsed_secs())));\n\n    let (controller, rx) = use_ref(cx, || {\n        let (tx, rx) = mpsc::unbounded_channel();\n        (AnimationController { tx }, Cell::new(Some(rx)))\n    });\n\n    let state: &RefCell<Option<State<T>>> = use_ref(cx, || RefCell::new(None));\n\n    let out = use_mut(cx, make_initial);\n\n    let time_cell = use_ref(cx, || Cell::new(start_cell.get().unwrap()));\n    use_world(cx, |time_res: Res<Time>| {\n        time_cell.set(time_res.elapsed_secs());\n    });\n\n    use_local_task(cx, move || async move {\n        let mut rx = rx.take().unwrap();\n        while let Some((to, duration, tx)) = rx.recv().await {\n            *state.borrow_mut() = Some(State {\n                from: *out,\n                to,\n                duration,\n                tx: Some(tx),\n            });\n            start_cell.set(Some(time_cell.get()));\n        }\n    });\n\n    use_world(cx, move |time: Res<Time>| {\n        if let Some(start) = start_cell.get() {\n            let mut state_cell = state.borrow_mut();\n            if let Some(state) = &mut *state_cell {\n                let elapsed = time.elapsed_secs() - start;\n\n                if elapsed < state.duration.as_secs_f32() {\n                    SignalMut::set(\n                        out,\n                        state.from.lerp(\n                            state.to,\n                            T::Scalar::from(elapsed / state.duration.as_secs_f32()),\n                        ),\n                    );\n                } else {\n                    SignalMut::set(out, state.to);\n                    state.tx.take().unwrap().send(()).unwrap();\n                    *state_cell = None;\n                }\n            }\n        }\n    });\n\n    UseAnimated {\n        value: SignalMut::as_ref(out),\n        controller,\n    }\n}\n\n/// Hook for [`use_animated`].\npub struct UseAnimated<'a, T> {\n    value: Signal<'a, T>,\n    controller: &'a AnimationController<T>,\n}\n\nimpl<T> UseAnimated<'_, T> {\n    /// Animate this value over a duration.\n    pub async fn animate(&self, to: T, duration: Duration) {\n        self.controller.animate(to, duration).await\n    }\n\n    /// Get the controller for this animation.\n    pub fn controller(&self) -> AnimationController<T> {\n        self.controller.clone()\n    }\n}\n\nimpl<T> Clone for UseAnimated<'_, T> {\n    fn clone(&self) -> Self {\n        *self\n    }\n}\n\nimpl<T> Copy for UseAnimated<'_, T> {}\n\nimpl<T> Deref for UseAnimated<'_, T> {\n    type Target = T;\n\n    fn deref(&self) -> &Self::Target {\n        &self.value\n    }\n}\n\nunsafe impl<T> Data for UseAnimated<'_, T> {}\n\n/// Controller for an animation created with [`use_animated`].\npub struct AnimationController<T> {\n    tx: mpsc::UnboundedSender<(T, Duration, oneshot::Sender<()>)>,\n}\n\nimpl<T> AnimationController<T> {\n    /// Animate this value over a duration.\n    pub async fn animate(&self, to: T, duration: Duration) {\n        let (tx, rx) = oneshot::channel();\n        self.tx.send((to, duration, tx)).unwrap();\n        rx.await.unwrap()\n    }\n}\n\nimpl<T> Clone for AnimationController<T> {\n    fn clone(&self) -> Self {\n        Self {\n            tx: self.tx.clone(),\n        }\n    }\n}\n"
  },
  {
    "path": "src/compose/catch.rs",
    "content": "use super::CatchContext;\nuse crate::{compose::Compose, data::Data, use_provider, Scope, Signal};\nuse alloc::rc::Rc;\nuse core::mem;\n\n/// Create a composable that catches errors from its children.\n/// This will catch all errors from its descendants, until another `catch` is encountered.\n///\n/// If a child returns a `Result<T, actuate::Error>`,\n/// any errors will be caught by this composable by calling `on_error`.\n///\n/// # Examples\n///\n/// ```no_run\n/// use actuate::prelude::*;\n///\n/// #[derive(Data)]\n/// struct A;\n///\n/// impl Compose for A {\n///     fn compose(_cx: Scope<Self>) -> impl Compose {\n///         let _: i32 = \"\".parse().map_err(Error::new)?;\n///\n///         Ok(())\n///     }\n/// }\n///\n/// #[derive(Data)]\n/// struct App;\n///\n/// impl Compose for App {\n///     fn compose(_cx: Scope<Self>) -> impl Compose {\n///         catch(\n///             |error| {\n///                 dbg!(error);\n///             },\n///             A,\n///         )\n///     }\n/// }\n/// ```\npub fn catch<'a, C: Compose>(\n    on_error: impl Fn(Box<dyn core::error::Error>) + 'a,\n    content: C,\n) -> Catch<'a, C> {\n    Catch {\n        content,\n        f: Rc::new(on_error),\n    }\n}\n\n/// Error catch composable.\n///\n/// See [`catch`] for more.\n#[derive(Clone, Data)]\n#[actuate(path = \"crate\")]\npub struct Catch<'a, C> {\n    /// Content of this composable.\n    content: C,\n\n    /// Function to handle errors.\n    f: Rc<dyn Fn(Box<dyn core::error::Error>) + 'a>,\n}\n\nimpl<C: Compose> Compose for Catch<'_, C> {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        let f: &dyn Fn(Box<dyn core::error::Error>) = &*cx.me().f;\n\n        // Cast this function to the `'static` lifetime.\n        // Safety: This function has a lifetime of `'a`, which is guaranteed to outlive this composables descendants.\n        let f: Rc<dyn Fn(Box<dyn core::error::Error>)> = unsafe { mem::transmute(f) };\n\n        use_provider(&cx, move || CatchContext { f: f.clone() });\n\n        // Safety: The content of this composable is only returned into the composition once.\n        unsafe { Signal::map_unchecked(cx.me(), |me| &me.content) }\n    }\n}\n"
  },
  {
    "path": "src/compose/dyn_compose.rs",
    "content": "use super::{drop_node, AnyCompose, Node, Runtime};\nuse crate::{compose::Compose, use_ref, Scope, ScopeData};\nuse alloc::rc::Rc;\nuse core::{\n    any::TypeId,\n    cell::{Cell, RefCell, UnsafeCell},\n    mem,\n};\nuse slotmap::DefaultKey;\n\n/// Create a new dynamically-typed composable.\n///\n/// # Examples\n///\n/// ```\n/// use actuate::prelude::*;\n///\n/// #[derive(Data)]\n/// struct A;\n///\n/// impl Compose for A {\n///     fn compose(_cx: Scope<Self>) -> impl Compose {\n///         dbg!(\"A\");\n///     }\n/// }\n///\n/// #[derive(Data)]\n/// struct B;\n///\n/// impl Compose for B {\n///     fn compose(_cx: Scope<Self>) -> impl Compose {\n///         dbg!(\"B\");\n///     }\n/// }\n///\n/// #[derive(Data)]\n/// struct App;\n///\n/// impl Compose for App {\n///     fn compose(cx: Scope<Self>) -> impl Compose {\n///         let count = use_mut(&cx, || 0);\n///\n///         SignalMut::update(count, |x| *x += 1);\n///\n///         if *count == 0 {\n///             dyn_compose(A)\n///         } else {\n///             dyn_compose(B)\n///         }\n///     }\n/// }\n/// ```\npub fn dyn_compose<'a>(content: impl Compose + 'a) -> DynCompose<'a> {\n    DynCompose {\n        compose: UnsafeCell::new(Some(Box::new(content))),\n    }\n}\n\n/// Dynamically-typed composable.\n#[must_use = \"Composables do nothing unless composed or returned from other composables.\"]\npub struct DynCompose<'a> {\n    compose: UnsafeCell<Option<Box<dyn AnyCompose + 'a>>>,\n}\n\n#[derive(Clone, Copy)]\nstruct DynComposeState {\n    key: DefaultKey,\n    data_id: TypeId,\n}\n\nimpl Compose for DynCompose<'_> {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        let state: &Cell<Option<DynComposeState>> = use_ref(&cx, || Cell::new(None));\n\n        let rt = Runtime::current();\n\n        if let Some(state) = state.get() {\n            let compose: &mut dyn AnyCompose = unsafe { &mut *cx.me().compose.get() }\n                .as_deref_mut()\n                .unwrap();\n            let mut compose: Box<dyn AnyCompose> = unsafe { mem::transmute(compose) };\n            let data_id = compose.data_id();\n\n            if data_id == state.data_id {\n                {\n                    let nodes = rt.nodes.borrow();\n                    let mut last = nodes[state.key].compose.borrow_mut();\n                    unsafe { compose.reborrow(last.as_ptr_mut()) };\n                }\n\n                rt.queue(state.key)\n            } else {\n                let mut nodes = rt.nodes.borrow_mut();\n                drop_node(&mut nodes, state.key);\n            }\n        }\n\n        let Some(compose) = unsafe { &mut *cx.me().compose.get() }.take() else {\n            if let Some(state) = state.get() {\n                rt.queue(state.key)\n            }\n\n            return;\n        };\n        let compose: Box<dyn AnyCompose> = unsafe { mem::transmute(compose) };\n        let data_id = compose.data_id();\n\n        let mut nodes = rt.nodes.borrow_mut();\n        let key = nodes.insert(Rc::new(Node {\n            compose: RefCell::new(crate::composer::ComposePtr::Boxed(compose)),\n            scope: ScopeData::default(),\n            parent: Some(rt.current_key.get()),\n            children: RefCell::new(Vec::new()),\n            child_idx: 0,\n        }));\n        state.set(Some(DynComposeState { key, data_id }));\n\n        nodes\n            .get(rt.current_key.get())\n            .unwrap()\n            .children\n            .borrow_mut()\n            .push(key);\n\n        let child_state = &nodes[key].scope;\n        *child_state.contexts.borrow_mut() = cx.contexts.borrow().clone();\n        child_state\n            .contexts\n            .borrow_mut()\n            .values\n            .extend(cx.child_contexts.borrow().values.clone());\n\n        drop(nodes);\n\n        rt.queue(key);\n    }\n}\n"
  },
  {
    "path": "src/compose/from_fn.rs",
    "content": "use crate::{compose::Compose, Data, Scope, ScopeState};\nuse core::marker::PhantomData;\n\n/// Create a composable from a function.\n///\n/// This will create a composable from a function that takes a [`ScopeState`] and returns some composable content.\n///\n/// # Examples\n///\n/// ```\n/// use actuate::prelude::*;\n///\n/// #[derive(Data)]\n/// struct User {\n///     id: i32,\n/// }\n///\n/// impl Compose for User {\n///     fn compose(cx: Scope<Self>) -> impl Compose {}\n/// }\n///\n/// #[derive(Data)]\n/// struct App;\n///\n/// impl Compose for App {\n///     fn compose(cx: Scope<Self>) -> impl Compose {\n///         compose::from_fn(|_cx| {\n///             User { id: 0 }\n///         })\n///     }\n/// }\n/// ```\npub fn from_fn<F, C>(f: F) -> FromFn<F, C>\nwhere\n    F: Fn(ScopeState) -> C,\n    C: Compose,\n{\n    FromFn {\n        f,\n        _marker: PhantomData,\n    }\n}\n\n/// Function composable.\n///\n/// For more see [`from_fn`].\npub struct FromFn<F, C> {\n    f: F,\n    _marker: PhantomData<C>,\n}\n\nimpl<F: Clone, C> Clone for FromFn<F, C> {\n    fn clone(&self) -> Self {\n        Self {\n            f: self.f.clone(),\n            _marker: PhantomData,\n        }\n    }\n}\n\nunsafe impl<F, C> Data for FromFn<F, C>\nwhere\n    F: Fn(ScopeState) -> C,\n    C: Compose,\n{\n}\n\nimpl<F, C> Compose for FromFn<F, C>\nwhere\n    F: Fn(ScopeState) -> C,\n    C: Compose,\n{\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        (cx.me().f)(&cx)\n    }\n}\n"
  },
  {
    "path": "src/compose/from_iter.rs",
    "content": "use super::{AnyCompose, Node, Runtime};\nuse crate::{compose::Compose, data::Data, use_ref, Scope, ScopeData, Signal};\nuse alloc::rc::Rc;\nuse core::{cell::RefCell, mem};\nuse slotmap::DefaultKey;\n\n/// Create a composable from an iterator.\n///\n/// `make_item` will be called for each item to produce a composable.\n///\n/// # Examples\n///\n/// ```\n/// use actuate::prelude::*;\n///\n/// #[derive(Data)]\n/// struct User {\n///     id: i32,\n/// }\n///\n/// impl Compose for User {\n///     fn compose(cx: Scope<Self>) -> impl Compose {}\n/// }\n///\n/// #[derive(Data)]\n/// struct App;\n///\n/// impl Compose for App {\n///     fn compose(cx: Scope<Self>) -> impl Compose {\n///         compose::from_iter(0..10, |id| {\n///             User { id: *id }\n///         })\n///     }\n/// }\n/// ```\npub fn from_iter<'a, I, C>(\n    iter: I,\n    make_item: impl Fn(Signal<'a, I::Item>) -> C + 'a,\n) -> FromIter<'a, I, I::Item, C>\nwhere\n    I: IntoIterator + Clone + Data,\n    I::Item: 'static,\n    C: Compose,\n{\n    FromIter {\n        iter,\n        make_item: Rc::new(make_item),\n    }\n}\n\n/// Composable from an iterator.\n///\n/// For more see [`from_iter`].\n#[must_use = \"Composables do nothing unless composed or returned from other composables.\"]\npub struct FromIter<'a, I, Item, C> {\n    iter: I,\n    make_item: Rc<dyn Fn(Signal<'a, Item>) -> C + 'a>,\n}\n\nimpl<I, Item, C> Clone for FromIter<'_, I, Item, C>\nwhere\n    I: Clone,\n    C: Clone,\n{\n    fn clone(&self) -> Self {\n        Self {\n            iter: self.iter.clone(),\n            make_item: self.make_item.clone(),\n        }\n    }\n}\n\nunsafe impl<I, Item, C> Data for FromIter<'_, I, Item, C>\nwhere\n    I: Data,\n    Item: 'static,\n    C: Data,\n{\n}\n\nimpl<I, Item, C> Compose for FromIter<'_, I, Item, C>\nwhere\n    I: IntoIterator<Item = Item> + Clone + Data,\n    Item: 'static,\n    C: Compose,\n{\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        let states: &RefCell<Vec<ItemState<Item>>> = use_ref(&cx, || RefCell::new(Vec::new()));\n        let mut states = states.borrow_mut();\n\n        let mut items: Vec<Option<_>> = cx.me().iter.clone().into_iter().map(Some).collect();\n\n        let rt = Runtime::current();\n\n        if items.len() >= states.len() {\n            for item in &mut items[states.len()..] {\n                let item = item.take().unwrap();\n\n                let state = ItemState { item, key: None };\n                states.push(state);\n            }\n        } else {\n            states.truncate(items.len());\n        }\n\n        for (idx, state) in states.iter_mut().enumerate() {\n            let mut nodes = rt.nodes.borrow_mut();\n\n            if state.key.is_none() {\n                let item_ref: &Item = &state.item;\n                let item_ref: &Item = unsafe { mem::transmute(item_ref) };\n                let compose = (cx.me().make_item)(Signal {\n                    value: item_ref,\n                    generation: &cx.generation as _,\n                });\n                let any_compose: Box<dyn AnyCompose> = Box::new(compose);\n                let any_compose: Box<dyn AnyCompose> = unsafe { mem::transmute(any_compose) };\n\n                let key = nodes.insert(Rc::new(Node {\n                    compose: RefCell::new(crate::composer::ComposePtr::Boxed(any_compose)),\n                    scope: ScopeData::default(),\n                    parent: Some(rt.current_key.get()),\n                    children: RefCell::new(Vec::new()),\n                    child_idx: idx,\n                }));\n                nodes\n                    .get(rt.current_key.get())\n                    .unwrap()\n                    .children\n                    .borrow_mut()\n                    .push(key);\n\n                state.key = Some(key);\n            }\n\n            let node = nodes.get(state.key.unwrap()).unwrap().clone();\n\n            *node.scope.contexts.borrow_mut() = cx.contexts.borrow().clone();\n            node.scope\n                .contexts\n                .borrow_mut()\n                .values\n                .extend(cx.child_contexts.borrow().values.clone());\n\n            drop(nodes);\n\n            rt.queue(state.key.unwrap());\n        }\n    }\n}\n\nstruct ItemState<T> {\n    item: T,\n    key: Option<DefaultKey>,\n}\n"
  },
  {
    "path": "src/compose/memo.rs",
    "content": "use super::{use_node, AnyCompose, Runtime};\nuse crate::{compose::Compose, composer::ComposePtr, data::Data, use_ref, Scope};\nuse alloc::borrow::Cow;\nuse core::{cell::RefCell, mem};\n\n/// Create a new memoized composable.\n///\n/// The content of the memoized composable is only re-composed when the dependency changes.\n///\n/// Children of this `Memo` may still be re-composed if their state has changed.\npub fn memo<D, C>(dependency: D, content: C) -> Memo<D, C>\nwhere\n    D: Data + Clone + PartialEq + 'static,\n    C: Compose,\n{\n    Memo {\n        dependency,\n        content,\n    }\n}\n\n/// Memoized composable.\n///\n/// See [`memo`] for more.\n#[derive(Clone, Data)]\n#[actuate(path = \"crate\")]\n#[must_use = \"Composables do nothing unless composed or returned from other composables.\"]\npub struct Memo<T, C> {\n    dependency: T,\n    content: C,\n}\n\nimpl<T, C> Compose for Memo<T, C>\nwhere\n    T: Clone + Data + PartialEq + 'static,\n    C: Compose,\n{\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        let rt = Runtime::current();\n\n        let ptr: *const dyn AnyCompose =\n            unsafe { mem::transmute(&cx.me().content as *const dyn AnyCompose) };\n        let (key, _) = use_node(&cx, ComposePtr::Ptr(ptr), 0);\n\n        let last = use_ref(&cx, RefCell::default);\n        let mut last = last.borrow_mut();\n\n        if let Some(last) = &mut *last {\n            if cx.me().dependency != *last {\n                *last = cx.me().dependency.clone();\n\n                rt.queue(key);\n            }\n        } else {\n            *last = Some(cx.me().dependency.clone());\n\n            rt.queue(key);\n        }\n    }\n\n    fn name() -> Option<Cow<'static, str>> {\n        Some(\n            C::name()\n                .map(|name| format!(\"Memo<{}>\", name).into())\n                .unwrap_or(\"Memo\".into()),\n        )\n    }\n}\n"
  },
  {
    "path": "src/compose/mod.rs",
    "content": "use crate::{\n    composer::{ComposePtr, Node, Runtime},\n    data::Data,\n    use_context, use_ref, Scope, ScopeData, ScopeState,\n};\nuse alloc::borrow::Cow;\nuse alloc::rc::Rc;\nuse core::{\n    any::TypeId,\n    cell::{Cell, RefCell, UnsafeCell},\n    fmt, mem,\n};\nuse slotmap::{DefaultKey, SlotMap};\n\nmod catch;\npub use self::catch::{catch, Catch};\n\nmod dyn_compose;\npub use self::dyn_compose::{dyn_compose, DynCompose};\n\nmod from_fn;\npub use self::from_fn::{from_fn, FromFn};\n\nmod from_iter;\npub use self::from_iter::{from_iter, FromIter};\n\nmod memo;\npub use self::memo::{memo, Memo};\n\n/// A composable function.\n///\n/// For a dynamically-typed composable, see [`DynCompose`].\n///\n/// Composables are the building blocks of reactivity in Actuate.\n/// A composable is essentially a function that is re-run whenever its state (or its parent state) is changed.\n/// Composables may return one or more children, that run after their parent.\n///\n/// When a composable is re-run, we call that \"recomposition\".\n/// For example, on the initial composition, hooks may initialize their state.\n/// Then on recomposition, hooks update their state from the last set value.\n///\n/// Triggering a state update will recompose each parent, and then each child,\n/// until either a [`Memo`] is reached or the composition is complete.\n///\n/// [`Memo`] is special in that it will only recompose in two cases:\n/// 1. It's provided dependencies have changed (see [`memo()`] for more)\n/// 2. Its own state has changed, which will then trigger the above parent-to-child process for its children.\n#[must_use = \"Composables do nothing unless composed or returned from other composables.\"]\npub trait Compose: Data {\n    /// Compose this function.\n    fn compose(cx: Scope<Self>) -> impl Compose;\n\n    #[doc(hidden)]\n    fn name() -> Option<Cow<'static, str>> {\n        let name = core::any::type_name::<Self>();\n        Some(\n            name.split('<')\n                .next()\n                .unwrap_or(name)\n                .split(\"::\")\n                .last()\n                .unwrap_or(name)\n                .into(),\n        )\n    }\n}\n\nimpl Compose for () {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        let _ = cx;\n    }\n}\n\nimpl<C: Compose> Compose for Option<C> {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        let child_key = use_ref(&cx, || Cell::new(None));\n\n        let rt = Runtime::current();\n        let mut nodes = rt.nodes.borrow_mut();\n\n        if let Some(content) = &*cx.me() {\n            if let Some(key) = child_key.get() {\n                let last = nodes.get_mut(key).unwrap();\n\n                let ptr = content as *const dyn AnyCompose;\n                let ptr: *const dyn AnyCompose = unsafe { mem::transmute(ptr) };\n\n                *last.compose.borrow_mut() = ComposePtr::Ptr(ptr);\n\n                drop(nodes);\n\n                rt.queue(key);\n            } else {\n                let ptr: *const dyn AnyCompose =\n                    unsafe { mem::transmute(content as *const dyn AnyCompose) };\n                let key = nodes.insert(Rc::new(Node {\n                    compose: RefCell::new(crate::composer::ComposePtr::Ptr(ptr)),\n                    scope: ScopeData::default(),\n                    parent: Some(rt.current_key.get()),\n                    children: RefCell::new(Vec::new()),\n                    child_idx: 0,\n                }));\n                child_key.set(Some(key));\n\n                nodes\n                    .get(rt.current_key.get())\n                    .unwrap()\n                    .children\n                    .borrow_mut()\n                    .push(key);\n\n                let child_state = &nodes[key].scope;\n\n                *child_state.contexts.borrow_mut() = cx.contexts.borrow().clone();\n                child_state\n                    .contexts\n                    .borrow_mut()\n                    .values\n                    .extend(cx.child_contexts.borrow().values.clone());\n\n                drop(nodes);\n\n                rt.queue(key);\n            }\n        } else if let Some(key) = child_key.get() {\n            child_key.set(None);\n\n            drop_node(&mut nodes, key);\n        }\n    }\n}\n\n// TODO replace with non-recursive algorithm.\nfn drop_node(nodes: &mut SlotMap<DefaultKey, Rc<Node>>, key: DefaultKey) {\n    let node = nodes[key].clone();\n    if let Some(parent) = node.parent {\n        let parent = nodes.get_mut(parent).unwrap();\n        parent.children.borrow_mut().retain(|&x| x != key);\n    }\n\n    let children = node.children.borrow().clone();\n    for key in children {\n        drop_node(nodes, key)\n    }\n\n    nodes.remove(key);\n}\n\n/// Composable error.\n///\n/// This can be handled by a parent composable with [`Catch`].\n#[derive(Data, thiserror::Error)]\n#[actuate(path = \"crate\")]\npub struct Error {\n    make_error: Box<dyn Fn() -> Box<dyn core::error::Error>>,\n}\n\nimpl Error {\n    /// Create a new composable error.\n    pub fn new(error: impl core::error::Error + Clone + 'static) -> Self {\n        Self {\n            make_error: Box::new(move || Box::new(error.clone())),\n        }\n    }\n}\n\nimpl fmt::Debug for Error {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        (self.make_error)().fmt(f)\n    }\n}\n\nimpl fmt::Display for Error {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        (self.make_error)().fmt(f)\n    }\n}\n\nimpl<C: Compose> Compose for Result<C, Error> {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        let catch_cx = use_context::<CatchContext>(&cx).unwrap();\n\n        let child_key = use_ref(&cx, || Cell::new(None));\n\n        let rt = Runtime::current();\n\n        match &*cx.me() {\n            Ok(content) => {\n                if let Some(key) = child_key.get() {\n                    let mut nodes = rt.nodes.borrow_mut();\n                    let last = nodes.get_mut(key).unwrap();\n\n                    let ptr = content as *const dyn AnyCompose;\n                    let ptr: *const dyn AnyCompose = unsafe { mem::transmute(ptr) };\n\n                    *last.compose.borrow_mut() = ComposePtr::Ptr(ptr);\n\n                    drop(nodes);\n\n                    rt.queue(key);\n                } else {\n                    let mut nodes = rt.nodes.borrow_mut();\n                    let ptr: *const dyn AnyCompose =\n                        unsafe { mem::transmute(content as *const dyn AnyCompose) };\n                    let key = nodes.insert(Rc::new(Node {\n                        compose: RefCell::new(crate::composer::ComposePtr::Ptr(ptr)),\n                        scope: ScopeData::default(),\n                        parent: Some(rt.current_key.get()),\n                        children: RefCell::new(Vec::new()),\n                        child_idx: 0,\n                    }));\n                    child_key.set(Some(key));\n\n                    nodes\n                        .get(rt.current_key.get())\n                        .unwrap()\n                        .children\n                        .borrow_mut()\n                        .push(key);\n\n                    let child_state = &nodes[key].scope;\n\n                    *child_state.contexts.borrow_mut() = cx.contexts.borrow().clone();\n                    child_state\n                        .contexts\n                        .borrow_mut()\n                        .values\n                        .extend(cx.child_contexts.borrow().values.clone());\n\n                    drop(nodes);\n\n                    rt.queue(key);\n                }\n            }\n            Err(error) => {\n                let mut nodes = rt.nodes.borrow_mut();\n\n                if let Some(key) = child_key.get() {\n                    drop_node(&mut nodes, key);\n                }\n\n                (catch_cx.f)((error.make_error)())\n            }\n        }\n    }\n}\n\npub(crate) struct CatchContext {\n    f: Rc<dyn Fn(Box<dyn core::error::Error>)>,\n}\n\nimpl CatchContext {\n    pub(crate) fn new(f: impl Fn(Box<dyn core::error::Error>) + 'static) -> Self {\n        Self { f: Rc::new(f) }\n    }\n}\n\nmacro_rules! impl_tuples {\n    ($($t:tt : $idx:tt),*) => {\n        unsafe impl<$($t: Data),*> Data for ($($t,)*) {}\n\n        impl<$($t: Compose),*> Compose for ($($t,)*) {\n            fn compose(cx: Scope<Self>) -> impl Compose {\n                $({\n                    let ptr: *const dyn AnyCompose = unsafe { mem::transmute(&cx.me().$idx as *const dyn AnyCompose) };\n                    let (key, _) = use_node(&cx, ComposePtr::Ptr(ptr), $idx);\n\n                    let rt = Runtime::current();\n                    rt.queue(key)\n                })*\n            }\n\n            fn name() -> Option<Cow<'static, str>> {\n                None\n            }\n        }\n    };\n}\n\nimpl_tuples!(T1:0);\nimpl_tuples!(T1:0, T2:1);\nimpl_tuples!(T1:0, T2:1, T3:2);\nimpl_tuples!(T1:0, T2:1, T3:2, T4:3);\nimpl_tuples!(T1:0, T2:1, T3:2, T4:3, T5:4);\nimpl_tuples!(T1:0, T2:1, T3:2, T4:3, T5:4, T6:5);\nimpl_tuples!(T1:0, T2:1, T3:2, T4:3, T5:4, T6:5, T7:6);\nimpl_tuples!(T1:0, T2:1, T3:2, T4:3, T5:4, T6:5, T7:6, T8:7);\n\nimpl<C> Compose for Vec<C>\nwhere\n    C: Compose,\n{\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        for (idx, item) in cx.me().iter().enumerate() {\n            let ptr: *const dyn AnyCompose =\n                unsafe { mem::transmute(item as *const dyn AnyCompose) };\n            let (key, _) = use_node(&cx, ComposePtr::Ptr(ptr), idx);\n\n            let rt = Runtime::current();\n            rt.queue(key);\n        }\n    }\n}\n\nfn use_node(\n    cx: ScopeState<'_>,\n    compose_ptr: ComposePtr,\n    child_idx: usize,\n) -> (DefaultKey, &Rc<Node>) {\n    let mut compose_ptr_cell = Some(compose_ptr);\n\n    let (key, node) = use_ref(cx, || {\n        let rt = Runtime::current();\n        let mut nodes = rt.nodes.borrow_mut();\n\n        let key = nodes.insert(Rc::new(Node {\n            compose: RefCell::new(compose_ptr_cell.take().unwrap()),\n            scope: ScopeData::default(),\n            parent: Some(rt.current_key.get()),\n            children: RefCell::new(Vec::new()),\n            child_idx,\n        }));\n\n        nodes\n            .get(rt.current_key.get())\n            .unwrap()\n            .children\n            .borrow_mut()\n            .push(key);\n\n        let child_state = &nodes[key].scope;\n        *child_state.contexts.borrow_mut() = cx.contexts.borrow().clone();\n        child_state\n            .contexts\n            .borrow_mut()\n            .values\n            .extend(cx.child_contexts.borrow().values.clone());\n\n        (key, nodes[key].clone())\n    });\n\n    // Reborrow the pointer to the node's composable.\n    if let Some(compose_ptr) = compose_ptr_cell.take() {\n        *node.compose.borrow_mut() = compose_ptr;\n    }\n\n    (*key, node)\n}\n\npub(crate) trait AnyCompose {\n    fn data_id(&self) -> TypeId;\n\n    fn as_ptr_mut(&mut self) -> *mut ();\n\n    unsafe fn reborrow(&mut self, ptr: *mut ());\n\n    /// Safety: The caller must ensure `&self` is valid for the lifetime of `state`.\n    unsafe fn any_compose(&self, state: &ScopeData);\n\n    fn name(&self) -> Option<Cow<'static, str>>;\n}\n\nimpl<C> AnyCompose for C\nwhere\n    C: Compose + Data,\n{\n    fn data_id(&self) -> TypeId {\n        typeid::of::<C>()\n    }\n\n    fn as_ptr_mut(&mut self) -> *mut () {\n        self as *mut Self as *mut ()\n    }\n\n    unsafe fn reborrow(&mut self, ptr: *mut ()) {\n        core::ptr::swap(self, ptr as _);\n    }\n\n    unsafe fn any_compose(&self, state: &ScopeData) {\n        // Reset the hook index.\n        state.hook_idx.set(0);\n\n        // Increment the scope's current generation.\n        state.generation.set(state.generation.get() + 1);\n\n        // Transmute the lifetime of `&Self`, `&ScopeData`, and the `Scope` containing both to the same`'a`.\n        // Safety: `self` and `state` are guranteed to have the same lifetime..\n        let state: ScopeState = unsafe { mem::transmute(state) };\n        let cx: Scope<'_, C> = Scope { me: self, state };\n        let cx: Scope<'_, C> = unsafe { mem::transmute(cx) };\n\n        // Cell for the Box used to re-allocate this composable.\n        let cell: &UnsafeCell<Option<Box<dyn AnyCompose>>> = use_ref(&cx, || UnsafeCell::new(None));\n        // Safety: This cell is only accessed by this composable.\n        let cell = unsafe { &mut *cell.get() };\n\n        let child_key_cell = use_ref(&cx, || Cell::new(None));\n\n        let rt = Runtime::current();\n\n        if cell.is_none() {\n            #[cfg(feature = \"tracing\")]\n            if let Some(name) = C::name() {\n                tracing::trace!(\"Compose: {}\", name);\n            }\n\n            let child = C::compose(cx);\n\n            if child.data_id() == typeid::of::<()>() {\n                return;\n            }\n\n            let child: Box<dyn AnyCompose> = Box::new(child);\n            let mut child: Box<dyn AnyCompose> = unsafe { mem::transmute(child) };\n\n            let mut nodes = rt.nodes.borrow_mut();\n\n            unsafe {\n                if let Some(key) = child_key_cell.get() {\n                    let last = nodes.get_mut(key).unwrap();\n                    child.reborrow(last.compose.borrow_mut().as_ptr_mut());\n                } else {\n                    let child_key = nodes.insert(Rc::new(Node {\n                        compose: RefCell::new(crate::composer::ComposePtr::Boxed(child)),\n                        scope: ScopeData::default(),\n                        parent: Some(rt.current_key.get()),\n                        children: RefCell::new(Vec::new()),\n                        child_idx: 0,\n                    }));\n                    child_key_cell.set(Some(child_key));\n\n                    nodes\n                        .get(rt.current_key.get())\n                        .unwrap()\n                        .children\n                        .borrow_mut()\n                        .push(child_key);\n\n                    let child_state = &nodes[child_key].scope;\n\n                    *child_state.contexts.borrow_mut() = cx.contexts.borrow().clone();\n                    child_state\n                        .contexts\n                        .borrow_mut()\n                        .values\n                        .extend(cx.child_contexts.borrow().values.clone());\n                }\n            }\n        }\n\n        if let Some(key) = child_key_cell.get() {\n            rt.queue(key)\n        }\n    }\n\n    fn name(&self) -> Option<Cow<'static, str>> {\n        C::name()\n    }\n}\n"
  },
  {
    "path": "src/composer.rs",
    "content": "use crate::{\n    compose::{AnyCompose, CatchContext, Compose},\n    ScopeData,\n};\nuse alloc::{collections::BTreeSet, rc::Rc, sync::Arc, task::Wake};\nuse core::{\n    any::TypeId,\n    cell::{Cell, RefCell},\n    cmp::Ordering,\n    error::Error,\n    fmt,\n    future::Future,\n    mem,\n    pin::Pin,\n    task::{Context, Poll, Waker},\n};\nuse crossbeam_queue::SegQueue;\nuse slotmap::{DefaultKey, SlotMap};\n\n#[cfg(feature = \"executor\")]\nuse tokio::sync::RwLock;\n\ntype RuntimeFuture = Pin<Box<dyn Future<Output = ()>>>;\n\npub(crate) enum ComposePtr {\n    Boxed(Box<dyn AnyCompose>),\n    Ptr(*const dyn AnyCompose),\n}\n\nimpl AnyCompose for ComposePtr {\n    fn data_id(&self) -> TypeId {\n        match self {\n            ComposePtr::Boxed(compose) => compose.data_id(),\n            ComposePtr::Ptr(ptr) => unsafe { (**ptr).data_id() },\n        }\n    }\n\n    fn as_ptr_mut(&mut self) -> *mut () {\n        match self {\n            ComposePtr::Boxed(compose) => compose.as_ptr_mut(),\n            ComposePtr::Ptr(ptr) => *ptr as *mut (),\n        }\n    }\n\n    unsafe fn reborrow(&mut self, ptr: *mut ()) {\n        match self {\n            ComposePtr::Boxed(compose) => compose.reborrow(ptr),\n            ComposePtr::Ptr(_) => {}\n        }\n    }\n\n    unsafe fn any_compose(&self, state: &ScopeData) {\n        match self {\n            ComposePtr::Boxed(compose) => compose.any_compose(state),\n            ComposePtr::Ptr(ptr) => (**ptr).any_compose(state),\n        }\n    }\n\n    fn name(&self) -> Option<std::borrow::Cow<'static, str>> {\n        match self {\n            ComposePtr::Boxed(compose) => compose.name(),\n            ComposePtr::Ptr(ptr) => unsafe { (**ptr).name() },\n        }\n    }\n}\n\n// Safety: `scope` must be dropped before `compose`.\npub(crate) struct Node {\n    pub(crate) compose: RefCell<ComposePtr>,\n    pub(crate) scope: ScopeData<'static>,\n    pub(crate) parent: Option<DefaultKey>,\n    pub(crate) children: RefCell<Vec<DefaultKey>>,\n    pub(crate) child_idx: usize,\n}\n\n/// Runtime for a [`Composer`].\n#[derive(Clone)]\npub(crate) struct Runtime {\n    /// Local task stored on this runtime.\n    pub(crate) tasks: Rc<RefCell<SlotMap<DefaultKey, RuntimeFuture>>>,\n\n    /// Queue for ready local tasks.\n    pub(crate) task_queue: Arc<SegQueue<DefaultKey>>,\n\n    /// Queue for updates that mutate the composition tree.\n    pub(crate) update_queue: Rc<SegQueue<Box<dyn FnMut()>>>,\n\n    #[cfg(feature = \"executor\")]\n    /// Update lock for shared tasks.\n    pub(crate) lock: Arc<RwLock<()>>,\n\n    pub(crate) waker: RefCell<Option<Waker>>,\n\n    pub(crate) nodes: Rc<RefCell<SlotMap<DefaultKey, Rc<Node>>>>,\n\n    pub(crate) current_key: Rc<Cell<DefaultKey>>,\n\n    pub(crate) root: DefaultKey,\n\n    pub(crate) pending: Rc<RefCell<BTreeSet<Pending>>>,\n}\n\nimpl Runtime {\n    /// Get the current [`Runtime`].\n    ///\n    /// # Panics\n    /// Panics if called outside of a runtime.\n    pub fn current() -> Self {\n        RUNTIME.with(|runtime| {\n            runtime\n                .borrow()\n                .as_ref()\n                .expect(\"Runtime::current() called outside of a runtime\")\n                .clone()\n        })\n    }\n\n    /// Enter this runtime, making it available to [`Runtime::current`].\n    pub fn enter(&self) {\n        RUNTIME.with(|runtime| {\n            *runtime.borrow_mut() = Some(self.clone());\n        });\n    }\n\n    /// Queue an update to run after [`Composer::compose`].\n    pub fn update(&self, f: impl FnOnce() + Send + 'static) {\n        let mut f_cell = Some(f);\n\n        #[cfg(feature = \"executor\")]\n        let lock = self.lock.clone();\n\n        self.update_queue.push(Box::new(move || {\n            #[cfg(feature = \"executor\")]\n            let _guard = lock.blocking_write();\n\n            let f = f_cell.take().unwrap();\n            f()\n        }));\n\n        if let Some(waker) = &*self.waker.borrow() {\n            waker.wake_by_ref();\n        }\n    }\n\n    pub fn pending(&self, key: DefaultKey) -> Pending {\n        let nodes = self.nodes.borrow();\n        let node = nodes[key].clone();\n\n        let mut indices = vec![node.child_idx];\n        let mut parent = node.parent;\n\n        while let Some(key) = parent {\n            indices.push(nodes.get(key).unwrap().child_idx);\n            parent = nodes.get(key).unwrap().parent;\n        }\n\n        indices.reverse();\n\n        Pending { key, indices }\n    }\n\n    pub fn queue(&self, key: DefaultKey) {\n        let pending = self.pending(key);\n        self.pending.borrow_mut().insert(pending);\n    }\n}\n\nthread_local! {\n    static RUNTIME: RefCell<Option<Runtime>> = const { RefCell::new(None) };\n}\n\nstruct TaskWaker {\n    key: DefaultKey,\n    queue: Arc<SegQueue<DefaultKey>>,\n    waker: Option<Waker>,\n}\n\nimpl Wake for TaskWaker {\n    fn wake(self: Arc<Self>) {\n        self.queue.push(self.key);\n        if let Some(waker) = self.waker.as_ref() {\n            waker.wake_by_ref();\n        }\n    }\n}\n\n/// Error for [`Composer::try_compose`].\n#[derive(Debug)]\npub enum TryComposeError {\n    /// No updates are ready to be applied.\n    Pending,\n\n    /// An error occurred during composition.\n    Error(Box<dyn Error>),\n}\n\nimpl PartialEq for TryComposeError {\n    fn eq(&self, other: &Self) -> bool {\n        mem::discriminant(self) == mem::discriminant(other)\n    }\n}\n\n#[derive(Clone, PartialEq, Eq)]\npub(crate) struct Pending {\n    pub(crate) key: DefaultKey,\n    pub(crate) indices: Vec<usize>,\n}\n\nimpl PartialOrd for Pending {\n    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\nimpl Ord for Pending {\n    fn cmp(&self, other: &Self) -> Ordering {\n        for (a, b) in self.indices.iter().zip(other.indices.iter()) {\n            match a.cmp(b) {\n                Ordering::Equal => {}\n                x => return x,\n            }\n        }\n\n        self.indices.len().cmp(&other.indices.len())\n    }\n}\n\n/// Composer for composable content.\n///\n/// ```\n/// use actuate::prelude::*;\n/// use actuate::composer::Composer;\n///\n/// #[derive(Data)]\n/// struct A;\n///\n/// impl Compose for A {\n///     fn compose(cx: Scope<Self>) -> impl Compose {\n///         (B, C)\n///     }\n/// }\n///\n/// #[derive(Data)]\n/// struct B;\n///\n/// impl Compose for B {\n///     fn compose(cx: Scope<Self>) -> impl Compose {}\n/// }\n///\n/// #[derive(Data)]\n/// struct C;\n///\n/// impl Compose for C {\n///     fn compose(cx: Scope<Self>) -> impl Compose {}\n/// }\n///\n/// let mut composer = Composer::new(A);\n/// composer.try_compose().unwrap();\n///\n/// assert_eq!(format!(\"{:?}\", composer), \"Composer(A(B, C))\")\n/// ```\npub struct Composer {\n    rt: Runtime,\n    task_queue: Arc<SegQueue<DefaultKey>>,\n    update_queue: Rc<SegQueue<Box<dyn FnMut()>>>,\n    is_initial: bool,\n}\n\nimpl Composer {\n    /// Create a new [`Composer`] with the given content, updater, and task executor.\n    pub fn new(content: impl Compose + 'static) -> Self {\n        #[cfg(feature = \"executor\")]\n        let lock = Arc::new(RwLock::new(()));\n\n        let task_queue = Arc::new(SegQueue::new());\n        let update_queue = Rc::new(SegQueue::new());\n\n        let mut nodes = SlotMap::new();\n        let root_key = nodes.insert(Rc::new(Node {\n            compose: RefCell::new(ComposePtr::Boxed(Box::new(content))),\n            scope: ScopeData::default(),\n            parent: None,\n            children: RefCell::new(Vec::new()),\n            child_idx: 0,\n        }));\n\n        Self {\n            rt: Runtime {\n                tasks: Rc::new(RefCell::new(SlotMap::new())),\n                task_queue: task_queue.clone(),\n                update_queue: update_queue.clone(),\n                waker: RefCell::new(None),\n                #[cfg(feature = \"executor\")]\n                lock,\n                nodes: Rc::new(RefCell::new(nodes)),\n                current_key: Rc::new(Cell::new(root_key)),\n                root: root_key,\n                pending: Rc::new(RefCell::new(BTreeSet::new())),\n            },\n            task_queue,\n            update_queue,\n            is_initial: true,\n        }\n    }\n\n    /// Try to immediately compose the content in this composer.\n    pub fn try_compose(&mut self) -> Result<(), TryComposeError> {\n        let mut is_pending = true;\n\n        for res in self.by_ref() {\n            res.map_err(TryComposeError::Error)?;\n\n            is_pending = false;\n        }\n\n        if is_pending {\n            Err(TryComposeError::Pending)\n        } else {\n            Ok(())\n        }\n    }\n\n    /// Poll a composition of the content in this composer.\n    pub fn poll_compose(&mut self, cx: &mut Context) -> Poll<Result<(), Box<dyn Error>>> {\n        *self.rt.waker.borrow_mut() = Some(cx.waker().clone());\n\n        match self.try_compose() {\n            Ok(()) => Poll::Ready(Ok(())),\n            Err(TryComposeError::Pending) => Poll::Pending,\n            Err(TryComposeError::Error(error)) => Poll::Ready(Err(error)),\n        }\n    }\n\n    /// Compose the content of this composer.\n    pub async fn compose(&mut self) -> Result<(), Box<dyn Error>> {\n        futures::future::poll_fn(|cx| self.poll_compose(cx)).await\n    }\n}\n\nimpl Drop for Composer {\n    fn drop(&mut self) {\n        let node = self.rt.nodes.borrow()[self.rt.root].clone();\n        drop_recursive(&self.rt, self.rt.root, node)\n    }\n}\n\nfn drop_recursive(rt: &Runtime, key: DefaultKey, node: Rc<Node>) {\n    let children = node.children.borrow().clone();\n    for child_key in children {\n        let child = rt.nodes.borrow()[child_key].clone();\n        drop_recursive(rt, child_key, child)\n    }\n\n    rt.nodes.borrow_mut().remove(key);\n}\n\nimpl Iterator for Composer {\n    type Item = Result<(), Box<dyn Error>>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        self.rt.enter();\n\n        let error_cell = Rc::new(Cell::new(None));\n        let error_cell_handle = error_cell.clone();\n\n        let root = self.rt.nodes.borrow().get(self.rt.root).unwrap().clone();\n        root.scope.contexts.borrow_mut().values.insert(\n            TypeId::of::<CatchContext>(),\n            Rc::new(CatchContext::new(move |error| {\n                error_cell_handle.set(Some(error));\n            })),\n        );\n\n        if !self.is_initial {\n            let key_cell = self.rt.pending.borrow_mut().pop_first();\n            if let Some(pending) = key_cell {\n                self.rt.current_key.set(pending.key);\n\n                let node = self.rt.nodes.borrow().get(pending.key).unwrap().clone();\n\n                // Safety: `self.compose` is guaranteed to live as long as `self.scope_state`.\n                unsafe { node.compose.borrow().any_compose(&node.scope) };\n            } else {\n                while let Some(key) = self.task_queue.pop() {\n                    let waker = Waker::from(Arc::new(TaskWaker {\n                        key,\n                        waker: self.rt.waker.borrow().clone(),\n                        queue: self.rt.task_queue.clone(),\n                    }));\n                    let mut cx = Context::from_waker(&waker);\n\n                    let mut tasks = self.rt.tasks.borrow_mut();\n                    let task = tasks.get_mut(key).unwrap();\n                    let _ = task.as_mut().poll(&mut cx);\n                }\n\n                while let Some(mut update) = self.update_queue.pop() {\n                    update();\n                }\n\n                return None;\n            }\n        } else {\n            self.is_initial = false;\n\n            self.rt.current_key.set(self.rt.root);\n\n            // Safety: `self.compose` is guaranteed to live as long as `self.scope_state`.\n            unsafe { root.compose.borrow().any_compose(&root.scope) };\n        }\n\n        Some(error_cell.take().map(Err).unwrap_or(Ok(())))\n    }\n}\n\nimpl fmt::Debug for Composer {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        let mut dbg_tuple = f.debug_tuple(\"Composer\");\n\n        dbg_composer(&mut dbg_tuple, &self.rt.nodes.borrow(), self.rt.root);\n\n        dbg_tuple.finish()\n    }\n}\n\nstruct Field<'a> {\n    name: &'a str,\n    nodes: &'a SlotMap<DefaultKey, Rc<Node>>,\n    children: &'a [DefaultKey],\n}\n\nimpl fmt::Debug for Field<'_> {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        let mut dbg_tuple = f.debug_tuple(self.name);\n\n        for child_key in self.children {\n            dbg_composer(&mut dbg_tuple, self.nodes, *child_key);\n        }\n\n        dbg_tuple.finish()\n    }\n}\n\nfn dbg_composer(\n    dbg_tuple: &mut fmt::DebugTuple,\n    nodes: &SlotMap<DefaultKey, Rc<Node>>,\n    key: DefaultKey,\n) {\n    let node = &nodes[key];\n    if let Some(name) = node.compose.borrow().name() {\n        dbg_tuple.field(&Field {\n            name: &name,\n            nodes,\n            children: &node.children.borrow(),\n        });\n    } else {\n        for child_key in &*node.children.borrow() {\n            dbg_composer(dbg_tuple, nodes, *child_key);\n        }\n    }\n}\n"
  },
  {
    "path": "src/data.rs",
    "content": "//! Data trait and macros.\n//!\n//! # Data\n//!\n//! [`Data`] is a trait that enforces pinned references to compososition state.\n//!\n//! The `#[derive(Data)]` macro can be used to derive the [`Data`] trait for a struct.\n//! This requires the struct's fields either:\n//! - Implement the [`Data`] trait.\n//! - Are `'static`.\n//! - Are functions that take `'static` arguments and return a type that implements the [`Data`] trait.\n//!\n//! # Trait objects\n//!\n//! Trait objects can also borrow from state:\n//!\n//! ```no_run\n//! use actuate::prelude::*;\n//!\n//! #[data]\n//! trait MyTrait: Data {\n//!     fn run(&self);\n//! }\n//!\n//! #[derive(Data)]\n//! struct A<'a> {\n//!     my_trait: Box<dyn MyTrait + 'a>,\n//! }\n//!\n//! impl Compose for A<'_> {\n//!     fn compose(cx: Scope<Self>) -> impl Compose {\n//!         cx.me().my_trait.run();\n//!     }\n//! }\n//!\n//! #[derive(Data)]\n//! struct X;\n//!\n//! impl MyTrait for X {\n//!     fn run(&self) {\n//!         dbg!(\"X\");\n//!     }\n//! }\n//!\n//! #[derive(Data)]\n//! struct App;\n//!\n//! impl Compose for App {\n//!     fn compose(_cx: Scope<Self>) -> impl Compose {\n//!         A {\n//!             my_trait: Box::new(X),\n//!         }\n//!     }\n//! }\n//! ```\n\nuse crate::{compose::DynCompose, HashMap};\nuse core::{error::Error, future::Future, ops::Range, pin::Pin};\n\npub use actuate_macros::{data, Data};\n\n/// Composable data.\n///\n/// In most cases, this trait should be derived with `#[derive(Data)]`.\n/// For more information, see the [module-level documentation](crate::data).\n///\n/// # Safety\n/// This struct must ensure the lifetime of the data it holds cannot escape while composing children.\n///\n/// For example, a `RefCell<&'a T>` is unsafe because the compiler will infer the lifetime of a child composable's lifetime (e.g. `'a`)\n/// as this struct's lifetime (e.g. `'a`).\npub unsafe trait Data {}\n\nmacro_rules! impl_data_for_std {\n    ($($t:ty),*) => {\n        $(\n            unsafe impl Data for $t {}\n        )*\n    }\n}\n\nimpl_data_for_std!(\n    (),\n    bool,\n    char,\n    f32,\n    f64,\n    i8,\n    i16,\n    i32,\n    i64,\n    i128,\n    isize,\n    u8,\n    u16,\n    u32,\n    u64,\n    u128,\n    usize,\n    String\n);\n\nunsafe impl Data for &str {}\n\nunsafe impl<T: Data> Data for Vec<T> {}\n\nunsafe impl<T: Data, U: Data, S: 'static> Data for HashMap<T, U, S> {}\n\nunsafe impl<T: 'static> Data for &T {}\n\nunsafe impl<T: Data> Data for Option<T> {}\n\nunsafe impl<T: Data, U: Data> Data for Result<T, U> {}\n\nunsafe impl<T: Data> Data for Pin<T> {}\n\nunsafe impl<T: 'static> Data for Range<T> {}\n\nunsafe impl Data for Box<dyn Error> {}\n\nunsafe impl Data for Box<dyn Future<Output = ()> + '_> {}\n\nunsafe impl Data for DynCompose<'_> {}\n\n#[doc(hidden)]\npub struct FieldWrap<T>(pub T);\n\n#[doc(hidden)]\npub unsafe trait FnField<Marker> {\n    fn check(&self) {\n        let _ = self;\n    }\n}\n\nmacro_rules! impl_data_for_fns {\n    ($($t:tt),*) => {\n        unsafe impl<$($t: 'static,)* R: Data, F: Fn($($t,)*) -> R> FnField<fn($($t,)*)> for &FieldWrap<F> {}\n\n        unsafe impl<$($t: 'static,)* R: Data> FnField<fn($($t,)*)> for &FieldWrap<alloc::rc::Rc<dyn Fn($($t,)*) -> R + '_>> {}\n    }\n}\n\nimpl_data_for_fns!();\nimpl_data_for_fns!(T1);\nimpl_data_for_fns!(T1, T2);\nimpl_data_for_fns!(T1, T2, T3);\nimpl_data_for_fns!(T1, T2, T3, T4);\nimpl_data_for_fns!(T1, T2, T3, T4, T5);\nimpl_data_for_fns!(T1, T2, T3, T4, T5, T6);\nimpl_data_for_fns!(T1, T2, T3, T4, T5, T6, T7);\nimpl_data_for_fns!(T1, T2, T3, T4, T5, T6, T7, T8);\n\n#[doc(hidden)]\npub unsafe trait DataField {\n    fn check(&self) {\n        let _ = self;\n    }\n}\n\nunsafe impl<T: Data> DataField for &FieldWrap<T> {}\n\n#[doc(hidden)]\npub unsafe trait StaticField {\n    fn check(&self) {\n        let _ = self;\n    }\n}\n\nunsafe impl<T: 'static> StaticField for &&FieldWrap<T> {}\n"
  },
  {
    "path": "src/ecs/mod.rs",
    "content": "use crate::{\n    compose::Compose,\n    composer::{Composer, Pending},\n    data::Data,\n    use_callback, use_drop, use_provider, use_ref, Cow, Scope, ScopeState, Signal,\n};\nuse bevy_app::{App, Plugin};\nuse bevy_ecs::{\n    component::{Component, Mutable, StorageType},\n    entity::Entity,\n    prelude::*,\n    system::{SystemParam, SystemParamItem, SystemState},\n    world::{CommandQueue, World},\n};\nuse bevy_winit::{EventLoopProxy, EventLoopProxyWrapper, WakeUp};\nuse core::fmt;\nuse hashbrown::HashMap;\nuse slotmap::{DefaultKey, SlotMap};\nuse std::{\n    cell::{Cell, RefCell},\n    collections::BTreeSet,\n    mem, ptr,\n    rc::Rc,\n    sync::Arc,\n    task::{Context, Wake, Waker},\n};\n\n#[cfg(feature = \"ui\")]\nuse bevy_ui::prelude::*;\n\n#[cfg(feature = \"picking\")]\nuse bevy_picking::prelude::*;\n\nmod spawn;\npub use self::spawn::{spawn, Spawn};\n\nmacro_rules! impl_trait_for_tuples {\n    ($t:tt) => {\n        $t!();\n        $t!(T1);\n        $t!(T1, T2);\n        $t!(T1, T2, T3);\n        $t!(T1, T2, T3, T4);\n        $t!(T1, T2, T3, T4, T5);\n        $t!(T1, T2, T3, T4, T5, T6);\n        $t!(T1, T2, T3, T4, T5, T6, T7);\n        $t!(T1, T2, T3, T4, T5, T6, T7, T8);\n    };\n}\n\n/// Actuate plugin to run [`Composition`]s.\npub struct ActuatePlugin;\n\nimpl Plugin for ActuatePlugin {\n    fn build(&self, app: &mut App) {\n        let rt = Runtime {\n            composers: RefCell::new(HashMap::new()),\n        };\n\n        app.insert_non_send_resource(rt)\n            .add_systems(bevy_app::prelude::Update, compose);\n    }\n}\n\ntype UpdateFn = Box<dyn FnMut(&mut World)>;\n\ntype WorldListenerFn = Rc<dyn Fn(&mut World)>;\n\nstruct Inner {\n    world_ptr: *mut World,\n    listeners: SlotMap<DefaultKey, WorldListenerFn>,\n    updates: Vec<UpdateFn>,\n    commands: Rc<RefCell<CommandQueue>>,\n}\n\n#[derive(Clone)]\nstruct RuntimeContext {\n    inner: Rc<RefCell<Inner>>,\n}\n\nimpl RuntimeContext {\n    fn current() -> Self {\n        RUNTIME_CONTEXT.with(|cell| {\n            let cell_ref = cell.borrow();\n            let Some(rt) = cell_ref.as_ref() else {\n                panic!(\"Must be called from within a composable.\")\n            };\n            rt.clone()\n        })\n    }\n\n    unsafe fn world_mut(&self) -> &'static mut World {\n        &mut *self.inner.borrow().world_ptr\n    }\n}\n\nthread_local! {\n    static RUNTIME_CONTEXT: RefCell<Option<RuntimeContext>> = const { RefCell::new(None) };\n}\n\nstruct RuntimeComposer {\n    composer: Composer,\n}\n\nstruct Runtime {\n    composers: RefCell<HashMap<Entity, RuntimeComposer>>,\n}\n\n/// Composition of some composable content.\npub struct Composition<C> {\n    content: Option<C>,\n    target: Option<Entity>,\n}\n\nimpl<C> Composition<C>\nwhere\n    C: Compose + Send + Sync + 'static,\n{\n    /// Create a new composition from its content.\n    pub fn new(content: C) -> Self {\n        Self {\n            content: Some(content),\n            target: None,\n        }\n    }\n\n    /// Get the target entity to spawn the composition into.\n    ///\n    /// If `None`, this will use the composition's parent (if any).\n    pub fn target(&self) -> Option<Entity> {\n        self.target\n    }\n\n    /// Set the target entity to spawn the composition into.\n    ///\n    /// If `None`, this will use the composition's parent (if any).\n    pub fn set_target(&mut self, target: Option<Entity>) {\n        self.target = target;\n    }\n\n    /// Set the target entity to spawn the composition into.\n    ///\n    /// If `None`, this will use the composition's parent (if any).\n    pub fn with_target(mut self, target: Entity) -> Self {\n        self.target = Some(target);\n        self\n    }\n}\n\nimpl<C> Component for Composition<C>\nwhere\n    C: Compose + Send + Sync + 'static,\n{\n    const STORAGE_TYPE: StorageType = StorageType::SparseSet;\n\n    type Mutability = Mutable;\n\n    fn on_insert() -> Option<bevy_ecs::lifecycle::ComponentHook> {\n        Some(|mut world, cx| {\n            world.commands().queue(move |world: &mut World| {\n                let mut composition = world.get_mut::<Composition<C>>(cx.entity).unwrap();\n\n                let content = composition.content.take().unwrap();\n                let target = composition.target.unwrap_or(cx.entity);\n\n                let rt = world.non_send_resource_mut::<Runtime>();\n\n                rt.composers.borrow_mut().insert(\n                    cx.entity,\n                    RuntimeComposer {\n                        composer: Composer::new(CompositionContent { content, target }),\n                    },\n                );\n            })\n        })\n    }\n}\n\n#[derive(Data)]\n#[actuate(path = \"crate\")]\nstruct CompositionContent<C> {\n    content: C,\n    target: Entity,\n}\n\nimpl<C: Compose> Compose for CompositionContent<C> {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        use_provider(&cx, || SpawnContext {\n            parent_entity: cx.me().target,\n            keys: RefCell::new(BTreeSet::new()),\n        });\n\n        unsafe { Signal::map_unchecked(cx.me(), |me| &me.content) }\n    }\n}\n\nstruct RuntimeWaker {\n    proxy: EventLoopProxy<WakeUp>,\n}\n\nimpl Wake for RuntimeWaker {\n    fn wake(self: Arc<Self>) {\n        self.proxy.send_event(WakeUp).unwrap();\n    }\n}\n\nfn compose(world: &mut World) {\n    RUNTIME_CONTEXT.with(|runtime_cx| {\n        let mut cell = runtime_cx.borrow_mut();\n        let runtime_cx = cell.get_or_insert_with(|| RuntimeContext {\n            inner: Rc::new(RefCell::new(Inner {\n                world_ptr: ptr::null_mut(),\n                listeners: SlotMap::new(),\n                updates: Vec::new(),\n                commands: Rc::new(RefCell::new(CommandQueue::default())),\n            })),\n        });\n\n        runtime_cx.inner.borrow_mut().world_ptr = world as *mut World;\n\n        for f in runtime_cx.inner.borrow().listeners.values() {\n            f(world)\n        }\n    });\n\n    world.increment_change_tick();\n    let rt_cx = RuntimeContext::current();\n    let mut rt = rt_cx.inner.borrow_mut();\n\n    for f in &mut rt.updates {\n        f(world);\n    }\n    rt.updates.clear();\n\n    rt.commands.borrow_mut().apply(world);\n    drop(rt);\n\n    let proxy = (*world\n        .get_resource::<EventLoopProxyWrapper<WakeUp>>()\n        .unwrap())\n    .clone();\n    let rt = &mut *world.non_send_resource_mut::<Runtime>();\n    let mut composers = rt.composers.borrow_mut();\n    for rt_composer in composers.values_mut() {\n        let waker = Waker::from(Arc::new(RuntimeWaker {\n            proxy: proxy.clone(),\n        }));\n        let mut cx = Context::from_waker(&waker);\n\n        // TODO handle composition error.\n        let _ = rt_composer.composer.poll_compose(&mut cx);\n    }\n}\n\n/// A function that takes a [`SystemParam`] as input.\n#[diagnostic::on_unimplemented(\n    message = \"`{Self}` is not a valid system\",\n    label = \"invalid system\"\n)]\npub trait SystemParamFunction<Marker> {\n    /// The input type to this system. See [`System::In`].\n    type In;\n\n    /// The return type of this system. See [`System::Out`].\n    type Out;\n\n    /// The [`SystemParam`].\n    type Param: SystemParam + 'static;\n\n    /// Run the function with the provided [`SystemParam`]'s item.\n    fn run(&mut self, input: Self::In, param_value: SystemParamItem<Self::Param>) -> Self::Out;\n}\n\n#[doc(hidden)]\npub struct Wrap<T>(T);\n\nmacro_rules! impl_system_param_fn {\n    ($($t:tt),*) => {\n        impl<Out, Func, $($t: SystemParam + 'static),*> SystemParamFunction<Wrap<fn($($t,)*) -> Out>> for Func\n        where\n        for <'a> &'a mut Func:\n                FnMut($($t),*) -> Out +\n                FnMut($(SystemParamItem<$t>),*) -> Out, Out: 'static\n        {\n            type In = ();\n            type Out = Out;\n            type Param = ($($t,)*);\n\n            #[inline]\n            #[allow(non_snake_case)]\n            fn run(&mut self, _input: (), param_value: SystemParamItem< ($($t,)*)>) -> Out {\n                #[allow(clippy::too_many_arguments)]\n                fn call_inner<Out, $($t,)*>(mut f: impl FnMut($($t,)*) -> Out, $($t: $t,)*)->Out{\n                    f($($t,)*)\n                }\n                let ($($t,)*) = param_value;\n                call_inner(self, $($t),*)\n            }\n        }\n\n        #[allow(non_snake_case)]\n        impl<Input, Out, Func, $($t: SystemParam + 'static),*> SystemParamFunction<fn(In<Input>, $($t,)*) -> Out> for Func\n        where\n        for <'a> &'a mut Func:\n                FnMut(In<Input>, $($t),*) -> Out +\n                FnMut(In<Input>, $(SystemParamItem<$t>),*) -> Out, Out: 'static\n        {\n            type In = Input;\n            type Out = Out;\n            type Param = ($($t,)*);\n            #[inline]\n            fn run(&mut self, input: Input, param_value: SystemParamItem< ($($t,)*)>) -> Out {\n                #[allow(clippy::too_many_arguments)]\n                fn call_inner<Input, Out, $($t,)*>(\n                    mut f: impl FnMut(In<Input>, $($t,)*)->Out,\n                    input: In<Input>,\n                    $($t: $t,)*\n                )->Out{\n                    f(input, $($t,)*)\n                }\n                let ($($t,)*) = param_value;\n                call_inner(self, In(input), $($t),*)\n            }\n        }\n\n        #[allow(non_snake_case)]\n        impl<E: Event, B: Bundle, Out, Func, $($t: SystemParam + 'static),*> SystemParamFunction<fn(On<E, B>, $($t,)*) -> Out> for Func\n        where\n        for <'a> &'a mut Func:\n                FnMut(On<E, B>, $($t),*) -> Out +\n                FnMut(On<E, B>, $(SystemParamItem<$t>),*) -> Out, Out: 'static\n        {\n            type In = On<'static,  'static,E, B>;\n            type Out = Out;\n            type Param = ($($t,)*);\n            #[inline]\n            fn run(&mut self, input: On<E, B>, param_value: SystemParamItem< ($($t,)*)>) -> Out {\n                #[allow(clippy::too_many_arguments)]\n                fn call_inner<E: Event, B: Bundle, Out, $($t,)*>(\n                    mut f: impl FnMut(On<E, B>, $($t,)*)->Out,\n                    input: On<E, B>,\n                    $($t: $t,)*\n                )->Out{\n                    f(input, $($t,)*)\n                }\n                let ($($t,)*) = param_value;\n                call_inner(self, input, $($t),*)\n            }\n        }\n    };\n}\n\nimpl_trait_for_tuples!(impl_system_param_fn);\n\n/// Use one or more [`SystemParam`]s from the ECS world.\n///\n/// `with_world` will be called on every frame with the latest query.\n///\n/// Change detection is implemented as a traditional system parameter.\n///\n/// # Examples\n///\n/// ```no_run\n/// use actuate::prelude::*;\n/// use bevy::prelude::*;\n///\n/// // Timer composable.\n/// #[derive(Data)]\n/// struct Timer;\n///\n/// impl Compose for Timer {\n///     fn compose(cx: Scope<Self>) -> impl Compose {\n///         let current_time = use_mut(&cx, Time::default);\n///\n///         // Use the `Time` resource from the ECS world, updating the `current_time`.\n///         use_world(&cx, move |time: Res<Time>| {\n///             SignalMut::set(current_time, *time)\n///         });\n///\n///         // Spawn a `Text` component, updating it when this scope is re-composed.\n///         spawn(Text::new(format!(\"Elapsed: {:?}\", current_time.elapsed())))\n///     }\n/// }\n/// ```\npub fn use_world<'a, Marker, F>(cx: ScopeState<'a>, mut with_world: F)\nwhere\n    F: SystemParamFunction<Marker, In = (), Out = ()> + 'a,\n{\n    let system_state_cell = use_ref(cx, || RefCell::new(None));\n\n    let f: Rc<dyn Fn(&'static mut World)> = use_callback(cx, move |world: &'static mut World| {\n        let mut system_state_cell = system_state_cell.borrow_mut();\n        let system_state =\n            system_state_cell.get_or_insert_with(|| SystemState::<F::Param>::new(world));\n\n        let params = system_state.get_mut(world);\n        with_world.run((), params);\n\n        system_state.apply(world);\n    })\n    .clone();\n\n    let key = *use_ref(cx, || {\n        let f: Rc<dyn Fn(&mut World)> = unsafe { mem::transmute(f) };\n\n        RuntimeContext::current()\n            .inner\n            .borrow_mut()\n            .listeners\n            .insert(f)\n    });\n\n    use_drop(cx, move || {\n        RuntimeContext::current()\n            .inner\n            .borrow_mut()\n            .listeners\n            .remove(key);\n    });\n}\n\n/// A function that takes a [`SystemParam`] as input.\n#[diagnostic::on_unimplemented(\n    message = \"`{Self}` is not a valid system\",\n    label = \"invalid system\"\n)]\npub trait SystemParamFunctionOnce<Marker> {\n    /// The [`SystemParam`].\n    type Param: SystemParam + 'static;\n\n    /// The return type of this function.\n    type Output: 'static;\n\n    /// Run the function with the provided [`SystemParam`]'s item.\n    fn run(self, param: <Self::Param as SystemParam>::Item<'_, '_>) -> Self::Output;\n}\n\nmacro_rules! impl_system_param_fn_once {\n    ($($t:tt),*) => {\n        impl<$($t: SystemParam + 'static,)* R: 'static, F: FnOnce($($t),*) -> R + FnOnce($($t::Item<'_, '_>),*) -> R> SystemParamFunctionOnce<fn($($t),*)> for F {\n            type Param = ($($t,)*);\n\n            type Output = R;\n\n            fn run(self, param: <Self::Param as SystemParam>::Item<'_, '_>) -> Self::Output {\n                #[allow(non_snake_case)]\n                let ($($t,)*) = param;\n                self($($t,)*)\n            }\n        }\n    };\n}\n\nimpl_trait_for_tuples!(impl_system_param_fn_once);\n\n/// Use one or more [`SystemParam`]s from the ECS world.\n///\n/// `with_world` will be called once during the first composition.\npub fn use_world_once<Marker, F>(cx: ScopeState<'_>, with_world: F) -> &F::Output\nwhere\n    F: SystemParamFunctionOnce<Marker>,\n{\n    use_ref(cx, || {\n        let world = unsafe { RuntimeContext::current().world_mut() };\n        let mut param = SystemState::<F::Param>::new(world);\n        let item = param.get_mut(world);\n\n        let output = with_world.run(item);\n        param.apply(world);\n        output\n    })\n}\n\n/// Hook for [`use_commands`].\npub struct UseCommands {\n    commands: Rc<RefCell<CommandQueue>>,\n}\n\nimpl UseCommands {\n    /// Push a [`Command`] to the command queue.\n    pub fn push<C>(&mut self, command: C)\n    where\n        C: Command,\n    {\n        self.commands.borrow_mut().push(command);\n    }\n}\n\n/// Use access to the current [`Command`] queue.\npub fn use_commands(cx: ScopeState<'_>) -> &UseCommands {\n    use_ref(cx, || {\n        let commands = RuntimeContext::current().inner.borrow().commands.clone();\n        UseCommands { commands }\n    })\n}\n\nstruct SpawnContext {\n    parent_entity: Entity,\n    keys: RefCell<BTreeSet<Pending>>,\n}\n\n/// Use a spawned bundle.\n///\n/// `make_bundle` is called once to create the bundle.\npub fn use_bundle<B: Bundle>(cx: ScopeState<'_>, make_bundle: impl FnOnce() -> B) -> Entity {\n    use_bundle_inner(cx, |world, cell| {\n        let bundle = make_bundle();\n        if let Some(entity) = cell {\n            world.entity_mut(*entity).insert(bundle);\n        } else {\n            *cell = Some(world.spawn(bundle).id());\n        }\n    })\n}\n\nfn use_bundle_inner(\n    cx: ScopeState<'_>,\n    spawn: impl FnOnce(&mut World, &mut Option<Entity>),\n) -> Entity {\n    let mut f_cell = Some(spawn);\n    let entity = *use_ref(cx, || {\n        let world = unsafe { RuntimeContext::current().world_mut() };\n\n        let mut cell = None;\n        f_cell.take().unwrap()(world, &mut cell);\n        cell.unwrap()\n    });\n\n    if let Some(f) = f_cell {\n        let world = unsafe { RuntimeContext::current().world_mut() };\n        f(world, &mut Some(entity));\n    }\n\n    use_drop(cx, move || {\n        let world = unsafe { RuntimeContext::current().world_mut() };\n        world.try_despawn(entity).ok();\n    });\n\n    entity\n}\n\n/// ECS bundle modifier.\n#[derive(Clone, Default)]\npub struct Modifier<'a> {\n    fns: Vec<Rc<dyn Fn(Spawn<'a>) -> Spawn<'a> + 'a>>,\n}\n\nimpl<'a> Modifier<'a> {\n    /// Apply this modifier.\n    pub fn apply(&self, spawn: Spawn<'a>) -> Spawn<'a> {\n        self.fns\n            .iter()\n            .fold(spawn, |spawn, modifier| modifier(spawn))\n    }\n\n    /// Append another stack of modifiers to this modifier.\n    pub fn append(&mut self, modifier: Cow<'a, Modifier>) {\n        let modifier: Modifier<'_> = modifier.into_owned();\n        let modifier: Modifier<'a> = unsafe { mem::transmute(modifier) };\n        self.fns.extend(modifier.fns);\n    }\n}\n\nimpl fmt::Debug for Modifier<'_> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Modifier\").finish()\n    }\n}\n\nunsafe impl Data for Modifier<'_> {}\n\nmacro_rules! ui_methods {\n    ($($i:ident: $t:path),*) => {\n        $(\n            #[cfg(feature = \"ui\")]\n            #[cfg_attr(docsrs, doc(cfg(feature = \"ui\")))]\n            #[doc = concat!(\"Set the `\", stringify!($i), \"` of this composable's spawned [`Node`].\")]\n            fn $i(self, $i: $t) -> Self\n            where\n                Self: Sized,\n            {\n                self.modify(move |spawn| {\n                    let $i = $i.clone();\n                    spawn.on_insert(move |mut entity| {\n                        let mut node = entity.get_mut::<Node>().unwrap();\n                        node.$i = $i.clone();\n                    })\n                })\n            }\n        )*\n    };\n}\n\nmacro_rules! handler_methods {\n    ($($i:ident: $e:ident),*) => {\n        $(\n            #[cfg(feature = \"picking\")]\n            #[cfg_attr(docsrs, doc(cfg(feature = \"picking\")))]\n            #[doc = concat!(\"Add an observer for `\", stringify!($e), \"` events to this composable's bundle.\")]\n            fn $i(self, f: impl Fn() + Send + Sync + 'a) -> Self\n            where\n                Self: Sized,\n            {\n                self.observe(move |_: On<Pointer<$e>>| f())\n            }\n        )*\n    };\n}\n\n/// Modifiable composable.\npub trait Modify<'a> {\n    /// Get a mutable reference to the modifier of this button.\n    fn modifier(&mut self) -> &mut Modifier<'a>;\n\n    /// Modify this composable with a function.\n    fn modify(mut self, f: impl Fn(Spawn<'a, ()>) -> Spawn<'a, ()> + 'a) -> Self\n    where\n        Self: Sized,\n    {\n        self.modifier().fns.push(Rc::new(f));\n        self\n    }\n\n    /// Append a modifier to this composable.\n    fn append(mut self, modifier: Cow<'a, Modifier>) -> Self\n    where\n        Self: Sized,\n    {\n        self.modifier().append(modifier);\n        self\n    }\n\n    /// Add a function to run when this composable's bundle is spawned.\n    fn on_insert<F>(self, f: F) -> Self\n    where\n        Self: Sized,\n        F: Fn(EntityWorldMut) + 'a,\n    {\n        let f = Rc::new(f);\n        self.modify(move |spawn| {\n            let f = f.clone();\n            spawn.on_insert(move |e| f(e))\n        })\n    }\n\n    #[cfg(feature = \"ui\")]\n    #[cfg_attr(docsrs, doc(cfg(feature = \"ui\")))]\n    /// Set the flex gap of this composable's spawned [`Node`].\n    ///\n    /// This will set the `column_gap` for a `FlexDirection::Row` or `FlexDirection::RowReverse`\n    /// and the `row_gap` for a `FlexDirection::Column` or `FlexDirection::ColumnReverse`.\n    fn flex_gap(self, gap: Val) -> Self\n    where\n        Self: Sized,\n    {\n        self.modify(move |spawn| {\n            spawn.on_insert(move |mut entity| {\n                let mut node = entity.get_mut::<Node>().unwrap();\n                match node.flex_direction {\n                    FlexDirection::Row | FlexDirection::RowReverse => node.column_gap = gap,\n                    FlexDirection::Column | FlexDirection::ColumnReverse => node.row_gap = gap,\n                }\n            })\n        })\n    }\n\n    ui_methods!(\n        display: Display,\n        position_type: PositionType,\n        overflow: Overflow,\n        overflow_clip_margin: OverflowClipMargin,\n        left: Val,\n        right: Val,\n        top: Val,\n        bottom: Val,\n        width: Val,\n        height: Val,\n        min_width: Val,\n        min_height: Val,\n        max_width: Val,\n        max_height: Val,\n        aspect_ratio: Option<f32>,\n        align_items: AlignItems,\n        justify_items: JustifyItems,\n        align_self: AlignSelf,\n        justify_self: JustifySelf,\n        align_content: AlignContent,\n        justify_content: JustifyContent,\n        margin: UiRect,\n        padding: UiRect,\n        border: UiRect,\n        flex_direction: FlexDirection,\n        flex_wrap: FlexWrap,\n        flex_grow: f32,\n        flex_shrink: f32,\n        flex_basis: Val,\n        row_gap: Val,\n        column_gap: Val,\n        grid_auto_flow: GridAutoFlow,\n        grid_template_rows: Vec<RepeatedGridTrack>,\n        grid_template_columns: Vec<RepeatedGridTrack>,\n        grid_auto_rows: Vec<GridTrack>,\n        grid_auto_columns: Vec<GridTrack>,\n        grid_row: GridPlacement,\n        grid_column: GridPlacement\n    );\n\n    /// Add an observer to this composable's bundle.\n    fn observe<F, E, B, Marker>(self, observer: F) -> Self\n    where\n        Self: Sized,\n        F: SystemParamFunction<Marker, In = On<'static, 'static, E, B>, Out = ()>\n            + Send\n            + Sync\n            + 'a,\n        E: EntityEvent,\n        B: Bundle,\n    {\n        let observer_cell = Cell::new(Some(observer));\n        self.modify(move |spawn| {\n            let observer = observer_cell.take().unwrap();\n            spawn.observe(observer)\n        })\n    }\n\n    handler_methods!(\n        on_mouse_in: Over,\n        on_mouse_out: Out,\n        on_click: Click,\n        on_mouse_down: Press,\n        on_mouse_up: Release,\n        on_drag: Drag,\n        on_drag_start: DragStart,\n        on_drag_end: DragEnd,\n        on_drag_enter: DragEnter,\n        on_drag_over: DragOver,\n        on_drag_drop: DragDrop,\n        on_drag_leave: DragLeave\n    );\n}\n"
  },
  {
    "path": "src/ecs/spawn.rs",
    "content": "use super::{use_bundle_inner, RuntimeContext, SpawnContext, SystemParamFunction};\nuse crate::{\n    compose::Compose, composer::Runtime, data::Data, use_context, use_drop, use_provider, use_ref,\n    Scope, Signal,\n};\nuse bevy_ecs::{entity::Entity, prelude::*, world::World};\nuse std::{\n    cell::{Cell, RefCell},\n    collections::BTreeSet,\n    mem,\n    rc::Rc,\n    sync::{Arc, Mutex},\n};\n\n/// Create a [`Spawn`] composable that spawns the provided `bundle` when composed.\n///\n/// On re-composition, the spawned entity is updated to the latest provided value.\n///\n/// # Examples\n///\n/// ```no_run\n/// use actuate::prelude::*;\n/// use bevy::prelude::*;\n///\n/// #[derive(Data)]\n/// struct Button {\n///     label: String,\n///     color: Color\n/// }\n///\n/// impl Compose for Button {\n///     fn compose(cx: Scope<Self>) -> impl Compose {\n///         // Spawn an entity with a `Text` and `BackgroundColor` component.\n///         spawn((Text::new(cx.me().label.clone()), BackgroundColor(cx.me().color)))\n///     }\n/// }\n/// ```\npub fn spawn<'a, B>(bundle: B) -> Spawn<'a>\nwhere\n    B: Bundle + Clone,\n{\n    Spawn {\n        spawn_fn: Rc::new(move |world, cell| {\n            if let Some(entity) = cell {\n                world.entity_mut(*entity).insert(bundle.clone());\n            } else {\n                *cell = Some(world.spawn(bundle.clone()).id())\n            }\n        }),\n        content: (),\n        target: None,\n        observer_fns: Vec::new(),\n        observer_guard: Arc::new(Mutex::new(true)),\n        on_spawn: Vec::new(),\n        on_insert: Vec::new(),\n    }\n}\n\ntype SpawnFn = Rc<dyn Fn(&mut World, &mut Option<Entity>)>;\n\ntype ObserverFn<'a> = Rc<dyn Fn(&mut EntityWorldMut) + 'a>;\n\ntype OnInsertFn<'a> = Rc<dyn Fn(EntityWorldMut) + 'a>;\n\n/// Composable to spawn an entity.\n///\n/// See [`spawn`] for more information.\n#[derive(Clone)]\n#[must_use = \"Composables do nothing unless composed or returned from other composables.\"]\npub struct Spawn<'a, C = ()> {\n    spawn_fn: SpawnFn,\n    content: C,\n    target: Option<Entity>,\n    observer_fns: Vec<ObserverFn<'a>>,\n    on_spawn: Vec<OnInsertFn<'a>>,\n    on_insert: Vec<OnInsertFn<'a>>,\n    observer_guard: Arc<Mutex<bool>>,\n}\n\nimpl<'a, C> Spawn<'a, C> {\n    /// Set the target entity to spawn the composition into.\n    ///\n    /// If `None`, this will use the composition's parent (if any).\n    pub fn target(mut self, target: Entity) -> Self {\n        self.target = Some(target);\n        self\n    }\n\n    /// Set the child content.\n    pub fn content<C2>(self, content: C2) -> Spawn<'a, C2> {\n        Spawn {\n            spawn_fn: self.spawn_fn,\n            content,\n            target: self.target,\n            observer_fns: self.observer_fns,\n            observer_guard: Arc::new(Mutex::new(false)),\n            on_spawn: self.on_spawn,\n            on_insert: self.on_insert,\n        }\n    }\n\n    /// Add a function to be called when this bundle is initially spawned.\n    pub fn on_spawn(mut self, f: impl Fn(EntityWorldMut) + 'a) -> Self {\n        self.on_insert.push(Rc::new(f));\n        self\n    }\n\n    /// Add a function to be called on every insert.\n    pub fn on_insert(mut self, f: impl Fn(EntityWorldMut) + 'a) -> Self {\n        self.on_insert.push(Rc::new(f));\n        self\n    }\n\n    /// Add an observer to the spawned entity.\n    pub fn observe<F, E, B, Marker>(mut self, observer: F) -> Self\n    where\n        F: SystemParamFunction<Marker, In = On<'static, 'static, E, B>, Out = ()>\n            + Send\n            + Sync\n            + 'a,\n        E: EntityEvent,\n        B: Bundle,\n    {\n        let cell = Cell::new(Some(observer));\n        let guard = self.observer_guard.clone();\n\n        self.observer_fns.push(Rc::new(move |entity| {\n            let mut observer = cell.take().unwrap();\n            let guard = guard.clone();\n\n            type SpawnObserveFn<'a, F, E, B, Marker> = Box<\n                dyn FnMut(\n                        On<'_, '_, E, B>,\n                        ParamSet<'_, '_, (<F as SystemParamFunction<Marker>>::Param,)>,\n                    ) + Send\n                    + Sync\n                    + 'a,\n            >;\n\n            let f: SpawnObserveFn<'a, F, E, B, Marker> = Box::new(move |trigger, mut params| {\n                let guard = guard.lock().unwrap();\n                if !*guard {\n                    panic!(\"Actuate observer called after its scope was dropped.\")\n                }\n\n                // Safety: The event will be accessed under a shortened lifetime.\n                let trigger: On<'static, 'static, E, B> = unsafe { mem::transmute(trigger) };\n                observer.run(trigger, params.p0())\n            });\n\n            // Safety: The observer will be disabled after this scope is dropped.\n            let f: SpawnObserveFn<'static, F, E, B, Marker> = unsafe { mem::transmute(f) };\n\n            entity.observe(f);\n        }));\n        self\n    }\n}\n\nunsafe impl<C: Data> Data for Spawn<'_, C> {}\n\nimpl<C: Compose> Compose for Spawn<'_, C> {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        let rt = Runtime::current();\n\n        let spawn_cx = use_context::<SpawnContext>(&cx);\n\n        let is_initial = use_ref(&cx, || Cell::new(true));\n        let entity = use_bundle_inner(&cx, |world, entity| {\n            if let Some(target) = cx.me().target {\n                *entity = Some(target);\n            }\n\n            // Check if this entity has been removed externally.\n            if let Some(entity) = entity {\n                if world.get_entity(*entity).is_err() {\n                    return;\n                }\n            }\n\n            (cx.me().spawn_fn)(world, entity);\n\n            for f in &cx.me().on_insert {\n                f(world.entity_mut(entity.unwrap()));\n            }\n\n            if is_initial.get() {\n                for f in &cx.me().on_spawn {\n                    f(world.entity_mut(entity.unwrap()));\n                }\n\n                let mut entity_mut = world.entity_mut(entity.unwrap());\n                for f in &cx.me().observer_fns {\n                    f(&mut entity_mut);\n                }\n\n                is_initial.set(false);\n            }\n        });\n        let key = use_ref(&cx, || rt.pending(rt.current_key.get()));\n\n        use_provider(&cx, || {\n            if cx.me().target.is_none() {\n                if let Ok(spawn_cx) = spawn_cx {\n                    spawn_cx.keys.borrow_mut().insert(key.clone());\n\n                    if let Some(idx) = spawn_cx\n                        .keys\n                        .borrow()\n                        .iter()\n                        .position(|pending| pending.key == rt.current_key.get())\n                    {\n                        let world = unsafe { RuntimeContext::current().world_mut() };\n                        world\n                            .entity_mut(spawn_cx.parent_entity)\n                            .insert_children(idx, &[entity]);\n                    }\n                }\n            }\n\n            SpawnContext {\n                parent_entity: entity,\n                keys: RefCell::new(BTreeSet::new()),\n            }\n        });\n\n        // Use the initial guard.\n        let guard = use_ref(&cx, || cx.me().observer_guard.clone());\n        use_drop(&cx, move || {\n            *guard.lock().unwrap() = false;\n\n            if let Ok(spawn_cx) = spawn_cx {\n                spawn_cx.keys.borrow_mut().remove(key);\n            }\n        });\n\n        unsafe { Signal::map_unchecked(cx.me(), |me| &me.content) }\n    }\n}\n"
  },
  {
    "path": "src/executor.rs",
    "content": "use alloc::{rc::Rc, sync::Arc};\nuse core::{future::Future, pin::Pin};\n\n/// Executor for async tasks.\npub trait Executor {\n    /// Spawn a boxed future on this executor.\n    fn spawn(&self, future: Pin<Box<dyn Future<Output = ()> + Send>>);\n}\n\n#[cfg(feature = \"rt\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"rt\")))]\nimpl Executor for tokio::runtime::Runtime {\n    fn spawn(&self, future: Pin<Box<dyn Future<Output = ()> + Send>>) {\n        self.spawn(future);\n    }\n}\n\nmacro_rules! impl_executor {\n    ($($t:tt),*) => {\n        $(\n            impl<T: Executor + ?Sized> Executor for $t<T> {\n                fn spawn(&self, future: Pin<Box<dyn Future<Output = ()> + Send>>) {\n                    (**self).spawn(future);\n                }\n            }\n        )*\n    };\n}\n\nimpl_executor!(Box, Rc, Arc);\n\n/// Context that contains the current [`Executor`].\npub struct ExecutorContext {\n    pub(crate) executor: Box<dyn Executor>,\n}\n\n#[cfg(feature = \"rt\")]\nimpl Default for ExecutorContext {\n    fn default() -> Self {\n        Self::new(tokio::runtime::Runtime::new().unwrap())\n    }\n}\n\nimpl ExecutorContext {\n    /// Create a new [`ExecutorContext`] with the provided [`Executor`].\n    pub fn new(executor: impl Executor + 'static) -> Self {\n        Self {\n            executor: Box::new(executor),\n        }\n    }\n\n    /// Spawn a future on the current runtime.\n    pub fn spawn<F>(&self, future: F)\n    where\n        F: Future<Output = ()> + Send + 'static,\n    {\n        self.spawn_boxed(Box::pin(future))\n    }\n\n    /// Spawn a boxed future on the current runtime.\n    pub fn spawn_boxed(&self, future: Pin<Box<dyn Future<Output = ()> + Send>>) {\n        self.executor.spawn(future);\n    }\n}\n"
  },
  {
    "path": "src/lib.rs",
    "content": "#![deny(missing_docs)]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n#![doc(\n    html_logo_url = \"https://avatars.githubusercontent.com/u/161107368\",\n    html_favicon_url = \"https://avatars.githubusercontent.com/u/161107368\"\n)]\n\n//! # Actuate\n//! A high-performance and borrow-checker friendly framework for declarative programming in Rust.\n//! This crate provides a generic library that lets you define reactive components\n//! (also known as composables, for more see [`Compose`]).\n//!\n//! ```no_run\n//! use actuate::prelude::*;\n//! use bevy::prelude::*;\n//!\n//! // Counter composable.\n//! #[derive(Data)]\n//! struct Counter {\n//!     start: i32,\n//! }\n//!\n//! impl Compose for Counter {\n//!     fn compose(cx: Scope<Self>) -> impl Compose {\n//!         let count = use_mut(&cx, || cx.me().start);\n//!\n//!         material_ui((\n//!             text::headline(format!(\"High five count: {}\", count)),\n//!             button(text::label(\"Up high\")).on_click(move || SignalMut::update(count, |x| *x += 1)),\n//!             button(text::label(\"Down low\")).on_click(move || SignalMut::update(count, |x| *x -= 1)),\n//!             if *count == 0 {\n//!                 Some(text::label(\"Gimme five!\"))\n//!             } else {\n//!                 None\n//!             },\n//!         ))\n//!         .align_items(AlignItems::Center)\n//!         .justify_content(JustifyContent::Center)\n//!     }\n//! }\n//!```\n//!\n//! ## Borrowing\n//! Composables can borrow from their ancestors, as well as state.\n//! ```no_run\n//! use actuate::prelude::*;\n//! use bevy::prelude::*;\n//!\n//! #[derive(Data)]\n//! struct User<'a> {\n//!     // `actuate::Cow` allows for either a borrowed or owned value.\n//!     name: Cow<'a, String>,\n//! }\n//!\n//! impl Compose for User<'_> {\n//!     fn compose(cx: Scope<Self>) -> impl Compose {\n//!         text::headline(cx.me().name.to_string())\n//!     }\n//! }\n//!\n//! #[derive(Data)]\n//! struct App {\n//!     name: String\n//! }\n//!\n//! impl Compose for App {\n//!     fn compose(cx: Scope<Self>) -> impl Compose {\n//!         // Get a mapped reference to the app's `name` field.\n//!         let name = Signal::map(cx.me(), |me| &me.name).into();\n//!\n//!         User { name }\n//!     }\n//! }\n//! ```\n//!\n//! ## Hooks\n//! Functions that begin with `use_` are called `hooks` in Actuate.\n//! Hooks are used to manage state and side effects in composables.\n//!\n//! Hooks must be used in the same order for every re-compose.\n//! Don’t use hooks inside loops, conditions, nested functions, or match blocks.\n//! Instead, always use hooks at the top level of your composable, before any early returns.\n//!\n//! ## Installation\n//! To add this crate to your project:\n//! ```sh\n//! cargo add actuate --features full\n//! ```\n//!\n//! ## Features\n//! - `std`: Enables features that use Rust's standard library (default). With this feature disabled Actuate can be used in `#![no_std]` environments.\n//! - `animation`: Enables the `animation` module for animating values from the [Bevy](https://crates.io/crates/bevy) ECS.\n//!   (enables the `ecs` feature).\n//! - `ecs`: Enables the `ecs` module for bindings to the [Bevy](https://crates.io/crates/bevy) ECS.\n//! - `executor`: Enables the `executor` module for multi-threaded tasks.\n//! - `material`: Enables the `material` module for Material UI (enables the `ecs` and `ui` features).\n//! - `picking`: Enables support for picking event handlers with `Modify` (requires the `ecs` feature).\n//! - `rt` Enables support for the [Tokio](https://crates.io/crates/tokio) runtime with the Executor trait.\n//!   (enables the `executor` feature).\n//! - `tracing`: Enables the logging through the `tracing` crate.\n//! - `ui`: Enables the `ui` module for user interface components.\n//! - `full`: Enables all features above.\n\nextern crate alloc;\n\nuse ahash::AHasher;\nuse alloc::rc::Rc;\nuse core::{\n    any::{Any, TypeId},\n    cell::{Cell, RefCell, UnsafeCell},\n    fmt,\n    future::Future,\n    hash::{BuildHasherDefault, Hash, Hasher},\n    marker::PhantomData,\n    mem,\n    ops::Deref,\n    pin::Pin,\n    ptr::NonNull,\n};\nuse slotmap::DefaultKey;\nuse thiserror::Error;\n\n#[cfg(not(feature = \"std\"))]\nuse hashbrown::HashMap;\n\n#[cfg(feature = \"std\")]\nuse std::collections::HashMap;\n\n/// Prelude of commonly used items.\npub mod prelude {\n    pub use crate::{\n        compose::{self, catch, dyn_compose, memo, Compose, DynCompose, Error, Memo},\n        data::{data, Data},\n        use_callback, use_context, use_drop, use_local_task, use_memo, use_mut, use_provider,\n        use_ref, Cow, Generational, Map, RefMap, Scope, ScopeState, Signal, SignalMut,\n    };\n\n    #[cfg(feature = \"animation\")]\n    #[cfg_attr(docsrs, doc(cfg(feature = \"animation\")))]\n    pub use crate::animation::{use_animated, UseAnimated};\n\n    #[cfg(feature = \"ecs\")]\n    #[cfg_attr(docsrs, doc(cfg(feature = \"ecs\")))]\n    pub use crate::ecs::{\n        spawn, use_bundle, use_commands, use_world, use_world_once, ActuatePlugin, Composition,\n        Modifier, Modify, Spawn, UseCommands,\n    };\n\n    #[cfg(feature = \"executor\")]\n    #[cfg_attr(docsrs, doc(cfg(feature = \"executor\")))]\n    pub use crate::use_task;\n\n    #[cfg(feature = \"ui\")]\n    #[cfg_attr(docsrs, doc(cfg(feature = \"ui\")))]\n    pub use crate::ui::{scroll_view, ScrollView};\n\n    #[cfg(feature = \"material\")]\n    #[cfg_attr(docsrs, doc(cfg(feature = \"material\")))]\n    pub use crate::ui::material::{\n        button, container, material_ui, radio_button, text, Button, MaterialUi, RadioButton, Theme,\n        TypographyKind, TypographyStyleKind,\n    };\n}\n\n#[cfg(feature = \"animation\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"animation\")))]\n/// Animation hooks.\npub mod animation;\n\n/// Composable functions.\npub mod compose;\nuse self::compose::{AnyCompose, Compose};\n\n/// Low-level composer.\npub mod composer;\nuse self::composer::Runtime;\n\n/// Data trait and macros.\npub mod data;\nuse crate::data::Data;\n\n#[cfg(feature = \"ecs\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"ecs\")))]\n/// Bevy ECS integration.\npub mod ecs;\n\n#[cfg(feature = \"executor\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"executor\")))]\n/// Task execution context.\npub mod executor;\n\n#[cfg(feature = \"ui\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"ui\")))]\n/// User interface components.\npub mod ui;\n\n/// Clone-on-write value.\n///\n/// This represents either a borrowed or owned value.\n/// A borrowed value is stored as a [`RefMap`], which can be either a reference or a mapped reference.\n#[derive(Debug)]\npub enum Cow<'a, T> {\n    /// Borrowed value, contained inside either a [`Signal`] or [`Map`].\n    Borrowed(RefMap<'a, T>),\n    /// Owned value.\n    Owned(T),\n}\n\nimpl<T> Cow<'_, T> {\n    /// Clone this value to an owned value.\n    pub fn to_owned(&self) -> T\n    where\n        T: Clone,\n    {\n        self.clone().into_owned()\n    }\n\n    /// Convert or clone this value to an owned value.\n    pub fn into_owned(self) -> T\n    where\n        T: Clone,\n    {\n        match self {\n            Cow::Borrowed(value) => (*value).clone(),\n            Cow::Owned(value) => value,\n        }\n    }\n}\n\nimpl<T> Clone for Cow<'_, T>\nwhere\n    T: Clone,\n{\n    fn clone(&self) -> Self {\n        match self {\n            Cow::Borrowed(value) => Cow::Borrowed(*value),\n            Cow::Owned(value) => Cow::Owned(value.clone()),\n        }\n    }\n}\n\nimpl<T> Deref for Cow<'_, T> {\n    type Target = T;\n\n    fn deref(&self) -> &Self::Target {\n        match self {\n            Cow::Borrowed(ref_map) => ref_map,\n            Cow::Owned(value) => value,\n        }\n    }\n}\n\nimpl<'a, T> From<RefMap<'a, T>> for Cow<'a, T> {\n    fn from(value: RefMap<'a, T>) -> Self {\n        Cow::Borrowed(value)\n    }\n}\n\nimpl<'a, T> From<Signal<'a, T>> for Cow<'a, T> {\n    fn from(value: Signal<'a, T>) -> Self {\n        RefMap::from(value).into()\n    }\n}\n\nimpl<'a, T> From<Map<'a, T>> for Cow<'a, T> {\n    fn from(value: Map<'a, T>) -> Self {\n        RefMap::from(value).into()\n    }\n}\n\nimpl<T: fmt::Display> fmt::Display for Cow<'_, T> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Cow::Borrowed(value) => value.fmt(f),\n            Cow::Owned(value) => value.fmt(f),\n        }\n    }\n}\n\nunsafe impl<T: Data> Data for Cow<'_, T> {}\n\n/// Immutable reference or mapped reference to a value.\n#[derive(Debug)]\npub enum RefMap<'a, T> {\n    /// Reference to a value.\n    Ref(&'a T),\n    /// Signal value.\n    Signal(Signal<'a, T>),\n    /// Mapped reference to a value.\n    Map(Map<'a, T>),\n}\n\nimpl<T> Clone for RefMap<'_, T> {\n    fn clone(&self) -> Self {\n        *self\n    }\n}\n\nimpl<T> Copy for RefMap<'_, T> {}\n\nimpl<T> Deref for RefMap<'_, T> {\n    type Target = T;\n\n    fn deref(&self) -> &Self::Target {\n        match self {\n            RefMap::Ref(r) => r,\n            RefMap::Signal(s) => s,\n            RefMap::Map(map) => map,\n        }\n    }\n}\n\nimpl<T: Hash> Hash for RefMap<'_, T> {\n    fn hash<H: Hasher>(&self, state: &mut H) {\n        (**self).hash(state);\n    }\n}\n\nimpl<'a, T> From<Signal<'a, T>> for RefMap<'a, T> {\n    fn from(value: Signal<'a, T>) -> Self {\n        RefMap::Signal(value)\n    }\n}\n\nimpl<'a, T> From<Map<'a, T>> for RefMap<'a, T> {\n    fn from(value: Map<'a, T>) -> Self {\n        RefMap::Map(value)\n    }\n}\n\nimpl<T: fmt::Display> fmt::Display for RefMap<'_, T> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        (**self).fmt(f)\n    }\n}\n\nunsafe impl<T: Data> Data for RefMap<'_, T> {}\n\n/// Mapped immutable reference to a value of type `T`.\n///\n/// This can be created with [`Signal::map`].\npub struct Map<'a, T> {\n    ptr: *const (),\n    map_fn: *const (),\n    deref_fn: fn(*const (), *const ()) -> &'a T,\n    generation: *const Cell<u64>,\n}\n\nimpl<T> Deref for Map<'_, T> {\n    type Target = T;\n\n    fn deref(&self) -> &Self::Target {\n        (self.deref_fn)(self.ptr, self.map_fn)\n    }\n}\n\n/// Unchecked, mapped immutable reference to a value of type `T`.\n///\n/// This can be created with [`Signal::map_unchecked`].\npub struct MapUnchecked<'a, T> {\n    map: Map<'a, T>,\n}\n\nunsafe impl<T> Data for MapUnchecked<'_, T> {}\n\nimpl<C: Compose> Compose for MapUnchecked<'_, C> {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        // Safety: The `Map` is dereferenced every re-compose, so it's guranteed not to point to\n        // an invalid memory location (e.g. an `Option` that previously returned `Some` is now `None`).\n        unsafe { (*cx.me().map).any_compose(cx.state) }\n    }\n\n    fn name() -> Option<std::borrow::Cow<'static, str>> {\n        C::name()\n    }\n}\n\nimpl<T> Hash for Map<'_, T> {\n    fn hash<H: Hasher>(&self, state: &mut H) {\n        self.ptr.hash(state);\n        self.generation.hash(state);\n    }\n}\n\n/// Immutable reference to a value of type `T`.\n///\n/// Memoizing this value will use pointer-equality for higher-performance.\n///\n/// This reference can be mapped to inner values with [`Signal::map`].\npub struct Signal<'a, T> {\n    /// Pinned reference to the value.\n    value: &'a T,\n\n    /// Pointer to this value's current generation.\n    generation: *const Cell<u64>,\n}\n\nimpl<'a, T> Signal<'a, T> {\n    /// Map this reference to a value of type `U`.\n    pub fn map<U>(me: Self, f: fn(&T) -> &U) -> Map<'a, U> {\n        Map {\n            ptr: me.value as *const _ as _,\n            map_fn: f as _,\n            deref_fn: |ptr, g| {\n                // Safety: `f` is guranteed to be a valid function pointer.\n                unsafe {\n                    let g: fn(&T) -> &U = mem::transmute(g);\n                    g(&*(ptr as *const T))\n                }\n            },\n            generation: me.generation,\n        }\n    }\n\n    /// Unsafely map this reference to a value of type `U`.\n    /// The returned `MapUnchecked` implements `Compose` to allow for borrowed child composables.\n    ///\n    /// # Safety\n    /// The returned `MapUnchecked` must only be returned once.\n    /// Composing the same `MapUnchecked` at multiple locations in the tree at the same time will result in undefined behavior.\n    pub unsafe fn map_unchecked<U>(me: Self, f: fn(&T) -> &U) -> MapUnchecked<'a, U> {\n        MapUnchecked {\n            map: Signal::map(me, f),\n        }\n    }\n}\n\nimpl<T> Deref for Signal<'_, T> {\n    type Target = T;\n\n    fn deref(&self) -> &Self::Target {\n        self.value\n    }\n}\n\nimpl<T> Hash for Signal<'_, T> {\n    fn hash<H: Hasher>(&self, state: &mut H) {\n        (self.value as *const T).hash(state);\n        self.generation.hash(state);\n    }\n}\n\n#[derive(Clone, Copy)]\nstruct UnsafeWrap<T: ?Sized>(T);\n\nunsafe impl<T: ?Sized> Send for UnsafeWrap<T> {}\n\nunsafe impl<T: ?Sized> Sync for UnsafeWrap<T> {}\n\n/// Mutable reference to a value of type `T`.\npub struct SignalMut<'a, T> {\n    /// Pointer to the boxed value.\n    ptr: NonNull<T>,\n\n    /// Key to this signal's scope.\n    scope_key: DefaultKey,\n\n    /// Pointer to this value's generation.\n    generation: *const Cell<u64>,\n\n    /// Marker for the lifetime of this immutable reference.\n    _marker: PhantomData<&'a ()>,\n}\n\nimpl<'a, T: 'static> SignalMut<'a, T> {\n    /// Queue an update to this value, triggering an update to the component owning this value.\n    pub fn update(me: Self, f: impl FnOnce(&mut T) + Send + 'static) {\n        let scope_key = me.scope_key;\n\n        Self::with(me, move |value| {\n            let rt = Runtime::current();\n            rt.queue(scope_key);\n\n            f(value)\n        })\n    }\n\n    /// Queue an update to this value, triggering an update to the component owning this value.\n    pub fn set(me: Self, value: T)\n    where\n        T: Send,\n    {\n        SignalMut::update(me, |x| *x = value)\n    }\n\n    /// Queue an update to this value if it is not equal to the given value.\n    pub fn set_if_neq(me: Self, value: T)\n    where\n        T: PartialEq + Send,\n    {\n        if *me != value {\n            SignalMut::set(me, value);\n        }\n    }\n\n    /// Queue an update to this value wtihout triggering an update.\n    pub fn with(me: Self, f: impl FnOnce(&mut T) + Send + 'static) {\n        let cell = UnsafeWrap(Some(f));\n        let ptr = UnsafeWrap(me.ptr);\n        let generation_ptr = UnsafeWrap(me.generation);\n\n        Runtime::current().update(move || {\n            let mut cell = cell;\n            let mut ptr = ptr;\n            let generation_ptr = generation_ptr;\n\n            // Safety: Updates are guaranteed to be called before any structural changes of the composition tree.\n            let value = unsafe { ptr.0.as_mut() };\n            cell.0.take().unwrap()(value);\n\n            // Increment the generation of this value.\n            // Safety: the pointer to this scope's generation is guranteed to outlive `me`.\n            let generation = unsafe { &*generation_ptr.0 };\n            generation.set(generation.get() + 1)\n        });\n    }\n\n    /// Convert this mutable reference to an immutable reference.\n    pub fn as_ref(me: Self) -> Signal<'a, T> {\n        Signal {\n            value: unsafe { me.ptr.as_ref() },\n            generation: me.generation,\n        }\n    }\n}\n\nimpl<T> Deref for SignalMut<'_, T> {\n    type Target = T;\n\n    fn deref(&self) -> &Self::Target {\n        unsafe { self.ptr.as_ref() }\n    }\n}\n\nmacro_rules! impl_pointer {\n    ($($t:ident),*) => {\n        $(\n            impl<T> Clone for $t<'_, T> {\n                fn clone(&self) -> Self {\n                    *self\n                }\n            }\n\n            impl<T> Copy for $t<'_, T> {}\n\n            impl<T: fmt::Debug> fmt::Debug for $t<'_, T> {\n                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n                    f.debug_struct(stringify!($t))\n                        .field(\"value\", &**self)\n                        .field(\"generation\", &unsafe { &*self.generation }.get())\n                        .finish()\n                }\n            }\n\n            impl<T: fmt::Display> fmt::Display for $t<'_, T> {\n                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n                    (&**self).fmt(f)\n                }\n            }\n\n            unsafe impl<T: Send + Sync> Send for $t<'_, T> {}\n\n            unsafe impl<T: Sync + Sync> Sync for $t<'_, T> {}\n\n            impl<'a, T: 'a> IntoIterator for $t<'a, T>\n            where\n                &'a T: IntoIterator,\n            {\n                type Item = <&'a T as IntoIterator>::Item;\n\n                type IntoIter = <&'a T as IntoIterator>::IntoIter;\n\n                fn into_iter(self) -> Self::IntoIter {\n                    let value: &T = &self;\n                    // Safety: the reference to `value` is guranteed to live as long as `self`.\n                    let value: &T = unsafe { mem::transmute(value) };\n                    value.into_iter()\n                }\n            }\n\n            unsafe impl<T: Data> Data for $t<'_, T> {}\n        )*\n    };\n}\nimpl_pointer!(Signal, Map, SignalMut);\n\n/// Map of [`TypeId`] to context values.\n#[derive(Clone, Default)]\nstruct Contexts {\n    values: HashMap<TypeId, Rc<dyn Any>, BuildHasherDefault<AHasher>>,\n}\n\n/// Scope state of a composable function.\npub type ScopeState<'a> = &'a ScopeData<'a>;\n\n/// State of a composable.\n#[derive(Default)]\npub struct ScopeData<'a> {\n    /// Hook values stored in this scope.\n    hooks: UnsafeCell<Vec<Box<dyn Any>>>,\n\n    /// Current hook index.\n    hook_idx: Cell<usize>,\n\n    /// Context values stored in this scope.\n    contexts: RefCell<Contexts>,\n\n    /// Context values for child composables.\n    child_contexts: RefCell<Contexts>,\n\n    /// Drop functions to run just before this scope is dropped.\n    drops: RefCell<Vec<usize>>,\n\n    /// Current generation of this scope.\n    generation: Cell<u64>,\n\n    /// Marker for the invariant lifetime of this scope.\n    _marker: PhantomData<&'a fn(ScopeData<'a>) -> ScopeData<'a>>,\n}\n\nimpl Drop for ScopeData<'_> {\n    fn drop(&mut self) {\n        for idx in &*self.drops.borrow() {\n            let hooks = unsafe { &mut *self.hooks.get() };\n            let any = hooks.get_mut(*idx).unwrap();\n            (**any).downcast_mut::<Box<dyn FnMut()>>().unwrap()();\n        }\n    }\n}\n\n/// Composable scope.\npub struct Scope<'a, C: ?Sized> {\n    me: &'a C,\n    state: ScopeState<'a>,\n}\n\nimpl<'a, C> Scope<'a, C> {\n    /// Get a [`Signal`] to this composable.\n    pub fn me(self) -> Signal<'a, C> {\n        Signal {\n            value: self.me,\n            generation: &self.state.generation,\n        }\n    }\n\n    /// Get the state of this composable.\n    pub fn state(self) -> ScopeState<'a> {\n        self.state\n    }\n}\n\nimpl<C> Clone for Scope<'_, C> {\n    fn clone(&self) -> Self {\n        *self\n    }\n}\n\nimpl<C> Copy for Scope<'_, C> {}\n\nimpl<'a, C> Deref for Scope<'a, C> {\n    type Target = ScopeState<'a>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.state\n    }\n}\n\n/// Use an immutable reference to a value of type `T`.\n///\n/// `make_value` will only be called once to initialize this value.\npub fn use_ref<T: 'static>(cx: ScopeState<'_>, make_value: impl FnOnce() -> T) -> &T {\n    let hooks = unsafe { &mut *cx.hooks.get() };\n\n    let idx = cx.hook_idx.get();\n    cx.hook_idx.set(idx + 1);\n\n    let any = if idx >= hooks.len() {\n        hooks.push(Box::new(make_value()));\n        hooks.last().unwrap()\n    } else {\n        hooks.get(idx).unwrap()\n    };\n    (**any).downcast_ref().unwrap()\n}\n\nstruct MutState<T> {\n    value: T,\n    generation: Cell<u64>,\n}\n\n/// Use a mutable reference to a value of type `T`.\n///\n/// `make_value` will only be called once to initialize this value.\npub fn use_mut<T: 'static>(cx: ScopeState<'_>, make_value: impl FnOnce() -> T) -> SignalMut<'_, T> {\n    let hooks = unsafe { &mut *cx.hooks.get() };\n\n    let idx = cx.hook_idx.get();\n    cx.hook_idx.set(idx + 1);\n\n    let any = if idx >= hooks.len() {\n        let state = MutState {\n            value: make_value(),\n            generation: Cell::new(0),\n        };\n        hooks.push(Box::new(state));\n        hooks.last_mut().unwrap()\n    } else {\n        hooks.get_mut(idx).unwrap()\n    };\n    let state: &mut MutState<T> = any.downcast_mut().unwrap();\n\n    SignalMut {\n        ptr: unsafe { NonNull::new_unchecked(&mut state.value as *mut _) },\n        scope_key: Runtime::current().current_key.get(),\n        generation: &state.generation,\n        _marker: PhantomData,\n    }\n}\n\n/// Use a callback function.\n/// The returned function will be updated to `f` whenever this component is re-composed.\npub fn use_callback<'a, T, R>(\n    cx: ScopeState<'a>,\n    f: impl FnMut(T) -> R + 'a,\n) -> &'a Rc<dyn Fn(T) -> R + 'a>\nwhere\n    T: 'static,\n    R: 'static,\n{\n    let f_cell: Option<Box<dyn FnMut(T) -> R + 'a>> = Some(Box::new(f));\n    let mut f_cell: Option<Box<dyn FnMut(T) -> R>> = unsafe { mem::transmute(f_cell) };\n\n    let callback = use_ref(cx, || Rc::new(RefCell::new(f_cell.take().unwrap()))).clone();\n\n    if let Some(f) = f_cell {\n        *callback.borrow_mut() = f;\n    }\n\n    use_ref(cx, move || {\n        let f = callback.clone();\n        Rc::new(move |input| f.borrow_mut()(input)) as Rc<dyn Fn(T) -> R>\n    })\n}\n\n#[derive(Error)]\n/// Error for a missing context.\npub struct ContextError<T> {\n    _marker: PhantomData<T>,\n}\n\nimpl<T> Clone for ContextError<T> {\n    fn clone(&self) -> Self {\n        *self\n    }\n}\n\nimpl<T> Copy for ContextError<T> {}\n\nimpl<T> fmt::Debug for ContextError<T> {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.debug_tuple(\"ContextError\")\n            .field(&core::any::type_name::<T>())\n            .finish()\n    }\n}\n\nimpl<T> fmt::Display for ContextError<T> {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        f.write_str(&format!(\n            \"Context value not found for type: {}\",\n            core::any::type_name::<T>()\n        ))\n    }\n}\n\n/// Use a context value of type `T`.\n///\n/// This context must have already been provided by a parent composable with [`use_provider`],\n/// otherwise this function will return a [`ContextError`].\npub fn use_context<T: 'static>(cx: ScopeState<'_>) -> Result<&Rc<T>, ContextError<T>> {\n    let result = use_ref(cx, || {\n        let Some(any) = cx.contexts.borrow().values.get(&TypeId::of::<T>()).cloned() else {\n            return Err(ContextError {\n                _marker: PhantomData,\n            });\n        };\n\n        let value: Rc<T> = Rc::downcast(any).unwrap();\n        Ok(value)\n    });\n\n    result.as_ref().map_err(|e| *e)\n}\n\n/// Provide a context value of type `T`.\n///\n/// This value will be available to [`use_context`] to all children of this composable.\npub fn use_provider<T: 'static>(cx: ScopeState<'_>, make_value: impl FnOnce() -> T) -> &Rc<T> {\n    use_ref(cx, || {\n        let value = Rc::new(make_value());\n        cx.child_contexts\n            .borrow_mut()\n            .values\n            .insert(TypeId::of::<T>(), value.clone());\n        value\n    })\n}\n\n/// Generational reference.\n/// This can be used to compare expensive values by pointer equality.\n///\n/// This trait is implemented for:\n/// - [`Signal`]\n/// - [`Map`]\n/// - [`SignalMut`]\npub trait Generational {\n    /// Get the current generation of this value.\n    fn generation(self) -> u64;\n}\n\nimpl<T> Generational for Signal<'_, T> {\n    fn generation(self) -> u64 {\n        // Safety: This pointer is valid for `'a`.\n        unsafe { &*self.generation }.get()\n    }\n}\n\nimpl<T> Generational for Map<'_, T> {\n    fn generation(self) -> u64 {\n        // Safety: This pointer is valid for `'a`.\n        unsafe { &*self.generation }.get()\n    }\n}\n\nimpl<T> Generational for SignalMut<'_, T> {\n    fn generation(self) -> u64 {\n        // Safety: This pointer is valid for `'a`.\n        unsafe { &*self.generation }.get()\n    }\n}\n\n/// Use an effect that will run whenever the provided dependency is changed.\npub fn use_effect<D, T>(cx: ScopeState<'_>, dependency: D, effect: impl FnOnce(&D))\nwhere\n    D: PartialEq + Send + 'static,\n{\n    let mut dependency_cell = Some(dependency);\n\n    let last_mut = use_mut(cx, || dependency_cell.take().unwrap());\n\n    if let Some(dependency) = dependency_cell.take() {\n        if dependency != *last_mut {\n            effect(&dependency);\n\n            SignalMut::set(last_mut, dependency);\n        }\n    } else {\n        effect(&last_mut);\n    }\n}\n\n/// Use a memoized value of type `T` with a dependency of type `D`.\n///\n/// `make_value` will update the returned value whenver `dependency` is changed.\npub fn use_memo<D, T>(\n    cx: ScopeState<'_>,\n    dependency: D,\n    make_value: impl FnOnce() -> T,\n) -> Signal<'_, T>\nwhere\n    D: PartialEq + Send + 'static,\n    T: Send + 'static,\n{\n    let mut dependency_cell = Some(dependency);\n    let mut make_value_cell = Some(make_value);\n\n    let value_mut = use_mut(cx, || make_value_cell.take().unwrap()());\n    let last_mut = use_mut(cx, || dependency_cell.take().unwrap());\n\n    if let Some(make_value) = make_value_cell {\n        if let Some(dependency) = dependency_cell.take() {\n            if dependency != *last_mut {\n                let value = make_value();\n                SignalMut::with(value_mut, move |update| *update = value);\n\n                SignalMut::with(last_mut, move |dst| *dst = dependency);\n            }\n        }\n    }\n\n    SignalMut::as_ref(value_mut)\n}\n\n/// Use a function that will be called when this scope is dropped.\npub fn use_drop<'a>(cx: ScopeState<'a>, f: impl FnOnce() + 'a) {\n    let mut f_cell = Some(f);\n\n    let cell = use_ref(cx, || {\n        let f: Box<dyn FnOnce()> = Box::new(f_cell.take().unwrap());\n\n        // Safety `f` is guranteed to live as long as `cx`.\n        let f: Box<dyn FnOnce()> = unsafe { mem::transmute(f) };\n\n        RefCell::new(Some(f))\n    });\n\n    let idx = cx.hook_idx.get();\n    use_ref(cx, || {\n        cx.drops.borrow_mut().push(idx);\n\n        let f: Box<dyn FnMut()> = Box::new(move || {\n            cell.borrow_mut().take().unwrap()();\n        });\n\n        // Safety `f` is guranteed to live as long as `cx`.\n        let f: Box<dyn FnMut()> = unsafe { mem::transmute(f) };\n        f\n    });\n\n    if let Some(f) = f_cell {\n        let f: Box<dyn FnOnce()> = Box::new(f);\n\n        // Safety `f` is guranteed to live as long as `cx`.\n        let f: Box<dyn FnOnce()> = unsafe { mem::transmute(f) };\n\n        *cell.borrow_mut() = Some(f);\n    }\n}\n\n/// Use a local task that runs on the current thread.\n///\n/// This will run on the window event loop, polling the task until it completes.\n///\n/// # Examples\n///\n/// Sending child state to parents.\n///\n/// ```\n/// use actuate::prelude::*;\n/// use tokio::sync::mpsc;\n/// use std::cell::Cell;\n///\n/// #[derive(Data)]\n/// struct Child<'a> {\n///     idx: usize,\n///     tx: &'a mpsc::UnboundedSender<usize>,\n/// }\n///\n/// impl Compose for Child<'_> {\n///     fn compose(cx: Scope<Self>) -> impl Compose {\n///         cx.me().tx.send(cx.me().idx).unwrap();  \n///     }\n/// }\n///\n/// #[derive(Data)]\n/// struct App;\n///\n/// impl Compose for App {\n///     fn compose(cx: Scope<Self>) -> impl Compose {\n///         let (tx, ref rx_cell) = use_ref(&cx, || {\n///         let (tx, rx) = mpsc::unbounded_channel();\n///             (tx, Cell::new(Some(rx)))\n///         });\n///\n///         use_local_task(&cx, move || async move {\n///             let mut rx = rx_cell.take().unwrap();\n///             while let Some(id) = rx.recv().await {\n///                 dbg!(\"Composed: {}\", id);\n///             }\n///         });\n///\n///         (\n///             Child { idx: 0, tx },\n///             Child { idx: 1, tx }\n///         )\n///    }\n/// }\n/// ```\npub fn use_local_task<'a, F>(cx: ScopeState<'a>, make_task: impl FnOnce() -> F)\nwhere\n    F: Future<Output = ()> + 'a,\n{\n    let key = *use_ref(cx, || {\n        let task: Pin<Box<dyn Future<Output = ()>>> = Box::pin(make_task());\n        let task: Pin<Box<dyn Future<Output = ()>>> = unsafe { mem::transmute(task) };\n\n        let rt = Runtime::current();\n        let key = rt.tasks.borrow_mut().insert(task);\n        rt.task_queue.push(key);\n        key\n    });\n\n    use_drop(cx, move || {\n        Runtime::current().tasks.borrow_mut().remove(key);\n    })\n}\n\n#[cfg(feature = \"executor\")]\ntype BoxedFuture = Pin<Box<dyn Future<Output = ()> + Send>>;\n\n#[cfg(feature = \"executor\")]\nstruct TaskFuture {\n    task: alloc::sync::Arc<std::sync::Mutex<Option<BoxedFuture>>>,\n    rt: Runtime,\n}\n\n#[cfg(feature = \"executor\")]\nimpl Future for TaskFuture {\n    type Output = ();\n\n    fn poll(\n        mut self: Pin<&mut Self>,\n        cx: &mut std::task::Context,\n    ) -> std::task::Poll<Self::Output> {\n        let me = &mut *self;\n\n        // Lock the guard on this task.\n        // This is to ensure the scope for this task is not dropped while polling.\n        let mut guard = me.task.lock().unwrap();\n\n        if let Some(task) = &mut *guard {\n            me.rt.enter();\n\n            let _guard = Box::pin(me.rt.lock.read()).as_mut().poll(cx);\n\n            task.as_mut().poll(cx)\n        } else {\n            // The scope is dropped, we must complete this task early.\n            std::task::Poll::Ready(())\n        }\n    }\n}\n\n#[cfg(feature = \"executor\")]\nunsafe impl Send for TaskFuture {}\n\n#[cfg(feature = \"executor\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"executor\")))]\n/// Use a multi-threaded task that runs on a separate thread.\n///\n/// This will run on the current [`Executor`](`crate::executor::Executor`), polling the task until it completes.\n///\n/// # Examples\n///\n/// ```\n/// use actuate::prelude::*;\n/// use bevy::prelude::*;\n/// use serde::Deserialize;\n/// use std::collections::HashMap;\n///\n/// // Dog breed composable.\n/// #[derive(Data)]\n/// struct Breed {\n///     name: String,\n///     families: Vec<String>,\n/// }\n///\n/// impl Compose for Breed {\n///     fn compose(cx: Scope<Self>) -> impl Compose {\n///         container((\n///             text::headline(cx.me().name.to_owned()),\n///             compose::from_iter(cx.me().families.clone(), |family| {\n///                 text::label(family.to_string())\n///             }),\n///         ))\n///     }\n/// }\n///\n/// #[derive(Deserialize)]\n/// struct Response {\n///     message: HashMap<String, Vec<String>>,\n/// }\n///\n/// // Dog breed list composable.\n/// #[derive(Data)]\n/// struct BreedList;\n///\n/// impl Compose for BreedList {\n///     fn compose(cx: Scope<Self>) -> impl Compose {\n///         let breeds = use_mut(&cx, HashMap::new);\n///\n///         // Spawn a task that loads dog breeds from an HTTP API.\n///         use_task(&cx, move || async move {\n///             let json: Response = reqwest::get(\"https://dog.ceo/api/breeds/list/all\")\n///                 .await\n///                 .unwrap()\n///                 .json()\n///                 .await\n///                 .unwrap();\n///\n///             SignalMut::set(breeds, json.message);\n///         });\n///\n///         // Render the currently loaded breeds.\n///         scroll_view(compose::from_iter((*breeds).clone(), |breed| Breed {\n///             name: breed.0.clone(),\n///             families: breed.1.clone(),\n///         }))\n///         .flex_gap(Val::Px(30.))\n///     }\n/// }\n/// ```\npub fn use_task<'a, F>(cx: ScopeState<'a>, make_task: impl FnOnce() -> F)\nwhere\n    F: Future<Output = ()> + Send + 'a,\n{\n    let runtime_cx = use_context::<executor::ExecutorContext>(cx).unwrap();\n    let task_lock = use_ref(cx, || {\n        // Safety: `task`` is guaranteed to live as long as `cx`, and is disabled after the scope is dropped.\n        let task: Pin<Box<dyn Future<Output = ()> + Send>> = Box::pin(make_task());\n        let task: Pin<Box<dyn Future<Output = ()> + Send>> = unsafe { mem::transmute(task) };\n        let task_lock = std::sync::Arc::new(std::sync::Mutex::new(Some(task)));\n\n        runtime_cx.executor.spawn(Box::pin(TaskFuture {\n            task: task_lock.clone(),\n            rt: Runtime::current(),\n        }));\n\n        task_lock\n    });\n\n    // Disable this task after the scope is dropped.\n    use_drop(cx, || {\n        *task_lock.lock().unwrap() = None;\n    });\n}\n"
  },
  {
    "path": "src/ui/material/button.rs",
    "content": "use super::{container, Theme};\nuse crate::{\n    compose::Compose,\n    ecs::{Modifier, Modify},\n    use_context, Data, Scope, Signal,\n};\nuse bevy_color::Color;\nuse bevy_ui::{BorderRadius, Node, UiRect, Val};\n\n/// Create a material UI button.\npub fn button<'a, C>(content: C) -> Button<'a, C> {\n    Button {\n        content,\n        background_color: None,\n        elevation: 0.,\n        height: Val::Px(40.),\n        padding: UiRect::left(Val::Px(24.)).with_right(Val::Px(24.)),\n        modifier: Modifier::default(),\n    }\n}\n\n/// Material UI button.\n#[derive(Clone, Debug, Data)]\n#[actuate(path = \"crate\")]\npub struct Button<'a, C> {\n    content: C,\n    background_color: Option<Color>,\n    padding: UiRect,\n    height: Val,\n    elevation: f32,\n    modifier: Modifier<'a>,\n}\n\nimpl<'a, C> Button<'a, C> {\n    /// Set the background color of this button.\n    pub fn background_color(mut self, background_color: Color) -> Self {\n        self.background_color = Some(background_color);\n        self\n    }\n\n    /// Set the elevation of this button.\n    pub fn elevation(mut self, elevation: f32) -> Self {\n        self.elevation = elevation;\n        self\n    }\n\n    /// Set the padding of this button.\n    pub fn padding(mut self, padding: UiRect) -> Self {\n        self.padding = padding;\n        self\n    }\n}\n\nimpl<C: Compose> Compose for Button<'_, C> {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        let theme = use_context::<Theme>(&cx).cloned().unwrap_or_default();\n\n        container(unsafe { Signal::map_unchecked(cx.me(), |me| &me.content) })\n            .background_color(cx.me().background_color.unwrap_or(theme.colors.primary))\n            .border_radius(\n                BorderRadius::all(Val::Px(10.))\n                    .with_left(Val::Px(20.))\n                    .with_right(Val::Px(20.)),\n            )\n            .on_insert(move |mut entity| {\n                let mut node = entity.get_mut::<Node>().unwrap();\n                node.height = cx.me().height;\n            })\n            .append(Signal::map(cx.me(), |me| &me.modifier).into())\n    }\n}\n\nimpl<'a, C: Compose> Modify<'a> for Button<'a, C> {\n    fn modifier(&mut self) -> &mut Modifier<'a> {\n        &mut self.modifier\n    }\n}\n"
  },
  {
    "path": "src/ui/material/container.rs",
    "content": "use super::Theme;\nuse crate::{\n    compose::Compose,\n    ecs::spawn,\n    ecs::{Modifier, Modify},\n    use_context, Data, Scope, Signal,\n};\nuse bevy_color::Color;\nuse bevy_ui::{\n    AlignItems, BackgroundColor, BorderRadius, BoxShadow, FlexDirection, JustifyContent, Node,\n    Overflow, UiRect, Val,\n};\n\n/// Create a material UI container.\npub fn container<'a, C>(content: C) -> Container<'a, C> {\n    Container {\n        content,\n        elevation: 0.,\n        padding: UiRect::all(Val::Px(12.))\n            .with_left(Val::Px(24.))\n            .with_right(Val::Px(24.)),\n        background_color: None,\n        border_radius: BorderRadius::all(Val::Px(12.)),\n        modifier: Modifier::default(),\n    }\n}\n\n/// Material UI container.\n///\n/// For more see [`container`].\n#[derive(Clone, Debug, Data)]\n#[actuate(path = \"crate\")]\npub struct Container<'a, C> {\n    content: C,\n    padding: UiRect,\n    elevation: f32,\n    modifier: Modifier<'a>,\n    background_color: Option<Color>,\n    border_radius: BorderRadius,\n}\n\nimpl<'a, C> Container<'a, C> {\n    /// Set the background color of this button.\n    pub fn background_color(mut self, background_color: Color) -> Self {\n        self.background_color = Some(background_color);\n        self\n    }\n\n    /// Set the border radius of this button.\n    pub fn border_radius(mut self, border_radius: BorderRadius) -> Self {\n        self.border_radius = border_radius;\n        self\n    }\n\n    /// Set the elevation of this button.\n    pub fn elevation(mut self, elevation: f32) -> Self {\n        self.elevation = elevation;\n        self\n    }\n\n    /// Set the padding of this button.\n    pub fn padding(mut self, padding: UiRect) -> Self {\n        self.padding = padding;\n        self\n    }\n}\n\nimpl<C: Compose> Compose for Container<'_, C> {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        let theme = use_context::<Theme>(&cx).cloned().unwrap_or_default();\n\n        cx.me()\n            .modifier\n            .apply(spawn((\n                Node {\n                    flex_direction: FlexDirection::Column,\n                    justify_content: JustifyContent::Center,\n                    align_items: AlignItems::Center,\n                    padding: cx.me().padding,\n                    overflow: Overflow::clip(),\n                    ..Default::default()\n                },\n                cx.me().border_radius,\n                BackgroundColor(\n                    cx.me()\n                        .background_color\n                        .unwrap_or(theme.colors.surface_container),\n                ),\n                BoxShadow::new(\n                    Color::srgba(0., 0., 0., 0.12 * cx.me().elevation),\n                    Val::Px(0.),\n                    Val::Px(1.),\n                    Val::Px(0.),\n                    Val::Px(3. * cx.me().elevation),\n                ),\n            )))\n            .content(unsafe { Signal::map_unchecked(cx.me(), |me| &me.content) })\n    }\n}\n\nimpl<'a, C: Compose> Modify<'a> for Container<'a, C> {\n    fn modifier(&mut self) -> &mut Modifier<'a> {\n        &mut self.modifier\n    }\n}\n"
  },
  {
    "path": "src/ui/material/mod.rs",
    "content": "use bevy_color::Color;\nuse std::ops::Index;\n\nmod button;\npub use self::button::{button, Button};\n\nmod container;\npub use self::container::{container, Container};\n\nmod radio;\npub use self::radio::{radio_button, RadioButton};\n\nmod ui;\npub use self::ui::{material_ui, MaterialUi};\n\n/// Text composables.\npub mod text;\n\n/// Colors for a [`MaterialTheme`].\n#[derive(Clone, PartialEq)]\npub struct Colors {\n    /// Background color.\n    pub background: Color,\n\n    /// Primary color.\n    pub primary: Color,\n\n    /// Surface container color.\n    pub surface_container: Color,\n\n    /// Text color.\n    pub text: Color,\n}\n\n/// Typography style.\n#[derive(Clone, PartialEq)]\npub struct TypographyStyle {\n    /// Font size.\n    pub font_size: f32,\n\n    /// Font weight.\n    pub font_weight: f32,\n\n    /// Line height.\n    pub line_height: f32,\n}\n\n/// Typography style kind.\n#[derive(Clone, Copy, PartialEq, Eq)]\npub enum TypographyStyleKind {\n    /// Small typography style.\n    Small,\n\n    /// Medium typography style.\n    Medium,\n\n    /// Large typography style.\n    Large,\n}\n\n/// Typography design token.\n#[derive(Clone, PartialEq)]\npub struct TypographyToken {\n    /// Small typography style.\n    pub small: TypographyStyle,\n\n    /// Medium typography style.\n    pub medium: TypographyStyle,\n\n    /// Large typography style.\n    pub large: TypographyStyle,\n}\n\nimpl Index<TypographyStyleKind> for TypographyToken {\n    type Output = TypographyStyle;\n\n    fn index(&self, index: TypographyStyleKind) -> &Self::Output {\n        match index {\n            TypographyStyleKind::Small => &self.small,\n            TypographyStyleKind::Medium => &self.medium,\n            TypographyStyleKind::Large => &self.large,\n        }\n    }\n}\n\n/// Typography kind.\n#[derive(Clone, Copy)]\npub enum TypographyKind {\n    /// Body typography.\n    Body,\n\n    /// Headline typography.\n    Headline,\n\n    /// Label typography.\n    Label,\n\n    /// Title typography.\n    Title,\n}\n\n/// Typography for a [`MaterialTheme`].\n#[derive(Clone, PartialEq)]\npub struct Typography {\n    /// Body typography.\n    pub body: TypographyToken,\n\n    /// Headline typography.\n    pub headline: TypographyToken,\n\n    /// Label typography.\n    pub label: TypographyToken,\n\n    /// Title typography.\n    pub title: TypographyToken,\n}\n\nimpl Index<TypographyKind> for Typography {\n    type Output = TypographyToken;\n\n    fn index(&self, index: TypographyKind) -> &Self::Output {\n        match index {\n            TypographyKind::Body => &self.body,\n            TypographyKind::Headline => &self.headline,\n            TypographyKind::Label => &self.label,\n            TypographyKind::Title => &self.title,\n        }\n    }\n}\n\n/// Material UI theme.\n#[derive(Clone, PartialEq)]\npub struct Theme {\n    /// Theme colors.\n    pub colors: Colors,\n\n    /// Theme typography.\n    pub typography: Typography,\n}\n\nimpl Default for Theme {\n    fn default() -> Self {\n        Self {\n            colors: Colors {\n                background: Color::WHITE,\n                primary: Color::srgb_u8(103, 80, 164),\n                surface_container: Color::srgb_u8(230, 224, 233),\n                text: Color::BLACK,\n            },\n            typography: Typography {\n                body: TypographyToken {\n                    small: TypographyStyle {\n                        font_size: 12.,\n                        font_weight: 400.,\n                        line_height: 16.,\n                    },\n                    medium: TypographyStyle {\n                        font_size: 14.,\n                        font_weight: 400.,\n                        line_height: 20.,\n                    },\n                    large: TypographyStyle {\n                        font_size: 16.,\n                        font_weight: 400.,\n                        line_height: 24.,\n                    },\n                },\n                headline: TypographyToken {\n                    small: TypographyStyle {\n                        font_size: 24.,\n                        font_weight: 400.,\n                        line_height: 32.,\n                    },\n                    medium: TypographyStyle {\n                        font_size: 28.,\n                        font_weight: 400.,\n                        line_height: 36.,\n                    },\n                    large: TypographyStyle {\n                        font_size: 32.,\n                        font_weight: 400.,\n                        line_height: 40.,\n                    },\n                },\n                label: TypographyToken {\n                    small: TypographyStyle {\n                        font_size: 11.,\n                        font_weight: 500.,\n                        line_height: 16.,\n                    },\n                    medium: TypographyStyle {\n                        font_size: 12.,\n                        font_weight: 500.,\n                        line_height: 16.,\n                    },\n                    large: TypographyStyle {\n                        font_size: 14.,\n                        font_weight: 500.,\n                        line_height: 20.,\n                    },\n                },\n                title: TypographyToken {\n                    small: TypographyStyle {\n                        font_size: 14.,\n                        font_weight: 500.,\n                        line_height: 20.,\n                    },\n                    medium: TypographyStyle {\n                        font_size: 16.,\n                        font_weight: 500.,\n                        line_height: 24.,\n                    },\n                    large: TypographyStyle {\n                        font_size: 22.,\n                        font_weight: 400.,\n                        line_height: 28.,\n                    },\n                },\n            },\n        }\n    }\n}\n"
  },
  {
    "path": "src/ui/material/radio.rs",
    "content": "use super::Theme;\nuse crate::{\n    compose::Compose,\n    ecs::spawn,\n    ecs::{Modifier, Modify},\n    use_context, Data, Scope,\n};\nuse bevy_color::Color;\nuse bevy_ui::{BackgroundColor, BorderColor, BorderRadius, BoxShadow, Node, UiRect, Val};\n\n/// Create a material UI radio button.\npub fn radio_button<'a>() -> RadioButton<'a> {\n    RadioButton {\n        is_enabled: true,\n        inner_radius: 10.,\n        outer_radius: 20.,\n        border_width: 2.,\n        elevation: 0.,\n        modifier: Modifier::default(),\n    }\n}\n\n/// Material UI radio button.\n#[derive(Clone, Debug, Data)]\n#[actuate(path = \"crate\")]\npub struct RadioButton<'a> {\n    is_enabled: bool,\n    inner_radius: f32,\n    outer_radius: f32,\n    border_width: f32,\n    elevation: f32,\n    modifier: Modifier<'a>,\n}\n\nimpl RadioButton<'_> {\n    /// Set the enabled state of this radio button.\n    pub fn is_enabled(mut self, is_enabled: bool) -> Self {\n        self.is_enabled = is_enabled;\n        self\n    }\n\n    /// Set the inner radius of this radio button.\n    pub fn inner_radius(mut self, inner_radius: f32) -> Self {\n        self.inner_radius = inner_radius;\n        self\n    }\n\n    /// Set the outer radius of this radio button.\n    pub fn outer_radius(mut self, outer_radius: f32) -> Self {\n        self.outer_radius = outer_radius;\n        self\n    }\n\n    /// Set the border width of this radio button.\n    pub fn border_width(mut self, border_width: f32) -> Self {\n        self.border_width = border_width;\n        self\n    }\n\n    /// Set the elevation of this radio button.\n    pub fn elevation(mut self, elevation: f32) -> Self {\n        self.elevation = elevation;\n        self\n    }\n}\n\nimpl Compose for RadioButton<'_> {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        let theme = use_context::<Theme>(&cx).cloned().unwrap_or_default();\n\n        let size = Val::Px(cx.me().outer_radius * 2.);\n        let inner_size = Val::Px(cx.me().inner_radius * 2.);\n        let offset = Val::Px((cx.me().outer_radius - cx.me().inner_radius) - 2.);\n\n        cx.me()\n            .modifier\n            .apply(spawn((\n                Node {\n                    width: size,\n                    height: size,\n                    border: UiRect::all(Val::Px(cx.me().border_width)),\n                    ..Default::default()\n                },\n                BorderRadius::MAX,\n                BorderColor::all(theme.colors.primary),\n                BoxShadow::new(\n                    Color::srgba(0., 0., 0., 0.12 * cx.me().elevation),\n                    Val::Px(0.),\n                    Val::Px(1.),\n                    Val::Px(0.),\n                    Val::Px(3. * cx.me().elevation),\n                ),\n            )))\n            .content(if cx.me().is_enabled {\n                Some(spawn((\n                    Node {\n                        width: inner_size,\n                        height: inner_size,\n                        top: offset,\n                        left: offset,\n\n                        ..Default::default()\n                    },\n                    BackgroundColor(theme.colors.primary),\n                    BorderRadius::MAX,\n                )))\n            } else {\n                None\n            })\n    }\n}\n\nimpl<'a> Modify<'a> for RadioButton<'a> {\n    fn modifier(&mut self) -> &mut Modifier<'a> {\n        &mut self.modifier\n    }\n}\n"
  },
  {
    "path": "src/ui/material/text.rs",
    "content": "use super::{Theme, TypographyKind, TypographyStyleKind};\nuse crate::{\n    ecs::{spawn, Modifier, Modify},\n    prelude::Compose,\n    use_context,\n};\nuse actuate_macros::Data;\nuse bevy_text::{TextColor, TextFont};\nuse bevy_ui::prelude::Text as UiText;\n\n/// Create a material UI text body.\npub fn body<'a>(content: impl Into<String>) -> Text<'a> {\n    text(content).typography(TypographyKind::Body)\n}\n\n/// Create a material UI text headline.\npub fn headline<'a>(content: impl Into<String>) -> Text<'a> {\n    text(content).typography(TypographyKind::Headline)\n}\n\n/// Create a material UI text label.\npub fn label<'a>(content: impl Into<String>) -> Text<'a> {\n    text(content).typography(TypographyKind::Label)\n}\n\n/// Create a material UI text title.\npub fn title<'a>(content: impl Into<String>) -> Text<'a> {\n    text(content).typography(TypographyKind::Title)\n}\n\n/// Create a material UI text label.\npub fn text<'a>(content: impl Into<String>) -> Text<'a> {\n    Text {\n        content: content.into(),\n        modifier: Modifier::default(),\n        typography: TypographyKind::Label,\n        typography_style: TypographyStyleKind::Medium,\n    }\n}\n\n/// Material UI text composable.\n#[derive(Data)]\n#[actuate(path = \"crate\")]\npub struct Text<'a> {\n    content: String,\n    typography: TypographyKind,\n    typography_style: TypographyStyleKind,\n    modifier: Modifier<'a>,\n}\n\nimpl Text<'_> {\n    /// Set the typography of this text.\n    pub fn typography(mut self, typography: TypographyKind) -> Self {\n        self.typography = typography;\n        self\n    }\n\n    /// Set the typography style of this text.\n    pub fn typography_style(mut self, typography_style: TypographyStyleKind) -> Self {\n        self.typography_style = typography_style;\n        self\n    }\n}\n\nimpl Compose for Text<'_> {\n    fn compose(cx: crate::Scope<Self>) -> impl Compose {\n        let theme = use_context::<Theme>(&cx).cloned().unwrap_or_default();\n\n        let style = &theme.typography[cx.me().typography][cx.me().typography_style];\n\n        spawn((\n            UiText::new(cx.me().content.clone()),\n            TextColor(theme.colors.text),\n            TextFont {\n                font_size: style.font_size,\n                ..Default::default()\n            },\n        ))\n    }\n}\n\nimpl<'a> Modify<'a> for Text<'a> {\n    fn modifier(&mut self) -> &mut Modifier<'a> {\n        &mut self.modifier\n    }\n}\n"
  },
  {
    "path": "src/ui/material/ui.rs",
    "content": "use super::Theme;\nuse crate::{\n    ecs::{spawn, Modifier, Modify},\n    prelude::Compose,\n    use_provider, Scope, Signal,\n};\nuse actuate_macros::Data;\nuse bevy_ui::{BackgroundColor, FlexDirection, Node, Val};\n\n/// Create a material UI composable.\n///\n/// This will provide a [`Theme`] and set the background for its content.\npub fn material_ui<'a, C: Compose>(content: C) -> MaterialUi<'a, C> {\n    MaterialUi {\n        content,\n        theme: Theme::default(),\n        modifier: Modifier::default(),\n    }\n}\n\n/// Material UI composable.\n///\n/// For more see [`material_ui`].\n#[derive(Data)]\n#[actuate(path = \"crate\")]\npub struct MaterialUi<'a, C> {\n    content: C,\n    theme: Theme,\n    modifier: Modifier<'a>,\n}\n\nimpl<'a, C> MaterialUi<'a, C> {\n    /// Set the theme of this composable.\n    pub fn theme(mut self, theme: Theme) -> Self {\n        self.theme = theme;\n        self\n    }\n}\n\nimpl<'a, C: Compose> Compose for MaterialUi<'a, C> {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        let theme = use_provider(&cx, || cx.me().theme.clone());\n\n        cx.me()\n            .modifier\n            .apply(spawn((\n                Node {\n                    flex_direction: FlexDirection::Column,\n                    width: Val::Percent(100.),\n                    height: Val::Percent(100.),\n                    ..Default::default()\n                },\n                BackgroundColor(theme.colors.background),\n            )))\n            .content(unsafe { Signal::map_unchecked(cx.me(), |me| &me.content) })\n    }\n}\n\nimpl<'a, C> Modify<'a> for MaterialUi<'a, C> {\n    fn modifier(&mut self) -> &mut Modifier<'a> {\n        &mut self.modifier\n    }\n}\n"
  },
  {
    "path": "src/ui/mod.rs",
    "content": "use crate::{\n    ecs::{spawn, use_world, Modifier, Modify},\n    prelude::Compose,\n    use_mut, Scope, Signal, SignalMut,\n};\nuse actuate_macros::Data;\nuse bevy_ecs::prelude::*;\nuse bevy_input::{\n    mouse::{MouseScrollUnit, MouseWheel},\n    prelude::*,\n};\nuse bevy_picking::prelude::*;\nuse bevy_ui::prelude::*;\nuse std::mem;\n\n#[cfg(feature = \"material\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"material\")))]\n/// Material UI.\npub mod material;\n\n/// Create a scroll view.\npub fn scroll_view<'a, C: Compose>(content: C) -> ScrollView<'a, C> {\n    ScrollView {\n        content,\n        line_size: 30.,\n        modifier: Modifier::default(),\n        scroll_x: true,\n        scroll_y: true,\n    }\n}\n\n#[derive(Data)]\n#[actuate(path = \"crate\")]\n/// Scroll view composable.\npub struct ScrollView<'a, C> {\n    content: C,\n    line_size: f32,\n    scroll_x: bool,\n    scroll_y: bool,\n    modifier: Modifier<'a>,\n}\n\nimpl<C> ScrollView<'_, C> {\n    /// Set the line size to scroll (default: 30).\n    pub fn line_size(mut self, size: f32) -> Self {\n        self.line_size = size;\n        self\n    }\n\n    /// Enable or disable horizontal scrolling (default: true).\n    pub fn scroll_x(mut self, scroll_x: bool) -> Self {\n        self.scroll_x = scroll_x;\n        self\n    }\n\n    /// Enable or disable vertical scrolling (default: true).\n    pub fn scroll_y(mut self, scroll_y: bool) -> Self {\n        self.scroll_y = scroll_y;\n        self\n    }\n}\n\nimpl<C: Compose> Compose for ScrollView<'_, C> {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        let is_hovered = use_mut(&cx, || false);\n\n        let entity_cell = use_mut(&cx, || None);\n\n        use_world(\n            &cx,\n            move |mut mouse_wheel_events: MessageReader<MouseWheel>,\n                  mut scrolled_node_query: Query<&mut ScrollPosition>,\n                  keyboard_input: Res<ButtonInput<KeyCode>>| {\n                for mouse_wheel_event in mouse_wheel_events.read() {\n                    let (mut dx, mut dy) = match mouse_wheel_event.unit {\n                        MouseScrollUnit::Line => (\n                            mouse_wheel_event.x * cx.me().line_size,\n                            mouse_wheel_event.y * cx.me().line_size,\n                        ),\n                        MouseScrollUnit::Pixel => (mouse_wheel_event.x, mouse_wheel_event.y),\n                    };\n\n                    if cx.me().scroll_x\n                        && cx.me().scroll_y\n                        && (keyboard_input.pressed(KeyCode::ControlLeft)\n                            || keyboard_input.pressed(KeyCode::ControlRight))\n                    {\n                        std::mem::swap(&mut dx, &mut dy)\n                    }\n\n                    if *is_hovered {\n                        if let Some(entity) = *entity_cell {\n                            if let Ok(mut scroll_position) = scrolled_node_query.get_mut(entity) {\n                                if cx.me().scroll_x {\n                                    scroll_position.x -= dx;\n                                }\n\n                                if cx.me().scroll_y {\n                                    scroll_position.y -= dy;\n                                }\n                            }\n                        }\n                    }\n                }\n            },\n        );\n\n        let modifier = &cx.me().modifier;\n        let modifier: &Modifier = unsafe { mem::transmute(modifier) };\n\n        modifier\n            .apply(\n                spawn(Node {\n                    flex_direction: FlexDirection::Column,\n                    overflow: Overflow::scroll_y(),\n                    ..Default::default()\n                })\n                .on_spawn(move |entity| SignalMut::set(entity_cell, Some(entity.id())))\n                .observe(move |_: On<Pointer<Over>>| SignalMut::set(is_hovered, true))\n                .observe(move |_: On<Pointer<Out>>| SignalMut::set(is_hovered, false)),\n            )\n            .content(unsafe { Signal::map_unchecked(cx.me(), |me| &me.content) })\n    }\n}\n\nimpl<'a, C: Compose> Modify<'a> for ScrollView<'a, C> {\n    fn modifier(&mut self) -> &mut Modifier<'a> {\n        &mut self.modifier\n    }\n}\n"
  },
  {
    "path": "tests/composer.rs",
    "content": "use actuate::{\n    composer::{Composer, TryComposeError},\n    prelude::*,\n};\nuse std::{\n    cell::{Cell, RefCell},\n    rc::Rc,\n};\n\n#[derive(Data)]\nstruct Counter {\n    x: Rc<Cell<i32>>,\n}\n\nimpl Compose for Counter {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        let updater = use_mut(&cx, || ());\n        SignalMut::set(updater, ());\n\n        cx.me().x.set(cx.me().x.get() + 1);\n    }\n}\n\n#[derive(Data)]\nstruct NonUpdateCounter {\n    x: Rc<Cell<i32>>,\n}\n\nimpl Compose for NonUpdateCounter {\n    fn compose(cx: Scope<Self>) -> impl Compose {\n        cx.me().x.set(cx.me().x.get() + 1);\n    }\n}\n\n#[test]\nfn it_composes() {\n    #[derive(Data)]\n    struct Wrap {\n        x: Rc<Cell<i32>>,\n    }\n\n    impl Compose for Wrap {\n        fn compose(cx: Scope<Self>) -> impl Compose {\n            Counter {\n                x: cx.me().x.clone(),\n            }\n        }\n    }\n\n    let x = Rc::new(Cell::new(0));\n    let mut composer = Composer::new(Wrap { x: x.clone() });\n\n    composer.try_compose().unwrap();\n    assert_eq!(x.get(), 1);\n\n    composer.try_compose().unwrap();\n    assert_eq!(x.get(), 2);\n}\n\n#[test]\nfn it_composes_depth_first() {\n    let a = Rc::new(Cell::new(0));\n    let out = a.clone();\n\n    let mut composer = Composer::new(compose::from_fn(move |_| {\n        a.set(0);\n\n        let b = a.clone();\n        let e = a.clone();\n\n        (\n            compose::from_fn(move |_| {\n                b.set(1);\n\n                let c = b.clone();\n                let d = b.clone();\n\n                (\n                    compose::from_fn(move |_| c.set(2)),\n                    compose::from_fn(move |_| d.set(3)),\n                )\n            }),\n            compose::from_fn(move |_| {\n                e.set(4);\n\n                let f = e.clone();\n                let g = e.clone();\n\n                (\n                    compose::from_fn(move |_| f.set(5)),\n                    compose::from_fn(move |_| g.set(6)),\n                )\n            }),\n        )\n    }));\n\n    composer.next().unwrap().unwrap();\n    assert_eq!(out.get(), 0);\n\n    // Compose (1, 4)\n    composer.next().unwrap().unwrap();\n\n    composer.next().unwrap().unwrap();\n    assert_eq!(out.get(), 1);\n\n    // Compose (2, 3)\n    composer.next().unwrap().unwrap();\n    composer.next().unwrap().unwrap();\n    assert_eq!(out.get(), 2);\n\n    composer.next().unwrap().unwrap();\n    assert_eq!(out.get(), 3);\n\n    composer.next().unwrap().unwrap();\n    assert_eq!(out.get(), 4);\n\n    // Compose (5, 6)\n    composer.next().unwrap().unwrap();\n\n    composer.next().unwrap().unwrap();\n    assert_eq!(out.get(), 5);\n\n    composer.next().unwrap().unwrap();\n    assert_eq!(out.get(), 6);\n}\n\n#[test]\nfn it_skips_recomposes() {\n    #[derive(Data)]\n    struct Wrap {\n        x: Rc<Cell<i32>>,\n    }\n\n    impl Compose for Wrap {\n        fn compose(cx: Scope<Self>) -> impl Compose {\n            NonUpdateCounter {\n                x: cx.me().x.clone(),\n            }\n        }\n    }\n\n    let x = Rc::new(Cell::new(0));\n    let mut composer = Composer::new(Wrap { x: x.clone() });\n\n    composer.try_compose().unwrap();\n    assert_eq!(x.get(), 1);\n\n    assert_eq!(composer.try_compose(), Err(TryComposeError::Pending));\n    assert_eq!(x.get(), 1);\n}\n\n#[test]\nfn it_composes_dyn_compose() {\n    #[derive(Data)]\n    struct Wrap {\n        x: Rc<Cell<i32>>,\n    }\n\n    impl Compose for Wrap {\n        fn compose(cx: crate::Scope<Self>) -> impl Compose {\n            dyn_compose(Counter {\n                x: cx.me().x.clone(),\n            })\n        }\n    }\n\n    let x = Rc::new(Cell::new(0));\n    let mut composer = Composer::new(Wrap { x: x.clone() });\n\n    composer.try_compose().unwrap();\n    assert_eq!(x.get(), 1);\n\n    composer.try_compose().unwrap();\n    assert_eq!(x.get(), 2);\n}\n\n#[test]\nfn it_composes_from_iter() {\n    #[derive(Data)]\n    struct Wrap {\n        x: Rc<Cell<i32>>,\n    }\n\n    impl Compose for Wrap {\n        fn compose(cx: crate::Scope<Self>) -> impl Compose {\n            compose::from_iter(0..2, move |_| Counter {\n                x: cx.me().x.clone(),\n            })\n        }\n    }\n\n    let x = Rc::new(Cell::new(0));\n    let mut composer = Composer::new(Wrap { x: x.clone() });\n\n    composer.try_compose().unwrap();\n    assert_eq!(x.get(), 2);\n\n    composer.try_compose().unwrap();\n    assert_eq!(x.get(), 4);\n}\n\n#[test]\nfn it_composes_memo() {\n    #[derive(Data)]\n    struct B {\n        x: Rc<RefCell<i32>>,\n    }\n\n    impl Compose for B {\n        fn compose(cx: Scope<Self>) -> impl Compose {\n            *cx.me().x.borrow_mut() += 1;\n        }\n    }\n\n    #[derive(Data)]\n    struct A {\n        x: Rc<RefCell<i32>>,\n    }\n\n    impl Compose for A {\n        fn compose(cx: Scope<Self>) -> impl Compose {\n            let x = cx.me().x.clone();\n            memo((), B { x })\n        }\n    }\n\n    let x = Rc::new(RefCell::new(0));\n    let mut composer = Composer::new(A { x: x.clone() });\n\n    composer.try_compose().unwrap();\n    assert_eq!(*x.borrow(), 1);\n\n    assert_eq!(composer.try_compose(), Err(TryComposeError::Pending));\n    assert_eq!(*x.borrow(), 1);\n}\n"
  }
]