hecs/serialize/
row.rs

1//! Human-friendly row-major serialization
2//!
3//! Stores each entity's components together. Preferred for data that will be read/written by
4//! humans. Less efficient than column-major serialization.
5//!
6//! This module builds on the public [`World::iter()`] and [`World::spawn_at()`] APIs, and are
7//! somewhat opinionated. For some applications, a custom approach may be preferable.
8//!
9//! In terms of the serde data model, we treat a [`World`] as a map of entity IDs to user-controlled
10//! maps of component IDs to data.
11
12use core::{cell::RefCell, fmt};
13
14use serde::{
15    de::{DeserializeSeed, MapAccess, Visitor},
16    ser::SerializeMap,
17    Deserializer, Serialize, Serializer,
18};
19
20use crate::{Component, EntityBuilder, EntityRef, Query, World};
21
22/// Implements serialization of individual entities
23///
24/// Data external to the [`World`] can be exposed during serialization by storing references inside
25/// the struct implementing this trait.
26///
27/// # Example
28///
29/// ```
30/// # use serde::{Serialize, Deserialize};
31/// # #[derive(Serialize)]
32/// # struct Position([f32; 3]);
33/// # #[derive(Serialize)]
34/// # struct Velocity([f32; 3]);
35/// use hecs::{*, serialize::row::*};
36///
37/// #[derive(Serialize, Deserialize)]
38/// enum ComponentId { Position, Velocity }
39///
40/// // Could include references to external state for use by `serialize_entity`
41/// struct Context;
42///
43/// impl SerializeContext for Context {
44///     fn serialize_entity<S>(
45///         &mut self,
46///         entity: EntityRef<'_>,
47///         mut map: S,
48///     ) -> Result<S::Ok, S::Error>
49///     where
50///         S: serde::ser::SerializeMap,
51///     {
52///         // Call `try_serialize` for every serializable component we want to save
53///         try_serialize::<Position, _, _>(&entity, &ComponentId::Position, &mut map)?;
54///         try_serialize::<Velocity, _, _>(&entity, &ComponentId::Velocity, &mut map)?;
55///         // Or do something custom for more complex cases.
56///         map.end()
57///     }
58/// }
59/// ```
60pub trait SerializeContext {
61    /// Serialize a single entity into a map
62    fn serialize_entity<S>(&mut self, entity: EntityRef<'_>, map: S) -> Result<S::Ok, S::Error>
63    where
64        S: SerializeMap;
65
66    /// Number of entries that [`serialize_entry`](Self::serialize_entity) will produce for
67    /// `entity`, if known
68    ///
69    /// Defaults to `None`. Must be overridden to return `Some` to support certain serializers, e.g.
70    /// bincode.
71    fn component_count(&self, entity: EntityRef<'_>) -> Option<usize> {
72        let _ = entity;
73        None
74    }
75}
76
77/// If `entity` has component `T`, serialize it under `key` in `map`
78///
79/// Convenience method for [`SerializeContext`] implementations.
80pub fn try_serialize<T: Component + Serialize, K: Serialize + ?Sized, S: SerializeMap>(
81    entity: &EntityRef<'_>,
82    key: &K,
83    map: &mut S,
84) -> Result<(), S::Error> {
85    if let Some(x) = entity.get::<&T>() {
86        map.serialize_key(key)?;
87        map.serialize_value(&*x)?;
88    }
89    Ok(())
90}
91
92/// Serialize a [`World`] through a [`SerializeContext`] to a [`Serializer`]
93// Note: deliberately not implemented in terms of `serialize_satisying::<(), _, _>` to avoid an
94// extra loop over the archetypes
95pub fn serialize<C, S>(world: &World, context: &mut C, serializer: S) -> Result<S::Ok, S::Error>
96where
97    C: SerializeContext,
98    S: Serializer,
99{
100    let mut seq = serializer.serialize_map(Some(world.len() as usize))?;
101    for entity in world {
102        seq.serialize_key(&entity.entity())?;
103        seq.serialize_value(&SerializeComponents(RefCell::new((context, Some(entity)))))?;
104    }
105    seq.end()
106}
107
108/// Serialize all entities in a [`World`] that satisfy the given [`Query`] through a [`SerializeContext`] to a [`Serializer`]
109pub fn serialize_satisfying<Q: Query, C, S>(
110    world: &World,
111    context: &mut C,
112    serializer: S,
113) -> Result<S::Ok, S::Error>
114where
115    C: SerializeContext,
116    S: Serializer,
117{
118    let entity_count = world
119        .archetypes()
120        .filter(|a| a.satisfies::<Q>())
121        .map(|a| a.len() as usize)
122        .sum();
123    let mut seq = serializer.serialize_map(Some(entity_count))?;
124    for entity in world {
125        if entity.satisfies::<Q>() {
126            seq.serialize_key(&entity.entity())?;
127            seq.serialize_value(&SerializeComponents(RefCell::new((context, Some(entity)))))?;
128        }
129    }
130    seq.end()
131}
132
133struct SerializeComponents<'a, C>(RefCell<(&'a mut C, Option<EntityRef<'a>>)>);
134
135impl<C: SerializeContext> Serialize for SerializeComponents<'_, C> {
136    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
137    where
138        S: serde::Serializer,
139    {
140        let mut this = self.0.borrow_mut();
141        let entity = this.1.take().unwrap();
142        let map = serializer.serialize_map(this.0.component_count(entity))?;
143        this.0.serialize_entity(entity, map)
144    }
145}
146
147/// Deserialize a [`World`] with a [`DeserializeContext`] and a [`Deserializer`]
148pub fn deserialize<'de, C, D>(context: &mut C, deserializer: D) -> Result<World, D::Error>
149where
150    C: DeserializeContext,
151    D: Deserializer<'de>,
152{
153    deserializer.deserialize_map(WorldVisitor(context))
154}
155
156/// Implements deserialization of entities from a serde [`MapAccess`] into an [`EntityBuilder`]
157///
158/// Data external to the [`World`] can be populated during deserialization by storing mutable
159/// references inside the struct implementing this trait.
160///
161/// # Example
162/// ```
163/// # use serde::{Serialize, Deserialize};
164/// # #[derive(Deserialize)]
165/// # struct Position([f32; 3]);
166/// # #[derive(Deserialize)]
167/// # struct Velocity([f32; 3]);
168/// use hecs::{*, serialize::row::*};
169///
170/// #[derive(Serialize, Deserialize)]
171/// enum ComponentId { Position, Velocity }
172///
173/// // Could include references to external state for use by `deserialize_entity`
174/// struct Context;
175///
176/// impl DeserializeContext for Context {
177///     fn deserialize_entity<'de, M>(
178///         &mut self,
179///         mut map: M,
180///         entity: &mut EntityBuilder,
181///     ) -> Result<(), M::Error>
182///     where
183///         M: serde::de::MapAccess<'de>,
184///     {
185///         while let Some(key) = map.next_key()? {
186///             match key {
187///                 ComponentId::Position => {
188///                     entity.add::<Position>(map.next_value()?);
189///                 }
190///                 ComponentId::Velocity => {
191///                     entity.add::<Velocity>(map.next_value()?);
192///                 }
193///             }
194///         }
195///         Ok(())
196///     }
197/// }
198/// ```
199pub trait DeserializeContext {
200    /// Deserialize a single entity
201    fn deserialize_entity<'de, M>(
202        &mut self,
203        map: M,
204        entity: &mut EntityBuilder,
205    ) -> Result<(), M::Error>
206    where
207        M: MapAccess<'de>;
208}
209
210struct WorldVisitor<'a, C>(&'a mut C);
211
212impl<'de, C> Visitor<'de> for WorldVisitor<'_, C>
213where
214    C: DeserializeContext,
215{
216    type Value = World;
217
218    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
219        formatter.write_str("a world")
220    }
221
222    fn visit_map<A>(self, mut map: A) -> Result<World, A::Error>
223    where
224        A: MapAccess<'de>,
225    {
226        let mut world = World::new();
227        let mut builder = EntityBuilder::new();
228        while let Some(id) = map.next_key()? {
229            map.next_value_seed(DeserializeComponents(self.0, &mut builder))?;
230            world.spawn_at(id, builder.build());
231        }
232        Ok(world)
233    }
234}
235
236struct DeserializeComponents<'a, C>(&'a mut C, &'a mut EntityBuilder);
237
238impl<'de, C> DeserializeSeed<'de> for DeserializeComponents<'_, C>
239where
240    C: DeserializeContext,
241{
242    type Value = ();
243
244    fn deserialize<D>(self, deserializer: D) -> Result<(), D::Error>
245    where
246        D: Deserializer<'de>,
247    {
248        deserializer.deserialize_map(ComponentsVisitor(self.0, self.1))
249    }
250}
251
252struct ComponentsVisitor<'a, C>(&'a mut C, &'a mut EntityBuilder);
253
254impl<'de, C> Visitor<'de> for ComponentsVisitor<'_, C>
255where
256    C: DeserializeContext,
257{
258    type Value = ();
259
260    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
261        formatter.write_str("an entity's components")
262    }
263
264    fn visit_map<A>(self, map: A) -> Result<(), A::Error>
265    where
266        A: MapAccess<'de>,
267    {
268        self.0.deserialize_entity(map, self.1)
269    }
270}
271
272#[cfg(test)]
273mod tests {
274    use core::marker::PhantomData;
275    use std::fmt;
276
277    use serde::{Deserialize, Serialize};
278
279    use super::*;
280    use crate::*;
281
282    #[derive(Serialize, Deserialize, PartialEq, Debug, Copy, Clone)]
283    struct Position([f32; 3]);
284    #[derive(Serialize, Deserialize, PartialEq, Debug, Copy, Clone)]
285    struct Velocity([f32; 3]);
286
287    struct Context;
288    #[derive(Serialize, Deserialize)]
289    enum ComponentId {
290        Position,
291        Velocity,
292    }
293
294    #[derive(Serialize, Deserialize)]
295    /// Bodge into serde_test's very strict interface
296    struct SerWorld(#[serde(with = "helpers")] World);
297
298    impl PartialEq for SerWorld {
299        fn eq(&self, other: &Self) -> bool {
300            fn same_components<T: Component + PartialEq>(x: &EntityRef, y: &EntityRef) -> bool {
301                x.get::<&T>().as_deref() == y.get::<&T>().as_deref()
302            }
303
304            for (x, y) in self.0.iter().zip(other.0.iter()) {
305                if x.entity() != y.entity()
306                    || !same_components::<Position>(&x, &y)
307                    || !same_components::<Velocity>(&x, &y)
308                {
309                    return false;
310                }
311            }
312            true
313        }
314    }
315
316    impl fmt::Debug for SerWorld {
317        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
318            f.debug_map()
319                .entries(self.0.iter().map(|e| {
320                    (
321                        e.entity(),
322                        (
323                            e.get::<&Position>().map(|x| *x),
324                            e.get::<&Velocity>().map(|x| *x),
325                        ),
326                    )
327                }))
328                .finish()
329        }
330    }
331
332    mod helpers {
333        use super::*;
334        pub fn serialize<S: Serializer>(x: &World, s: S) -> Result<S::Ok, S::Error> {
335            crate::serialize::row::serialize(x, &mut Context, s)
336        }
337        pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<World, D::Error> {
338            crate::serialize::row::deserialize(&mut Context, d)
339        }
340    }
341
342    impl DeserializeContext for Context {
343        fn deserialize_entity<'de, M>(
344            &mut self,
345            mut map: M,
346            entity: &mut EntityBuilder,
347        ) -> Result<(), M::Error>
348        where
349            M: serde::de::MapAccess<'de>,
350        {
351            while let Some(key) = map.next_key()? {
352                match key {
353                    ComponentId::Position => {
354                        entity.add::<Position>(map.next_value()?);
355                    }
356                    ComponentId::Velocity => {
357                        entity.add::<Velocity>(map.next_value()?);
358                    }
359                }
360            }
361            Ok(())
362        }
363    }
364
365    impl SerializeContext for Context {
366        fn serialize_entity<S>(
367            &mut self,
368            entity: EntityRef<'_>,
369            mut map: S,
370        ) -> Result<S::Ok, S::Error>
371        where
372            S: serde::ser::SerializeMap,
373        {
374            try_serialize::<Position, _, _>(&entity, &ComponentId::Position, &mut map)?;
375            try_serialize::<Velocity, _, _>(&entity, &ComponentId::Velocity, &mut map)?;
376            map.end()
377        }
378    }
379
380    #[test]
381    #[rustfmt::skip]
382    fn roundtrip() {
383        use serde_test::{Token, assert_tokens};
384
385        let mut world = World::new();
386        let p0 = Position([0.0, 0.0, 0.0]);
387        let v0 = Velocity([1.0, 1.0, 1.0]);
388        let p1 = Position([2.0, 2.0, 2.0]);
389        let e0 = world.spawn((p0, v0));
390        let e1 = world.spawn((p1,));
391
392        assert_tokens(&SerWorld(world), &[
393            Token::NewtypeStruct { name: "SerWorld" },
394            Token::Map { len: Some(2) },
395
396            Token::U64(e0.to_bits().into()),
397            Token::Map { len: None },
398
399            Token::UnitVariant { name: "ComponentId", variant: "Position" },
400            Token::NewtypeStruct { name: "Position" },
401            Token::Tuple { len: 3 },
402            Token::F32(0.0),
403            Token::F32(0.0),
404            Token::F32(0.0),
405            Token::TupleEnd,
406
407            Token::UnitVariant { name: "ComponentId", variant: "Velocity" },
408            Token::NewtypeStruct { name: "Velocity" },
409            Token::Tuple { len: 3 },
410            Token::F32(1.0),
411            Token::F32(1.0),
412            Token::F32(1.0),
413            Token::TupleEnd,
414
415            Token::MapEnd,
416
417            Token::U64(e1.to_bits().into()),
418            Token::Map { len: None },
419
420            Token::UnitVariant { name: "ComponentId", variant: "Position" },
421            Token::NewtypeStruct { name: "Position" },
422            Token::Tuple { len: 3 },
423            Token::F32(2.0),
424            Token::F32(2.0),
425            Token::F32(2.0),
426            Token::TupleEnd,
427
428            Token::MapEnd,
429
430            Token::MapEnd,
431        ])
432    }
433
434    #[derive(Deserialize)]
435    /// Bodge into serde_test's very strict interface
436    struct SerSatisfyingWorld<Q>(
437        #[serde(with = "helpers")] World,
438        #[serde(skip)] PhantomData<Q>,
439    );
440
441    impl<Q> PartialEq for SerSatisfyingWorld<Q> {
442        fn eq(&self, other: &Self) -> bool {
443            fn same_components<T: Component + PartialEq>(x: &EntityRef, y: &EntityRef) -> bool {
444                x.get::<&T>().as_deref() == y.get::<&T>().as_deref()
445            }
446
447            for (x, y) in self.0.iter().zip(other.0.iter()) {
448                if x.entity() != y.entity()
449                    || !same_components::<Position>(&x, &y)
450                    || !same_components::<Velocity>(&x, &y)
451                {
452                    return false;
453                }
454            }
455            true
456        }
457    }
458
459    impl<Q> fmt::Debug for SerSatisfyingWorld<Q> {
460        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
461            f.debug_map()
462                .entries(self.0.iter().map(|e| {
463                    (
464                        e.entity(),
465                        (
466                            e.get::<&Position>().map(|x| *x),
467                            e.get::<&Velocity>().map(|x| *x),
468                        ),
469                    )
470                }))
471                .finish()
472        }
473    }
474
475    struct SerSatisfyingWorldInner<'a, Q>(&'a World, PhantomData<Q>);
476
477    impl<'a, Q: Query> Serialize for SerSatisfyingWorldInner<'a, Q> {
478        fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
479            crate::serialize::row::serialize_satisfying::<Q, Context, S>(self.0, &mut Context, s)
480        }
481    }
482
483    impl<Q: Query> Serialize for SerSatisfyingWorld<Q> {
484        fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
485            use serde::ser::SerializeTupleStruct;
486            let mut t = s.serialize_tuple_struct("SerSatisfyingWorld", 1)?;
487            t.serialize_field(&SerSatisfyingWorldInner(&self.0, self.1))?;
488            t.end()
489        }
490    }
491
492    #[test]
493    #[rustfmt::skip]
494    fn test_serialize_satisfying() {
495        use serde_test::{Token, assert_tokens, assert_ser_tokens};
496
497        let p0 = Position([0.0, 0.0, 0.0]);
498        let v0 = Velocity([1.0, 1.0, 1.0]);
499        let p1 = Position([2.0, 2.0, 2.0]);
500
501        let world = || {
502            let mut world = World::new();
503            let e0 = world.spawn((p0, v0));
504            let e1 = world.spawn((p1,));
505            (world, e0, e1)
506        };
507
508        let (world0, e00, e01) = world();
509        let (world1, e10, _e11) = world();
510
511        assert_tokens(&SerSatisfyingWorld(world0, PhantomData::<()>), &[
512            Token::TupleStruct { name: "SerSatisfyingWorld", len: 1 },
513            Token::Map { len: Some(2) },
514
515            Token::U64(e00.to_bits().into()),
516            Token::Map { len: None },
517
518            Token::UnitVariant { name: "ComponentId", variant: "Position" },
519            Token::NewtypeStruct { name: "Position" },
520            Token::Tuple { len: 3 },
521            Token::F32(0.0),
522            Token::F32(0.0),
523            Token::F32(0.0),
524            Token::TupleEnd,
525
526            Token::UnitVariant { name: "ComponentId", variant: "Velocity" },
527            Token::NewtypeStruct { name: "Velocity" },
528            Token::Tuple { len: 3 },
529            Token::F32(1.0),
530            Token::F32(1.0),
531            Token::F32(1.0),
532            Token::TupleEnd,
533
534            Token::MapEnd,
535
536            Token::U64(e01.to_bits().into()),
537            Token::Map { len: None },
538
539            Token::UnitVariant { name: "ComponentId", variant: "Position" },
540            Token::NewtypeStruct { name: "Position" },
541            Token::Tuple { len: 3 },
542            Token::F32(2.0),
543            Token::F32(2.0),
544            Token::F32(2.0),
545            Token::TupleEnd,
546            Token::MapEnd,
547            Token::MapEnd,
548
549            Token::TupleStructEnd,
550        ]);
551
552        assert_ser_tokens(&SerSatisfyingWorld(world1, PhantomData::<(&Velocity,)>), &[
553            Token::TupleStruct { name: "SerSatisfyingWorld", len: 1 },
554            Token::Map { len: Some(1) },
555
556            Token::U64(e10.to_bits().into()),
557            Token::Map { len: None },
558
559            Token::UnitVariant { name: "ComponentId", variant: "Position" },
560            Token::NewtypeStruct { name: "Position" },
561            Token::Tuple { len: 3 },
562            Token::F32(0.0),
563            Token::F32(0.0),
564            Token::F32(0.0),
565            Token::TupleEnd,
566
567            Token::UnitVariant { name: "ComponentId", variant: "Velocity" },
568            Token::NewtypeStruct { name: "Velocity" },
569            Token::Tuple { len: 3 },
570            Token::F32(1.0),
571            Token::F32(1.0),
572            Token::F32(1.0),
573            Token::TupleEnd,
574
575            Token::MapEnd,
576
577            Token::MapEnd,
578
579            Token::TupleStructEnd,
580        ])
581    }
582}