style: run cargo fmt
This commit is contained in:
+248
-245
@@ -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 {}
|
||||||
|
// }
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
tab_spaces = 2
|
||||||
Reference in New Issue
Block a user