![]() # Objective Currently, the observer API looks like this: ```rust app.add_observer(|trigger: Trigger<Explode>| { info!("Entity {} exploded!", trigger.target()); }); ``` Future plans for observers also include "multi-event observers" with a trigger that looks like this (see [Cart's example](https://github.com/bevyengine/bevy/issues/14649#issuecomment-2960402508)): ```rust trigger: Trigger<( OnAdd<Pressed>, OnRemove<Pressed>, OnAdd<InteractionDisabled>, OnRemove<InteractionDisabled>, OnInsert<Hovered>, )>, ``` In scenarios like this, there is a lot of repetition of `On`. These are expected to be very high-traffic APIs especially in UI contexts, so ergonomics and readability are critical. By renaming `Trigger` to `On`, we can make these APIs read more cleanly and get rid of the repetition: ```rust app.add_observer(|trigger: On<Explode>| { info!("Entity {} exploded!", trigger.target()); }); ``` ```rust trigger: On<( Add<Pressed>, Remove<Pressed>, Add<InteractionDisabled>, Remove<InteractionDisabled>, Insert<Hovered>, )>, ``` Names like `On<Add<Pressed>>` emphasize the actual event listener nature more than `Trigger<OnAdd<Pressed>>`, and look cleaner. This *also* frees up the `Trigger` name if we want to use it for the observer event type, splitting them out from buffered events (bikeshedding this is out of scope for this PR though). For prior art: [`bevy_eventlistener`](https://github.com/aevyrie/bevy_eventlistener) used [`On`](https://docs.rs/bevy_eventlistener/latest/bevy_eventlistener/event_listener/struct.On.html) for its event listener type. Though in our case, the observer is the event listener, and `On` is just a type containing information about the triggered event. ## Solution Steal from `bevy_event_listener` by @aevyrie and use `On`. - Rename `Trigger` to `On` - Rename `OnAdd` to `Add` - Rename `OnInsert` to `Insert` - Rename `OnReplace` to `Replace` - Rename `OnRemove` to `Remove` - Rename `OnDespawn` to `Despawn` ## Discussion ### Naming Conflicts?? Using a name like `Add` might initially feel like a very bad idea, since it risks conflict with `core::ops::Add`. However, I don't expect this to be a big problem in practice. - You rarely need to actually implement the `Add` trait, especially in modules that would use the Bevy ECS. - In the rare cases where you *do* get a conflict, it is very easy to fix by just disambiguating, for example using `ops::Add`. - The `Add` event is a struct while the `Add` trait is a trait (duh), so the compiler error should be very obvious. For the record, renaming `OnAdd` to `Add`, I got exactly *zero* errors or conflicts within Bevy itself. But this is of course not entirely representative of actual projects *using* Bevy. You might then wonder, why not use `Added`? This would conflict with the `Added` query filter, so it wouldn't work. Additionally, the current naming convention for observer events does not use past tense. ### Documentation This does make documentation slightly more awkward when referring to `On` or its methods. Previous docs often referred to `Trigger::target` or "sends a `Trigger`" (which is... a bit strange anyway), which would now be `On::target` and "sends an observer `Event`". You can see the diff in this PR to see some of the effects. I think it should be fine though, we may just need to reword more documentation to read better. |
||
---|---|---|
.. | ||
src | ||
Cargo.toml | ||
README.md |
Bevy no_std
Compatible Library
This example demonstrates how to create a no_std
-compatible library crate for use with Bevy.
For the sake of demonstration, this library adds a way for a component to be added to an entity after a certain delay has elapsed.
Check the Cargo.toml and lib.rs for details around how this is implemented, and how we're able to make a library compatible for all users in the Bevy community.
Testing no_std
Compatibility
To check if your library is no_std
compatible, it's not enough to just compile with your std
feature disabled.
The problem is dependencies can still include std
even if the top-most crate is declared as #![no_std]
.
Instead, you need to compile your library without the standard library at all.
The simplest way to compile Rust code while ensuring std
isn't linked is to simply use a target without the standard library.
Targets with Tier 2 or Tier 3 support often do not have access to std
, and therefore can only compile if no_std
compatible.
Some recommended targets you can check against are:
x86_64-unknown-none
- Representative of desktop architectures.
- Should be the most similar to typical
std
targets so it's a good starting point when porting existing libraries.
wasm32v1-none
- Newer WebAssembly target with the bare minimum functionality for broad compatibility.
- Similar to
wasm32-unknown-unknown
, which is typically used for web builds.
thumbv6m-none-eabi
- Representative of embedded platforms.
- Has only partial support for atomics, making this target a good indicator for atomic incompatibility in your code.
Note that the first time you attempt to compile for a new target, you will need to install the supporting components via rustup
:
rustup target add x86_64-unknown-none
Once installed, you can check your library by specifying the appropriate features and target:
cargo check --no-default-features --features libm,critical-section --target x86_64-unknown-none
CI
Checking no_std
compatibility can be tedious and easy to forget if you're not actively using it yourself.
To avoid accidentally breaking that compatibility, we recommend adding these checks to your CI pipeline.
For example, here is a GitHub Action you could use as a starting point:
jobs:
check-compiles-no-std:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target:
- "x86_64-unknown-none"
- "wasm32v1-none"
- "thumbv6m-none-eabi"
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Check Compile
run: cargo check --no-default-features --features libm,critical-section --target ${{ matrix.target }}