bevy/crates/bevy_ecs/src
Gino Valente df61117850
bevy_reflect: Function registry (#14098)
# Objective

#13152 added support for reflecting functions. Now, we need a way to
register those functions such that they may be accessed anywhere within
the ECS.

## Solution

Added a `FunctionRegistry` type similar to `TypeRegistry`.

This allows a function to be registered and retrieved by name.

```rust
fn foo() -> i32 {
    123
}

let mut registry = FunctionRegistry::default();
registry.register("my_function", foo);

let function = registry.get_mut("my_function").unwrap();
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
assert_eq!(value.downcast_ref::<i32>(), Some(&123));
```

Additionally, I added an `AppFunctionRegistry` resource which wraps a
`FunctionRegistryArc`. Functions can be registered into this resource
using `App::register_function` or by getting a mutable reference to the
resource itself.

### Limitations

#### `Send + Sync`

In order to get this registry to work across threads, it needs to be
`Send + Sync`. This means that `DynamicFunction` needs to be `Send +
Sync`, which means that its internal function also needs to be `Send +
Sync`.

In most cases, this won't be an issue because standard Rust functions
(the type most likely to be registered) are always `Send + Sync`.
Additionally, closures tend to be `Send + Sync` as well, granted they
don't capture any `!Send` or `!Sync` variables.

This PR adds this `Send + Sync` requirement, but as mentioned above, it
hopefully shouldn't be too big of an issue.

#### Closures

Unfortunately, closures can't be registered yet. This will likely be
explored and added in a followup PR.

### Future Work

Besides addressing the limitations listed above, another thing we could
look into is improving the lookup of registered functions. One aspect is
in the performance of hashing strings. The other is in the developer
experience of having to call `std::any::type_name_of_val` to get the
name of their function (assuming they didn't give it a custom name).

## Testing

You can run the tests locally with:

```
cargo test --package bevy_reflect
```

---

## Changelog

- Added `FunctionRegistry`
- Added `AppFunctionRegistry` (a `Resource` available from `bevy_ecs`)
- Added `FunctionRegistryArc`
- Added `FunctionRegistrationError`
- Added `reflect_functions` feature to `bevy_ecs` and `bevy_app`
- `FunctionInfo` is no longer `Default`
- `DynamicFunction` now requires its wrapped function be `Send + Sync`

## Internal Migration Guide

> [!important]
> Function reflection was introduced as part of the 0.15 dev cycle. This
migration guide was written for developers relying on `main` during this
cycle, and is not a breaking change coming from 0.14.

`DynamicFunction` (both those created manually and those created with
`IntoFunction`), now require `Send + Sync`. All standard Rust functions
should meet that requirement. Closures, on the other hand, may not if
they capture any `!Send` or `!Sync` variables from its environment.
2024-08-06 01:09:48 +00:00
..
entity Fix Entity Debug Format (#14539) 2024-07-31 01:36:41 +00:00
event Minimal Bubbling Observers (#13991) 2024-07-15 13:39:41 +00:00
identifier feat: Reflection implementations on Identifier (#13648) 2024-06-03 16:33:14 +00:00
observer Make QueryState::transmute&co validate the world of the &Components used (#14631) 2024-08-05 22:39:31 +00:00
query Add a ComponentIndex and update QueryState creation/update to use it (#13460) 2024-08-06 00:57:15 +00:00
reflect bevy_reflect: Function registry (#14098) 2024-08-06 01:09:48 +00:00
schedule Fix common capitalization errors in documentation (#14562) 2024-07-31 21:16:05 +00:00
storage Track source location in change detection (#14034) 2024-07-30 12:02:38 +00:00
system Make QueryState::transmute&co validate the world of the &Components used (#14631) 2024-08-05 22:39:31 +00:00
world Make QueryState::transmute&co validate the world of the &Components used (#14631) 2024-08-05 22:39:31 +00:00
archetype.rs Add a ComponentIndex and update QueryState creation/update to use it (#13460) 2024-08-06 00:57:15 +00:00
batching.rs Parallel event reader (#12554) 2024-04-22 16:37:42 +00:00
bundle.rs Track source location in change detection (#14034) 2024-07-30 12:02:38 +00:00
change_detection.rs Track source location in change detection (#14034) 2024-07-30 12:02:38 +00:00
component.rs Component Lifecycle Hook & Observer Trigger for replaced values (#14212) 2024-07-15 15:24:15 +00:00
intern.rs Moves intern and label modules into bevy_ecs (#12772) 2024-04-08 15:34:11 +00:00
label.rs Add mappings to EntityMapper (#13727) 2024-06-08 12:52:23 +00:00
lib.rs bevy_reflect: Function registry (#14098) 2024-08-06 01:09:48 +00:00
removal_detection.rs Created an EventMutator for when you want to mutate an event before reading (#13818) 2024-07-08 14:53:06 +00:00
traversal.rs Minimal Bubbling Observers (#13991) 2024-07-15 13:39:41 +00:00