subtr_actor_spec/
actor_state.rs

1use crate::*;
2use boxcars;
3use std::collections::HashMap;
4
5/// A struct representing the state of an actor.
6///
7/// This includes both attributes and derived attributes, along with the
8/// associated object id and name id.
9#[derive(PartialEq, Debug, Clone)]
10pub struct ActorState {
11    /// A map of the actor's attributes with their corresponding object ids and
12    /// frame indices.
13    pub attributes: HashMap<boxcars::ObjectId, (boxcars::Attribute, usize)>,
14    /// A map of the actor's derived attributes with their corresponding object
15    /// ids and frame indices.
16    pub derived_attributes: HashMap<String, (boxcars::Attribute, usize)>,
17    /// The object id associated with the actor.
18    pub object_id: boxcars::ObjectId,
19    /// Optional name id associated with the actor.
20    pub name_id: Option<i32>,
21}
22
23impl ActorState {
24    /// Creates a new `ActorState` from a given `NewActor`.
25    ///
26    /// # Arguments
27    ///
28    /// * `new_actor` - The new actor to initialize the state from.
29    ///
30    /// # Returns
31    ///
32    /// A new `ActorState` object.
33    fn new(new_actor: &boxcars::NewActor) -> Self {
34        Self {
35            attributes: HashMap::new(),
36            derived_attributes: HashMap::new(),
37            object_id: new_actor.object_id,
38            name_id: new_actor.name_id,
39        }
40    }
41
42    /// Updates an attribute in the `ActorState`.
43    ///
44    /// # Arguments
45    ///
46    /// * `update` - The updated attribute.
47    /// * `frame_index` - The index of the frame at which the update occurs.
48    ///
49    /// # Returns
50    ///
51    /// An optional tuple of the updated attribute and its frame index.
52    fn update_attribute(
53        &mut self,
54        update: &boxcars::UpdatedAttribute,
55        frame_index: usize,
56    ) -> Option<(boxcars::Attribute, usize)> {
57        self.attributes
58            .insert(update.object_id, (update.attribute.clone(), frame_index))
59    }
60}
61
62/// A struct modeling the states of multiple actors at a given point in time.
63/// Provides methods to update that state with successive frames from a
64/// boxcars::Replay.
65pub struct ActorStateModeler {
66    /// A map of actor states with their corresponding actor ids.
67    pub actor_states: HashMap<boxcars::ActorId, ActorState>,
68    /// A map of actor ids with their corresponding object ids.
69    pub actor_ids_by_type: HashMap<boxcars::ObjectId, Vec<boxcars::ActorId>>,
70}
71
72impl ActorStateModeler {
73    /// Creates a new [`ActorStateModeler`].
74    ///
75    /// # Returns
76    ///
77    /// A new [`ActorStateModeler`]. object.
78    pub fn new() -> Self {
79        Self {
80            actor_states: HashMap::new(),
81            actor_ids_by_type: HashMap::new(),
82        }
83    }
84
85    /// Processes a frame, including handling of new, updated, and deleted actors.
86    ///
87    /// # Arguments
88    ///
89    /// * `frame` - The frame to be processed.
90    /// * `frame_index` - The index of the frame to be processed.
91    ///
92    /// # Returns
93    ///
94    /// An empty result (`Ok(())`) on success, [`SubtrActorError`] on failure.
95    pub fn process_frame(
96        &mut self,
97        frame: &boxcars::Frame,
98        frame_index: usize,
99    ) -> SubtrActorResult<()> {
100        if let Some(err) = frame
101            .deleted_actors
102            .iter()
103            .map(|n| self.delete_actor(n))
104            .find(|r| r.is_err())
105        {
106            return err.map(|_| ());
107        }
108        if let Some(err) = frame
109            .new_actors
110            .iter()
111            .map(|n| self.new_actor(n))
112            .find(|r| r.is_err())
113        {
114            return err;
115        }
116        if let Some(err) = frame
117            .updated_actors
118            .iter()
119            .map(|u| self.update_attribute(u, frame_index))
120            .find(|r| r.is_err())
121        {
122            return err.map(|_| ());
123        }
124        Ok(())
125    }
126
127    pub fn new_actor(&mut self, new_actor: &boxcars::NewActor) -> SubtrActorResult<()> {
128        if let Some(state) = self.actor_states.get(&new_actor.actor_id) {
129            if state.object_id != new_actor.object_id {
130                return SubtrActorError::new_result(SubtrActorErrorVariant::ActorIdAlreadyExists {
131                    actor_id: new_actor.actor_id.clone(),
132                    object_id: new_actor.object_id.clone(),
133                });
134            }
135        } else {
136            self.actor_states
137                .insert(new_actor.actor_id, ActorState::new(new_actor));
138            self.actor_ids_by_type
139                .entry(new_actor.object_id)
140                .or_insert_with(|| Vec::new())
141                .push(new_actor.actor_id)
142        }
143        Ok(())
144    }
145
146    pub fn update_attribute(
147        &mut self,
148        update: &boxcars::UpdatedAttribute,
149        frame_index: usize,
150    ) -> SubtrActorResult<Option<(boxcars::Attribute, usize)>> {
151        self.actor_states
152            .get_mut(&update.actor_id)
153            .map(|state| state.update_attribute(update, frame_index))
154            .ok_or_else(|| {
155                SubtrActorError::new(SubtrActorErrorVariant::UpdatedActorIdDoesNotExist {
156                    update: update.clone(),
157                })
158            })
159    }
160
161    pub fn delete_actor(&mut self, actor_id: &boxcars::ActorId) -> SubtrActorResult<ActorState> {
162        let state = self.actor_states.remove(actor_id).ok_or_else(|| {
163            SubtrActorError::new(SubtrActorErrorVariant::NoStateForActorId {
164                actor_id: actor_id.clone(),
165            })
166        })?;
167
168        self.actor_ids_by_type
169            .entry(state.object_id)
170            .or_insert_with(|| Vec::new())
171            .retain(|x| x != actor_id);
172
173        Ok(state)
174    }
175}