style: run cargo fmt

This commit is contained in:
nativerv
2024-02-16 03:49:36 +03:00
parent 1f972d8a5d
commit b88f37457b
6 changed files with 889 additions and 892 deletions
+248 -245
View File
@@ -1,245 +1,248 @@
use std::hash::Hash; use std::hash::Hash;
use bevy_ecs::{schedule::States, system::Resource}; use bevy_ecs::{schedule::States, system::Resource};
#[cfg(feature = "inspector-egui")] #[cfg(feature = "inspector-egui")]
use bevy_inspector_egui::inspector_options::InspectorOptionsType; use bevy_inspector_egui::inspector_options::InspectorOptionsType;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
// #[cfg(all(feature = "reflect", feature = "serialize"))] // #[cfg(all(feature = "reflect", feature = "serialize"))]
// use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; // use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
#[cfg(feature = "reflect")] #[cfg(feature = "reflect")]
use bevy_reflect::{FromReflect, Reflect, TypePath}; use bevy_reflect::{FromReflect, Reflect, TypePath};
#[cfg(feature = "serialize")] #[cfg(feature = "serialize")]
use serde::{de::DeserializeOwned, Serialize}; use serde::{de::DeserializeOwned, Serialize};
use crate::resource::PlayerInputs; use crate::resource::PlayerInputs;
pub trait ActionInner: pub trait ActionInner:
'static 'static
+ std::marker::Sync + std::marker::Sync
+ std::marker::Send + std::marker::Send
+ PartialEq + PartialEq
+ Eq + Eq
+ Hash + Hash
+ IntoEnumIterator + IntoEnumIterator
+ Clone + Clone
+ Copy + Copy
+ std::fmt::Debug + std::fmt::Debug
{ {
} }
pub trait GameStateInner: 'static + std::marker::Sync + std::marker::Send + States + Default + std::fmt::Debug {} pub trait GameStateInner:
'static + std::marker::Sync + std::marker::Send + States + Default + std::fmt::Debug
pub trait InputsContainerInner<A: Action>: {
'static + std::marker::Sync + std::marker::Send + Resource + Default + std::fmt::Debug }
{
/// The method returning an iterator over references to the PlayerInputs. pub trait InputsContainerInner<A: Action>:
/// Note: the use of 'a for both the method's lifetime and the returned Iterator's lifetime. 'static + std::marker::Sync + std::marker::Send + Resource + Default + std::fmt::Debug
fn iter_inputs<'a>(&'a self) -> Box<dyn Iterator<Item = &'a PlayerInputs<A>> + 'a>; {
/// The method returning an player inputs of this client. /// The method returning an iterator over references to the PlayerInputs.
fn me<'a>(&'a self) -> Option<&'a PlayerInputs<A>>; /// Note: the use of 'a for both the method's lifetime and the returned Iterator's lifetime.
/// The method returning an mutable player inputs of this client. fn iter_inputs<'a>(&'a self) -> Box<dyn Iterator<Item = &'a PlayerInputs<A>> + 'a>;
fn me_mut<'a>(&'a mut self) -> Option<&'a mut PlayerInputs<A>>; /// The method returning an player inputs of this client.
} fn me<'a>(&'a self) -> Option<&'a PlayerInputs<A>>;
/// The method returning an mutable player inputs of this client.
#[cfg(feature = "serialize")] fn me_mut<'a>(&'a mut self) -> Option<&'a mut PlayerInputs<A>>;
pub trait SerializeImpl: Serialize + DeserializeOwned {} }
#[cfg(feature = "reflect")] #[cfg(feature = "serialize")]
pub trait ReflectImpl: Reflect + TypePath + FromReflect {} pub trait SerializeImpl: Serialize + DeserializeOwned {}
#[cfg(feature = "inspector-egui")] #[cfg(feature = "reflect")]
pub trait InspectorEguiImpl: InspectorOptionsType {} pub trait ReflectImpl: Reflect + TypePath + FromReflect {}
// ===== Action ===== #[cfg(feature = "inspector-egui")]
// SAFETY: inspector-egui includes reflect pub trait InspectorEguiImpl: InspectorOptionsType {}
#[cfg(all(
not(feature = "serialize"), // ===== Action =====
not(feature = "reflect"), // SAFETY: inspector-egui includes reflect
not(feature = "inspector-egui") #[cfg(all(
))] not(feature = "serialize"),
pub trait Action: ActionInner {} not(feature = "reflect"),
not(feature = "inspector-egui")
#[cfg(all( ))]
feature = "serialize", pub trait Action: ActionInner {}
not(feature = "reflect"),
not(feature = "inspector-egui") #[cfg(all(
))] feature = "serialize",
pub trait Action: ActionInner + SerializeImpl {} not(feature = "reflect"),
not(feature = "inspector-egui")
#[cfg(all( ))]
not(feature = "serialize"), pub trait Action: ActionInner + SerializeImpl {}
feature = "reflect",
not(feature = "inspector-egui") #[cfg(all(
))] not(feature = "serialize"),
pub trait Action: ActionInner + ReflectImpl {} feature = "reflect",
not(feature = "inspector-egui")
#[cfg(all( ))]
feature = "serialize", pub trait Action: ActionInner + ReflectImpl {}
feature = "reflect",
not(feature = "inspector-egui") #[cfg(all(
))] feature = "serialize",
pub trait Action: ActionInner + SerializeImpl + ReflectImpl {} feature = "reflect",
not(feature = "inspector-egui")
#[cfg(all(not(feature = "serialize"), feature = "inspector-egui"))] ))]
pub trait Action: ActionInner + ReflectImpl + InspectorEguiImpl {} pub trait Action: ActionInner + SerializeImpl + ReflectImpl {}
#[cfg(all(feature = "serialize", feature = "inspector-egui"))] #[cfg(all(not(feature = "serialize"), feature = "inspector-egui"))]
pub trait Action: ActionInner + SerializeImpl + ReflectImpl + InspectorEguiImpl {} pub trait Action: ActionInner + ReflectImpl + InspectorEguiImpl {}
// ===== GameState ===== #[cfg(all(feature = "serialize", feature = "inspector-egui"))]
// SAFETY: inspector-egui includes reflect pub trait Action: ActionInner + SerializeImpl + ReflectImpl + InspectorEguiImpl {}
#[cfg(all(
not(feature = "serialize"), // ===== GameState =====
not(feature = "reflect"), // SAFETY: inspector-egui includes reflect
not(feature = "inspector-egui") #[cfg(all(
))] not(feature = "serialize"),
pub trait GameState: GameStateInner {} not(feature = "reflect"),
not(feature = "inspector-egui")
#[cfg(all( ))]
feature = "serialize", pub trait GameState: GameStateInner {}
not(feature = "reflect"),
not(feature = "inspector-egui") #[cfg(all(
))] feature = "serialize",
pub trait GameState: GameStateInner + SerializeImpl {} not(feature = "reflect"),
not(feature = "inspector-egui")
#[cfg(all( ))]
not(feature = "serialize"), pub trait GameState: GameStateInner + SerializeImpl {}
feature = "reflect",
not(feature = "inspector-egui") #[cfg(all(
))] not(feature = "serialize"),
pub trait GameState: GameStateInner + ReflectImpl {} feature = "reflect",
not(feature = "inspector-egui")
#[cfg(all( ))]
feature = "serialize", pub trait GameState: GameStateInner + ReflectImpl {}
feature = "reflect",
not(feature = "inspector-egui") #[cfg(all(
))] feature = "serialize",
pub trait GameState: GameStateInner + SerializeImpl + ReflectImpl {} feature = "reflect",
not(feature = "inspector-egui")
#[cfg(all(not(feature = "serialize"), feature = "inspector-egui"))] ))]
pub trait GameState: GameStateInner + ReflectImpl + InspectorEguiImpl {} pub trait GameState: GameStateInner + SerializeImpl + ReflectImpl {}
#[cfg(all(feature = "serialize", feature = "inspector-egui"))] #[cfg(all(not(feature = "serialize"), feature = "inspector-egui"))]
pub trait GameState: GameStateInner + SerializeImpl + ReflectImpl + InspectorEguiImpl {} pub trait GameState: GameStateInner + ReflectImpl + InspectorEguiImpl {}
// ===== InputsContainer ===== #[cfg(all(feature = "serialize", feature = "inspector-egui"))]
// SAFETY: inspector-egui includes reflect pub trait GameState: GameStateInner + SerializeImpl + ReflectImpl + InspectorEguiImpl {}
#[cfg(all(
not(feature = "serialize"), // ===== InputsContainer =====
not(feature = "reflect"), // SAFETY: inspector-egui includes reflect
not(feature = "inspector-egui") #[cfg(all(
))] not(feature = "serialize"),
pub trait InputsContainer<A: Action>: InputsContainerInner<A> {} not(feature = "reflect"),
not(feature = "inspector-egui")
#[cfg(all( ))]
feature = "serialize", pub trait InputsContainer<A: Action>: InputsContainerInner<A> {}
not(feature = "reflect"),
not(feature = "inspector-egui") #[cfg(all(
))] feature = "serialize",
pub trait InputsContainer<A: Action>: InputsContainerInner<A> + SerializeImpl {} not(feature = "reflect"),
not(feature = "inspector-egui")
#[cfg(all( ))]
not(feature = "serialize"), pub trait InputsContainer<A: Action>: InputsContainerInner<A> + SerializeImpl {}
feature = "reflect",
not(feature = "inspector-egui") #[cfg(all(
))] not(feature = "serialize"),
pub trait InputsContainer<A: Action>: InputsContainerInner<A> + ReflectImpl {} feature = "reflect",
not(feature = "inspector-egui")
#[cfg(all( ))]
feature = "serialize", pub trait InputsContainer<A: Action>: InputsContainerInner<A> + ReflectImpl {}
feature = "reflect",
not(feature = "inspector-egui") #[cfg(all(
))] feature = "serialize",
pub trait InputsContainer<A: Action>: feature = "reflect",
InputsContainerInner<A> + SerializeImpl + ReflectImpl not(feature = "inspector-egui")
{ ))]
} pub trait InputsContainer<A: Action>:
InputsContainerInner<A> + SerializeImpl + ReflectImpl
#[cfg(all(not(feature = "serialize"), feature = "inspector-egui"))] {
pub trait InputsContainer<A: Action>: }
InputsContainerInner<A> + ReflectImpl + InspectorEguiImpl
{ #[cfg(all(not(feature = "serialize"), feature = "inspector-egui"))]
} pub trait InputsContainer<A: Action>:
InputsContainerInner<A> + ReflectImpl + InspectorEguiImpl
#[cfg(all(feature = "serialize", feature = "inspector-egui"))] {
pub trait InputsContainer<A: Action>: }
InputsContainerInner<A> + SerializeImpl + ReflectImpl + InspectorEguiImpl
{ #[cfg(all(feature = "serialize", feature = "inspector-egui"))]
} pub trait InputsContainer<A: Action>:
InputsContainerInner<A> + SerializeImpl + ReflectImpl + InspectorEguiImpl
// #[cfg(test)] {
// mod test { }
// use bevy_ecs::{entity::Entity, schedule::States};
// use bevy_utils::{HashMap, prelude::default}; // #[cfg(test)]
// use strum_macros::EnumIter; // mod test {
// use bevy_ecs::{entity::Entity, schedule::States};
// #[cfg(feature = "serialize")] // use bevy_utils::{HashMap, prelude::default};
// use serde::{Serialize, Deserialize}; // use strum_macros::EnumIter;
// use crate::{hashmap, resource::PlayerInputs, common_traits_conditions}; // #[cfg(feature = "serialize")]
// use serde::{Serialize, Deserialize};
// common_traits_conditions! {
// #[derive(Debug, Clone, PartialEq)] // use crate::{hashmap, resource::PlayerInputs, common_traits_conditions};
// #[cfg_attr(feature = "reflect", reflect(Resource))]
// pub struct Lobby { // common_traits_conditions! {
// pub me: PlayerId, // #[derive(Debug, Clone, PartialEq)]
// pub players: HashMap<PlayerId, Player>, // #[cfg_attr(feature = "reflect", reflect(Resource))]
// } // pub struct Lobby {
// } // pub me: PlayerId,
// pub players: HashMap<PlayerId, Player>,
// impl Default for Lobby { // }
// fn default() -> Self { // }
// Self {
// me: PlayerId::Host, // impl Default for Lobby {
// players: hashmap! { // fn default() -> Self {
// PlayerId::Host => Player::default() // Self {
// }, // me: PlayerId::Host,
// } // players: hashmap! {
// } // PlayerId::Host => Player::default()
// } // },
// }
// common_traits_conditions! { // }
// #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] // }
// pub enum PlayerId {
// /// Host or alone // common_traits_conditions! {
// Host, // #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
// /// Client // pub enum PlayerId {
// Client(()), // /// Host or alone
// } // Host,
// /// Client
// #[derive(Default, Debug, PartialEq, Clone)] // Client(()),
// pub struct Player { // }
// /// Client do not need to know about other clients
// #[cfg_attr(feature = "serialize", serde(skip))] // #[derive(Default, Debug, PartialEq, Clone)]
// pub inputs: PlayerInputs<Action>, // pub struct Player {
// #[cfg_attr(feature = "serialize", serde(skip))] // /// Client do not need to know about other clients
// pub entity: Option<Entity>, // #[cfg_attr(feature = "serialize", serde(skip))]
// } // pub inputs: PlayerInputs<Action>,
// } // #[cfg_attr(feature = "serialize", serde(skip))]
// pub entity: Option<Entity>,
// #[derive(Debug, PartialEq, Clone, States, Default, Hash, Eq)] // }
// pub enum GameState { // }
// #[default]
// LevelEditor, // #[derive(Debug, PartialEq, Clone, States, Default, Hash, Eq)]
// InGame, // pub enum GameState {
// } // #[default]
// LevelEditor,
// impl super::GameState for GameState {} // InGame,
// }
// // TODO: it is just plug, it must be a trait
// /// Actions that can be performed by player // impl super::GameState for GameState {}
// #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug, EnumIter)]
// pub enum Action { // // TODO: it is just plug, it must be a trait
// /// Move forward // /// Actions that can be performed by player
// LeverEditorForward, // #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug, EnumIter)]
// /// Move backward // pub enum Action {
// LevelEditorBackward, // /// Move forward
// /// Move left // LeverEditorForward,
// LevelEditorLeft, // /// Move backward
// /// Move right // LevelEditorBackward,
// LevelEditorRight, // /// Move left
// LevelEditorFly, // LevelEditorLeft,
// } // /// Move right
// LevelEditorRight,
// impl super::Action for Action {} // LevelEditorFly,
// } // }
// impl super::Action for Action {}
// }
+2 -2
View File
@@ -1,6 +1,6 @@
pub mod resource;
pub mod plugin;
pub mod contract; pub mod contract;
pub mod plugin;
pub mod resource;
mod util; mod util;
pub use util::*; pub use util::*;
+247 -260
View File
@@ -1,260 +1,247 @@
use bevy_app::{Plugin, App, Update}; use bevy_app::{App, Plugin, Update};
use bevy_ecs::{system::{Res, ResMut}, schedule::State}; use bevy_ecs::{
use bevy_input::{Input, keyboard::KeyCode, mouse::MouseButton}; schedule::State,
system::{Res, ResMut},
use crate::{resource::*, contract::{Action, GameState, InputsContainer}}; };
use bevy_input::{keyboard::KeyCode, mouse::MouseButton, Input};
pub struct ControlsPlugin<A, Ic, Gs> {
_action: std::marker::PhantomData<A>, use crate::{
_inputs_container: std::marker::PhantomData<Ic>, contract::{Action, GameState, InputsContainer},
_game_state: std::marker::PhantomData<Gs>, resource::*,
} };
impl<A, Ic, Gs> Default for ControlsPlugin<A, Ic, Gs> { pub struct ControlsPlugin<A, Ic, Gs> {
fn default() -> Self { _action: std::marker::PhantomData<A>,
Self { _inputs_container: std::marker::PhantomData<Ic>,
_action: std::marker::PhantomData, _game_state: std::marker::PhantomData<Gs>,
_inputs_container: std::marker::PhantomData, }
_game_state: std::marker::PhantomData,
} impl<A, Ic, Gs> Default for ControlsPlugin<A, Ic, Gs> {
} fn default() -> Self {
} Self {
_action: std::marker::PhantomData,
impl< _inputs_container: std::marker::PhantomData,
A: Action, _game_state: std::marker::PhantomData,
Ic: InputsContainer<A>, }
Gs: GameState }
> Plugin for ControlsPlugin<A, Ic, Gs> { }
fn build(&self, app: &mut App) {
app.init_resource::<Controls<A, Gs>>() impl<A: Action, Ic: InputsContainer<A>, Gs: GameState> Plugin for ControlsPlugin<A, Ic, Gs> {
.init_resource::<Ic>() fn build(&self, app: &mut App) {
.add_state::<Gs>() app
.add_systems(Update, Self::save_input); .init_resource::<Controls<A, Gs>>()
.init_resource::<Ic>()
#[cfg(feature = "reflect")] .add_state::<Gs>()
app.register_type::<Controls<A, Gs>>(); .add_systems(Update, Self::save_input);
}
#[cfg(feature = "reflect")]
} app.register_type::<Controls<A, Gs>>();
}
impl< }
A: Action,
Ic: InputsContainer<A>, impl<A: Action, Ic: InputsContainer<A>, Gs: GameState> ControlsPlugin<A, Ic, Gs> {
Gs: GameState /// Process all hard inputs and bindings to update [`PlayerInputs`]
> ControlsPlugin<A, Ic, Gs> { fn save_input(
/// Process all hard inputs and bindings to update [`PlayerInputs`] keyboard_input: Res<Input<KeyCode>>,
fn save_input( mouse_input: Res<Input<MouseButton>>,
keyboard_input: Res<Input<KeyCode>>, mut inputs_container: ResMut<Ic>,
mouse_input: Res<Input<MouseButton>>, controls: Res<Controls<A, Gs>>,
mut inputs_container: ResMut<Ic>, game_state: Res<State<Gs>>,
controls: Res<Controls<A, Gs>>, ) {
game_state: Res<State<Gs>>, if let Some(inputs) = inputs_container.me_mut() {
) { for (action, config) in controls.iter() {
if let Some(inputs) = inputs_container.me_mut() { 'bindings_loop: for binding in config.bindings.iter() {
for (action, config) in controls.iter() { for condition in &binding.conditions {
'bindings_loop: for binding in config.bindings.iter() { match condition {
for condition in &binding.conditions { BindingCondition::InGameState(state) => {
match condition { if *state != *game_state.get() {
BindingCondition::InGameState(state) => { continue 'bindings_loop;
if *state != *game_state.get() { }
continue 'bindings_loop; }
} }
} }
}
} log::trace!("action binding {:?} {:?} in condition", action, binding);
log::trace!("action binding {:?} {:?} in condition", action, binding); match &binding.input {
ButtonCombination::Single(button) => match button {
match &binding.input { InputType::Keyboard(key) => {
ButtonCombination::Single(button) => match button { log::trace!("presed?: {:?}", keyboard_input.pressed(*key));
InputType::Keyboard(key) => { log::trace!("active");
log::trace!("presed?: {:?}", keyboard_input.pressed(*key)); if keyboard_input.pressed(*key) {
log::trace!("active"); inputs.forced_set(*action, true);
if keyboard_input.pressed(*key) { break; // when on binding trigered no sence check another
inputs.forced_set(*action, true); }
break; // when on binding trigered no sence check another inputs.forced_set(*action, false); // FIXME: this is happening on every pass so too frequently
} }
inputs.forced_set(*action, false); // FIXME: this is happening on every pass so too frequently InputType::Mouse(input) => match input {
} MouseInput::Axis(_axis) => {
InputType::Mouse(input) => { todo!();
match input { }
MouseInput::Axis(_axis) => { MouseInput::Button(button) => {
todo!(); if !mouse_input.get_pressed().any(|b| b == button) {
} continue 'bindings_loop;
MouseInput::Button(button) => { }
if !mouse_input }
.get_pressed() MouseInput::Wheel(_axis) => {
.any(|b| b == button) todo!();
{ }
continue 'bindings_loop; },
} },
} ButtonCombination::Chord(buttons) => {
MouseInput::Wheel(_axis) => { // If any button in chord is not pressed we skip this `binding`
todo!(); for button in buttons {
} match button {
} InputType::Keyboard(key) => {
} if !keyboard_input.pressed(*key) {
}, continue 'bindings_loop;
ButtonCombination::Chord(buttons) => { }
// If any button in chord is not pressed we skip this `binding` }
for button in buttons { InputType::Mouse(input) => match input {
match button { MouseInput::Axis(_axis) => {
InputType::Keyboard(key) => { todo!();
if !keyboard_input.pressed(*key) { }
continue 'bindings_loop; MouseInput::Button(button) => {
} if !mouse_input.get_pressed().any(|b| b == button) {
} continue 'bindings_loop;
InputType::Mouse(input) => { }
match input { }
MouseInput::Axis(_axis) => { MouseInput::Wheel(_axis) => {
todo!(); todo!();
} }
MouseInput::Button(button) => { },
if !mouse_input }
.get_pressed() }
.any(|b| b == button)
{ log::trace!("active");
continue 'bindings_loop; // TODO: should be [`Chord`](ButtonCombination::Chord) only [`Boolean`](InputValue::Boolean) type
} inputs.forced_set(*action, true);
} break; // when on binding trigered no sence check another
MouseInput::Wheel(_axis) => { }
todo!(); }
} }
} }
} } else {
} log::error!("cannot find me in inputs container")
} }
}
log::trace!("active"); }
// TODO: should be [`Chord`](ButtonCombination::Chord) only [`Boolean`](InputValue::Boolean) type
inputs.forced_set(*action, true); // #[cfg(test)]
break; // when on binding trigered no sence check another // mod performance_test {
} // use crate::{ util::test::{enable_loggings, measure_time, Times}, resource::PlayerInputs};
}
} // use super::Controls;
} // use std::time::Duration;
} else {
log::error!("cannot find me in inputs container") // /// Test for execution time for [`Controls`] get
} // ///
} // /// Example:
} // /// ```
// /// cargo test --package pih-pah-app --lib --features "dev, ui_egui" -- controls::test::controls_get --exact --nocapture
// /// ```
// #[cfg(test)] // #[test]
// mod performance_test { // fn controls_get() {
// use crate::{ util::test::{enable_loggings, measure_time, Times}, resource::PlayerInputs}; // enable_loggings();
// use super::Controls; // let controls = Controls::default();
// use std::time::Duration;
// let duration = measure_time(
// /// Test for execution time for [`Controls`] get // || {
// /// // controls.get(Action::LeverEditorForward);
// /// Example: // controls.get(Action::LevelEditorBackward);
// /// ``` // controls.get(Action::LevelEditorLeft);
// /// cargo test --package pih-pah-app --lib --features "dev, ui_egui" -- controls::test::controls_get --exact --nocapture // controls.get(Action::LevelEditorRight);
// /// ``` // },
// #[test] // Times::default(),
// fn controls_get() { // );
// enable_loggings();
// log::info!("time: {:?}", duration);
// let controls = Controls::default(); // }
// let duration = measure_time( // /// Test for execution speed for [`PlayerInputs`] get
// || { // fn player_inputs_get() -> Duration {
// controls.get(Action::LeverEditorForward); // enable_loggings();
// controls.get(Action::LevelEditorBackward);
// controls.get(Action::LevelEditorLeft); // let inputs = PlayerInputs::default();
// controls.get(Action::LevelEditorRight);
// }, // let duration = measure_time(
// Times::default(), // || {
// ); // inputs.get(Action::LeverEditorForward);
// inputs.get(Action::LevelEditorBackward);
// log::info!("time: {:?}", duration); // inputs.get(Action::LevelEditorLeft);
// } // inputs.get(Action::LevelEditorRight);
// },
// /// Test for execution speed for [`PlayerInputs`] get // Times::default(),
// fn player_inputs_get() -> Duration { // );
// enable_loggings();
// duration
// let inputs = PlayerInputs::default(); // }
// let duration = measure_time( // /// Test for execution speed for [`PlayerInputs`] get_many
// || { // fn player_inputs_get_many() -> Duration {
// inputs.get(Action::LeverEditorForward); // enable_loggings();
// inputs.get(Action::LevelEditorBackward);
// inputs.get(Action::LevelEditorLeft); // let inputs = PlayerInputs::default();
// inputs.get(Action::LevelEditorRight);
// }, // let duration = measure_time(
// Times::default(), // || {
// ); // inputs.get_many(vec![
// Action::LeverEditorForward,
// duration // Action::LevelEditorBackward,
// } // Action::LevelEditorLeft,
// Action::LevelEditorRight,
// /// Test for execution speed for [`PlayerInputs`] get_many // ]);
// fn player_inputs_get_many() -> Duration { // },
// enable_loggings(); // Times::default(),
// );
// let inputs = PlayerInputs::default();
// duration
// let duration = measure_time( // }
// || {
// inputs.get_many(vec![ // /// Test for execution speed for [`PlayerInputs`] get and get_many
// Action::LeverEditorForward, // ///
// Action::LevelEditorBackward, // /// Example:
// Action::LevelEditorLeft, // /// ```
// Action::LevelEditorRight, // /// cargo test --package pih-pah-app --lib --features "dev, ui_egui" -- controls::test::compare_player_inputs_get_and_get_many --exact --nocapture
// ]); // /// ```
// }, // #[test]
// Times::default(), // fn compare_player_inputs_get_and_get_many() {
// ); // let get = player_inputs_get();
// let get_many = player_inputs_get_many();
// duration
// } // log::info!("get: {:?}", get);
// log::info!("get_many: {:?}", get_many);
// /// Test for execution speed for [`PlayerInputs`] get and get_many // }
// ///
// /// Example: // /// Test for execution speed for [`InputValue`] casting
// /// ``` // #[test]
// /// cargo test --package pih-pah-app --lib --features "dev, ui_egui" -- controls::test::compare_player_inputs_get_and_get_many --exact --nocapture // fn action_casting() {
// /// ``` // enable_loggings();
// #[test]
// fn compare_player_inputs_get_and_get_many() { // let inputs = PlayerInputs::default();
// let get = player_inputs_get();
// let get_many = player_inputs_get_many(); // let duration = measure_time(
// || {
// log::info!("get: {:?}", get); // let _ = (inputs.get(Action::LeverEditorForward).as_boolean() as i8
// log::info!("get_many: {:?}", get_many); // - inputs.get(Action::LevelEditorBackward).as_boolean() as i8)
// } // as f32;
// },
// /// Test for execution speed for [`InputValue`] casting // 10000000.into(),
// #[test] // );
// fn action_casting() {
// enable_loggings(); // log::info!("with casting: {:?}", duration);
// let inputs = PlayerInputs::default(); // let inputs = PlayerInputs::default();
// let duration = measure_time( // let duration = measure_time(
// || { // || {
// let _ = (inputs.get(Action::LeverEditorForward).as_boolean() as i8 // let _ = inputs.get(Action::LeverEditorForward);
// - inputs.get(Action::LevelEditorBackward).as_boolean() as i8) // let _ = inputs.get(Action::LevelEditorBackward);
// as f32; // },
// }, // 10000000.into(),
// 10000000.into(), // );
// );
// log::info!("without casting: {:?}", duration);
// log::info!("with casting: {:?}", duration); // }
// }
// let inputs = PlayerInputs::default();
// let duration = measure_time(
// || {
// let _ = inputs.get(Action::LeverEditorForward);
// let _ = inputs.get(Action::LevelEditorBackward);
// },
// 10000000.into(),
// );
// log::info!("without casting: {:?}", duration);
// }
// }
+314 -308
View File
@@ -10,32 +10,35 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
use bevy_utils::HashMap; use bevy_utils::HashMap;
use log::warn; use log::warn;
#[cfg(feature = "serialize")] #[cfg(feature = "serialize")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::mem::discriminant; use std::mem::discriminant;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
#[cfg(feature = "reflect")] #[cfg(feature = "reflect")]
use {bevy_ecs::prelude::ReflectResource, bevy_reflect::Reflect}; use {bevy_ecs::prelude::ReflectResource, bevy_reflect::Reflect};
use crate::{common_traits_conditions, contract::{Action, GameState}}; use crate::{
common_traits_conditions,
contract::{Action, GameState},
};
/// Validate that all enum variants are in the hash map /// Validate that all enum variants are in the hash map
pub fn validate_hash_map<K, V>(hash_map: &HashMap<K, V>) -> bool pub fn validate_hash_map<K, V>(hash_map: &HashMap<K, V>) -> bool
where where
K: Eq + std::hash::Hash + Copy + IntoEnumIterator, K: Eq + std::hash::Hash + Copy + IntoEnumIterator,
K::Iterator: Iterator<Item = K>, K::Iterator: Iterator<Item = K>,
{ {
let all_keys = K::iter().collect::<Vec<_>>(); let all_keys = K::iter().collect::<Vec<_>>();
if hash_map.len() != all_keys.len() { if hash_map.len() != all_keys.len() {
return false; return false;
} }
for key in all_keys { for key in all_keys {
if !hash_map.contains_key(&key) { if !hash_map.contains_key(&key) {
return false; return false;
}
} }
}
true true
} }
common_traits_conditions! { common_traits_conditions! {
@@ -54,143 +57,143 @@ common_traits_conditions! {
} }
impl<A: Action> Default for PlayerInputs<A> { impl<A: Action> Default for PlayerInputs<A> {
fn default() -> Self { fn default() -> Self {
PlayerInputs { PlayerInputs {
current: Inputs( current: Inputs(
A::iter() A::iter()
.map(|action| (action, InputValue::Empty)) .map(|action| (action, InputValue::Empty))
.collect(), .collect(),
), ),
previous: Inputs( previous: Inputs(
A::iter() A::iter()
.map(|action| (action, InputValue::Empty)) .map(|action| (action, InputValue::Empty))
.collect(), .collect(),
), ),
}
} }
}
} }
impl<A: Action> PlayerInputs<A> { impl<A: Action> PlayerInputs<A> {
/// Returns current input value for action /// Returns current input value for action
/// ///
/// in any case faster that `get_many` method /// in any case faster that `get_many` method
pub fn get(&self, action: A) -> InputValue { pub fn get(&self, action: A) -> InputValue {
// SAFETY: action is always valid // SAFETY: action is always valid
// because we iterate over all actions in `default` method // because we iterate over all actions in `default` method
*self.current.get(&action).unwrap() *self.current.get(&action).unwrap()
}
// TODO
// /// Returns current input value for action
// ///
// /// in any case faster that `get_many` method
// pub fn all_active(&self) -> InputValue {
// *self.current.iter().filter(|a| {a.})
// }
/// Returns current input values for actions
pub fn get_many(&self, actions: Vec<A>) -> Vec<InputValue> {
// SAFETY: action is always valid
// because we iterate over all actions in `default` method
actions
.iter()
.map(|action| *self.current.get(action).unwrap())
.collect()
}
/// Returns `true` if current `InputValue` has become `InputValue::Boolean(true)` in this frame
/// If input has not same type as `InputValue` on previous frame call `panic`
pub fn just_pressed(&self, action: A) -> bool {
// SAFETY: action is always valid
// because we iterate over all actions in `default` method
if let InputValue::Boolean(current) = *self.current.get(&action).unwrap() {
if let InputValue::Boolean(previous) = *self.previous.get(&action).unwrap() {
return current && !previous;
}
panic!("Previous input is not boolean");
} }
panic!("This input is not boolean")
}
// TODO // TODO this is must be binding option for non axis inputs
// /// Returns current input value for action /// Returns `true` if current `InputValue` has become `InputValue::Boolean(true)` in this frame
// /// /// If input has not same type as `InputValue` on previous frame return `Error()`
// /// in any case faster that `get_many` method pub fn get_just_pressed(&self, action: A) -> Result<bool, Box<dyn error::Error>> {
// pub fn all_active(&self) -> InputValue { // SAFETY: action is always valid
// *self.current.iter().filter(|a| {a.}) // because we iterate over all actions in `default` method
// } if let InputValue::Boolean(current) = *self.current.get(&action).unwrap() {
if let InputValue::Boolean(previous) = *self.previous.get(&action).unwrap() {
/// Returns current input values for actions return Ok(current && !previous);
pub fn get_many(&self, actions: Vec<A>) -> Vec<InputValue> { }
// SAFETY: action is always valid return Err("Previous input is not boolean".into());
// because we iterate over all actions in `default` method
actions
.iter()
.map(|action| *self.current.get(action).unwrap())
.collect()
} }
Err("This input is not boolean".into())
}
/// Returns `true` if current `InputValue` has become `InputValue::Boolean(true)` in this frame /// Set input value to new
/// If input has not same type as `InputValue` on previous frame call `panic` ///
pub fn just_pressed(&self, action: A) -> bool { /// notice: not recomended to use if you do not know what do you do
// SAFETY: action is always valid pub fn forced_set(&mut self, action: A, value: impl Into<InputValue>) {
// because we iterate over all actions in `default` method // SAFETY: action is always valid
if let InputValue::Boolean(current) = *self.current.get(&action).unwrap() { // because we iterate over all actions in `default` method
if let InputValue::Boolean(previous) = *self.previous.get(&action).unwrap() { let current_input = self.current.get_mut(&action).unwrap();
return current && !previous; *self.previous.get_mut(&action).unwrap() = *current_input;
} *current_input = value.into();
panic!("Previous input is not boolean"); }
}
panic!("This input is not boolean") /// Set input value to new
/// if it is not the same InputValue type return `Error()`
///
/// notice: not recomended to use if you do not know what do you do
pub fn set(
&mut self,
action: A,
value: impl Into<InputValue>,
) -> Result<(), Box<dyn error::Error>> {
// SAFETY: action is always valid
// because we iterate over all actions in `default` method
let current_input = self.current.get_mut(&action).unwrap();
let previos_input = self.previous.get_mut(&action).unwrap();
// check if enum type is the same ignoring value
if discriminant(current_input) == discriminant(previos_input) {
*previos_input = *current_input;
*current_input = value.into();
Ok(())
} else {
Err("Input type is not the same".into())
} }
}
// TODO this is must be binding option for non axis inputs /// Update current inputs
/// Returns `true` if current `InputValue` has become `InputValue::Boolean(true)` in this frame ///
/// If input has not same type as `InputValue` on previous frame return `Error()` /// notice: not recomended to use if you do not know what do you do
pub fn get_just_pressed(&self, action: A) -> Result<bool, Box<dyn error::Error>> { pub fn forced_update(&mut self, inputs: Inputs<A>) {
// SAFETY: action is always valid *self.previous = self.current.clone().0;
// because we iterate over all actions in `default` method *self.current = inputs.0;
if let InputValue::Boolean(current) = *self.current.get(&action).unwrap() { }
if let InputValue::Boolean(previous) = *self.previous.get(&action).unwrap() {
return Ok(current && !previous); /// Update current inputs
} /// if any input is not the same InputValue type return `Error()`
return Err("Previous input is not boolean".into()); /// ! remember that it work safely but slow
} ///
Err("This input is not boolean".into()) /// notice: not recomended to use if you do not know what do you do
} pub fn update(&mut self, inputs: Inputs<A>) -> Result<(), Box<dyn error::Error>> {
// SAFETY: action is always valid
/// Set input value to new // because we iterate over all actions in `default` method
/// for (action, value) in inputs.0.iter() {
/// notice: not recomended to use if you do not know what do you do let current_input = self.current.get_mut(action).unwrap();
pub fn forced_set(&mut self, action: A, value: impl Into<InputValue>) { let previos_input = self.previous.get_mut(action).unwrap();
// SAFETY: action is always valid
// because we iterate over all actions in `default` method // check if enum type is not the same ignoring value
let current_input = self.current.get_mut(&action).unwrap(); if discriminant(current_input) != discriminant(previos_input) {
*self.previous.get_mut(&action).unwrap() = *current_input; return Err("Input type is not the same".into());
*current_input = value.into(); }
} *previos_input = *current_input;
*current_input = *value;
/// Set input value to new
/// if it is not the same InputValue type return `Error()`
///
/// notice: not recomended to use if you do not know what do you do
pub fn set(
&mut self,
action: A,
value: impl Into<InputValue>,
) -> Result<(), Box<dyn error::Error>> {
// SAFETY: action is always valid
// because we iterate over all actions in `default` method
let current_input = self.current.get_mut(&action).unwrap();
let previos_input = self.previous.get_mut(&action).unwrap();
// check if enum type is the same ignoring value
if discriminant(current_input) == discriminant(previos_input) {
*previos_input = *current_input;
*current_input = value.into();
Ok(())
} else {
Err("Input type is not the same".into())
}
}
/// Update current inputs
///
/// notice: not recomended to use if you do not know what do you do
pub fn forced_update(&mut self, inputs: Inputs<A>) {
*self.previous = self.current.clone().0;
*self.current = inputs.0;
}
/// Update current inputs
/// if any input is not the same InputValue type return `Error()`
/// ! remember that it work safely but slow
///
/// notice: not recomended to use if you do not know what do you do
pub fn update(&mut self, inputs: Inputs<A>) -> Result<(), Box<dyn error::Error>> {
// SAFETY: action is always valid
// because we iterate over all actions in `default` method
for (action, value) in inputs.0.iter() {
let current_input = self.current.get_mut(action).unwrap();
let previos_input = self.previous.get_mut(action).unwrap();
// check if enum type is not the same ignoring value
if discriminant(current_input) != discriminant(previos_input) {
return Err("Input type is not the same".into());
}
*previos_input = *current_input;
*current_input = *value;
}
Ok(())
} }
Ok(())
}
} }
common_traits_conditions! { common_traits_conditions! {
@@ -251,28 +254,28 @@ common_traits_conditions! {
} }
impl Default for ActivationOptions { impl Default for ActivationOptions {
fn default() -> Self { fn default() -> Self {
Self { Self {
mode: ActivationMode::Tap, // Because it is more safe mode: ActivationMode::Tap, // Because it is more safe
option: OptionsMode::Immutable, option: OptionsMode::Immutable,
delay: 0.05, // 20 times per second; 14 - world record? delay: 0.05, // 20 times per second; 14 - world record?
}
} }
}
} }
impl ActivationOptions { impl ActivationOptions {
pub fn new(mode: ActivationMode, option: OptionsMode) -> Self { pub fn new(mode: ActivationMode, option: OptionsMode) -> Self {
Self { Self {
mode, mode,
option, option,
..Default::default() ..Default::default()
}
} }
}
pub fn with_delay(mut self, delay: f32) -> Self { pub fn with_delay(mut self, delay: f32) -> Self {
self.delay = delay; self.delay = delay;
self self
} }
} }
common_traits_conditions! { common_traits_conditions! {
@@ -303,26 +306,26 @@ common_traits_conditions! {
} }
impl<Gs: GameState> From<ButtonCombination> for Binding<Gs> { impl<Gs: GameState> From<ButtonCombination> for Binding<Gs> {
fn from(input: ButtonCombination) -> Self { fn from(input: ButtonCombination) -> Self {
Binding { Binding {
input, input,
conditions: Vec::new(), conditions: Vec::new(),
}
} }
}
} }
impl<Gs: GameState> Binding<Gs> { impl<Gs: GameState> Binding<Gs> {
pub fn new(input: ButtonCombination) -> Self { pub fn new(input: ButtonCombination) -> Self {
Self { Self {
input, input,
conditions: Vec::new(), conditions: Vec::new(),
}
} }
}
pub fn with_condition(mut self, condition: BindingCondition<Gs>) -> Self { pub fn with_condition(mut self, condition: BindingCondition<Gs>) -> Self {
self.conditions.push(condition); self.conditions.push(condition);
self self
} }
} }
common_traits_conditions! { common_traits_conditions! {
@@ -337,55 +340,55 @@ common_traits_conditions! {
} }
impl From<bool> for InputValue { impl From<bool> for InputValue {
fn from(value: bool) -> Self { fn from(value: bool) -> Self {
InputValue::Boolean(value) InputValue::Boolean(value)
} }
} }
impl From<f32> for InputValue { impl From<f32> for InputValue {
fn from(value: f32) -> Self { fn from(value: f32) -> Self {
InputValue::Float(value) InputValue::Float(value)
} }
} }
impl From<InputValue> for bool { impl From<InputValue> for bool {
fn from(value: InputValue) -> Self { fn from(value: InputValue) -> Self {
match value { match value {
InputValue::Boolean(value) => value, InputValue::Boolean(value) => value,
_ => panic!("InputValue is not boolean"), _ => panic!("InputValue is not boolean"),
}
} }
}
} }
impl From<InputValue> for f32 { impl From<InputValue> for f32 {
fn from(value: InputValue) -> Self { fn from(value: InputValue) -> Self {
match value { match value {
InputValue::Float(value) => value, InputValue::Float(value) => value,
_ => panic!("InputValue is not float"), _ => panic!("InputValue is not float"),
}
} }
}
} }
impl InputValue { impl InputValue {
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
matches!(self, InputValue::Empty) matches!(self, InputValue::Empty)
} }
pub fn is_boolean(&self) -> bool { pub fn is_boolean(&self) -> bool {
matches!(self, InputValue::Boolean(_)) matches!(self, InputValue::Boolean(_))
} }
pub fn is_float(&self) -> bool { pub fn is_float(&self) -> bool {
matches!(self, InputValue::Float(_)) matches!(self, InputValue::Float(_))
} }
pub fn to_boolean(&self) -> bool { pub fn to_boolean(&self) -> bool {
match self { match self {
InputValue::Boolean(value) => *value, InputValue::Boolean(value) => *value,
InputValue::Float(value) => *value > 0.0, InputValue::Float(value) => *value > 0.0,
InputValue::Empty => false, InputValue::Empty => false,
}
} }
}
} }
common_traits_conditions! { common_traits_conditions! {
@@ -400,74 +403,74 @@ common_traits_conditions! {
} }
impl<Gs: GameState> Default for Bindings<Gs> { impl<Gs: GameState> Default for Bindings<Gs> {
fn default() -> Self { fn default() -> Self {
Self { Self {
list: Vec::new(), list: Vec::new(),
options: OptionsMode::Immutable, options: OptionsMode::Immutable,
}
} }
}
} }
impl<Gs: GameState> Bindings<Gs> { impl<Gs: GameState> Bindings<Gs> {
pub fn new(bindings: Vec<Binding<Gs>>, options: OptionsMode) -> Self { pub fn new(bindings: Vec<Binding<Gs>>, options: OptionsMode) -> Self {
Self { Self {
list: bindings, list: bindings,
options, options,
}
} }
}
pub fn force_push(&mut self, binding: Binding<Gs>) { pub fn force_push(&mut self, binding: Binding<Gs>) {
self.list.push(binding); self.list.push(binding);
} }
pub fn push(&mut self, binding: Binding<Gs>) { pub fn push(&mut self, binding: Binding<Gs>) {
if self.options == OptionsMode::Immutable { if self.options == OptionsMode::Immutable {
warn!("You try to push binding to immutable bindings"); warn!("You try to push binding to immutable bindings");
return; return;
}
self.list.push(binding);
} }
self.list.push(binding);
}
pub fn clear(&mut self) { pub fn clear(&mut self) {
if self.options == OptionsMode::Immutable { if self.options == OptionsMode::Immutable {
warn!("You try to clear immutable bindings"); warn!("You try to clear immutable bindings");
return; return;
}
self.list.clear();
} }
self.list.clear();
}
pub fn retain<F>(&mut self, f: F) pub fn retain<F>(&mut self, f: F)
where where
F: FnMut(&Binding<Gs>) -> bool, F: FnMut(&Binding<Gs>) -> bool,
{ {
if self.options == OptionsMode::Immutable { if self.options == OptionsMode::Immutable {
warn!("You try to retain immutable bindings"); warn!("You try to retain immutable bindings");
return; return;
}
self.list.retain(f);
} }
self.list.retain(f);
}
pub fn iter(&self) -> impl Iterator<Item = &Binding<Gs>> { pub fn iter(&self) -> impl Iterator<Item = &Binding<Gs>> {
self.list.iter() self.list.iter()
} }
pub fn iter_mut( pub fn iter_mut(
&mut self, &mut self,
) -> Result<impl Iterator<Item = &mut Binding<Gs>>, Box<dyn error::Error>> { ) -> Result<impl Iterator<Item = &mut Binding<Gs>>, Box<dyn error::Error>> {
if self.options == OptionsMode::Immutable { if self.options == OptionsMode::Immutable {
warn!("You try to iterate over immutable bindings"); warn!("You try to iterate over immutable bindings");
return Err("You try to iterate over immutable bindings".into()); return Err("You try to iterate over immutable bindings".into());
}
Ok(self.list.iter_mut())
} }
Ok(self.list.iter_mut())
}
pub fn is_customizable(&self) -> bool { pub fn is_customizable(&self) -> bool {
self.options == OptionsMode::Customizable self.options == OptionsMode::Customizable
} }
pub fn is_immutable(&self) -> bool { pub fn is_immutable(&self) -> bool {
self.options == OptionsMode::Immutable self.options == OptionsMode::Immutable
} }
} }
common_traits_conditions! { common_traits_conditions! {
@@ -483,12 +486,12 @@ common_traits_conditions! {
} }
impl<Gs: GameState> BindingConfig<Gs> { impl<Gs: GameState> BindingConfig<Gs> {
pub fn new(bindings: Bindings<Gs>, activation: ActivationOptions) -> Self { pub fn new(bindings: Bindings<Gs>, activation: ActivationOptions) -> Self {
Self { Self {
bindings, bindings,
activation, activation,
}
} }
}
} }
common_traits_conditions! { common_traits_conditions! {
@@ -504,67 +507,70 @@ common_traits_conditions! {
} }
impl<A: Action, Gs: GameState> Default for Controls<A, Gs> { impl<A: Action, Gs: GameState> Default for Controls<A, Gs> {
fn default() -> Self { fn default() -> Self {
// TODO: default must create empty controls or fill empty / default BindingConfig on any actions // TODO: default must create empty controls or fill empty / default BindingConfig on any actions
let mut controls = HashMap::new(); let mut controls = HashMap::new();
for key in A::iter() { for key in A::iter() {
controls.insert(key, BindingConfig::default()); controls.insert(key, BindingConfig::default());
}
// If you see this error, you may add new action in menu_actions
// or make sure that you have only one Menufor<'a> Action<'a> with the same name in the Menufor<'a> Action<'a>s
assert!(validate_hash_map(&controls));
Self(controls)
} }
// If you see this error, you may add new action in menu_actions
// or make sure that you have only one Menufor<'a> Action<'a> with the same name in the Menufor<'a> Action<'a>s
assert!(validate_hash_map(&controls));
Self(controls)
}
} }
impl<A: Action, Gs: GameState> Controls<A, Gs> { impl<A: Action, Gs: GameState> Controls<A, Gs> {
/// Returns bindings for action /// Returns bindings for action
pub fn get(&self, action: A) -> Option<&BindingConfig<Gs>> { pub fn get(&self, action: A) -> Option<&BindingConfig<Gs>> {
self.0.get(&action) self.0.get(&action)
} }
/// Forced push new binding for action /// Forced push new binding for action
pub fn force_push(&mut self, action: A, binding: Binding<Gs>) { pub fn force_push(&mut self, action: A, binding: Binding<Gs>) {
// TODO: warning if config is not exist yet // TODO: warning if config is not exist yet
// TODO: interface for [`ActivationOptions`] // TODO: interface for [`ActivationOptions`]
self.0 self
.entry(action) .0
.or_insert_with(BindingConfig::default) .entry(action)
.bindings .or_insert_with(BindingConfig::default)
.force_push(binding); .bindings
} .force_push(binding);
}
/// Push new binding for action /// Push new binding for action
pub fn push(&mut self, action: A, binding: Binding<Gs>) { pub fn push(&mut self, action: A, binding: Binding<Gs>) {
// TODO: warning if config is not exist yet // TODO: warning if config is not exist yet
// TODO: interface for [`ActivationOptions`] // TODO: interface for [`ActivationOptions`]
self.0 self
.entry(action) .0
.or_insert_with(BindingConfig::default) .entry(action)
.bindings .or_insert_with(BindingConfig::default)
.push(binding); .bindings
} .push(binding);
}
/// Remove all bindings for action /// Remove all bindings for action
pub fn remove(&mut self, action: A) { pub fn remove(&mut self, action: A) {
// TODO: warning if config is not exist yet // TODO: warning if config is not exist yet
self.0 self
.entry(action) .0
.or_insert_with(BindingConfig::default) .entry(action)
.bindings .or_insert_with(BindingConfig::default)
.clear(); .bindings
} .clear();
}
pub fn remove_binding(&mut self, action: A, binding: Binding<Gs>) { pub fn remove_binding(&mut self, action: A, binding: Binding<Gs>) {
if let Some(config) = self.0.get_mut(&action) { if let Some(config) = self.0.get_mut(&action) {
config.bindings.retain(|b| *b == binding); config.bindings.retain(|b| *b == binding);
}
} }
}
pub fn iter(&self) -> impl Iterator<Item = (&A, &BindingConfig<Gs>)> { pub fn iter(&self) -> impl Iterator<Item = (&A, &BindingConfig<Gs>)> {
self.0.iter() self.0.iter()
} }
} }
+77 -77
View File
@@ -75,105 +75,105 @@ macro_rules! common_traits_conditions {
#[cfg(test)] #[cfg(test)]
pub mod test { pub mod test {
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use bevy_derive::{Deref, DerefMut}; use bevy_derive::{Deref, DerefMut};
use log::Level; use log::Level;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deref, DerefMut)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deref, DerefMut)]
pub struct Times(u64); pub struct Times(u64);
impl Into<u64> for Times { impl Into<u64> for Times {
fn into(self) -> u64 { fn into(self) -> u64 {
self.0 self.0
}
} }
}
impl Into<usize> for Times { impl Into<usize> for Times {
fn into(self) -> usize { fn into(self) -> usize {
self.0 as usize self.0 as usize
}
} }
}
impl Into<u32> for Times { impl Into<u32> for Times {
fn into(self) -> u32 { fn into(self) -> u32 {
self.0 as u32 self.0 as u32
}
} }
}
impl Into<i32> for Times { impl Into<i32> for Times {
fn into(self) -> i32 { fn into(self) -> i32 {
self.0 as i32 self.0 as i32
}
} }
}
impl From<u64> for Times { impl From<u64> for Times {
fn from(times: u64) -> Self { fn from(times: u64) -> Self {
Self(times) Self(times)
}
} }
}
impl From<usize> for Times { impl From<usize> for Times {
fn from(times: usize) -> Self { fn from(times: usize) -> Self {
Self(times as u64) Self(times as u64)
}
} }
}
impl From<u32> for Times { impl From<u32> for Times {
fn from(times: u32) -> Self { fn from(times: u32) -> Self {
Self(times as u64) Self(times as u64)
}
} }
}
impl From<i32> for Times { impl From<i32> for Times {
fn from(times: i32) -> Self { fn from(times: i32) -> Self {
Self(times as u64) Self(times as u64)
}
} }
}
impl Default for Times { impl Default for Times {
/// Value that may be enough for most cases /// Value that may be enough for most cases
fn default() -> Self { fn default() -> Self {
Self(100000) Self(100000)
}
} }
}
/// Enable logging for debug /// Enable logging for debug
pub fn enable_loggings() { pub fn enable_loggings() {
use std::env; use std::env;
use std::io::Write; use std::io::Write;
let _ = env::set_var("RUST_LOG", "debug"); let _ = env::set_var("RUST_LOG", "debug");
// FIXME: colorize logs // FIXME: colorize logs
// TODO: colorize thorwed args // TODO: colorize thorwed args
let _ = env_logger::builder() let _ = env_logger::builder()
.is_test(true) .is_test(true)
.format(|buf, record| { .format(|buf, record| {
let mut style = buf.style(); let mut style = buf.style();
let level = record.level(); let level = record.level();
match level { match level {
Level::Trace => style.set_color(env_logger::fmt::Color::Magenta), Level::Trace => style.set_color(env_logger::fmt::Color::Magenta),
Level::Debug => style.set_color(env_logger::fmt::Color::Blue), Level::Debug => style.set_color(env_logger::fmt::Color::Blue),
Level::Info => style.set_color(env_logger::fmt::Color::Green), Level::Info => style.set_color(env_logger::fmt::Color::Green),
Level::Warn => style.set_color(env_logger::fmt::Color::Yellow), Level::Warn => style.set_color(env_logger::fmt::Color::Yellow),
Level::Error => style.set_color(env_logger::fmt::Color::Red), Level::Error => style.set_color(env_logger::fmt::Color::Red),
}; };
writeln!(buf, "{}: {}", style.value(level), record.args()) writeln!(buf, "{}: {}", style.value(level), record.args())
}) })
.try_init(); .try_init();
} }
/// Measure time of predicate /// Measure time of predicate
pub fn measure_time<F: Copy>(predicate: F, times: Times) -> Duration pub fn measure_time<F: Copy>(predicate: F, times: Times) -> Duration
where where
F: FnOnce() -> (), F: FnOnce() -> (),
{ {
let start = Instant::now(); let start = Instant::now();
for _ in 0..times.clone().into() { for _ in 0..times.clone().into() {
predicate(); predicate();
}
let global_duration = start.elapsed();
global_duration / times.into()
} }
let global_duration = start.elapsed();
global_duration / times.into()
}
} }
+1
View File
@@ -0,0 +1 @@
tab_spaces = 2