1use std::collections::HashMap;
2
3use crate::{
4 world::local::{
5 local_entity::{HostEntity, OwnedLocalEntity, RemoteEntity},
6 local_entity_record::LocalEntityRecord,
7 },
8 EntityDoesNotExistError, GlobalEntity, HostType, Instant, LocalEntityAndGlobalEntityConverter,
9};
10
11pub struct LocalEntityMap {
13 host_type: HostType,
14 global_to_local: HashMap<GlobalEntity, LocalEntityRecord>,
15 host_to_global: HashMap<HostEntity, GlobalEntity>,
18 remote_to_global: HashMap<RemoteEntity, GlobalEntity>,
19 entity_redirects: HashMap<OwnedLocalEntity, (OwnedLocalEntity, Instant)>,
20}
21
22impl LocalEntityAndGlobalEntityConverter for LocalEntityMap {
23 fn global_entity_to_host_entity(
24 &self,
25 global_entity: &GlobalEntity,
26 ) -> Result<HostEntity, EntityDoesNotExistError> {
27 if let Some(record) = self.global_to_local.get(global_entity) {
28 if record.is_host_owned() {
29 return Ok(record.host_entity());
30 }
31 }
32 Err(EntityDoesNotExistError)
33 }
34
35 fn global_entity_to_remote_entity(
36 &self,
37 global_entity: &GlobalEntity,
38 ) -> Result<RemoteEntity, EntityDoesNotExistError> {
39 if let Some(record) = self.global_to_local.get(global_entity) {
40 if record.is_remote_owned() {
41 return Ok(record.remote_entity());
42 }
43 }
44 Err(EntityDoesNotExistError)
45 }
46
47 fn global_entity_to_owned_entity(
48 &self,
49 global_entity: &GlobalEntity,
50 ) -> Result<OwnedLocalEntity, EntityDoesNotExistError> {
51 if let Some(record) = self.global_to_local.get(global_entity) {
52 return Ok(record.owned_entity());
54 }
55 Err(EntityDoesNotExistError)
56 }
57
58 fn host_entity_to_global_entity(
59 &self,
60 host_entity: &HostEntity,
61 ) -> Result<GlobalEntity, EntityDoesNotExistError> {
62 if let Some(global_entity) = self.host_to_global.get(host_entity) {
63 return Ok(*global_entity);
64 }
65 Err(EntityDoesNotExistError)
66 }
67
68 fn static_host_entity_to_global_entity(
69 &self,
70 host_entity: &HostEntity,
71 ) -> Result<GlobalEntity, EntityDoesNotExistError> {
72 if let Some(global_entity) = self.host_to_global.get(host_entity) {
73 return Ok(*global_entity);
74 }
75 Err(EntityDoesNotExistError)
76 }
77
78 fn remote_entity_to_global_entity(
79 &self,
80 remote_entity: &RemoteEntity,
81 ) -> Result<GlobalEntity, EntityDoesNotExistError> {
82 if let Some(global_entity) = self.remote_to_global.get(remote_entity) {
83 return Ok(*global_entity);
84 }
85 Err(EntityDoesNotExistError)
86 }
87
88 fn apply_entity_redirect(&self, entity: &OwnedLocalEntity) -> OwnedLocalEntity {
89 if let Some((new_entity, _timestamp)) = self.entity_redirects.get(entity) {
90 *new_entity
91 } else {
92 *entity
93 }
94 }
95}
96
97impl LocalEntityMap {
98 pub fn new(host_type: HostType) -> Self {
100 Self {
101 host_type,
102 global_to_local: HashMap::new(),
103 host_to_global: HashMap::new(),
104 remote_to_global: HashMap::new(),
105 entity_redirects: HashMap::new(),
106 }
107 }
108
109 pub fn host_type(&self) -> HostType {
111 self.host_type
112 }
113
114 pub fn insert_with_host_entity(
116 &mut self,
117 global_entity: GlobalEntity,
118 host_entity: HostEntity,
119 ) {
120 if self.global_to_local.contains_key(&global_entity) {
121 panic!(
122 "Cannot overwrite inserted global entity: {:?}",
123 global_entity
124 );
125 }
126 if self.host_to_global.contains_key(&host_entity) {
127 panic!("Cannot overwrite inserted host entity {:?}", host_entity);
128 }
129
130 self.global_to_local.insert(
131 global_entity,
132 LocalEntityRecord::new_host_owned_entity(host_entity),
133 );
134
135 self.host_to_global.insert(host_entity, global_entity);
136 }
137
138 pub fn insert_with_static_host_entity(
140 &mut self,
141 global_entity: GlobalEntity,
142 host_entity: HostEntity,
143 ) {
144 if self.global_to_local.contains_key(&global_entity) {
145 panic!(
146 "Cannot overwrite inserted global entity: {:?}",
147 global_entity
148 );
149 }
150 if self.host_to_global.contains_key(&host_entity) {
151 panic!("Cannot overwrite inserted static host entity {:?}", host_entity);
152 }
153
154 self.global_to_local.insert(
155 global_entity,
156 LocalEntityRecord::new_static_host_owned_entity(host_entity),
157 );
158
159 self.host_to_global.insert(host_entity, global_entity);
160 }
161
162 pub fn insert_with_remote_entity(
164 &mut self,
165 global_entity: GlobalEntity,
166 remote_entity: RemoteEntity,
167 ) {
168 if self.global_to_local.contains_key(&global_entity) {
169 panic!(
170 "Cannot overwrite inserted global entity: {:?}",
171 global_entity
172 );
173 }
174 if self.remote_to_global.contains_key(&remote_entity) {
175 panic!(
176 "Cannot overwrite inserted remote entity {:?}",
177 remote_entity
178 );
179 }
180
181 self.global_to_local.insert(
182 global_entity,
183 LocalEntityRecord::new_remote_owned_entity(remote_entity),
184 );
185 self.remote_to_global.insert(remote_entity, global_entity);
186 }
187
188 pub fn global_entity_from_remote(&self, remote_entity: &RemoteEntity) -> Option<&GlobalEntity> {
190 self.remote_to_global.get(remote_entity)
191 }
192
193 pub fn global_entity_from_host(&self, host_entity: &HostEntity) -> Option<&GlobalEntity> {
195 self.host_to_global.get(host_entity)
196 }
197
198pub fn remove_by_global_entity(
200 &mut self,
201 global_entity: &GlobalEntity,
202 ) -> Option<LocalEntityRecord> {
203 let record_opt = self.global_to_local.remove(global_entity);
205 if let Some(record) = &record_opt {
206 if record.is_host_owned() {
207 let host_entity = record.host_entity();
208 self.host_to_global.remove(&host_entity);
209 } else {
210 let remote_entity = record.remote_entity();
211 self.remote_to_global.remove(&remote_entity);
212 }
213 }
214 record_opt
215 }
216
217 pub(crate) fn remove_by_remote_entity(&mut self, remote_entity: &RemoteEntity) -> GlobalEntity {
218 let global_entity = self.remote_to_global.remove(remote_entity);
219 let Some(global_entity) = global_entity else {
220 panic!(
221 "Attempting to remove remote entity which does not exist: {:?}",
222 remote_entity
223 );
224 };
225 self.remove_by_global_entity(&global_entity);
226 global_entity
227 }
228
229 pub(crate) fn remove_remote_mapping_if_exists(&mut self, remote_entity: &RemoteEntity) {
232 if let Some(_global_entity) = self.remote_to_global.remove(remote_entity) {
236 }
240 }
241
242 pub fn contains_global_entity(&self, global_entity: &GlobalEntity) -> bool {
244 self.global_to_local.contains_key(global_entity)
245 }
246
247 pub fn contains_host_entity(&self, host_entity: &HostEntity) -> bool {
249 self.host_to_global.contains_key(host_entity)
250 }
251
252 pub fn contains_remote_entity(&self, remote_entity: &RemoteEntity) -> bool {
254 self.remote_to_global.contains_key(remote_entity)
255 }
256
257 pub fn iter(&self) -> impl Iterator<Item = (&GlobalEntity, &LocalEntityRecord)> {
259 self.global_to_local.iter()
260 }
261
262 pub(crate) fn remote_entities(&self) -> Vec<GlobalEntity> {
263 self.iter()
264 .filter(|(_, record)| record.is_remote_owned())
265 .map(|(global_entity, _)| *global_entity)
266 .collect::<Vec<GlobalEntity>>()
267 }
268
269 pub fn entity_converter(&self) -> &dyn LocalEntityAndGlobalEntityConverter {
278 self
279 }
280
281 pub fn install_entity_redirect(
283 &mut self,
284 old_entity: OwnedLocalEntity,
285 new_entity: OwnedLocalEntity,
286 ) {
287 let now = Instant::now();
288 self.entity_redirects.insert(old_entity, (new_entity, now));
289 }
290
291 pub(crate) fn apply_entity_redirect(&self, entity: &OwnedLocalEntity) -> OwnedLocalEntity {
292 self.entity_redirects
293 .get(entity)
294 .map(|(new_entity, _)| *new_entity)
295 .unwrap_or(*entity)
296 }
297
298 pub(crate) fn cleanup_old_redirects(&mut self, now: &Instant, ttl_seconds: u64) {
299 use std::time::Duration;
300 let ttl_duration = Duration::from_secs(ttl_seconds);
301 self.entity_redirects
302 .retain(|_, (_, timestamp)| timestamp.elapsed(now) < ttl_duration);
303 }
304}