flax/serialize/
mod.rs

1mod de;
2mod ser;
3
4use alloc::string::String;
5pub use de::*;
6pub use ser::*;
7use serde::{Deserialize, Serialize};
8
9use crate::{
10    component::{ComponentKey, ComponentValue},
11    filter::And,
12    filter::{All, StaticFilter},
13    Component,
14};
15
16#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
17struct ComponentSerKey {
18    key: String,
19    id: ComponentKey,
20}
21
22#[derive(serde::Deserialize)]
23#[serde(field_identifier, rename_all = "lowercase")]
24enum WorldFields {
25    Archetypes,
26}
27
28#[derive(serde::Deserialize)]
29#[serde(field_identifier, rename_all = "lowercase")]
30enum RowFields {
31    Entities,
32}
33
34/// Describes the serialialization format
35#[derive(Debug, Clone, serde::Deserialize)]
36pub enum SerializeFormat {
37    /// Serialize the world in a row major format.
38    /// This is less efficient and uses slightly more space since each entity is
39    /// serialized as a map, though it is more human readable and easier for git
40    /// merges.
41    #[serde(rename = "row")]
42    RowMajor,
43    /// Serialize the world in a column major format.
44    /// This is more efficient but less human readable.
45    #[serde(rename = "col")]
46    ColumnMajor,
47}
48
49/// Allows constructing a serialize and deserialize context with the same
50/// supported types allowing for easier roundtrips.
51pub struct SerdeBuilder<F = All> {
52    ser: SerializeBuilder<F>,
53    de: DeserializeBuilder,
54}
55
56impl SerdeBuilder {
57    /// Creates a new builder which simultaneously constructs a serialialization
58    /// and deserialization context
59    pub fn new() -> Self {
60        Self {
61            ser: Default::default(),
62            de: Default::default(),
63        }
64    }
65}
66
67impl Default for SerdeBuilder {
68    fn default() -> Self {
69        Self::new()
70    }
71}
72
73impl<F> SerdeBuilder<F>
74where
75    F: StaticFilter + 'static + Clone,
76{
77    /// Register a component using the component name.
78    ///
79    /// See [`Self::with_name`]
80    pub fn with<T>(&mut self, component: Component<T>) -> &mut Self
81    where
82        T: ComponentValue + Serialize + for<'de> Deserialize<'de>,
83    {
84        self.with_name(component.name(), component)
85    }
86
87    /// Register a component for both serialization and deserialiaztion
88    pub fn with_name<T>(&mut self, key: impl Into<String>, component: Component<T>) -> &mut Self
89    where
90        T: ComponentValue + Serialize + for<'de> Deserialize<'de>,
91    {
92        let key = key.into();
93        self.ser.with_name(key.clone(), component);
94        self.de.with_name(key, component);
95        self
96    }
97
98    /// Add a new filter to specify which entities will be serialized.
99    pub fn with_filter<G>(self, filter: G) -> SerdeBuilder<And<F, G>> {
100        SerdeBuilder {
101            ser: self.ser.with_filter(filter),
102            de: self.de,
103        }
104    }
105
106    /// Finish constructing the serialize and deserialize context.
107    pub fn build(&mut self) -> (SerializeContext, DeserializeContext) {
108        (self.ser.build(), self.de.build())
109    }
110}
111
112#[cfg(test)]
113mod test {
114    use alloc::format;
115    use alloc::vec;
116    use alloc::vec::Vec;
117    use rand::{
118        distributions::{Standard, Uniform},
119        rngs::StdRng,
120        Rng, SeedableRng,
121    };
122
123    use crate::{archetype::BatchSpawn, component, components::name, Entity, World};
124
125    use super::*;
126
127    #[test]
128    fn serialize() {
129        let mut world = World::new();
130
131        component! {
132            health: f32,
133            pos: (f32, f32),
134            items: Vec<String>,
135            status_effects: Vec<String>,
136        }
137
138        let player = Entity::builder()
139            .set(name(), "Player".into())
140            .set(pos(), (1.4, 5.3))
141            .set(items(), vec!["Dagger".into(), "Estradiol".into()])
142            .set(health(), 67.8)
143            .spawn(&mut world);
144
145        let mut rng = StdRng::seed_from_u64(42);
146
147        let mut batch = BatchSpawn::new(16);
148        batch
149            .set(name(), (0..).map(|i| format!("Enemy.{i}")))
150            .unwrap();
151        batch
152            .set(
153                health(),
154                (&mut rng)
155                    .sample_iter(Uniform::new(0.0, 100.0))
156                    .map(|v: f32| (v * 5.0).round() / 5.0),
157            )
158            .unwrap();
159
160        batch.set(pos(), (&mut rng).sample_iter(Standard)).unwrap();
161
162        let enemies = batch.spawn(&mut world);
163
164        world
165            .entry(enemies[2], status_effects())
166            .unwrap()
167            .or_default()
168            .push("Poison".into());
169
170        world
171            .entry(enemies[5], status_effects())
172            .unwrap()
173            .or_default()
174            .push("Fire".into());
175
176        let all_entities = [vec![player], enemies].concat();
177
178        let test_eq = |world: &World, new_world: &World| {
179            // Check that all are identical
180            for &id in &all_entities {
181                assert_eq!(
182                    world.get(id, health()).as_deref(),
183                    new_world.get(id, health()).as_deref()
184                );
185
186                assert_eq!(
187                    world.get(id, pos()).as_deref(),
188                    new_world.get(id, pos()).as_deref()
189                );
190
191                assert_eq!(
192                    world.get(id, items()).as_deref(),
193                    new_world.get(id, items()).as_deref()
194                );
195
196                assert_eq!(
197                    world.get(id, status_effects()).as_deref(),
198                    new_world.get(id, status_effects()).as_deref()
199                );
200            }
201        };
202
203        let (serializer, deserializer) = SerdeBuilder::new()
204            .with(name())
205            .with(health())
206            .with(pos())
207            .with(items())
208            .with(status_effects())
209            .build();
210
211        let json =
212            serde_json::to_string(&serializer.serialize(&world, SerializeFormat::ColumnMajor))
213                .unwrap();
214
215        let new_world: World = deserializer
216            .deserialize(&mut serde_json::Deserializer::from_str(&json[..]))
217            .expect("Failed to deserialize world");
218
219        test_eq(&world, &new_world);
220
221        let json =
222            serde_json::to_string_pretty(&serializer.serialize(&world, SerializeFormat::RowMajor))
223                .unwrap();
224
225        let world = new_world;
226        let new_world = deserializer
227            .deserialize(&mut serde_json::Deserializer::from_str(&json[..]))
228            .expect("Failed to deserialize world");
229
230        test_eq(&world, &new_world);
231
232        let encoded =
233            ron::to_string(&serializer.serialize(&world, SerializeFormat::RowMajor)).unwrap();
234        let new_world = deserializer
235            .deserialize(&mut ron::Deserializer::from_str(&encoded).unwrap())
236            .unwrap();
237
238        test_eq(&world, &new_world);
239
240        let encoded =
241            ron::to_string(&serializer.serialize(&world, SerializeFormat::ColumnMajor)).unwrap();
242
243        let new_world = deserializer
244            .deserialize(&mut ron::Deserializer::from_str(&encoded).unwrap())
245            .unwrap();
246
247        test_eq(&world, &new_world);
248    }
249}