diff --git a/dotlottie-rs/src/state_machine_engine/inputs/mod.rs b/dotlottie-rs/src/state_machine_engine/inputs/mod.rs index b47e8994..e54a493e 100644 --- a/dotlottie-rs/src/state_machine_engine/inputs/mod.rs +++ b/dotlottie-rs/src/state_machine_engine/inputs/mod.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use serde::Deserialize; @@ -15,128 +15,113 @@ pub enum Input { #[derive(Clone, Debug)] pub enum InputValue { Numeric(f32), - String(String), Boolean(bool), + String(String), Event(String), } -pub trait InputTrait { - fn set_initial_boolean(&mut self, key: &str, value: bool); - fn set_initial_string(&mut self, key: &str, value: String); - fn set_initial_numeric(&mut self, key: &str, value: f32); - fn set_initial_event(&mut self, key: &str, value: &str); - fn new() -> Self; - fn set_boolean(&mut self, key: &str, value: bool) -> Option; - fn set_string(&mut self, key: &str, value: String) -> Option; - fn set_numeric(&mut self, key: &str, value: f32) -> Option; - fn get_numeric(&self, key: &str) -> Option; - fn get_string(&self, key: &str) -> Option; - fn get_boolean(&self, key: &str) -> Option; - fn get_event(&self, key: &str) -> Option; - fn reset(&mut self, key: &str) -> Option<(InputValue, InputValue)>; -} - pub struct InputManager { - pub inputs: HashMap, - default_values: HashMap, + pub(super) numeric: HashMap, + pub(super) boolean: HashMap, + pub(super) string: HashMap, + pub(super) event: HashSet, } -impl InputTrait for InputManager { - fn new() -> Self { - let inputs = HashMap::new(); - - // Store defaults - let default_values = inputs.clone(); - - InputManager { - inputs, - default_values, - } +impl Default for InputManager { + fn default() -> Self { + Self::new() } +} - fn reset(&mut self, key: &str) -> Option<(InputValue, InputValue)> { - if let Some(default_value) = self.default_values.get(key) { - return Some(( - self.inputs - .insert(key.to_string(), default_value.clone()) - .unwrap_or(default_value.clone()), - default_value.clone(), - )); +impl InputManager { + pub fn new() -> Self { + Self { + numeric: HashMap::new(), + boolean: HashMap::new(), + string: HashMap::new(), + event: HashSet::new(), } - - None } - fn set_numeric(&mut self, key: &str, value: f32) -> Option { - self.inputs - .insert(key.to_string(), InputValue::Numeric(value)) + pub fn len(&self) -> usize { + self.numeric.len() + self.boolean.len() + self.string.len() + self.event.len() } - // Get methods for each type - fn get_numeric(&self, key: &str) -> Option { - match self.inputs.get(key) { - Some(InputValue::Numeric(value)) => Some(*value), - _ => None, - } + pub fn is_empty(&self) -> bool { + self.numeric.is_empty() + && self.boolean.is_empty() + && self.string.is_empty() + && self.event.is_empty() } - fn set_string(&mut self, key: &str, value: String) -> Option { - self.inputs - .insert(key.to_string(), InputValue::String(value)) + pub fn set_initial_numeric(&mut self, key: &str, value: f32) { + self.numeric.insert(key.to_string(), (value, value)); } - fn get_string(&self, key: &str) -> Option { - match self.inputs.get(key) { - Some(InputValue::String(value)) => Some(value.clone()), - _ => None, - } + pub fn set_initial_string(&mut self, key: &str, value: &str) { + self.string + .insert(key.to_string(), (value.to_string(), value.to_string())); } - fn set_boolean(&mut self, key: &str, value: bool) -> Option { - self.inputs - .insert(key.to_string(), InputValue::Boolean(value)) + pub fn set_initial_boolean(&mut self, key: &str, value: bool) { + self.boolean.insert(key.to_string(), (value, value)); } - fn get_boolean(&self, key: &str) -> Option { - match self.inputs.get(key) { - Some(InputValue::Boolean(value)) => Some(*value), - _ => None, - } + pub fn set_initial_event(&mut self, key: &str) { + self.event.insert(key.to_string()); } - fn get_event(&self, key: &str) -> Option { - match self.inputs.get(key) { - Some(InputValue::Event(value)) => Some(value.clone()), - _ => None, - } + pub fn set_numeric(&mut self, key: &str, value: f32) -> Option { + let (current, _) = self.numeric.get_mut(key)?; + let old = *current; + *current = value; + Some(old) } - fn set_initial_numeric(&mut self, key: &str, value: f32) { - self.inputs - .insert(key.to_string(), InputValue::Numeric(value)); + pub fn set_boolean(&mut self, key: &str, value: bool) -> Option { + let (current, _) = self.boolean.get_mut(key)?; + let old = *current; + *current = value; + Some(old) + } - self.default_values - .insert(key.to_string(), InputValue::Numeric(value)); + pub fn set_string(&mut self, key: &str, value: &str) -> Option { + let (current, _) = self.string.get_mut(key)?; + Some(std::mem::replace(current, value.to_string())) } - fn set_initial_string(&mut self, key: &str, value: String) { - self.inputs - .insert(key.to_string(), InputValue::String(value.clone())); + pub fn get_numeric(&self, key: &str) -> Option { + self.numeric.get(key).map(|(v, _)| *v) + } - self.default_values - .insert(key.to_string(), InputValue::String(value.clone())); + pub fn get_boolean(&self, key: &str) -> Option { + self.boolean.get(key).map(|(v, _)| *v) } - fn set_initial_boolean(&mut self, key: &str, value: bool) { - self.inputs - .insert(key.to_string(), InputValue::Boolean(value)); + pub fn get_string(&self, key: &str) -> Option<&str> { + self.string.get(key).map(|(v, _)| v.as_str()) + } - self.default_values - .insert(key.to_string(), InputValue::Boolean(value)); + pub fn get_event(&self, key: &str) -> Option<&str> { + self.event.get(key).map(|s| s.as_str()) } - fn set_initial_event(&mut self, key: &str, value: &str) { - self.inputs - .insert(key.to_string(), InputValue::Event(value.to_string())); + pub fn reset(&mut self, key: &str) -> Option<(InputValue, InputValue)> { + if let Some((current, default)) = self.numeric.get_mut(key) { + let old = InputValue::Numeric(*current); + *current = *default; + return Some((old, InputValue::Numeric(*default))); + } + if let Some((current, default)) = self.boolean.get_mut(key) { + let old = InputValue::Boolean(*current); + *current = *default; + return Some((old, InputValue::Boolean(*default))); + } + if let Some((current, default)) = self.string.get_mut(key) { + let new_val = default.clone(); + let old_val = std::mem::replace(current, new_val.clone()); + return Some((InputValue::String(old_val), InputValue::String(new_val))); + } + None } } diff --git a/dotlottie-rs/src/state_machine_engine/mod.rs b/dotlottie-rs/src/state_machine_engine/mod.rs index 36e47fcb..7a14f6b0 100644 --- a/dotlottie-rs/src/state_machine_engine/mod.rs +++ b/dotlottie-rs/src/state_machine_engine/mod.rs @@ -14,7 +14,7 @@ pub mod transitions; use actions::open_url_policy::OpenUrlPolicy; use actions::{Action, ActionTrait}; -use inputs::{Input, InputManager, InputTrait, InputValue}; +use inputs::{Input, InputManager, InputValue}; use interactions::InteractionTrait; use state_machine::StateMachine; use states::StateTrait; @@ -158,7 +158,7 @@ impl<'a> StateMachineEngine<'a> { value: f32, run_pipeline: bool, called_from_action: bool, - ) -> Option { + ) -> Option { // Modifying triggers whilst tweening isn't allowed if self.status == StateMachineEngineStatus::Tweening { return None; @@ -166,8 +166,8 @@ impl<'a> StateMachineEngine<'a> { let ret = self.inputs.set_numeric(key, value); - if let Some(InputValue::Numeric(old_value)) = &ret { - self.observe_numeric_input_value_change(key, *old_value, value); + if let Some(old_value) = ret { + self.observe_numeric_input_value_change(key, old_value, value); } if called_from_action { @@ -191,16 +191,16 @@ impl<'a> StateMachineEngine<'a> { value: &str, run_pipeline: bool, called_from_action: bool, - ) -> Option { + ) -> Option { // Modifying triggers whilst tweening isn't allowed if self.status == StateMachineEngineStatus::Tweening { return None; } - let ret = self.inputs.set_string(key, value.to_string()); + let ret = self.inputs.set_string(key, value); - if let Some(InputValue::String(old_value)) = ret.clone() { - self.observe_string_input_value_change(key, &old_value, value); + if let Some(ref old_value) = ret { + self.observe_string_input_value_change(key, old_value, value); } if called_from_action { @@ -215,7 +215,7 @@ impl<'a> StateMachineEngine<'a> { } pub fn get_string_input(&self, key: &str) -> Option { - self.inputs.get_string(key) + self.inputs.get_string(key).map(Into::into) } pub fn set_boolean_input( @@ -224,7 +224,7 @@ impl<'a> StateMachineEngine<'a> { value: bool, run_pipeline: bool, called_from_action: bool, - ) -> Option { + ) -> Option { // Modifying triggers whilst tweening isn't allowed if self.status == StateMachineEngineStatus::Tweening { return None; @@ -232,7 +232,7 @@ impl<'a> StateMachineEngine<'a> { let ret = self.inputs.set_boolean(key, value); - if let Some(InputValue::Boolean(old_value)) = ret.clone() { + if let Some(old_value) = ret { self.observe_boolean_input_value_change(key, old_value, value); } @@ -252,31 +252,22 @@ impl<'a> StateMachineEngine<'a> { } pub fn reset_input(&mut self, key: &str, run_pipeline: bool, called_from_action: bool) { - // Modifying triggers whilst tweening isn't allowed if self.status != StateMachineEngineStatus::Running { return; } - let ret = self.inputs.reset(key); - - if let Some((old_value, new_value)) = ret { - match old_value { - InputValue::Numeric(old_value) => { - if let InputValue::Numeric(new_value) = new_value { - self.observe_numeric_input_value_change(key, old_value, new_value); - } + if let Some((old, new)) = self.inputs.reset(key) { + match (old, new) { + (InputValue::Numeric(old), InputValue::Numeric(new)) => { + self.observe_numeric_input_value_change(key, old, new); } - InputValue::String(old_value) => { - if let InputValue::String(new_value) = new_value { - self.observe_string_input_value_change(key, &old_value, &new_value); - } + (InputValue::String(old), InputValue::String(new)) => { + self.observe_string_input_value_change(key, &old, &new); } - InputValue::Boolean(old_value) => { - if let InputValue::Boolean(new_value) = new_value { - self.observe_boolean_input_value_change(key, old_value, new_value); - } + (InputValue::Boolean(old), InputValue::Boolean(new)) => { + self.observe_boolean_input_value_change(key, old, new); } - InputValue::Event(_) => {} + _ => {} } } @@ -290,11 +281,9 @@ impl<'a> StateMachineEngine<'a> { } pub fn fire(&mut self, event: &str, run_pipeline: bool) -> Result<(), StateMachineEngineError> { - // If the event is a valid input - if let Some(valid_event) = self.inputs.get_event(event) { - self.observe_on_input_fired(&valid_event); - - self.curr_event = Some(valid_event.to_string()); + if self.inputs.get_event(event).is_some() { + self.observe_on_input_fired(event); + self.curr_event = Some(event.to_string()); // Run pipeline is always false if called from an action if run_pipeline { @@ -369,15 +358,13 @@ impl<'a> StateMachineEngine<'a> { new_state_machine.inputs.set_initial_numeric(name, *value); } Input::String { name, value } => { - new_state_machine - .inputs - .set_initial_string(name, value.to_string()); + new_state_machine.inputs.set_initial_string(name, value); } Input::Boolean { name, value } => { new_state_machine.inputs.set_initial_boolean(name, *value); } Input::Event { name } => { - new_state_machine.inputs.set_initial_event(name, name); + new_state_machine.inputs.set_initial_event(name); } } } @@ -1144,8 +1131,8 @@ impl<'a> StateMachineEngine<'a> { } // We didn't hit any listened layers - if !hit { - self.pointer_management.curr_entered_layer = "".to_string(); + if !hit && !old_layer.is_empty() { + self.pointer_management.curr_entered_layer.clear(); let pointer_exit_interactions = self.interactions(Some(event_type_name!(PointerExit))); @@ -1419,18 +1406,22 @@ impl<'a> StateMachineEngine<'a> { } pub fn get_inputs(&self) -> Vec { - let mut result = Vec::with_capacity(self.inputs.inputs.len() * 2); - for (key, value) in self.inputs.inputs.iter() { - result.push(key.clone()); - result.push( - match value { - crate::inputs::InputValue::Numeric(_) => "Numeric", - crate::inputs::InputValue::String(_) => "String", - crate::inputs::InputValue::Boolean(_) => "Boolean", - crate::inputs::InputValue::Event(_) => "Event", - } - .to_string(), - ); + let mut result = Vec::with_capacity(self.inputs.len() * 2); + for name in self.inputs.numeric.keys() { + result.push(name.clone()); + result.push("Numeric".to_string()); + } + for name in self.inputs.boolean.keys() { + result.push(name.clone()); + result.push("Boolean".to_string()); + } + for name in self.inputs.string.keys() { + result.push(name.clone()); + result.push("String".to_string()); + } + for name in self.inputs.event.iter() { + result.push(name.clone()); + result.push("Event".to_string()); } result } diff --git a/dotlottie-rs/src/state_machine_engine/state_machine/mod.rs b/dotlottie-rs/src/state_machine_engine/state_machine/mod.rs index 3130c3b9..12a111cf 100644 --- a/dotlottie-rs/src/state_machine_engine/state_machine/mod.rs +++ b/dotlottie-rs/src/state_machine_engine/state_machine/mod.rs @@ -2,11 +2,7 @@ use serde::Deserialize; use crate::errors::StateMachineError; -use super::{ - inputs::Input, - interactions::Interaction, - states::{State, StateTrait}, -}; +use super::{inputs::Input, interactions::Interaction, states::State}; #[derive(Debug, Clone, Deserialize, PartialEq)] #[serde(untagged)] @@ -70,10 +66,6 @@ impl StateMachine { pub fn inputs(&self) -> Option<&Vec> { self.inputs.as_ref() } - - pub fn get_state_by_name(&self, name: &str) -> Option<&State> { - self.states.iter().find(|state| state.name() == name) - } } impl Default for StateMachine { diff --git a/dotlottie-rs/src/state_machine_engine/transitions/guard.rs b/dotlottie-rs/src/state_machine_engine/transitions/guard.rs index 3bf4f179..3161c893 100644 --- a/dotlottie-rs/src/state_machine_engine/transitions/guard.rs +++ b/dotlottie-rs/src/state_machine_engine/transitions/guard.rs @@ -1,7 +1,7 @@ use serde::Deserialize; use crate::{ - inputs::{InputManager, InputTrait}, + inputs::InputManager, state_machine::{StringBool, StringNumberBool}, }; @@ -116,7 +116,7 @@ impl GuardTrait for Guard { let value = mut_compare_to.trim_start_matches('$'); let opt_string_value = input.get_string(value); if let Some(string_value) = opt_string_value { - mut_compare_to = string_value.clone(); + mut_compare_to = string_value.to_string(); } else { // Failed to get value from inputs return false; @@ -125,10 +125,10 @@ impl GuardTrait for Guard { match condition_type { TransitionGuardConditionType::Equal => { - return input_value == *mut_compare_to; + return *input_value == *mut_compare_to; } TransitionGuardConditionType::NotEqual => { - return input_value != *mut_compare_to; + return *input_value != *mut_compare_to; } _ => return false, }