Skip to main content

akashi/ecs/
entity_store.rs

1//! Akashi's storage system for [`Entities`](Entity).
2
3use std::any;
4use std::fmt;
5use std::ops::Deref;
6use std::sync::{Arc, Weak};
7
8extern crate stable_deref_trait;
9use stable_deref_trait::CloneStableDeref;
10
11use dashmap::DashMap;
12use downcast_rs::{Downcast, DowncastSync};
13use parking_lot::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
14
15use super::{ComponentManager, Entity};
16use crate::snowflake::Snowflake;
17use crate::util::Result;
18
19rental! {
20    pub mod handle_ref {
21        //! Self-referential wrappers around shared locks.
22        use super::*;
23
24        /// A self-referential type that wraps `Arc<RwLock<StoreHandle>>`
25        /// into a read-locked immutable reference.
26        ///
27        /// This struct effectively contains an `Arc` pointing to an
28        /// `RwLock` and a read guard for that same lock.
29        ///
30        /// It also supports `Deref` to the inner StoreHandle, which is
31        /// usually all you'll need.
32        #[rental(debug, clone, deref_suffix, covariant, map_suffix = "T")]
33        pub struct HandleReadRef<H: CloneStableDeref + Deref + 'static, T: 'static> {
34            head: H,
35            suffix: RwLockReadGuard<'head, T>,
36        }
37
38        /// A self-referential type that wraps `Arc<RwLock<StoreHandle>>`
39        /// into a write-locked mutable reference.
40        ///
41        /// This struct effectively contains an `Arc` pointing to an
42        /// `RwLock` and a write guard for that same lock.
43        ///
44        /// It also supports `Deref` and `DerefMut` to the inner
45        /// StoreHandle, which is usually all you'll need.
46        #[rental(debug, clone, deref_mut_suffix, covariant, map_suffix = "T")]
47        pub struct HandleWriteRef<H: CloneStableDeref + Deref + 'static, T: 'static> {
48            head: H,
49            suffix: RwLockWriteGuard<'head, T>,
50        }
51    }
52}
53
54pub use handle_ref::{HandleReadRef, HandleWriteRef};
55
56pub type StoreReference<T> = Arc<RwLock<T>>;
57type WeakStoreReference<T> = Weak<RwLock<T>>;
58pub type ReadReference<T> = HandleReadRef<StoreReference<T>, T>;
59pub type WriteReference<T> = HandleWriteRef<StoreReference<T>, T>;
60
61/// Converts `Arc<RwLock<T>>` to a [`ReadReference`] by taking the inner read lock.
62pub fn read_store_reference<T: 'static>(head: StoreReference<T>) -> ReadReference<T> {
63    HandleReadRef::new(head, |s| s.read())
64}
65
66/// Converts `Arc<RwLock<T>>` to a [`WriteReference`] by locking the inner write lock.
67pub fn write_store_reference<T: 'static>(head: StoreReference<T>) -> WriteReference<T> {
68    HandleWriteRef::new(head, |s| s.write())
69}
70
71/// This is a trait for wrapping up objects that contain stores for
72/// multiple types of [`Entity`].
73pub trait SharedStore<T, U>
74where
75    T: Entity + 'static,
76    U: EntityBackend<T> + Sync + Send + 'static,
77{
78    fn get_store<'a>(&'a self) -> &'a Store<T, U>;
79}
80
81/// A shared handle to an [`Entity`] and its storage backend.
82///
83/// # Errors
84///
85/// Most of the methods associated with `StoreHandle` call methods on
86/// storage backend objects. Errors returned by these methods will bubble up
87/// through `StoreHandle`'s methods.
88pub struct StoreHandle<T>
89where
90    T: Entity + 'static,
91{
92    backend: Arc<dyn EntityBackend<T> + Sync + Send + 'static>,
93    id: Snowflake,
94    object: Option<T>,
95}
96
97impl<T> StoreHandle<T>
98where
99    T: Entity + 'static,
100{
101    fn new<U>(backend: Arc<U>, id: Snowflake, object: Option<T>) -> StoreHandle<T>
102    where
103        U: EntityBackend<T> + Sync + Send + 'static,
104    {
105        StoreHandle {
106            backend,
107            id,
108            object,
109        }
110    }
111
112    /// Gets a reference to the object within this handle.
113    pub fn get(&self) -> Option<&T> {
114        self.object.as_ref()
115    }
116
117    /// Gets a mutable reference to the object within this handle.
118    pub fn get_mut(&mut self) -> Option<&mut T> {
119        self.object.as_mut()
120    }
121
122    /// Replaces the object within this handle with something else.
123    pub fn replace(&mut self, object: T) -> Option<T> {
124        self.object.replace(object)
125    }
126
127    /// Gets the ID of the [`Entity`] in this handle.
128    pub fn id(&self) -> Snowflake {
129        self.id
130    }
131
132    /// Checks whether anything is actually contained in this handle.
133    pub fn exists(&self) -> bool {
134        self.object.is_some()
135    }
136
137    /// Puts whatever is in this handle into storage.
138    pub fn store(&self) -> Result<()> {
139        match &self.object {
140            None => self.backend.delete(self.id),
141            Some(obj) => self.backend.store(self.id, &obj),
142        }
143    }
144
145    /// Clears out the data in this handle, then deletes the [`Entity`]
146    /// from storage.
147    pub fn delete(&mut self) -> Result<()> {
148        if let Some(obj) = &mut self.object {
149            obj.clear_components()?;
150        }
151
152        self.object = None;
153        self.backend.delete(self.id)
154    }
155
156    fn set_object(&mut self, object: Option<T>) {
157        self.object = object;
158    }
159}
160
161impl<T> Drop for StoreHandle<T>
162where
163    T: Entity + 'static,
164{
165    fn drop(&mut self) {
166        if let Some(entity) = &self.object {
167            if entity.dirty() {
168                // No good way of handling errors here
169                let _e = self.backend.store(self.id, &entity);
170            }
171        }
172    }
173}
174
175#[doc(hidden)]
176#[derive(Clone)]
177pub struct StoredHandleData<T>
178where
179    T: Entity + 'static,
180{
181    initializer: Arc<Once>,
182    handle: WeakStoreReference<StoreHandle<T>>,
183}
184
185// Strong version of StoredHandleData
186#[doc(hidden)]
187#[derive(Clone)]
188pub struct HandleData<T>
189where
190    T: Entity + 'static,
191{
192    initializer: Arc<Once>,
193    handle: StoreReference<StoreHandle<T>>,
194}
195
196/// Handles storing [`Entities`](Entity) and coordinating access to
197/// them across multiple threads.
198///
199/// # Errors
200///
201/// Most of the methods associated with `Store` call methods on storage
202/// backend objects. Errors returned by these methods will bubble up
203/// through `Store`'s methods.
204pub struct Store<T, U>
205where
206    T: Entity + 'static,
207    U: EntityBackend<T> + Sync + Send + 'static,
208{
209    backend: Arc<U>,
210    refs: DashMap<Snowflake, StoredHandleData<T>>,
211}
212
213impl<T, U> Store<T, U>
214where
215    T: Entity + 'static,
216    U: EntityBackend<T> + Sync + Send + 'static,
217{
218    /// Creates a new `Store` using the given storage backend.
219    pub fn new(backend: Arc<U>) -> Store<T, U> {
220        Store {
221            backend,
222            refs: DashMap::new(),
223        }
224    }
225
226    /// Retrieves or creates a possibly-uninitialized [`StoreHandle`] from
227    /// the underlying hashmap.
228    fn get_handle(&self, id: Snowflake) -> HandleData<T> {
229        let mut entry = self.refs.entry(id).or_insert_with(|| StoredHandleData {
230            initializer: Arc::new(Once::new()),
231            handle: Weak::new(),
232        });
233
234        if let Some(strong) = entry.handle.upgrade() {
235            HandleData {
236                initializer: entry.initializer.clone(),
237                handle: strong,
238            }
239        } else {
240            let handle: StoreHandle<T> = StoreHandle::new(self.backend.clone(), id, None);
241            let initializer = Arc::new(Once::new());
242            let strong = Arc::new(RwLock::new(handle));
243
244            entry.handle = Arc::downgrade(&strong);
245            entry.initializer = initializer.clone();
246
247            HandleData {
248                initializer,
249                handle: strong,
250            }
251        }
252    }
253
254    // Initializes a handle by loading data from the backend.
255    // Uses the `initializer` contained in the handle_data to ensure
256    // that only one thread tries to initialize at once.
257    fn initialize_handle(
258        &self,
259        id: Snowflake,
260        cm: Arc<ComponentManager<T>>,
261        handle_data: HandleData<T>,
262    ) -> Result<HandleData<T>> {
263        let mut res: Result<()> = Result::Ok(());
264
265        handle_data.initializer.call_once(|| {
266            let mut write_handle = handle_data.handle.write();
267            match self.backend.load(id, cm) {
268                Err(e) => {
269                    res = Err(e);
270                    write_handle.set_object(None);
271                }
272                Ok(data) => {
273                    write_handle.set_object(data);
274                }
275            };
276        });
277
278        match res {
279            Err(e) => Err(e),
280            Ok(_v) => Ok(handle_data),
281        }
282    }
283
284    pub fn load_handle(
285        &self,
286        id: Snowflake,
287        cm: Arc<ComponentManager<T>>,
288    ) -> Result<StoreReference<StoreHandle<T>>> {
289        let handle_data = self.initialize_handle(id, cm, self.get_handle(id))?;
290        Ok(handle_data.handle.clone())
291    }
292
293    /// Gets an immutable reference to the handle for the [`Entity`]
294    /// with the given ID.
295    ///
296    /// Data for the [`Entity`] will be loaded from storage if needed.
297    ///
298    /// The returned reference is read-locked, so multiple threads can
299    /// use references from this function at once.
300    pub fn load(
301        &self,
302        id: Snowflake,
303        cm: Arc<ComponentManager<T>>,
304    ) -> Result<ReadReference<StoreHandle<T>>> {
305        let handle_data = self.initialize_handle(id, cm, self.get_handle(id))?;
306        Ok(read_store_reference(handle_data.handle))
307    }
308
309    /// Gets a mutable reference to the handle for the [`Entity`] with
310    /// the given ID.
311    ///
312    /// Data for the [`Entity`] will be loaded from storage if needed.
313    ///
314    /// The returned reference is write-locked, so exclusive access to
315    /// the handle is ensured.
316    pub fn load_mut(
317        &self,
318        id: Snowflake,
319        cm: Arc<ComponentManager<T>>,
320    ) -> Result<WriteReference<StoreHandle<T>>> {
321        let handle_data = self.initialize_handle(id, cm, self.get_handle(id))?;
322        Ok(write_store_reference(handle_data.handle))
323    }
324
325    /// Puts the given [`Entity`] into storage, overwriting any previously
326    /// stored [`Entity`] data with the same ID.
327    pub fn store(&self, object: T) -> Result<()> {
328        let id = object.id();
329        let handle_data = self.get_handle(id);
330
331        // If the initializer gets called, `object` gets set to None,
332        // and initializer_result is filled in with the result value.
333        //
334        // If the initializer is _not_ called, `object` remains as Some(object),
335        // and initializer_result is None.
336        let mut object: Option<T> = Some(object);
337        let mut initializer_result: Option<Result<()>> = None;
338
339        handle_data.initializer.call_once(|| {
340            let mut handle = handle_data.handle.write();
341            handle.set_object(object.take());
342            initializer_result = Some(handle.store());
343        });
344
345        if let Some(obj) = object {
346            let mut handle = handle_data.handle.write();
347            handle.set_object(Some(obj));
348            handle.store()
349        } else {
350            // This should be safe, because in the initializer,
351            // object.take() is immediately followed by setting
352            // initializer_result to some result.
353            initializer_result.unwrap()
354        }
355    }
356
357    /// Moves the given [`Entity`] into a store handle without writing
358    /// it to storage, overwriting anything that may have been there before.
359    ///
360    /// Returns a write-locked reference to the handle.
361    pub fn insert(&self, object: T) -> WriteReference<StoreHandle<T>> {
362        let id = object.id();
363        let handle_data = self.get_handle(id);
364
365        // If the initializer gets called, `object` gets set to None,
366        // and initializer_result is filled in with the result value.
367        //
368        // If the initializer is _not_ called, `object` remains as Some(object),
369        // and initializer_result is None.
370        let mut object: Option<T> = Some(object);
371        let mut initializer_result: Option<WriteReference<StoreHandle<T>>> = None;
372
373        handle_data.initializer.call_once(|| {
374            let mut handle = write_store_reference(handle_data.handle.clone());
375            handle.set_object(object.take());
376            initializer_result = Some(handle);
377        });
378
379        if let Some(obj) = object {
380            let mut ret = write_store_reference(handle_data.handle.clone());
381            ret.set_object(Some(obj));
382            ret
383        } else {
384            // This should be safe, because in the initializer,
385            // object.take() is immediately followed by setting
386            // initializer_result to some result.
387            initializer_result.unwrap()
388        }
389    }
390
391    /// Deletes the [`Entity`] with the given ID from storage.
392    ///
393    /// Note that internally, this method loads the [`Entity`] prior to
394    /// deleting it, so that attached [`Components`](crate::Component) are
395    /// properly deleted.
396    ///
397    /// If you already have an open handle to the [`Entity`], you should
398    /// use [`StoreHandle::delete`] instead.
399    pub fn delete(&self, id: Snowflake, cm: Arc<ComponentManager<T>>) -> Result<()> {
400        let mut handle = self.load_mut(id, cm)?;
401        handle.delete()
402    }
403
404    /// Checks to see if an [`Entity`] with the given ID exists.
405    pub fn exists(&self, id: Snowflake) -> Result<bool> {
406        let handle_data = self.get_handle(id);
407
408        if handle_data.initializer.state().done() {
409            let read_lock = handle_data.handle.read();
410            Ok(read_lock.exists())
411        } else {
412            self.backend.exists(id)
413        }
414    }
415
416    /// Retrieves a list of [`Entity`] IDs from storage.
417    pub fn keys(&self, page: u64, limit: u64) -> Result<Vec<Snowflake>> {
418        self.backend.keys(page, limit)
419    }
420}
421
422/// Used as a 'stepping stone' when downcasting from an `EntityStoreDowncast`
423/// trait object to an `EntityStore<T>`.
424///
425/// We can't downcast directly between two trait objects, so we need to
426/// add an intermediate concrete type that `EntityStoreDowncast` can be
427/// downcasted to, and from which we can further downcast to `EntityStore`.
428#[doc(hidden)]
429pub struct EntityStoreDowncastHelper<T: Entity + 'static>(pub Box<dyn EntityStore<T> + 'static>);
430
431/// A downcastable trait that allows for erasing the [`Entity`] type parameter
432/// from [`EntityStore`] trait objects.
433///
434/// You probably shouldn't use this yourself.
435#[doc(hidden)]
436pub trait EntityStoreDowncast: Downcast + Send + Sync + 'static {}
437downcast_rs::impl_downcast!(EntityStoreDowncast);
438
439impl<T: Entity + 'static> EntityStoreDowncast for EntityStoreDowncastHelper<T> {}
440
441/// An interface for loading and storing [`Entities`](Entity).
442///
443/// This trait provides an abstract interface for loading and storing
444/// [`Entities`](Entity) objects.
445///
446/// For example, you can use it as a way to access [`Stores`](Store)
447/// without having to carry around a [`EntityBackend`](EntityBackend)
448/// type parameter everywhere. This comes at the cost of dynamic dispatch
449/// overhead, though.
450pub trait EntityStore<T>: DowncastSync
451where
452    T: Entity + 'static,
453{
454    fn load(
455        &self,
456        id: Snowflake,
457        cm: Arc<ComponentManager<T>>,
458    ) -> Result<ReadReference<StoreHandle<T>>>;
459
460    fn load_mut(
461        &self,
462        id: Snowflake,
463        cm: Arc<ComponentManager<T>>,
464    ) -> Result<WriteReference<StoreHandle<T>>>;
465
466    fn store(&self, object: T) -> Result<()>;
467    fn insert(&self, object: T) -> WriteReference<StoreHandle<T>>;
468    fn delete(&self, id: Snowflake, cm: Arc<ComponentManager<T>>) -> Result<()>;
469    fn exists(&self, id: Snowflake) -> Result<bool>;
470    fn keys(&self, page: u64, limit: u64) -> Result<Vec<Snowflake>>;
471}
472
473downcast_rs::impl_downcast!(sync EntityStore<T> where T: Entity + 'static);
474
475impl<T, U> EntityStore<T> for Store<T, U>
476where
477    T: Entity + 'static,
478    U: EntityBackend<T> + Sync + Send + 'static,
479{
480    fn load(
481        &self,
482        id: Snowflake,
483        cm: Arc<ComponentManager<T>>,
484    ) -> Result<ReadReference<StoreHandle<T>>> {
485        self.load(id, cm)
486    }
487
488    fn load_mut(
489        &self,
490        id: Snowflake,
491        cm: Arc<ComponentManager<T>>,
492    ) -> Result<WriteReference<StoreHandle<T>>> {
493        self.load_mut(id, cm)
494    }
495
496    fn store(&self, object: T) -> Result<()> {
497        self.store(object)
498    }
499
500    fn insert(&self, object: T) -> WriteReference<StoreHandle<T>> {
501        self.insert(object)
502    }
503
504    fn delete(&self, id: Snowflake, cm: Arc<ComponentManager<T>>) -> Result<()> {
505        self.delete(id, cm)
506    }
507
508    fn exists(&self, id: Snowflake) -> Result<bool> {
509        self.exists(id)
510    }
511
512    fn keys(&self, page: u64, limit: u64) -> Result<Vec<Snowflake>> {
513        self.keys(page, limit)
514    }
515}
516
517impl<T, U> fmt::Debug for Store<T, U>
518where
519    T: Entity + 'static,
520    U: EntityBackend<T> + Sync + Send + 'static,
521{
522    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
523        write!(
524            f,
525            "Store<{}, {}> {{ {} keys }}",
526            any::type_name::<T>(),
527            any::type_name::<U>(),
528            self.refs.len()
529        )
530    }
531}
532
533/// This trait is used to mark backing storage objects for [`Entities`](Entity).
534///
535/// Structs that implement this trait can be used as backing storage
536/// for [`Entities`](Entity) such as [`Players`](crate::Player) and
537/// [`Cards`](crate::Card), and can be passed to [`Store::new`].
538pub trait EntityBackend<T: Entity + 'static> {
539    /// Loads data for an [`Entity`] from storage, if any [`Entity`] with
540    /// the given ID exists.
541    fn load(&self, id: Snowflake, cm: Arc<ComponentManager<T>>) -> Result<Option<T>>;
542
543    /// Checks to see if an [`Entity`] with the given ID exists in storage.
544    fn exists(&self, id: Snowflake) -> Result<bool>;
545
546    /// Saves data for an [`Entity`] to storage.
547    fn store(&self, id: Snowflake, object: &T) -> Result<()>;
548
549    /// Deletes data for an [`Entity`] from storage.
550    fn delete(&self, id: Snowflake) -> Result<()>;
551
552    /// Retrieve a list of [`Entity`] IDs from storage.
553    fn keys(&self, page: u64, limit: u64) -> Result<Vec<Snowflake>>;
554}
555
556#[cfg(test)]
557mod tests {
558    use super::*;
559
560    use std::any::TypeId;
561    use std::collections::{HashMap, HashSet};
562    use std::sync::{mpsc, Arc, Barrier, RwLock};
563    use std::thread;
564
565    use dashmap::DashMap;
566
567    use crate::ecs::Component;
568    use crate::snowflake::SnowflakeGenerator;
569
570    struct MockStoredData {
571        id: Snowflake,
572        field_a: String,
573        field_b: u64,
574        cm: Arc<ComponentManager<MockStoredData>>,
575        components_attached: HashSet<TypeId>,
576        component_preloads: DashMap<TypeId, Box<dyn Component<Self> + Send + Sync + 'static>>,
577        dirty: bool,
578    }
579
580    impl MockStoredData {
581        fn new(
582            id: Snowflake,
583            field_a: String,
584            field_b: u64,
585            cm: Arc<ComponentManager<MockStoredData>>,
586        ) -> MockStoredData {
587            MockStoredData {
588                id,
589                field_a,
590                field_b,
591                cm,
592                components_attached: HashSet::new(),
593                component_preloads: DashMap::new(),
594                dirty: false,
595            }
596        }
597
598        fn id<'a>(&'a self) -> &'a Snowflake {
599            &self.id
600        }
601    }
602
603    impl Entity for MockStoredData {
604        fn new(
605            id: Snowflake,
606            cm: Arc<ComponentManager<Self>>,
607            _components: HashSet<TypeId>,
608        ) -> Self {
609            MockStoredData::new(id, String::from(""), 0, cm)
610        }
611
612        fn id(&self) -> Snowflake {
613            self.id
614        }
615
616        fn component_manager(&self) -> &ComponentManager<MockStoredData> {
617            &self.cm
618        }
619
620        fn components_attached(&self) -> &HashSet<TypeId> {
621            &self.components_attached
622        }
623
624        fn components_attached_mut(&mut self) -> &mut HashSet<TypeId> {
625            &mut self.components_attached
626        }
627
628        fn preloaded_components(
629            &self,
630        ) -> &DashMap<TypeId, Box<dyn Component<Self> + Send + Sync + 'static>> {
631            &self.component_preloads
632        }
633
634        fn dirty(&self) -> bool {
635            self.dirty
636        }
637
638        fn dirty_mut(&mut self) -> &mut bool {
639            &mut self.dirty
640        }
641    }
642
643    impl Clone for MockStoredData {
644        fn clone(&self) -> Self {
645            Self {
646                id: self.id,
647                dirty: self.dirty,
648                cm: self.cm.clone(),
649                components_attached: self.components_attached.clone(),
650                component_preloads: DashMap::new(),
651                field_a: self.field_a.clone(),
652                field_b: self.field_b,
653            }
654        }
655    }
656
657    struct MockEntityBackend {
658        data: RwLock<HashMap<Snowflake, MockStoredData>>,
659        remove_on_load: bool,
660    }
661
662    impl MockEntityBackend {
663        fn new() -> MockEntityBackend {
664            MockEntityBackend {
665                data: RwLock::new(HashMap::new()),
666                remove_on_load: false,
667            }
668        }
669
670        fn set_remove_on_load(&mut self, flag: bool) {
671            self.remove_on_load = flag;
672        }
673    }
674    impl EntityBackend<MockStoredData> for MockEntityBackend {
675        fn exists(&self, id: Snowflake) -> Result<bool> {
676            let map = self.data.read().unwrap();
677            Ok(map.contains_key(&id))
678        }
679
680        fn load(
681            &self,
682            id: Snowflake,
683            _cm: Arc<ComponentManager<MockStoredData>>,
684        ) -> Result<Option<MockStoredData>> {
685            if !self.remove_on_load {
686                let map = self.data.read().unwrap();
687                Ok(map.get(&id).map(|pl| pl.clone()))
688            } else {
689                let mut map = self.data.write().unwrap();
690                let res = Ok(map.get(&id).map(|pl| pl.clone()));
691                map.remove(&id);
692                res
693            }
694        }
695
696        fn store(&self, id: Snowflake, data: &MockStoredData) -> Result<()> {
697            let mut map = self.data.write().unwrap();
698            map.insert(id, data.clone());
699
700            Ok(())
701        }
702
703        fn delete(&self, id: Snowflake) -> Result<()> {
704            let mut map = self.data.write().unwrap();
705            map.remove(&id);
706
707            Ok(())
708        }
709
710        fn keys(&self, page: u64, limit: u64) -> Result<Vec<Snowflake>> {
711            let ids: Vec<Snowflake>;
712            let start_index = page * limit;
713
714            let data = self.data.read().unwrap();
715            ids = data
716                .keys()
717                .skip(start_index as usize)
718                .take(limit as usize)
719                .map(|x| *x)
720                .collect();
721
722            Ok(ids)
723        }
724    }
725
726    type MockStore = Store<MockStoredData, MockEntityBackend>;
727
728    #[test]
729    fn test_exists() {
730        let mut snowflake_gen = SnowflakeGenerator::new(0, 0);
731        let backend = Arc::new(MockEntityBackend::new());
732        let data = MockStoredData::new(
733            snowflake_gen.generate(),
734            "foo".to_owned(),
735            1,
736            Arc::new(ComponentManager::new()),
737        );
738
739        backend.store(*data.id(), &data).unwrap();
740        let store = MockStore::new(backend);
741
742        let id2 = snowflake_gen.generate();
743        assert!(store.exists(*data.id()).unwrap());
744        assert!(!store.exists(id2).unwrap());
745    }
746
747    #[test]
748    fn test_load_nonexistent() {
749        let mut snowflake_gen = SnowflakeGenerator::new(0, 0);
750        let backend = Arc::new(MockEntityBackend::new());
751        let store = MockStore::new(backend);
752        let handle = store
753            .load(snowflake_gen.generate(), Arc::new(ComponentManager::new()))
754            .unwrap();
755
756        assert!(!handle.exists());
757    }
758
759    #[test]
760    fn test_load() {
761        let mut snowflake_gen = SnowflakeGenerator::new(0, 0);
762        let backend = Arc::new(MockEntityBackend::new());
763        let data = MockStoredData::new(
764            snowflake_gen.generate(),
765            "foo".to_owned(),
766            1,
767            Arc::new(ComponentManager::new()),
768        );
769
770        backend.store(*data.id(), &data).unwrap();
771        let store = MockStore::new(backend);
772
773        let handle = store
774            .load(*data.id(), Arc::new(ComponentManager::new()))
775            .unwrap();
776
777        assert!(handle.exists());
778        let data_copy = handle.get().unwrap();
779
780        assert_eq!(*data.id(), *data_copy.id());
781        assert_eq!(data.field_a, data_copy.field_a);
782        assert_eq!(data.field_b, data_copy.field_b);
783    }
784
785    #[test]
786    fn test_concurrent_load() {
787        // Create some test data to load.
788        let mut snowflake_gen = SnowflakeGenerator::new(0, 0);
789        let backend = Arc::new(MockEntityBackend::new());
790        let id = snowflake_gen.generate();
791        let data = MockStoredData::new(id, "foo".to_owned(), 1, Arc::new(ComponentManager::new()));
792        backend.store(id, &data).unwrap();
793
794        // Create a bunch of threads.
795        // These threads will all try to access the same data at the same
796        // time.
797        let store = Arc::new(MockStore::new(backend));
798        let mut threads = Vec::with_capacity(9);
799        let barrier = Arc::new(Barrier::new(10));
800
801        for _ in 0..9 {
802            let b_clone = barrier.clone();
803            let s_clone = store.clone();
804
805            let handle = thread::spawn(move || {
806                b_clone.wait();
807                let wrapper = s_clone.get_handle(id);
808                wrapper
809            });
810
811            threads.push(handle);
812        }
813
814        barrier.wait();
815        let our_wrapper = store.get_handle(id);
816
817        for thread in threads {
818            // Check what the other threads got for a handle.
819            // Both wrapper objects should contain Arcs pointing to the
820            // same data.
821            let their_wrapper = thread.join().unwrap();
822            assert!(Arc::ptr_eq(&our_wrapper.handle, &their_wrapper.handle));
823        }
824    }
825
826    #[test]
827    fn test_concurrent_access() {
828        // Create some test data to load.
829        let mut snowflake_gen = SnowflakeGenerator::new(0, 0);
830        let mut backend = MockEntityBackend::new();
831        let id = snowflake_gen.generate();
832        let data = MockStoredData::new(id, "foo".to_owned(), 1, Arc::new(ComponentManager::new()));
833
834        // Detect if and when we end up performing multiple backend loads.
835        backend.set_remove_on_load(true);
836        backend.store(id, &data).unwrap();
837
838        // Like in test_concurrent_load, create a bunch of threads primed
839        // to access the data simultaneously.
840        //
841        // Unlike in test_concurrent_load, however, these threads will attempt
842        // a full retrieval from the backend.
843        let store = Arc::new(MockStore::new(Arc::new(backend)));
844        let barrier = Arc::new(Barrier::new(10));
845        let mut threads = Vec::with_capacity(9);
846        let (tx, rx) = mpsc::channel();
847
848        for _ in 0..9 {
849            let b_clone = barrier.clone();
850            let s_clone = store.clone();
851            let tx_clone = tx.clone();
852
853            let handle = thread::spawn(move || {
854                b_clone.wait();
855                let handle = s_clone.load(id, Arc::new(ComponentManager::new())).unwrap();
856                let data = handle.get().unwrap();
857
858                tx_clone
859                    .send((data.id, data.field_a.clone(), data.field_b))
860                    .unwrap();
861
862                // Threads need to hang around to ensure that at least one
863                // Arc to the handle exists at all times.
864                b_clone.wait();
865                assert_eq!(data.id, id);
866            });
867
868            threads.push(handle);
869        }
870
871        // Make sure our handle to the data is dropped before telling the
872        // other threads to exit.
873        {
874            barrier.wait();
875            let handle = store.load(id, Arc::new(ComponentManager::new())).unwrap();
876            let data = handle.get().unwrap();
877
878            // Get the data as seen by all threads.
879            for _ in 0..9 {
880                let their_data = rx.recv().unwrap();
881
882                assert_eq!(data.id, their_data.0);
883                assert_eq!(data.field_a, their_data.1);
884                assert_eq!(data.field_b, their_data.2);
885            }
886        }
887
888        // Tell all other threads to exit.
889        // Once they all drop their handles, the underlying MockStoreData
890        // should get dropped as well.
891        barrier.wait();
892        for thread in threads {
893            thread.join().unwrap();
894        }
895
896        // Now make sure that the MockStoreData actually _did_ get dropped.
897        // Since we did `backend.set_remove_on_load`, this should now load
898        // None into the handle.
899        let handle = store.load(id, Arc::new(ComponentManager::new())).unwrap();
900        let data = handle.get();
901        assert!(data.is_none());
902    }
903
904    #[test]
905    fn test_multiple_single_thread_access() {
906        // Create some test data to load.
907        let mut snowflake_gen = SnowflakeGenerator::new(0, 0);
908        let backend = MockEntityBackend::new();
909        let id = snowflake_gen.generate();
910        let data = MockStoredData::new(id, "foo".to_owned(), 1, Arc::new(ComponentManager::new()));
911        backend.store(id, &data).unwrap();
912
913        let store = MockStore::new(Arc::new(backend));
914
915        // Try to load two read handles to the same Entity at once on
916        // the same thread.
917        //
918        // The main failure mode we want to check for here is deadlocking
919        // (due to trying to grab write access to the handle for
920        // initialization, say)
921        let handle_1 = store.load(id, Arc::new(ComponentManager::new())).unwrap();
922        let data_1 = handle_1.get().unwrap();
923
924        let handle_2 = store.load(id, Arc::new(ComponentManager::new())).unwrap();
925        let data_2 = handle_2.get().unwrap();
926
927        assert_eq!(data_1.id, data_2.id);
928        assert_eq!(data_1.field_a, data_2.field_a);
929        assert_eq!(data_1.field_b, data_2.field_b);
930
931        assert_eq!(data_1.id, data.id);
932        assert_eq!(data_1.field_a, data.field_a);
933        assert_eq!(data_1.field_b, data.field_b);
934    }
935
936    #[test]
937    fn test_store() {
938        let mut snowflake_gen = SnowflakeGenerator::new(0, 0);
939        let id = snowflake_gen.generate();
940        let cm = Arc::new(ComponentManager::new());
941        let data = MockStoredData::new(id, "foo".to_owned(), 1, cm.clone());
942
943        let backend = Arc::new(MockEntityBackend::new());
944        let store = MockStore::new(backend);
945
946        {
947            let mut handle = store.load_mut(*data.id(), cm.clone()).unwrap();
948            assert!(!handle.exists());
949
950            handle.replace(data.clone());
951            handle.store().unwrap();
952        }
953
954        let handle = store.load(*data.id(), cm).unwrap();
955        let data_copy = handle.get().unwrap();
956
957        assert_eq!(*data_copy.id(), id);
958        assert_eq!(data.field_a, data_copy.field_a);
959        assert_eq!(data.field_b, data_copy.field_b);
960    }
961
962    #[test]
963    fn test_handle_drop() {
964        use super::ComponentManager;
965        use crate::local_storage::LocalComponentStorage;
966        use crate::Component;
967
968        #[derive(Clone)]
969        struct TestComponent(u64);
970        impl Component<MockStoredData> for TestComponent {};
971
972        let backend = Arc::new(MockEntityBackend::new());
973        let store = MockStore::new(backend);
974        let mut cm: ComponentManager<MockStoredData> = ComponentManager::new();
975
976        cm.register_component(
977            "TestComponent",
978            LocalComponentStorage::<MockStoredData, TestComponent>::new(),
979        )
980        .unwrap();
981
982        let cm = Arc::new(cm);
983
984        let mut snowflake_gen = SnowflakeGenerator::new(0, 0);
985        let id = snowflake_gen.generate();
986
987        {
988            let data = MockStoredData::new(id, "foo".to_owned(), 1, cm.clone());
989
990            let mut handle = store.insert(data);
991            let data = handle.get_mut().unwrap();
992
993            data.set_component(TestComponent(50)).unwrap();
994        }
995
996        let handle = store.load(id, cm.clone()).unwrap();
997        let data = handle.get().unwrap();
998        let component: TestComponent = data.get_component().unwrap().unwrap();
999
1000        assert_eq!(component.0, 50);
1001    }
1002}