rework scene format. use property value serializer, removing the need for ron fork / enabling any serde target
This commit is contained in:
		
							parent
							
								
									d86d3ddcbc
								
							
						
					
					
						commit
						59dbf22e39
					
				| @ -148,10 +148,6 @@ pub fn derive_properties(input: TokenStream) -> TokenStream { | ||||
|             fn iter_props(&self) -> #bevy_property_path::PropertyIter { | ||||
|                 #bevy_property_path::PropertyIter::new(self) | ||||
|             } | ||||
| 
 | ||||
|             fn properties_type(&self) -> #bevy_property_path::PropertiesType { | ||||
|                 #bevy_property_path::PropertiesType::Map | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         impl #impl_generics #bevy_property_path::Property for #struct_name#ty_generics { | ||||
| @ -181,11 +177,11 @@ pub fn derive_properties(input: TokenStream) -> TokenStream { | ||||
|             #[inline] | ||||
|             fn apply(&mut self, value: &dyn #bevy_property_path::Property) { | ||||
|                 if let Some(properties) = value.as_properties() { | ||||
|                     if properties.properties_type() != self.properties_type() { | ||||
|                     if properties.property_type() != self.property_type() { | ||||
|                         panic!( | ||||
|                             "Properties type mismatch. This type is {:?} but the applied type is {:?}", | ||||
|                             self.properties_type(), | ||||
|                             properties.properties_type() | ||||
|                             self.property_type(), | ||||
|                             properties.property_type() | ||||
|                         ); | ||||
|                     } | ||||
|                     for (i, prop) in properties.iter_props().enumerate() { | ||||
| @ -202,8 +198,12 @@ pub fn derive_properties(input: TokenStream) -> TokenStream { | ||||
|                 Some(self) | ||||
|             } | ||||
| 
 | ||||
|             fn serializable(&self) -> #bevy_property_path::Serializable { | ||||
|                 #bevy_property_path::Serializable::Owned(Box::new(#bevy_property_path::property_serde::MapSerializer::new(self))) | ||||
|             fn serializable(&self) -> #bevy_property_path::property_serde::Serializable { | ||||
|                 #bevy_property_path::property_serde::Serializable::Owned(Box::new(#bevy_property_path::property_serde::MapSerializer::new(self))) | ||||
|             } | ||||
| 
 | ||||
|             fn property_type(&self) -> #bevy_property_path::PropertyType { | ||||
|                 #bevy_property_path::PropertyType::Map | ||||
|             } | ||||
|         } | ||||
|     }) | ||||
| @ -258,8 +258,14 @@ pub fn derive_property(input: TokenStream) -> TokenStream { | ||||
|             } | ||||
| 
 | ||||
|             #[inline] | ||||
|             fn serializable(&self) -> #bevy_property_path::Serializable { | ||||
|                 #bevy_property_path::Serializable::Borrowed(self) | ||||
|             fn serializable(&self) -> #bevy_property_path::property_serde::Serializable { | ||||
|                 #bevy_property_path::property_serde::Serializable::Owned(Box::new(#bevy_property_path::property_serde::PropertyValueSerializer { | ||||
|                     property: self, | ||||
|                 })) | ||||
|             } | ||||
| 
 | ||||
|             fn property_type(&self) -> #bevy_property_path::PropertyType { | ||||
|                 #bevy_property_path::PropertyType::Value | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| @ -337,7 +343,9 @@ pub fn impl_property(input: TokenStream) -> TokenStream { | ||||
|         quote! { #serialize_fn(self) } | ||||
|     } else { | ||||
|         quote! { | ||||
|             #bevy_property_path::Serializable::Borrowed(self) | ||||
|             #bevy_property_path::property_serde::Serializable::Owned(Box::new(#bevy_property_path::property_serde::PropertyValueSerializer { | ||||
|                 property: self, | ||||
|             })) | ||||
|         } | ||||
|     }; | ||||
|     let deserialize_fn = if let Some(deserialize_fn) = property_def.deserialize_fn { | ||||
| @ -387,9 +395,13 @@ pub fn impl_property(input: TokenStream) -> TokenStream { | ||||
|             } | ||||
| 
 | ||||
|             #[inline] | ||||
|             fn serializable(&self) -> #bevy_property_path::Serializable { | ||||
|             fn serializable(&self) -> #bevy_property_path::property_serde::Serializable { | ||||
|                 #serialize_fn | ||||
|             } | ||||
| 
 | ||||
|             fn property_type(&self) -> #bevy_property_path::PropertyType { | ||||
|                 #bevy_property_path::PropertyType::Value | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         impl #impl_generics #bevy_property_path::DeserializeProperty for #ty#ty_generics #where_clause  { | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| use crate::{Properties, PropertiesType, Property, PropertyIter, Serializable}; | ||||
| use crate::{property_serde::Serializable, Properties, Property, PropertyIter, PropertyType}; | ||||
| use std::{any::Any, borrow::Cow, collections::HashMap}; | ||||
| 
 | ||||
| pub struct DynamicProperties { | ||||
| @ -6,7 +6,7 @@ pub struct DynamicProperties { | ||||
|     pub props: Vec<Box<dyn Property>>, | ||||
|     pub prop_names: Vec<Cow<'static, str>>, | ||||
|     pub prop_indices: HashMap<Cow<'static, str>, usize>, | ||||
|     pub properties_type: PropertiesType, | ||||
|     pub property_type: PropertyType, | ||||
| } | ||||
| 
 | ||||
| impl DynamicProperties { | ||||
| @ -16,7 +16,7 @@ impl DynamicProperties { | ||||
|             props: Default::default(), | ||||
|             prop_names: Default::default(), | ||||
|             prop_indices: Default::default(), | ||||
|             properties_type: PropertiesType::Map, | ||||
|             property_type: PropertyType::Map, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -26,7 +26,7 @@ impl DynamicProperties { | ||||
|             props: Default::default(), | ||||
|             prop_names: Default::default(), | ||||
|             prop_indices: Default::default(), | ||||
|             properties_type: PropertiesType::Seq, | ||||
|             property_type: PropertyType::Seq, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -88,9 +88,10 @@ impl Properties for DynamicProperties { | ||||
| 
 | ||||
|     #[inline] | ||||
|     fn prop_name(&self, index: usize) -> Option<&str> { | ||||
|         match self.properties_type { | ||||
|             PropertiesType::Seq => None, | ||||
|             PropertiesType::Map => self.prop_names.get(index).map(|name| name.as_ref()), | ||||
|         match self.property_type { | ||||
|             PropertyType::Seq => None, | ||||
|             PropertyType::Map => self.prop_names.get(index).map(|name| name.as_ref()), | ||||
|             _ => panic!("DynamicProperties cannot be Value types"), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -105,11 +106,6 @@ impl Properties for DynamicProperties { | ||||
|             index: 0, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     #[inline] | ||||
|     fn properties_type(&self) -> PropertiesType { | ||||
|         self.properties_type | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Property for DynamicProperties { | ||||
| @ -142,25 +138,26 @@ impl Property for DynamicProperties { | ||||
|     #[inline] | ||||
|     fn apply(&mut self, value: &dyn Property) { | ||||
|         if let Some(properties) = value.as_properties() { | ||||
|             if properties.properties_type() != self.properties_type { | ||||
|             if properties.property_type() != self.property_type { | ||||
|                 panic!( | ||||
|                     "Properties type mismatch. This type is {:?} but the applied type is {:?}", | ||||
|                     self.properties_type, | ||||
|                     properties.properties_type() | ||||
|                     self.property_type, | ||||
|                     properties.property_type() | ||||
|                 ); | ||||
|             } | ||||
|             match self.properties_type { | ||||
|                 PropertiesType::Map => { | ||||
|             match self.property_type { | ||||
|                 PropertyType::Map => { | ||||
|                     for (i, prop) in properties.iter_props().enumerate() { | ||||
|                         let name = properties.prop_name(i).unwrap(); | ||||
|                         self.prop_mut(name).map(|p| p.apply(prop)); | ||||
|                     } | ||||
|                 } | ||||
|                 PropertiesType::Seq => { | ||||
|                 PropertyType::Seq => { | ||||
|                     for (i, prop) in properties.iter_props().enumerate() { | ||||
|                         self.prop_with_index_mut(i).map(|p| p.apply(prop)); | ||||
|                     } | ||||
|                 } | ||||
|                 _ => panic!("DynamicProperties cannot be Value types"), | ||||
|             } | ||||
|         } else { | ||||
|             panic!("attempted to apply non-Properties type to Properties type"); | ||||
| @ -171,11 +168,11 @@ impl Property for DynamicProperties { | ||||
|         Some(self) | ||||
|     } | ||||
| 
 | ||||
|     fn is_sequence(&self) -> bool { | ||||
|         self.properties_type == PropertiesType::Seq | ||||
|     } | ||||
| 
 | ||||
|     fn serializable(&self) -> Serializable { | ||||
|         Serializable::Borrowed(self) | ||||
|     } | ||||
| 
 | ||||
|     fn property_type(&self) -> PropertyType { | ||||
|         self.property_type | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| use crate::{impl_property, Property, PropertyTypeRegistry, Serializable}; | ||||
| use crate::{impl_property, Property, PropertyTypeRegistry, property_serde::Serializable}; | ||||
| use erased_serde::Deserializer; | ||||
| use legion::prelude::Entity; | ||||
| use serde::Deserialize; | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| use crate::{Serializable, Property}; | ||||
| use crate::{Property, PropertyType, property_serde::Serializable}; | ||||
| use serde::Serialize; | ||||
| use smallvec::{Array, SmallVec}; | ||||
| use std::any::Any; | ||||
| @ -43,4 +43,8 @@ where | ||||
|     fn serializable(&self) -> Serializable { | ||||
|         Serializable::Borrowed(self) | ||||
|     } | ||||
| 
 | ||||
|     fn property_type(&self) -> PropertyType { | ||||
|         PropertyType::Value | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| use crate::{impl_property, Properties, PropertiesType, Property, PropertyIter, Serializable, property_serde::SeqSerializer}; | ||||
| use crate::{impl_property, Properties, Property, PropertyIter, property_serde::{Serializable, SeqSerializer}}; | ||||
| use serde::{Serialize, Deserialize}; | ||||
| use std::{ | ||||
|     any::Any, | ||||
| @ -32,9 +32,6 @@ where | ||||
|     fn iter_props(&self) -> PropertyIter { | ||||
|         PropertyIter::new(self) | ||||
|     } | ||||
|     fn properties_type(&self) -> PropertiesType { | ||||
|         PropertiesType::Seq | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T> Property for Vec<T> | ||||
| @ -56,11 +53,11 @@ where | ||||
|     } | ||||
|     fn set(&mut self, value: &dyn Property) { | ||||
|         if let Some(properties) = value.as_properties() { | ||||
|             if properties.properties_type() != self.properties_type() { | ||||
|             if properties.property_type() != self.property_type() { | ||||
|                 panic!( | ||||
|                     "Properties type mismatch. This type is {:?} but the applied type is {:?}", | ||||
|                     self.properties_type(), | ||||
|                     properties.properties_type() | ||||
|                     self.property_type(), | ||||
|                     properties.property_type() | ||||
|                 ); | ||||
|             } | ||||
|             for (i, prop) in properties.iter_props().enumerate() { | ||||
| @ -78,10 +75,6 @@ where | ||||
|         Some(self) | ||||
|     } | ||||
| 
 | ||||
|     fn is_sequence(&self) -> bool { | ||||
|         true | ||||
|     } | ||||
| 
 | ||||
|     fn serializable(&self) -> Serializable { | ||||
|         Serializable::Owned(Box::new(SeqSerializer::new(self))) | ||||
|     } | ||||
|  | ||||
| @ -1,10 +1,4 @@ | ||||
| use crate::{DynamicProperties, Property, PropertyVal}; | ||||
| 
 | ||||
| #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] | ||||
| pub enum PropertiesType { | ||||
|     Map, | ||||
|     Seq, | ||||
| } | ||||
| use crate::{DynamicProperties, Property, PropertyType, PropertyVal}; | ||||
| 
 | ||||
| pub trait Properties: Property { | ||||
|     fn prop(&self, name: &str) -> Option<&dyn Property>; | ||||
| @ -14,7 +8,6 @@ pub trait Properties: Property { | ||||
|     fn prop_name(&self, index: usize) -> Option<&str>; | ||||
|     fn prop_len(&self) -> usize; | ||||
|     fn iter_props(&self) -> PropertyIter; | ||||
|     fn properties_type(&self) -> PropertiesType; | ||||
|     fn set_prop(&mut self, name: &str, value: &dyn Property) { | ||||
|         if let Some(prop) = self.prop_mut(name) { | ||||
|             prop.set(value); | ||||
| @ -22,25 +15,27 @@ pub trait Properties: Property { | ||||
|             panic!("prop does not exist: {}", name); | ||||
|         } | ||||
|     } | ||||
|     fn to_dynamic(&self) -> DynamicProperties | ||||
|     { | ||||
|         let mut dynamic_props = match self.properties_type() { | ||||
|             PropertiesType::Map => { | ||||
|     fn to_dynamic(&self) -> DynamicProperties { | ||||
|         let mut dynamic_props = match self.property_type() { | ||||
|             PropertyType::Map => { | ||||
|                 let mut dynamic_props = DynamicProperties::map(); | ||||
|                 for (i, prop) in self.iter_props().enumerate() { | ||||
|                     let name = self.prop_name(i).expect("All properties in maps should have a name"); | ||||
|                     let name = self | ||||
|                         .prop_name(i) | ||||
|                         .expect("All properties in maps should have a name"); | ||||
|                     dynamic_props.set_box(name, prop.clone_prop()); | ||||
|                 } | ||||
|                 dynamic_props | ||||
|             }, | ||||
|             PropertiesType::Seq => { | ||||
|             } | ||||
|             PropertyType::Seq => { | ||||
|                 let mut dynamic_props = DynamicProperties::seq(); | ||||
|                 for prop in self.iter_props() { | ||||
|                     dynamic_props.push(prop.clone_prop(), None); | ||||
|                 } | ||||
|                 dynamic_props | ||||
|             } | ||||
|         } ; | ||||
|             _ => panic!("Properties cannot be Value types"), | ||||
|         }; | ||||
| 
 | ||||
|         dynamic_props.type_name = self.type_name().to_string(); | ||||
|         dynamic_props | ||||
|  | ||||
| @ -1,20 +1,12 @@ | ||||
| use crate::{PropertyTypeRegistry, Properties}; | ||||
| use crate::{property_serde::Serializable, Properties, PropertyTypeRegistry}; | ||||
| use erased_serde::Deserializer; | ||||
| use std::any::Any; | ||||
| use erased_serde::{Deserializer, Serialize}; | ||||
| 
 | ||||
| 
 | ||||
| pub enum Serializable<'a> { | ||||
|     Owned(Box<dyn Serialize + 'a>), | ||||
|     Borrowed(&'a dyn Serialize), | ||||
| } | ||||
| 
 | ||||
| impl<'a> Serializable<'a> { | ||||
|     pub fn borrow(&self) -> &dyn Serialize { | ||||
|         match self { | ||||
|             Serializable::Borrowed(serialize) => serialize, | ||||
|             Serializable::Owned(serialize) => serialize, | ||||
|         } | ||||
|     } | ||||
| #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] | ||||
| pub enum PropertyType { | ||||
|     Map, | ||||
|     Seq, | ||||
|     Value, | ||||
| } | ||||
| 
 | ||||
| // TODO: consider removing send + sync requirements
 | ||||
| @ -25,18 +17,20 @@ pub trait Property: Send + Sync + Any + 'static { | ||||
|     fn clone_prop(&self) -> Box<dyn Property>; | ||||
|     fn set(&mut self, value: &dyn Property); | ||||
|     fn apply(&mut self, value: &dyn Property); | ||||
|     fn property_type(&self) -> PropertyType { | ||||
|         PropertyType::Value | ||||
|     } | ||||
|     fn as_properties(&self) -> Option<&dyn Properties> { | ||||
|         None | ||||
|     } | ||||
|     fn is_sequence(&self) -> bool { | ||||
|         false | ||||
|     } | ||||
| 
 | ||||
|     fn serializable(&self) -> Serializable; | ||||
| } | ||||
| 
 | ||||
| pub trait DeserializeProperty { | ||||
|     fn deserialize(deserializer: &mut dyn Deserializer, property_type_registry: &PropertyTypeRegistry) -> Result<Box<dyn Property>, erased_serde::Error>; | ||||
|     fn deserialize( | ||||
|         deserializer: &mut dyn Deserializer, | ||||
|         property_type_registry: &PropertyTypeRegistry, | ||||
|     ) -> Result<Box<dyn Property>, erased_serde::Error>; | ||||
| } | ||||
| 
 | ||||
| pub trait PropertyVal { | ||||
|  | ||||
| @ -1,58 +1,74 @@ | ||||
| use crate::{DynamicProperties, Properties, PropertiesType, Property, PropertyTypeRegistry}; | ||||
| use crate::{DynamicProperties, Properties, Property, PropertyType, PropertyTypeRegistry}; | ||||
| use de::SeqAccess; | ||||
| use serde::{ | ||||
|     de::{self, DeserializeSeed, MapAccess, Visitor}, | ||||
|     ser::{SerializeMap, SerializeSeq}, | ||||
|     Serialize, | ||||
| }; | ||||
| use std::{cell::RefCell, rc::Rc}; | ||||
| 
 | ||||
| pub const TYPE_FIELD: &str = "type"; | ||||
| pub const MAP_FIELD: &str = "map"; | ||||
| pub const SEQ_FIELD: &str = "seq"; | ||||
| pub const VALUE_FIELD: &str = "value"; | ||||
| 
 | ||||
| pub enum Serializable<'a> { | ||||
|     Owned(Box<dyn erased_serde::Serialize + 'a>), | ||||
|     Borrowed(&'a dyn erased_serde::Serialize), | ||||
| } | ||||
| 
 | ||||
| impl<'a> Serializable<'a> { | ||||
|     pub fn borrow(&self) -> &dyn erased_serde::Serialize { | ||||
|         match self { | ||||
|             Serializable::Borrowed(serialize) => serialize, | ||||
|             Serializable::Owned(serialize) => serialize, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| pub struct PropertyValueSerializer<'a, T> | ||||
| where | ||||
|     T: Property + Serialize, | ||||
| { | ||||
|     pub property: &'a T, | ||||
| } | ||||
| 
 | ||||
| impl<'a, T> PropertyValueSerializer<'a, T> | ||||
| where | ||||
|     T: Property + Serialize, | ||||
| { | ||||
|     pub fn new(property: &'a T) -> Self { | ||||
|         PropertyValueSerializer { property } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<'a, T> Serialize for PropertyValueSerializer<'a, T> | ||||
| where | ||||
|     T: Property + Serialize, | ||||
| { | ||||
|     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ||||
|     where | ||||
|         S: serde::Serializer, | ||||
|     { | ||||
|         let mut state = serializer.serialize_map(Some(2))?; | ||||
|         state.serialize_entry(TYPE_FIELD, self.property.type_name())?; | ||||
|         state.serialize_entry(VALUE_FIELD, self.property)?; | ||||
|         state.end() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Serialize for DynamicProperties { | ||||
|     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ||||
|     where | ||||
|         S: serde::Serializer, | ||||
|     { | ||||
|         match self.properties_type { | ||||
|             PropertiesType::Map => MapSerializer::new(self).serialize(serializer), | ||||
|             PropertiesType::Seq => SeqSerializer::new(self).serialize(serializer), | ||||
|         match self.property_type { | ||||
|             PropertyType::Map => MapSerializer::new(self).serialize(serializer), | ||||
|             PropertyType::Seq => SeqSerializer::new(self).serialize(serializer), | ||||
|             _ => { | ||||
|                 return Err(serde::ser::Error::custom( | ||||
|                     "DynamicProperties cannot be Value type", | ||||
|                 )) | ||||
|             } | ||||
|         } | ||||
| } | ||||
| 
 | ||||
| pub struct DynamicPropertiesDeserializer<'a> { | ||||
|     pub registry: &'a PropertyTypeRegistry, | ||||
|     pub current_type_name: Rc<RefCell<Option<String>>>, | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'de> DeserializeSeed<'de> for DynamicPropertiesDeserializer<'a> { | ||||
|     type Value = DynamicProperties; | ||||
|     fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> | ||||
|     where | ||||
|         D: serde::Deserializer<'de>, | ||||
|     { | ||||
|         deserializer.deserialize_map(DynamicPropertyMapVisiter { | ||||
|             registry: self.registry, | ||||
|             current_type_name: self.current_type_name, | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct DynamicPropertyMapVisiter<'a> { | ||||
|     registry: &'a PropertyTypeRegistry, | ||||
|     current_type_name: Rc<RefCell<Option<String>>>, | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'de> Visitor<'de> for DynamicPropertyMapVisiter<'a> { | ||||
|     type Value = DynamicProperties; | ||||
|     fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { | ||||
|         formatter.write_str("properties map") | ||||
|     } | ||||
| 
 | ||||
|     fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error> | ||||
|     where | ||||
|         V: MapAccess<'de>, | ||||
|     { | ||||
|         visit_map(map, self.registry, self.current_type_name) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -67,31 +83,47 @@ impl<'a> MapSerializer<'a> { | ||||
| } | ||||
| 
 | ||||
| impl<'a> Serialize for MapSerializer<'a> { | ||||
|     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ||||
|     where | ||||
|         S: serde::Serializer, | ||||
|     { | ||||
|         let mut state = serializer.serialize_map(Some(2))?; | ||||
|         state.serialize_entry(TYPE_FIELD, self.properties.type_name())?; | ||||
|         state.serialize_entry( | ||||
|             MAP_FIELD, | ||||
|             &MapValueSerializer { | ||||
|                 properties: self.properties, | ||||
|             }, | ||||
|         )?; | ||||
|         state.end() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct MapValueSerializer<'a> { | ||||
|     pub properties: &'a dyn Properties, | ||||
| } | ||||
| 
 | ||||
| impl<'a> Serialize for MapValueSerializer<'a> { | ||||
|     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ||||
|     where | ||||
|         S: serde::Serializer, | ||||
|     { | ||||
|         let mut state = serializer.serialize_map(Some(self.properties.prop_len()))?; | ||||
|         state.serialize_entry("type", self.properties.type_name())?; | ||||
|         for (index, property) in self.properties.iter_props().enumerate() { | ||||
|             let name = self.properties.prop_name(index).unwrap(); | ||||
|             if property.is_sequence() { | ||||
|                 state.serialize_entry(name, &SeqSerializer { property })?; | ||||
|             } else { | ||||
|             state.serialize_entry(name, property.serializable().borrow())?; | ||||
|         } | ||||
|         } | ||||
|         state.end() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct SeqSerializer<'a> { | ||||
|     pub property: &'a dyn Property, | ||||
|     pub properties: &'a dyn Properties, | ||||
| } | ||||
| 
 | ||||
| impl<'a> SeqSerializer<'a> { | ||||
|     pub fn new(property: &'a dyn Property) -> Self { | ||||
|         SeqSerializer { property } | ||||
|     pub fn new(properties: &'a dyn Properties) -> Self { | ||||
|         SeqSerializer { properties } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -101,22 +133,22 @@ impl<'a> Serialize for SeqSerializer<'a> { | ||||
|         S: serde::Serializer, | ||||
|     { | ||||
|         let mut state = serializer.serialize_map(Some(2))?; | ||||
|         if let Some(properties) = self.property.as_properties() { | ||||
|             state.serialize_entry("seq_type", self.property.type_name())?; | ||||
|             state.serialize_entry("data", &PropertiesSeqSerializer { properties })?; | ||||
|         } else { | ||||
|             state.serialize_entry("seq_value_type", self.property.type_name())?; | ||||
|             state.serialize_entry("data", self.property.serializable().borrow())?; | ||||
|         } | ||||
|         state.serialize_entry(TYPE_FIELD, self.properties.type_name())?; | ||||
|         state.serialize_entry( | ||||
|             SEQ_FIELD, | ||||
|             &SeqValueSerializer { | ||||
|                 properties: self.properties, | ||||
|             }, | ||||
|         )?; | ||||
|         state.end() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct PropertiesSeqSerializer<'a> { | ||||
| pub struct SeqValueSerializer<'a> { | ||||
|     pub properties: &'a dyn Properties, | ||||
| } | ||||
| 
 | ||||
| impl<'a> Serialize for PropertiesSeqSerializer<'a> { | ||||
| impl<'a> Serialize for SeqValueSerializer<'a> { | ||||
|     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ||||
|     where | ||||
|         S: serde::Serializer, | ||||
| @ -130,8 +162,8 @@ impl<'a> Serialize for PropertiesSeqSerializer<'a> { | ||||
| } | ||||
| 
 | ||||
| pub struct PropertyDeserializer<'a> { | ||||
|     pub registry: &'a PropertyTypeRegistry, | ||||
|     pub current_type_name: Rc<RefCell<Option<String>>>, | ||||
|     type_name: Option<&'a str>, | ||||
|     registry: &'a PropertyTypeRegistry, | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'de> DeserializeSeed<'de> for PropertyDeserializer<'a> { | ||||
| @ -140,37 +172,41 @@ impl<'a, 'de> DeserializeSeed<'de> for PropertyDeserializer<'a> { | ||||
|     where | ||||
|         D: serde::Deserializer<'de>, | ||||
|     { | ||||
|         if let Some(type_name) = self.type_name { | ||||
|             let registration = self.registry.get_short(type_name).ok_or_else(|| { | ||||
|                 de::Error::custom(format!("TypeRegistration is missing for {}", type_name)) | ||||
|             })?; | ||||
|             let mut erased = erased_serde::Deserializer::erase(deserializer); | ||||
|             (registration.deserialize)(&mut erased, self.registry) | ||||
|                 .map_err(<<D as serde::Deserializer<'de>>::Error as serde::de::Error>::custom) | ||||
|         } else { | ||||
|             deserializer.deserialize_any(AnyPropVisiter { | ||||
|             property_type_registry: self.registry, | ||||
|             current_type_name: self.current_type_name, | ||||
|                 registry: self.registry, | ||||
|             }) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct PropSeqDeserializer<'a> { | ||||
| pub struct SeqPropertyDeserializer<'a> { | ||||
|     registry: &'a PropertyTypeRegistry, | ||||
|     current_type_name: Rc<RefCell<Option<String>>>, | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'de> DeserializeSeed<'de> for PropSeqDeserializer<'a> { | ||||
| impl<'a, 'de> DeserializeSeed<'de> for SeqPropertyDeserializer<'a> { | ||||
|     type Value = DynamicProperties; | ||||
|     fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> | ||||
|     where | ||||
|         D: serde::Deserializer<'de>, | ||||
|     { | ||||
|         deserializer.deserialize_seq(PropSeqVisiter { | ||||
|         deserializer.deserialize_seq(SeqPropertyVisiter { | ||||
|             registry: self.registry, | ||||
|             current_type_name: self.current_type_name.clone(), | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct PropSeqVisiter<'a> { | ||||
| pub struct SeqPropertyVisiter<'a> { | ||||
|     registry: &'a PropertyTypeRegistry, | ||||
|     current_type_name: Rc<RefCell<Option<String>>>, | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'de> Visitor<'de> for PropSeqVisiter<'a> { | ||||
| impl<'a, 'de> Visitor<'de> for SeqPropertyVisiter<'a> { | ||||
|     type Value = DynamicProperties; | ||||
|     fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { | ||||
|         formatter.write_str("property value") | ||||
| @ -183,7 +219,7 @@ impl<'a, 'de> Visitor<'de> for PropSeqVisiter<'a> { | ||||
|         let mut dynamic_properties = DynamicProperties::seq(); | ||||
|         while let Some(prop) = seq.next_element_seed(PropertyDeserializer { | ||||
|             registry: self.registry, | ||||
|             current_type_name: self.current_type_name.clone(), | ||||
|             type_name: None, | ||||
|         })? { | ||||
|             dynamic_properties.push(prop, None); | ||||
|         } | ||||
| @ -191,40 +227,59 @@ impl<'a, 'de> Visitor<'de> for PropSeqVisiter<'a> { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct MapValueDeserializer<'a> { | ||||
| pub struct MapPropertyDeserializer<'a> { | ||||
|     registry: &'a PropertyTypeRegistry, | ||||
|     current_type_name: Rc<RefCell<Option<String>>>, | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'de> DeserializeSeed<'de> for MapValueDeserializer<'a> { | ||||
|     type Value = Box<dyn Property>; | ||||
| impl<'a> MapPropertyDeserializer<'a> { | ||||
|     pub fn new(registry: &'a PropertyTypeRegistry) -> Self { | ||||
|         MapPropertyDeserializer { | ||||
|             registry, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'de> DeserializeSeed<'de> for MapPropertyDeserializer<'a> { | ||||
|     type Value = DynamicProperties; | ||||
|     fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> | ||||
|     where | ||||
|         D: serde::Deserializer<'de>, | ||||
|     { | ||||
|         if self.current_type_name.borrow().is_some() { | ||||
|             let registration = { | ||||
|                 let current_type_name = self.current_type_name.borrow(); | ||||
|                 let type_name = current_type_name.as_ref().unwrap(); | ||||
|                 self.registry.get_short(type_name).ok_or_else(|| { | ||||
|                     de::Error::custom(format!("TypeRegistration is missing for {}", type_name)) | ||||
|                 })? | ||||
|             }; | ||||
|             let mut erased = erased_serde::Deserializer::erase(deserializer); | ||||
|             (registration.deserialize)(&mut erased, self.registry) | ||||
|                 .map_err(<<D as serde::Deserializer<'de>>::Error as serde::de::Error>::custom) | ||||
|         } else { | ||||
|             deserializer.deserialize_any(AnyPropVisiter { | ||||
|                 property_type_registry: self.registry, | ||||
|                 current_type_name: self.current_type_name, | ||||
|         deserializer.deserialize_map(MapPropertyVisiter { | ||||
|             registry: self.registry, | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| struct MapPropertyVisiter<'a> { | ||||
|     registry: &'a PropertyTypeRegistry, | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'de> Visitor<'de> for MapPropertyVisiter<'a> { | ||||
|     type Value = DynamicProperties; | ||||
|     fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { | ||||
|         formatter.write_str("map value") | ||||
|     } | ||||
| 
 | ||||
|     fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error> | ||||
|     where | ||||
|         V: MapAccess<'de>, | ||||
|     { | ||||
|         let mut dynamic_properties = DynamicProperties::map(); | ||||
|         while let Some(key) = map.next_key::<String>()? { | ||||
|             let property = map.next_value_seed(PropertyDeserializer { | ||||
|                 registry: self.registry, | ||||
|                 type_name: None, | ||||
|             })?; | ||||
|             dynamic_properties.set_box(&key, property); | ||||
|         } | ||||
| 
 | ||||
|         Ok(dynamic_properties) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| struct AnyPropVisiter<'a> { | ||||
|     property_type_registry: &'a PropertyTypeRegistry, | ||||
|     current_type_name: Rc<RefCell<Option<String>>>, | ||||
|     registry: &'a PropertyTypeRegistry, | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'de> Visitor<'de> for AnyPropVisiter<'a> { | ||||
| @ -324,57 +379,53 @@ impl<'a, 'de> Visitor<'de> for AnyPropVisiter<'a> { | ||||
|         Ok(Box::new(v.to_string())) | ||||
|     } | ||||
| 
 | ||||
|     fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error> | ||||
|     fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error> | ||||
|     where | ||||
|         V: MapAccess<'de>, | ||||
|     { | ||||
|         Ok(Box::new(visit_map( | ||||
|             map, | ||||
|             self.property_type_registry, | ||||
|             self.current_type_name, | ||||
|         )?)) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn visit_map<'a, 'de, V>( | ||||
|     mut map: V, | ||||
|     property_type_registry: &'a PropertyTypeRegistry, | ||||
|     current_type_name: Rc<RefCell<Option<String>>>, | ||||
| ) -> Result<DynamicProperties, V::Error> | ||||
| where | ||||
|     V: MapAccess<'de>, | ||||
| { | ||||
|     let mut dynamic_properties = DynamicProperties::map(); | ||||
|         let mut type_name: Option<String> = None; | ||||
|     let mut is_seq = false; | ||||
|     // TODO: support seq_value_type
 | ||||
|         while let Some(key) = map.next_key::<String>()? { | ||||
|         if key == "type" { | ||||
|             match key.as_str() { | ||||
|                 TYPE_FIELD => { | ||||
|                     type_name = Some(map.next_value()?); | ||||
|         } else if key == "seq_type" { | ||||
|             type_name = Some(map.next_value()?); | ||||
|             is_seq = true; | ||||
|         } else if is_seq { | ||||
|             if key != "data" { | ||||
|                 return Err(de::Error::custom( | ||||
|                     "seq_type must be immediately followed by a data field", | ||||
|                 } | ||||
|                 MAP_FIELD => { | ||||
|                     let type_name = type_name | ||||
|                         .take() | ||||
|                         .ok_or_else(|| de::Error::missing_field(TYPE_FIELD))?; | ||||
|                     let mut dynamic_properties = | ||||
|                         map.next_value_seed(MapPropertyDeserializer { registry: self.registry })?; | ||||
|                     dynamic_properties.type_name = type_name.to_string(); | ||||
|                     return Ok(Box::new( | ||||
|                         dynamic_properties, | ||||
|                     )); | ||||
|                 } | ||||
|             dynamic_properties = map.next_value_seed(PropSeqDeserializer { | ||||
|                 registry: property_type_registry, | ||||
|                 current_type_name: current_type_name.clone(), | ||||
|             })?; | ||||
|             break; | ||||
|         } else { | ||||
|             let prop = map.next_value_seed(MapValueDeserializer { | ||||
|                 registry: property_type_registry, | ||||
|                 current_type_name: current_type_name.clone(), | ||||
|             })?; | ||||
|             dynamic_properties.set_box(&key, prop); | ||||
|                 SEQ_FIELD => { | ||||
|                     let type_name = type_name | ||||
|                         .take() | ||||
|                         .ok_or_else(|| de::Error::missing_field(TYPE_FIELD))?; | ||||
|                     let mut dynamic_properties = | ||||
|                         map.next_value_seed(SeqPropertyDeserializer { registry: self.registry })?; | ||||
|                     dynamic_properties.type_name = type_name; | ||||
|                     return Ok(Box::new( | ||||
|                         dynamic_properties, | ||||
|                     )); | ||||
|                 } | ||||
|                 VALUE_FIELD => { | ||||
|                     let type_name = type_name | ||||
|                         .take() | ||||
|                         .ok_or_else(|| de::Error::missing_field(TYPE_FIELD))?; | ||||
|                     return map.next_value_seed( | ||||
|                         PropertyDeserializer { | ||||
|                             registry: self.registry, | ||||
|                             type_name: Some(&type_name), | ||||
|                         }, | ||||
|                     ); | ||||
|                 } | ||||
|                 _ => return Err(de::Error::unknown_field(key.as_str(), &[])), | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     let type_name = type_name.ok_or_else(|| de::Error::missing_field("type"))?; | ||||
|     dynamic_properties.type_name = type_name.to_string(); | ||||
|     Ok(dynamic_properties) | ||||
|         Err(de::Error::custom("Maps in this location must have the \'type\' field and one of the following fields: \'map\', \'seq\', \'value\'")) | ||||
|     } | ||||
| } | ||||
| @ -1,24 +1,12 @@ | ||||
| use crate::{ | ||||
|     property_serde::DynamicPropertiesDeserializer, DynamicProperties, PropertyTypeRegistry, | ||||
| }; | ||||
| use crate::{property_serde::MapPropertyDeserializer, DynamicProperties, PropertyTypeRegistry}; | ||||
| use ron::de::Deserializer; | ||||
| use serde::de::DeserializeSeed; | ||||
| use std::{cell::RefCell, rc::Rc}; | ||||
| 
 | ||||
| pub fn deserialize_dynamic_properties( | ||||
|     ron_string: &str, | ||||
|     property_type_registry: &PropertyTypeRegistry, | ||||
| ) -> Result<DynamicProperties, ron::Error> { | ||||
|     let mut deserializer = Deserializer::from_str(&ron_string).unwrap(); | ||||
|     let last_type_name = Rc::new(RefCell::new(None)); | ||||
|     let mut callback = |ident: &Option<&[u8]>| { | ||||
|         let mut last_type_name = last_type_name.borrow_mut(); | ||||
|         *last_type_name = ident.map(|i| String::from_utf8(i.to_vec()).unwrap()); | ||||
|     }; | ||||
|     deserializer.set_callback(&mut callback); | ||||
|     let dynamic_properties_deserializer = DynamicPropertiesDeserializer { | ||||
|         current_type_name: last_type_name.clone(), | ||||
|         registry: &property_type_registry, | ||||
|     }; | ||||
|     let dynamic_properties_deserializer = MapPropertyDeserializer::new(&property_type_registry); | ||||
|     dynamic_properties_deserializer.deserialize(&mut deserializer) | ||||
| } | ||||
|  | ||||
| @ -5,7 +5,7 @@ use bevy_asset::AssetLoader; | ||||
| use bevy_component_registry::PropertyTypeRegistryContext; | ||||
| use legion::prelude::Resources; | ||||
| use serde::de::DeserializeSeed; | ||||
| use std::{cell::RefCell, path::Path, rc::Rc}; | ||||
| use std::path::Path; | ||||
| 
 | ||||
| pub struct SceneLoader { | ||||
|     property_type_registry: PropertyTypeRegistryContext, | ||||
| @ -24,19 +24,9 @@ impl AssetLoader<Scene> for SceneLoader { | ||||
|     fn from_bytes(&self, _asset_path: &Path, bytes: Vec<u8>) -> Result<Scene> { | ||||
|         let registry = self.property_type_registry.value.read().unwrap(); | ||||
|         let mut deserializer = ron::de::Deserializer::from_bytes(&bytes).unwrap(); | ||||
|         let current_type_name = Rc::new(RefCell::new(None)); | ||||
|         let scene_deserializer = SceneDeserializer { | ||||
|             property_type_registry: ®istry, | ||||
|             current_type_name: current_type_name.clone(), | ||||
|         }; | ||||
| 
 | ||||
|         // this callback is executed whenever an explicit type name is encountered in a map
 | ||||
|         let mut callback = |ident: &Option<&[u8]>| { | ||||
|             let mut last_type_name = current_type_name.borrow_mut(); | ||||
|             *last_type_name = ident.map(|i| String::from_utf8(i.to_vec()).unwrap()); | ||||
|         }; | ||||
|         deserializer.set_callback(&mut callback); | ||||
| 
 | ||||
|         let scene = scene_deserializer.deserialize(&mut deserializer).unwrap(); | ||||
|         Ok(scene) | ||||
|     } | ||||
|  | ||||
| @ -1,11 +1,12 @@ | ||||
| use crate::{Entity, Scene}; | ||||
| use anyhow::Result; | ||||
| use bevy_property::{DynamicProperties, PropertyTypeRegistry, property_serde::DynamicPropertiesDeserializer}; | ||||
| use bevy_property::{ | ||||
|     property_serde::MapPropertyDeserializer, DynamicProperties, PropertyTypeRegistry, | ||||
| }; | ||||
| use serde::{ | ||||
|     de::{DeserializeSeed, Error, MapAccess, SeqAccess, Visitor}, | ||||
|     Deserialize, Serialize, | ||||
| }; | ||||
| use std::{cell::RefCell, rc::Rc}; | ||||
| 
 | ||||
| impl Serialize for Scene { | ||||
|     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ||||
| @ -18,7 +19,6 @@ impl Serialize for Scene { | ||||
| 
 | ||||
| pub struct SceneDeserializer<'a> { | ||||
|     pub property_type_registry: &'a PropertyTypeRegistry, | ||||
|     pub current_type_name: Rc<RefCell<Option<String>>>, | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'de> DeserializeSeed<'de> for SceneDeserializer<'a> { | ||||
| @ -30,7 +30,6 @@ impl<'a, 'de> DeserializeSeed<'de> for SceneDeserializer<'a> { | ||||
|         let mut scene = Scene::default(); | ||||
|         scene.entities = deserializer.deserialize_seq(SceneEntitySeqVisiter { | ||||
|             property_type_registry: self.property_type_registry, | ||||
|             current_type_name: self.current_type_name, | ||||
|         })?; | ||||
| 
 | ||||
|         Ok(scene) | ||||
| @ -39,7 +38,6 @@ impl<'a, 'de> DeserializeSeed<'de> for SceneDeserializer<'a> { | ||||
| 
 | ||||
| struct SceneEntitySeqVisiter<'a> { | ||||
|     pub property_type_registry: &'a PropertyTypeRegistry, | ||||
|     pub current_type_name: Rc<RefCell<Option<String>>>, | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'de> Visitor<'de> for SceneEntitySeqVisiter<'a> { | ||||
| @ -55,7 +53,6 @@ impl<'a, 'de> Visitor<'de> for SceneEntitySeqVisiter<'a> { | ||||
|         let mut entities = Vec::new(); | ||||
|         while let Some(entity) = seq.next_element_seed(SceneEntityDeserializer { | ||||
|             property_type_registry: self.property_type_registry, | ||||
|             current_type_name: self.current_type_name.clone(), | ||||
|         })? { | ||||
|             entities.push(entity); | ||||
|         } | ||||
| @ -66,7 +63,6 @@ impl<'a, 'de> Visitor<'de> for SceneEntitySeqVisiter<'a> { | ||||
| 
 | ||||
| pub struct SceneEntityDeserializer<'a> { | ||||
|     pub property_type_registry: &'a PropertyTypeRegistry, | ||||
|     pub current_type_name: Rc<RefCell<Option<String>>>, | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'de> DeserializeSeed<'de> for SceneEntityDeserializer<'a> { | ||||
| @ -79,8 +75,7 @@ impl<'a, 'de> DeserializeSeed<'de> for SceneEntityDeserializer<'a> { | ||||
|             "Entity", | ||||
|             &["id", "components"], | ||||
|             SceneEntityVisiter { | ||||
|                 property_type_registry: self.property_type_registry, | ||||
|                 current_type_name: self.current_type_name, | ||||
|                 registry: self.property_type_registry, | ||||
|             }, | ||||
|         ) | ||||
|     } | ||||
| @ -97,8 +92,7 @@ pub const ENTITY_FIELD_ID: &str = "id"; | ||||
| pub const ENTITY_FIELD_COMPONENTS: &str = "components"; | ||||
| 
 | ||||
| struct SceneEntityVisiter<'a> { | ||||
|     pub property_type_registry: &'a PropertyTypeRegistry, | ||||
|     pub current_type_name: Rc<RefCell<Option<String>>>, | ||||
|     pub registry: &'a PropertyTypeRegistry, | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'de> Visitor<'de> for SceneEntityVisiter<'a> { | ||||
| @ -127,8 +121,7 @@ impl<'a, 'de> Visitor<'de> for SceneEntityVisiter<'a> { | ||||
|                     } | ||||
| 
 | ||||
|                     components = Some(map.next_value_seed(ComponentVecDeserializer { | ||||
|                         current_type_name: self.current_type_name.clone(), | ||||
|                         registry: self.property_type_registry, | ||||
|                         registry: self.registry, | ||||
|                     })?); | ||||
|                 } | ||||
|             } | ||||
| @ -150,7 +143,6 @@ impl<'a, 'de> Visitor<'de> for SceneEntityVisiter<'a> { | ||||
| 
 | ||||
| pub struct ComponentVecDeserializer<'a> { | ||||
|     pub registry: &'a PropertyTypeRegistry, | ||||
|     pub current_type_name: Rc<RefCell<Option<String>>>, | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'de> DeserializeSeed<'de> for ComponentVecDeserializer<'a> { | ||||
| @ -161,14 +153,12 @@ impl<'a, 'de> DeserializeSeed<'de> for ComponentVecDeserializer<'a> { | ||||
|     { | ||||
|         deserializer.deserialize_seq(ComponentSeqVisiter { | ||||
|             registry: self.registry, | ||||
|             current_type_name: self.current_type_name, | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| struct ComponentSeqVisiter<'a> { | ||||
|     pub registry: &'a PropertyTypeRegistry, | ||||
|     pub current_type_name: Rc<RefCell<Option<String>>>, | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'de> Visitor<'de> for ComponentSeqVisiter<'a> { | ||||
| @ -182,10 +172,9 @@ impl<'a, 'de> Visitor<'de> for ComponentSeqVisiter<'a> { | ||||
|         A: SeqAccess<'de>, | ||||
|     { | ||||
|         let mut dynamic_properties = Vec::new(); | ||||
|         while let Some(entity) = seq.next_element_seed(DynamicPropertiesDeserializer { | ||||
|             current_type_name: self.current_type_name.clone(), | ||||
|             registry: self.registry, | ||||
|         })? { | ||||
|         while let Some(entity) = | ||||
|             seq.next_element_seed(MapPropertyDeserializer::new(self.registry))? | ||||
|         { | ||||
|             dynamic_properties.push(entity); | ||||
|         } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Carter Anderson
						Carter Anderson