Skip to main content

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