Skip to main content

subtr_actor/processor/
actor_state.rs

1use crate::{SubtrActorError, SubtrActorErrorVariant, SubtrActorResult};
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    pub(crate) fn set_derived_attribute(
62        &mut self,
63        key: &'static str,
64        attribute: boxcars::Attribute,
65        frame_index: usize,
66    ) {
67        if let Some(entry) = self.derived_attributes.get_mut(key) {
68            *entry = (attribute, frame_index);
69        } else {
70            self.derived_attributes
71                .insert(key.to_owned(), (attribute, frame_index));
72        }
73    }
74}
75
76/// A struct modeling the states of multiple actors at a given point in time.
77/// Provides methods to update that state with successive frames from a
78/// boxcars::Replay.
79pub struct ActorStateModeler {
80    /// A map of actor states with their corresponding actor ids.
81    pub actor_states: HashMap<boxcars::ActorId, ActorState>,
82    /// A map of actor ids with their corresponding object ids.
83    pub actor_ids_by_type: HashMap<boxcars::ObjectId, Vec<boxcars::ActorId>>,
84    /// Actor states deleted while processing the current frame.
85    ///
86    /// This preserves last-known attributes long enough for code that runs after
87    /// deletion, such as same-frame demolition extraction, to still inspect the
88    /// removed actor.
89    pub recently_deleted_actor_states: HashMap<boxcars::ActorId, ActorState>,
90}
91
92impl Default for ActorStateModeler {
93    fn default() -> Self {
94        Self::new()
95    }
96}
97
98impl ActorStateModeler {
99    /// Creates a new [`ActorStateModeler`].
100    ///
101    /// # Returns
102    ///
103    /// A new [`ActorStateModeler`]. object.
104    pub fn new() -> Self {
105        Self {
106            actor_states: HashMap::new(),
107            actor_ids_by_type: HashMap::new(),
108            recently_deleted_actor_states: HashMap::new(),
109        }
110    }
111
112    /// Processes a frame, including handling of new, updated, and deleted actors.
113    ///
114    /// # Arguments
115    ///
116    /// * `frame` - The frame to be processed.
117    /// * `frame_index` - The index of the frame to be processed.
118    ///
119    /// # Returns
120    ///
121    /// An empty result (`Ok(())`) on success, [`SubtrActorError`] on failure.
122    pub fn process_frame(
123        &mut self,
124        frame: &boxcars::Frame,
125        frame_index: usize,
126    ) -> SubtrActorResult<()> {
127        self.recently_deleted_actor_states.clear();
128        if let Some(err) = frame
129            .deleted_actors
130            .iter()
131            .map(|n| self.delete_actor(n))
132            .find(|r| r.is_err())
133        {
134            return err.map(|_| ());
135        }
136        if let Some(err) = frame
137            .new_actors
138            .iter()
139            .map(|n| self.new_actor(n))
140            .find(|r| r.is_err())
141        {
142            return err;
143        }
144        if let Some(err) = frame
145            .updated_actors
146            .iter()
147            .map(|u| self.update_attribute(u, frame_index))
148            .find(|r| r.is_err())
149        {
150            return err.map(|_| ());
151        }
152        Ok(())
153    }
154
155    pub fn new_actor(&mut self, new_actor: &boxcars::NewActor) -> SubtrActorResult<()> {
156        if let Some(state) = self.actor_states.get(&new_actor.actor_id) {
157            if state.object_id != new_actor.object_id {
158                return SubtrActorError::new_result(SubtrActorErrorVariant::ActorIdAlreadyExists {
159                    actor_id: new_actor.actor_id,
160                    object_id: new_actor.object_id,
161                });
162            }
163        } else {
164            self.actor_states
165                .insert(new_actor.actor_id, ActorState::new(new_actor));
166            self.actor_ids_by_type
167                .entry(new_actor.object_id)
168                .or_default()
169                .push(new_actor.actor_id)
170        }
171        Ok(())
172    }
173
174    pub fn update_attribute(
175        &mut self,
176        update: &boxcars::UpdatedAttribute,
177        frame_index: usize,
178    ) -> SubtrActorResult<Option<(boxcars::Attribute, usize)>> {
179        self.actor_states
180            .get_mut(&update.actor_id)
181            .map(|state| state.update_attribute(update, frame_index))
182            .ok_or_else(|| {
183                SubtrActorError::new(SubtrActorErrorVariant::UpdatedActorIdDoesNotExist {
184                    update: update.clone(),
185                })
186            })
187    }
188
189    pub fn delete_actor(&mut self, actor_id: &boxcars::ActorId) -> SubtrActorResult<ActorState> {
190        let state = self.actor_states.remove(actor_id).ok_or_else(|| {
191            SubtrActorError::new(SubtrActorErrorVariant::NoStateForActorId {
192                actor_id: *actor_id,
193            })
194        })?;
195
196        self.actor_ids_by_type
197            .entry(state.object_id)
198            .or_default()
199            .retain(|x| x != actor_id);
200
201        self.recently_deleted_actor_states
202            .insert(*actor_id, state.clone());
203
204        Ok(state)
205    }
206}