mirror of
https://github.com/bevyengine/bevy
synced 2024-12-24 03:53:06 +00:00
d70595b667
# Objective - Fixes #6370 - Closes #6581 ## Solution - Added the following lints to the workspace: - `std_instead_of_core` - `std_instead_of_alloc` - `alloc_instead_of_core` - Used `cargo +nightly fmt` with [item level use formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Item%5C%3A) to split all `use` statements into single items. - Used `cargo clippy --workspace --all-targets --all-features --fix --allow-dirty` to _attempt_ to resolve the new linting issues, and intervened where the lint was unable to resolve the issue automatically (usually due to needing an `extern crate alloc;` statement in a crate root). - Manually removed certain uses of `std` where negative feature gating prevented `--all-features` from finding the offending uses. - Used `cargo +nightly fmt` with [crate level use formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Crate%5C%3A) to re-merge all `use` statements matching Bevy's previous styling. - Manually fixed cases where the `fmt` tool could not re-merge `use` statements due to conditional compilation attributes. ## Testing - Ran CI locally ## Migration Guide The MSRV is now 1.81. Please update to this version or higher. ## Notes - This is a _massive_ change to try and push through, which is why I've outlined the semi-automatic steps I used to create this PR, in case this fails and someone else tries again in the future. - Making this change has no impact on user code, but does mean Bevy contributors will be warned to use `core` and `alloc` instead of `std` where possible. - This lint is a critical first step towards investigating `no_std` options for Bevy. --------- Co-authored-by: François Mockers <francois.mockers@vleue.com>
166 lines
5.5 KiB
Rust
166 lines
5.5 KiB
Rust
use crate::state::{FreelyMutableState, NextState, State, States};
|
|
|
|
use bevy_ecs::{reflect::from_reflect_with_fallback, world::World};
|
|
use bevy_reflect::{FromType, Reflect, TypePath, TypeRegistry};
|
|
|
|
/// A struct used to operate on the reflected [`States`] trait of a type.
|
|
///
|
|
/// A [`ReflectState`] for type `T` can be obtained via
|
|
/// [`bevy_reflect::TypeRegistration::data`].
|
|
#[derive(Clone)]
|
|
pub struct ReflectState(ReflectStateFns);
|
|
|
|
/// The raw function pointers needed to make up a [`ReflectState`].
|
|
#[derive(Clone)]
|
|
pub struct ReflectStateFns {
|
|
/// Function pointer implementing [`ReflectState::reflect()`].
|
|
pub reflect: fn(&World) -> Option<&dyn Reflect>,
|
|
}
|
|
|
|
impl ReflectStateFns {
|
|
/// Get the default set of [`ReflectStateFns`] for a specific component type using its
|
|
/// [`FromType`] implementation.
|
|
///
|
|
/// This is useful if you want to start with the default implementation before overriding some
|
|
/// of the functions to create a custom implementation.
|
|
pub fn new<T: States + Reflect>() -> Self {
|
|
<ReflectState as FromType<T>>::from_type().0
|
|
}
|
|
}
|
|
|
|
impl ReflectState {
|
|
/// Gets the value of this [`States`] type from the world as a reflected reference.
|
|
pub fn reflect<'a>(&self, world: &'a World) -> Option<&'a dyn Reflect> {
|
|
(self.0.reflect)(world)
|
|
}
|
|
}
|
|
|
|
impl<S: States + Reflect> FromType<S> for ReflectState {
|
|
fn from_type() -> Self {
|
|
ReflectState(ReflectStateFns {
|
|
reflect: |world| {
|
|
world
|
|
.get_resource::<State<S>>()
|
|
.map(|res| res.get() as &dyn Reflect)
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
/// A struct used to operate on the reflected [`FreelyMutableState`] trait of a type.
|
|
///
|
|
/// A [`ReflectFreelyMutableState`] for type `T` can be obtained via
|
|
/// [`bevy_reflect::TypeRegistration::data`].
|
|
#[derive(Clone)]
|
|
pub struct ReflectFreelyMutableState(ReflectFreelyMutableStateFns);
|
|
|
|
/// The raw function pointers needed to make up a [`ReflectFreelyMutableState`].
|
|
#[derive(Clone)]
|
|
pub struct ReflectFreelyMutableStateFns {
|
|
/// Function pointer implementing [`ReflectFreelyMutableState::set_next_state()`].
|
|
pub set_next_state: fn(&mut World, &dyn Reflect, &TypeRegistry),
|
|
}
|
|
|
|
impl ReflectFreelyMutableStateFns {
|
|
/// Get the default set of [`ReflectFreelyMutableStateFns`] for a specific component type using its
|
|
/// [`FromType`] implementation.
|
|
///
|
|
/// This is useful if you want to start with the default implementation before overriding some
|
|
/// of the functions to create a custom implementation.
|
|
pub fn new<T: FreelyMutableState + Reflect + TypePath>() -> Self {
|
|
<ReflectFreelyMutableState as FromType<T>>::from_type().0
|
|
}
|
|
}
|
|
|
|
impl ReflectFreelyMutableState {
|
|
/// Tentatively set a pending state transition to a reflected [`ReflectFreelyMutableState`].
|
|
pub fn set_next_state(&self, world: &mut World, state: &dyn Reflect, registry: &TypeRegistry) {
|
|
(self.0.set_next_state)(world, state, registry);
|
|
}
|
|
}
|
|
|
|
impl<S: FreelyMutableState + Reflect + TypePath> FromType<S> for ReflectFreelyMutableState {
|
|
fn from_type() -> Self {
|
|
ReflectFreelyMutableState(ReflectFreelyMutableStateFns {
|
|
set_next_state: |world, reflected_state, registry| {
|
|
let new_state: S = from_reflect_with_fallback(
|
|
reflected_state.as_partial_reflect(),
|
|
world,
|
|
registry,
|
|
);
|
|
if let Some(mut next_state) = world.get_resource_mut::<NextState<S>>() {
|
|
next_state.set(new_state);
|
|
}
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate as bevy_state;
|
|
use crate::{
|
|
app::{AppExtStates, StatesPlugin},
|
|
reflect::{ReflectFreelyMutableState, ReflectState},
|
|
state::State,
|
|
};
|
|
use bevy_app::App;
|
|
use bevy_ecs::prelude::AppTypeRegistry;
|
|
use bevy_reflect::Reflect;
|
|
use bevy_state_macros::States;
|
|
use core::any::TypeId;
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, States, Reflect)]
|
|
enum StateTest {
|
|
A,
|
|
B,
|
|
}
|
|
|
|
#[test]
|
|
fn test_reflect_state_operations() {
|
|
let mut app = App::new();
|
|
app.add_plugins(StatesPlugin)
|
|
.insert_state(StateTest::A)
|
|
.register_type_mutable_state::<StateTest>();
|
|
|
|
let type_registry = app.world_mut().resource::<AppTypeRegistry>().0.clone();
|
|
let type_registry = type_registry.read();
|
|
|
|
let (reflect_state, reflect_mutable_state) = (
|
|
type_registry
|
|
.get_type_data::<ReflectState>(TypeId::of::<StateTest>())
|
|
.unwrap()
|
|
.clone(),
|
|
type_registry
|
|
.get_type_data::<ReflectFreelyMutableState>(TypeId::of::<StateTest>())
|
|
.unwrap()
|
|
.clone(),
|
|
);
|
|
|
|
let current_value = reflect_state.reflect(app.world()).unwrap();
|
|
assert_eq!(
|
|
current_value.downcast_ref::<StateTest>().unwrap(),
|
|
&StateTest::A
|
|
);
|
|
|
|
reflect_mutable_state.set_next_state(app.world_mut(), &StateTest::B, &type_registry);
|
|
|
|
assert_ne!(
|
|
app.world().resource::<State<StateTest>>().get(),
|
|
&StateTest::B
|
|
);
|
|
|
|
app.update();
|
|
|
|
assert_eq!(
|
|
app.world().resource::<State<StateTest>>().get(),
|
|
&StateTest::B
|
|
);
|
|
|
|
let current_value = reflect_state.reflect(app.world()).unwrap();
|
|
assert_eq!(
|
|
current_value.downcast_ref::<StateTest>().unwrap(),
|
|
&StateTest::B
|
|
);
|
|
}
|
|
}
|