specs/saveload/
marker.rs

1//! Provides `Marker` and `MarkerAllocator` traits
2
3use std::{
4    collections::HashMap,
5    fmt::{self, Debug},
6    hash::{Hash, Hasher},
7    marker::PhantomData,
8};
9
10use serde::{de::DeserializeOwned, Deserialize, Serialize};
11
12use crate::{
13    prelude::*,
14    storage::AccessMut,
15    world::{EntitiesRes, EntityResBuilder, LazyBuilder},
16};
17
18/// A common trait for `EntityBuilder` and `LazyBuilder` with a marker function,
19/// allowing either to be used.
20pub trait MarkedBuilder {
21    /// Add a `Marker` to the entity by fetching the associated allocator.
22    ///
23    /// ## Examples
24    ///
25    /// ```
26    /// use specs::{
27    ///     prelude::*,
28    ///     saveload::{MarkedBuilder, SimpleMarker, SimpleMarkerAllocator},
29    /// };
30    ///
31    /// struct NetworkSync;
32    ///
33    /// fn mark_entity<M: Builder + MarkedBuilder>(markable: M) -> Entity {
34    ///     markable
35    ///    /* .with(Component1) */
36    ///     .marked::<SimpleMarker<NetworkSync>>()
37    ///     .build()
38    /// }
39    ///
40    /// let mut world = World::new();
41    /// world.register::<SimpleMarker<NetworkSync>>();
42    /// world.insert(SimpleMarkerAllocator::<NetworkSync>::new());
43    ///
44    /// mark_entity(world.create_entity());
45    /// ```
46    fn marked<M: Marker>(self) -> Self;
47}
48
49impl<'a> MarkedBuilder for EntityBuilder<'a> {
50    fn marked<M>(self) -> Self
51    where
52        M: Marker,
53    {
54        let mut alloc = self.world.write_resource::<M::Allocator>();
55        alloc.mark(self.entity, &mut self.world.write_storage::<M>());
56
57        self
58    }
59}
60
61impl<'a> MarkedBuilder for LazyBuilder<'a> {
62    /// Add a `Marker` to the entity by fetching the associated allocator.
63    ///
64    /// This will be applied on the next `world.maintain()`.
65    ///
66    /// ## Examples
67    ///
68    /// ```rust
69    /// use specs::{
70    ///     prelude::*,
71    ///     saveload::{MarkedBuilder, SimpleMarker, SimpleMarkerAllocator},
72    /// };
73    ///
74    /// struct NetworkSync;
75    ///
76    /// let mut world = World::new();
77    /// world.register::<SimpleMarker<NetworkSync>>();
78    /// world.insert(SimpleMarkerAllocator::<NetworkSync>::new());
79    ///
80    /// # let lazy = world.read_resource::<LazyUpdate>();
81    /// # let entities = world.entities();
82    /// let my_entity = lazy
83    ///     .create_entity(&entities)
84    ///     /* .with(Component1) */
85    ///     .marked::<SimpleMarker<NetworkSync>>()
86    ///     .build();
87    /// ```
88    ///
89    /// ## Panics
90    ///
91    /// Panics during `world.maintain()` in case there's no allocator
92    /// added to the `World`.
93    fn marked<M>(self) -> Self
94    where
95        M: Marker,
96    {
97        let entity = self.entity;
98        self.lazy.exec(move |world| {
99            let mut alloc = world.write_resource::<M::Allocator>();
100            alloc.mark(entity, &mut world.write_storage::<M>());
101        });
102
103        self
104    }
105}
106
107impl<'a> EntityResBuilder<'a> {
108    /// Add a `Marker` to the entity with the associated allocator,
109    /// and component storage.
110    ///
111    /// ## Examples
112    ///
113    /// ```
114    /// use specs::{
115    ///     prelude::*,
116    ///     saveload::{SimpleMarker, SimpleMarkerAllocator},
117    /// };
118    ///
119    /// struct NetworkSync;
120    ///
121    /// let mut world = World::new();
122    /// world.register::<SimpleMarker<NetworkSync>>();
123    /// world.insert(SimpleMarkerAllocator::<NetworkSync>::new());
124    ///
125    /// let mut storage = world.write_storage::<SimpleMarker<NetworkSync>>();
126    /// let mut alloc = world.write_resource::<SimpleMarkerAllocator<NetworkSync>>();
127    ///
128    /// let entities = world.entities();
129    /// entities
130    ///     .build_entity()
131    ///     /* .with(Component1) */
132    ///     .marked(&mut storage, &mut alloc)
133    ///     .build();
134    /// ```
135    pub fn marked<M>(self, storage: &mut WriteStorage<M>, alloc: &mut M::Allocator) -> Self
136    where
137        M: Marker,
138    {
139        alloc.mark(self.entity, storage);
140        self
141    }
142}
143
144/// This trait should be implemented by a component which is going to be used as
145/// marker. This marker should be set to entity that should be serialized.
146/// If serialization strategy needs to set marker to some entity
147/// then it should use newly allocated marker from `Marker::Allocator`.
148///
149/// ## Example
150///
151/// ```rust
152/// extern crate specs;
153/// #[macro_use]
154/// extern crate serde;
155/// use std::{collections::HashMap, ops::Range};
156///
157/// use specs::{
158///     prelude::*,
159///     saveload::{MarkedBuilder, Marker, MarkerAllocator},
160///     world::EntitiesRes,
161/// };
162///
163/// // Marker for entities that should be synced over network
164/// #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
165/// struct NetMarker {
166///     id: u64,
167///     seq: u64,
168/// }
169///
170/// impl Component for NetMarker {
171///     type Storage = DenseVecStorage<Self>;
172/// }
173///
174/// impl Marker for NetMarker {
175///     type Allocator = NetNode;
176///     type Identifier = u64;
177///
178///     fn id(&self) -> u64 {
179///         self.id
180///     }
181///
182///     // Updates sequence id.
183///     // Entities with too old sequence id get deleted.
184///     fn update(&mut self, update: Self) {
185///         assert_eq!(self.id, update.id);
186///         self.seq = update.seq;
187///     }
188/// }
189///
190/// // Each client and server has one
191/// // Contains id range and `NetMarker -> Entity` mapping
192/// struct NetNode {
193///     range: Range<u64>,
194///     mapping: HashMap<u64, Entity>,
195/// }
196///
197/// impl MarkerAllocator<NetMarker> for NetNode {
198///     fn allocate(&mut self, entity: Entity, id: Option<u64>) -> NetMarker {
199///         let id = id.unwrap_or_else(|| {
200///             self.range
201///                 .next()
202///                 .expect("Id range must be virtually endless")
203///         });
204///         let marker = NetMarker { id, seq: 0 };
205///         self.mapping.insert(id, entity);
206///         marker
207///     }
208///
209///     fn retrieve_entity_internal(&self, id: u64) -> Option<Entity> {
210///         self.mapping.get(&id).cloned()
211///     }
212///
213///     fn maintain(&mut self, entities: &EntitiesRes, storage: &ReadStorage<NetMarker>) {
214///         self.mapping = (entities, storage)
215///             .join()
216///             .map(|(e, m)| (m.id(), e))
217///             .collect();
218///     }
219/// }
220///
221/// fn main() {
222///     let mut world = World::new();
223///     world.register::<NetMarker>();
224///
225///     world.insert(NetNode {
226///         range: 0..100,
227///         mapping: HashMap::new(),
228///     });
229///
230///     let entity = world.create_entity().marked::<NetMarker>().build();
231///     let storage = &mut world.write_storage::<NetMarker>();
232///     let marker = storage.get(entity).unwrap().clone();
233///     assert_eq!(
234///         world
235///             .write_resource::<NetNode>()
236///             .retrieve_entity(marker, storage, &world.entities()),
237///         entity
238///     );
239/// }
240/// ```
241pub trait Marker: Clone + Component + Debug + Eq + Hash + DeserializeOwned + Serialize {
242    /// Id of the marker
243    type Identifier;
244    /// Allocator for this `Marker`
245    type Allocator: MarkerAllocator<Self>;
246
247    /// Get this marker internal id.
248    /// The value of this method should be constant.
249    fn id(&self) -> Self::Identifier;
250
251    /// This gets called when an entity is deserialized by
252    /// `DeserializeComponents`. It can be used to update internal data that
253    /// is not used for identification.
254    ///
255    /// ## Contract
256    ///
257    /// This function may assume that `self.id() == new_revision.id()`.
258    /// However, it must not exhibit undefined behavior in such a case.
259    ///
260    /// ## Panics
261    ///
262    /// May panic if `self.id()` != `new_revision.id()`.
263    ///
264    /// ## Default implementation
265    ///
266    /// The default implementation just sets `self` to `new_revision`.
267    ///
268    /// ## Examples
269    ///
270    /// ```rust,ignore
271    /// #[derive(Clone, Debug, Deserialize, Eq, Hash, Serialize)]
272    /// struct MyMarker {
273    ///     id: u64,
274    ///     last_modified: String,
275    /// }
276    ///
277    /// impl Marker for MyMarker {
278    ///     type Identifier = u64;
279    ///
280    ///     fn id(&self) -> u64 {
281    ///         self.id
282    ///     }
283    ///
284    ///     fn update(&self, new: Self) {
285    ///         self.last_modified = new.last_modified;
286    ///     }
287    /// }
288    /// ```
289    ///
290    /// Now, the marker always contains the name of the client who updated the
291    /// entity associated with this marker.
292    fn update(&mut self, new_revision: Self) {
293        *self = new_revision;
294    }
295}
296
297/// This allocator is used with the `Marker` trait.
298/// It provides a method for allocating new `Marker`s.
299/// It should also provide a `Marker -> Entity` mapping.
300/// The `maintain` method can be implemented for cleanup and actualization.
301/// See docs for `Marker` for an example.
302pub trait MarkerAllocator<M: Marker>: Resource {
303    /// Allocates a new marker for a given entity.
304    /// If you don't pass an id, a new unique id will be created.
305    fn allocate(&mut self, entity: Entity, id: Option<M::Identifier>) -> M;
306
307    /// Get an `Entity` by a marker identifier.
308    /// This function only accepts an id; it does not update the marker data.
309    ///
310    /// Implementors usually maintain a marker -> entity mapping
311    /// and use that to retrieve the entity.
312    fn retrieve_entity_internal(&self, id: M::Identifier) -> Option<Entity>;
313
314    /// Tries to retrieve an entity by the id of the marker;
315    /// if no entity has a marker with the same id, a new entity
316    /// will be created and `marker` will be inserted for it.
317    ///
318    /// In case the entity existed,
319    /// this method will update the marker data using `Marker::update`.
320    fn retrieve_entity(
321        &mut self,
322        marker: M,
323        storage: &mut WriteStorage<M>,
324        entities: &EntitiesRes,
325    ) -> Entity {
326        if let Some(entity) = self.retrieve_entity_internal(marker.id()) {
327            if let Some(mut marker_comp) = storage.get_mut(entity) {
328                marker_comp.access_mut().update(marker);
329
330                return entity;
331            }
332        }
333
334        let entity = entities.create();
335        let marker = self.allocate(entity, Some(marker.id()));
336
337        // It's not possible for this to fail, as there's no way a freshly
338        // created entity could be dead this fast.
339        storage.insert(entity, marker).unwrap();
340        entity
341    }
342
343    /// Create new unique marker `M` and attach it to entity.
344    /// Or get old marker if this entity is already marked.
345    /// If entity is dead then this will return `None`.
346    fn mark<'m>(
347        &mut self,
348        entity: Entity,
349        storage: &'m mut WriteStorage<M>,
350    ) -> Option<(&'m M, bool)> {
351        let new = if let Ok(entry) = storage.entry(entity) {
352            let mut new = false;
353            let _marker = entry.or_insert_with(|| {
354                new = true;
355                self.allocate(entity, None)
356            });
357
358            new
359        } else {
360            return None;
361        };
362        Some((storage.get(entity).unwrap(), new))
363    }
364
365    /// Maintain internal data. Cleanup if necessary.
366    fn maintain(&mut self, _entities: &EntitiesRes, _storage: &ReadStorage<M>);
367}
368
369/// Basic marker implementation usable for saving and loading, uses `u64` as
370/// identifier
371#[derive(Serialize, Deserialize)]
372#[repr(transparent)]
373pub struct SimpleMarker<T: ?Sized>(u64, #[serde(skip)] PhantomData<T>);
374
375impl<T: ?Sized> Clone for SimpleMarker<T> {
376    fn clone(&self) -> Self {
377        *self
378    }
379}
380
381impl<T: ?Sized> Copy for SimpleMarker<T> {}
382
383impl<T: ?Sized> PartialEq for SimpleMarker<T> {
384    fn eq(&self, other: &Self) -> bool {
385        self.0 == other.0
386    }
387}
388
389impl<T: ?Sized> Eq for SimpleMarker<T> {}
390
391impl<T: ?Sized> Hash for SimpleMarker<T> {
392    fn hash<H: Hasher>(&self, state: &mut H) {
393        self.0.hash(state);
394    }
395}
396
397impl<T: ?Sized> Debug for SimpleMarker<T> {
398    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
399        fmt.debug_tuple("SimpleMarker")
400            .field(&self.0)
401            .field(&self.1)
402            .finish()
403    }
404}
405
406impl<T> Component for SimpleMarker<T>
407where
408    T: 'static + ?Sized + Send + Sync,
409{
410    type Storage = DenseVecStorage<Self>;
411}
412
413impl<T> Marker for SimpleMarker<T>
414where
415    T: 'static + ?Sized + Send + Sync,
416{
417    type Allocator = SimpleMarkerAllocator<T>;
418    type Identifier = u64;
419
420    fn id(&self) -> u64 {
421        self.0
422    }
423}
424
425/// Basic marker allocator, uses `u64` as identifier
426pub struct SimpleMarkerAllocator<T: ?Sized> {
427    index: u64,
428    mapping: HashMap<u64, Entity>,
429    _phantom_data: PhantomData<T>,
430}
431
432impl<T: ?Sized> Debug for SimpleMarkerAllocator<T> {
433    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
434        fmt.debug_struct("SimpleMarkerAllocator")
435            .field("index", &self.index)
436            .field("mapping", &self.mapping)
437            .field("_phantom_data", &self._phantom_data)
438            .finish()
439    }
440}
441
442impl<T: ?Sized> Clone for SimpleMarkerAllocator<T> {
443    fn clone(&self) -> Self {
444        Self {
445            index: self.index,
446            mapping: self.mapping.clone(),
447            _phantom_data: PhantomData,
448        }
449    }
450}
451
452impl<T: ?Sized> Default for SimpleMarkerAllocator<T> {
453    fn default() -> Self {
454        Self::new()
455    }
456}
457
458impl<T: ?Sized> SimpleMarkerAllocator<T> {
459    /// Create new `SimpleMarkerAllocator` which will yield `SimpleMarker`s
460    /// starting with `0`
461    pub fn new() -> Self {
462        Self {
463            index: 0,
464            mapping: HashMap::new(),
465            _phantom_data: PhantomData,
466        }
467    }
468}
469
470impl<T> MarkerAllocator<SimpleMarker<T>> for SimpleMarkerAllocator<T>
471where
472    T: 'static + ?Sized + Send + Sync,
473{
474    fn allocate(&mut self, entity: Entity, id: Option<u64>) -> SimpleMarker<T> {
475        let marker = if let Some(id) = id {
476            if id >= self.index {
477                self.index = id + 1;
478            }
479            SimpleMarker(id, PhantomData)
480        } else {
481            self.index += 1;
482            SimpleMarker(self.index - 1, PhantomData)
483        };
484        self.mapping.insert(marker.id(), entity);
485
486        marker
487    }
488
489    fn retrieve_entity_internal(&self, id: u64) -> Option<Entity> {
490        self.mapping.get(&id).cloned()
491    }
492
493    fn maintain(&mut self, entities: &EntitiesRes, storage: &ReadStorage<SimpleMarker<T>>) {
494        // FIXME: may be too slow
495        self.mapping = (entities, storage)
496            .join()
497            .map(|(e, m)| (m.id(), e))
498            .collect();
499    }
500}