props: add type peeking to ron, support arbitrary property types

This commit is contained in:
Carter Anderson 2020-05-24 19:36:01 -07:00
parent c5ab7df98f
commit 1cd3b4c987
13 changed files with 453 additions and 45 deletions

View File

@ -1,6 +1,6 @@
[ [
( (
entity: 3072676124, entity: 1279729879,
components: [ components: [
{ {
"type": "load_scene::Test", "type": "load_scene::Test",
@ -10,7 +10,7 @@
], ],
), ),
( (
entity: 3949176536, entity: 1639302665,
components: [ components: [
{ {
"type": "load_scene::Test", "type": "load_scene::Test",

View File

@ -9,4 +9,5 @@ edition = "2018"
[dependencies] [dependencies]
serde = "1" serde = "1"
erased-serde = "0.3" erased-serde = "0.3"
bevy_property_derive = { path = "bevy_property_derive" } bevy_property_derive = { path = "bevy_property_derive" }
ron = { path = "../ron" }

View File

@ -1,10 +1,13 @@
use crate::{AsProperties, Properties, Property, PropertyIter, PropertyVal}; use crate::{
use serde::{ AsProperties, Properties, Property, PropertyIter, PropertyTypeRegistration,
de::{self, MapAccess, Visitor}, PropertyTypeRegistry, PropertyVal,
ser::SerializeMap,
Deserialize, Serialize,
}; };
use std::{any::Any, borrow::Cow, collections::HashMap}; use serde::{
de::{self, DeserializeSeed, MapAccess, Visitor},
ser::SerializeMap,
Serialize,
};
use std::{any::Any, borrow::Cow, cell::RefCell, collections::HashMap, rc::Rc};
#[derive(Default)] #[derive(Default)]
pub struct DynamicProperties { pub struct DynamicProperties {
@ -100,14 +103,22 @@ impl Serialize for DynamicProperties {
} }
} }
impl<'de> Deserialize<'de> for DynamicProperties { pub struct DynamicPropertiesDeserializer<'a> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> pub property_type_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 where
D: serde::Deserializer<'de>, D: serde::Deserializer<'de>,
{ {
let mut dynamic_properties = DynamicProperties::default(); let mut dynamic_properties = DynamicProperties::default();
deserializer.deserialize_map(PropMapVisiter { deserializer.deserialize_map(PropMapVisiter {
dynamic_properties: &mut dynamic_properties, dynamic_properties: &mut dynamic_properties,
property_type_registry: self.property_type_registry,
current_type_name: self.current_type_name,
})?; })?;
Ok(dynamic_properties) Ok(dynamic_properties)
@ -116,6 +127,8 @@ impl<'de> Deserialize<'de> for DynamicProperties {
struct PropMapVisiter<'a> { struct PropMapVisiter<'a> {
dynamic_properties: &'a mut DynamicProperties, dynamic_properties: &'a mut DynamicProperties,
property_type_registry: &'a PropertyTypeRegistry,
current_type_name: Rc<RefCell<Option<String>>>,
} }
impl<'a, 'de> Visitor<'de> for PropMapVisiter<'a> { impl<'a, 'de> Visitor<'de> for PropMapVisiter<'a> {
@ -133,7 +146,10 @@ impl<'a, 'de> Visitor<'de> for PropMapVisiter<'a> {
if &key == "type" { if &key == "type" {
type_name = Some(map.next_value()?); type_name = Some(map.next_value()?);
} else { } else {
let prop = map.next_value()?; let prop = map.next_value_seed(MapValueDeserializer {
property_type_registry: self.property_type_registry,
current_type_name: self.current_type_name.clone(),
})?;
self.dynamic_properties.set_box(&key, prop); self.dynamic_properties.set_box(&key, prop);
} }
} }
@ -144,18 +160,50 @@ impl<'a, 'de> Visitor<'de> for PropMapVisiter<'a> {
} }
} }
impl<'de> Deserialize<'de> for Box<dyn Property> { pub struct MapValueDeserializer<'a> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> property_type_registry: &'a PropertyTypeRegistry,
current_type_name: Rc<RefCell<Option<String>>>,
}
impl<'a, 'de> DeserializeSeed<'de> for MapValueDeserializer<'a> {
type Value = Box<dyn Property>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where where
D: serde::Deserializer<'de>, D: serde::Deserializer<'de>,
{ {
deserializer.deserialize_any(AnyPropVisiter) 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
.property_type_registry
.get(type_name)
.ok_or_else(|| {
de::Error::custom(format!(
"TypeRegistration is missing for {}",
type_name
))
})?
};
let mut erased = erased_serde::Deserializer::erase(deserializer);
let res = (registration.deserialize)(&mut erased)
.map_err(<<D as serde::Deserializer<'de>>::Error as serde::de::Error>::custom);
res
} else {
deserializer.deserialize_any(AnyPropVisiter {
property_type_registry: self.property_type_registry,
current_type_name: self.current_type_name,
})
}
} }
} }
struct AnyPropVisiter; struct AnyPropVisiter<'a> {
property_type_registry: &'a PropertyTypeRegistry,
current_type_name: Rc<RefCell<Option<String>>>,
}
impl<'de> Visitor<'de> for AnyPropVisiter { impl<'a, 'de> Visitor<'de> for AnyPropVisiter<'a> {
type Value = Box<dyn Property>; type Value = Box<dyn Property>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("property value") formatter.write_str("property value")
@ -251,7 +299,10 @@ impl<'de> Visitor<'de> for AnyPropVisiter {
{ {
let mut dynamic_properties = DynamicProperties::default(); let mut dynamic_properties = DynamicProperties::default();
while let Some(key) = map.next_key()? { while let Some(key) = map.next_key()? {
let prop = map.next_value::<Box<dyn Property>>()?; let prop = map.next_value_seed(MapValueDeserializer {
property_type_registry: self.property_type_registry,
current_type_name: self.current_type_name.clone(),
})?;
if key == "type" { if key == "type" {
dynamic_properties.type_name = prop dynamic_properties.type_name = prop
.val::<String>() .val::<String>()
@ -261,10 +312,27 @@ impl<'de> Visitor<'de> for AnyPropVisiter {
dynamic_properties.set_box(key, prop); dynamic_properties.set_box(key, prop);
} }
} }
Ok(Box::new(dynamic_properties)) Ok(Box::new(dynamic_properties))
} }
} }
struct PropertyTypeDeserializer<'a> {
registration: &'a PropertyTypeRegistration,
}
impl<'a, 'de> DeserializeSeed<'de> for PropertyTypeDeserializer<'a> {
type Value = Box<dyn Property>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
let mut erased = erased_serde::Deserializer::erase(deserializer);
(self.registration.deserialize)(&mut erased)
.map_err(<<D as serde::Deserializer<'de>>::Error as serde::de::Error>::custom)
}
}
impl Property for DynamicProperties { impl Property for DynamicProperties {
#[inline] #[inline]
fn any(&self) -> &dyn Any { fn any(&self) -> &dyn Any {

View File

@ -3,10 +3,13 @@
mod property; mod property;
mod properties; mod properties;
mod dynamic_properties; mod dynamic_properties;
mod type_registry;
pub mod ron;
pub use property::*; pub use property::*;
pub use properties::*; pub use properties::*;
pub use dynamic_properties::*; pub use dynamic_properties::*;
pub use type_registry::*;
pub use bevy_property_derive::*; pub use bevy_property_derive::*;
pub use serde; pub use serde;

View File

@ -0,0 +1,19 @@
use ron::de::Deserializer;
use std::{cell::RefCell, rc::Rc};
use crate::{DynamicPropertiesDeserializer, PropertyTypeRegistry, DynamicProperties};
use serde::de::DeserializeSeed;
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(),
property_type_registry: &property_type_registry,
};
dynamic_properties_deserializer.deserialize(&mut deserializer)
}

View File

@ -0,0 +1,43 @@
use crate::Property;
use serde::Deserialize;
use std::{any::TypeId, collections::HashMap};
#[derive(Default)]
pub struct PropertyTypeRegistry {
pub registrations: HashMap<String, PropertyTypeRegistration>,
}
impl PropertyTypeRegistry {
pub fn register<T>(&mut self)
where
T: Property + for<'de> Deserialize<'de>,
{
let registration = PropertyTypeRegistration::of::<T>();
self.registrations.insert(registration.short_name.to_string(), registration);
}
pub fn get(&self, type_name: &str) -> Option<&PropertyTypeRegistration> {
self.registrations.get(type_name)
}
}
#[derive(Clone)]
pub struct PropertyTypeRegistration {
pub ty: TypeId,
pub deserialize: fn(deserializer: &mut dyn erased_serde::Deserializer) -> Result<Box<dyn Property>, erased_serde::Error>,
pub short_name: &'static str,
}
impl PropertyTypeRegistration {
pub fn of<T: Property + for<'de> Deserialize<'de>>() -> Self {
let ty = TypeId::of::<T>();
Self {
ty,
deserialize: |deserializer: &mut dyn erased_serde::Deserializer| {
let property = <T as Deserialize>::deserialize(deserializer)?;
Ok(Box::new(property))
},
short_name: std::any::type_name::<T>().split("::").last().unwrap(),
}
}
}

View File

@ -1,14 +1,20 @@
use bevy_app::AppBuilder; use bevy_app::AppBuilder;
use bevy_property::{Properties, Property}; use bevy_property::{Properties, Property, PropertyTypeRegistry};
use legion::{ use legion::{
prelude::{Entity, World}, prelude::{Entity, World},
storage::{Component, ComponentTypeId, ComponentResourceSet}, storage::{Component, ComponentResourceSet, ComponentTypeId},
}; };
use serde::Deserialize;
use std::{ use std::{
collections::HashMap, collections::HashMap,
sync::{Arc, RwLock}, sync::{Arc, RwLock},
}; };
#[derive(Clone, Default)]
pub struct PropertyTypeRegistryContext {
pub value: Arc<RwLock<PropertyTypeRegistry>>,
}
#[derive(Default)] #[derive(Default)]
pub struct ComponentRegistryContext { pub struct ComponentRegistryContext {
pub value: Arc<RwLock<ComponentRegistry>>, pub value: Arc<RwLock<ComponentRegistry>>,
@ -69,9 +75,10 @@ impl ComponentRegistration {
component.apply(property); component.apply(property);
world.add_component(entity, component).unwrap(); world.add_component(entity, component).unwrap();
}, },
component_properties_fn: |component_resource_set: &ComponentResourceSet, index: usize| { component_properties_fn: |component_resource_set: &ComponentResourceSet,
index: usize| {
// the type has been looked up by the caller, so this is safe // the type has been looked up by the caller, so this is safe
unsafe { &component_resource_set.data_slice::<T>()[index] } unsafe { &component_resource_set.data_slice::<T>()[index] }
}, },
short_name: ty.0.split("::").last().unwrap(), short_name: ty.0.split("::").last().unwrap(),
} }
@ -82,6 +89,9 @@ pub trait RegisterComponent {
fn register_component<T>(&mut self) -> &mut Self fn register_component<T>(&mut self) -> &mut Self
where where
T: Properties + Component + Default; T: Properties + Component + Default;
fn register_property_type<T>(&mut self) -> &mut Self
where
T: Property + for<'de> Deserialize<'de>;
} }
impl RegisterComponent for AppBuilder { impl RegisterComponent for AppBuilder {
@ -98,4 +108,18 @@ impl RegisterComponent for AppBuilder {
} }
self self
} }
fn register_property_type<T>(&mut self) -> &mut Self
where
T: Property + for<'de> Deserialize<'de>,
{
{
let registry_context = self
.resources()
.get_mut::<PropertyTypeRegistryContext>()
.unwrap();
registry_context.value.write().unwrap().register::<T>();
}
self
}
} }

View File

@ -11,7 +11,8 @@ pub struct ComponentRegistryPlugin;
impl AppPlugin for ComponentRegistryPlugin { impl AppPlugin for ComponentRegistryPlugin {
fn build(&self, app: &mut AppBuilder) { fn build(&self, app: &mut AppBuilder) {
app.init_resource::<ComponentRegistryContext>(); app.init_resource::<ComponentRegistryContext>()
.init_resource::<PropertyTypeRegistryContext>();
} }
} }

View File

@ -1,17 +1,28 @@
use crate::ComponentRegistry; use crate::{ComponentRegistry, PropertyTypeRegistryContext};
use anyhow::Result; use anyhow::Result;
use bevy_app::FromResources;
use bevy_asset::AssetLoader; use bevy_asset::AssetLoader;
use bevy_property::DynamicProperties; use bevy_property::{DynamicProperties, PropertyTypeRegistry, DynamicPropertiesDeserializer};
use legion::prelude::{Entity, World}; use legion::prelude::{Entity, Resources, World};
use serde::{Deserialize, Serialize}; use serde::{
use std::{num::Wrapping, path::Path}; de::{DeserializeSeed, SeqAccess, Visitor, MapAccess, Error},
Serialize,
Deserialize
};
use std::{cell::RefCell, num::Wrapping, path::Path, rc::Rc};
use thiserror::Error; use thiserror::Error;
#[derive(Serialize, Deserialize, Default)] #[derive(Default)]
pub struct Scene { pub struct Scene {
pub entities: Vec<SceneEntity>, pub entities: Vec<SceneEntity>,
} }
#[derive(Serialize)]
pub struct SceneEntity {
pub entity: u32,
pub components: Vec<DynamicProperties>,
}
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum SceneAddError { pub enum SceneAddError {
#[error("Scene contains an unregistered component.")] #[error("Scene contains an unregistered component.")]
@ -85,20 +96,219 @@ impl Scene {
} }
} }
#[derive(Serialize, Deserialize)] impl Serialize for Scene {
pub struct SceneEntity { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
pub entity: u32, where
pub components: Vec<DynamicProperties>, S: serde::Serializer,
{
self.entities.serialize(serializer)
}
} }
#[derive(Default)] pub struct SceneDeserializer<'a> {
pub struct SceneLoader; pub property_type_registry: &'a PropertyTypeRegistry,
pub current_type_name: Rc<RefCell<Option<String>>>,
}
impl<'a, 'de> DeserializeSeed<'de> for SceneDeserializer<'a> {
type Value = Scene;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
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)
}
}
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> {
type Value = Vec<SceneEntity>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("list of entities")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
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);
}
Ok(entities)
}
}
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> {
type Value = SceneEntity;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_struct("", &["entity", "components"], SceneEntityVisiter {
property_type_registry: self.property_type_registry,
current_type_name: self.current_type_name,
})
}
}
#[derive(Deserialize)]
#[serde(field_identifier, rename_all = "lowercase")]
enum EntityField {
Entity,
Components,
}
pub const ENTITY_FIELD_ENTITY: &str = "entity";
pub const ENTITY_FIELD_COMPONENTS: &str = "components";
struct SceneEntityVisiter<'a> {
pub property_type_registry: &'a PropertyTypeRegistry,
pub current_type_name: Rc<RefCell<Option<String>>>,
}
impl<'a, 'de> Visitor<'de> for SceneEntityVisiter<'a> {
type Value = SceneEntity;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("entities")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where A: MapAccess<'de> {
let mut entity = None;
let mut components = None;
while let Some(key) = map.next_key()? {
match key {
EntityField::Entity => {
if entity.is_some() {
return Err(Error::duplicate_field(ENTITY_FIELD_ENTITY));
}
entity = Some(map.next_value::<u32>()?);
}
EntityField::Components => {
if components.is_some() {
return Err(Error::duplicate_field(ENTITY_FIELD_COMPONENTS));
}
components = Some(map.next_value_seed(ComponentVecDeserializer {
current_type_name: self.current_type_name.clone(),
property_type_registry: self.property_type_registry
})?);
}
}
}
let entity = entity
.as_ref()
.ok_or_else(|| Error::missing_field(ENTITY_FIELD_ENTITY))?;
let components = components
.take()
.ok_or_else(|| Error::missing_field(ENTITY_FIELD_COMPONENTS))?;
Ok(SceneEntity {
entity: *entity,
components,
})
}
}
pub struct ComponentVecDeserializer<'a> {
pub property_type_registry: &'a PropertyTypeRegistry,
pub current_type_name: Rc<RefCell<Option<String>>>,
}
impl<'a, 'de> DeserializeSeed<'de> for ComponentVecDeserializer<'a> {
type Value = Vec<DynamicProperties>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_seq(ComponentSeqVisiter {
property_type_registry: self.property_type_registry,
current_type_name: self.current_type_name,
})
}
}
struct ComponentSeqVisiter<'a> {
pub property_type_registry: &'a PropertyTypeRegistry,
pub current_type_name: Rc<RefCell<Option<String>>>,
}
impl<'a, 'de> Visitor<'de> for ComponentSeqVisiter<'a> {
type Value = Vec<DynamicProperties>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("list of components")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
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(),
property_type_registry: self.property_type_registry
})? {
dynamic_properties.push(entity);
}
Ok(dynamic_properties)
}
}
pub struct SceneLoader {
property_type_registry: PropertyTypeRegistryContext,
}
impl FromResources for SceneLoader {
fn from_resources(resources: &Resources) -> Self {
let property_type_registry = resources.get::<PropertyTypeRegistryContext>().unwrap();
SceneLoader {
property_type_registry: property_type_registry.clone(),
}
}
}
impl AssetLoader<Scene> for SceneLoader { impl AssetLoader<Scene> for SceneLoader {
fn from_bytes(&self, _asset_path: &Path, bytes: Vec<u8>) -> Result<Scene> { 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 mut deserializer = ron::de::Deserializer::from_bytes(&bytes).unwrap();
let entities = Vec::<SceneEntity>::deserialize(&mut deserializer).unwrap(); let current_type_name = Rc::new(RefCell::new(None));
Ok(Scene { entities }) let scene_deserializer = SceneDeserializer {
property_type_registry: &registry,
current_type_name: current_type_name.clone(),
};
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)
} }
fn extensions(&self) -> &[&str] { fn extensions(&self) -> &[&str] {
static EXTENSIONS: &[&str] = &["scn"]; static EXTENSIONS: &[&str] = &["scn"];

View File

@ -23,6 +23,7 @@ mod value;
/// you can use the `from_str` convenience function. /// you can use the `from_str` convenience function.
pub struct Deserializer<'de> { pub struct Deserializer<'de> {
bytes: Bytes<'de>, bytes: Bytes<'de>,
type_callback: Option<&'de mut dyn FnMut(&Option<&[u8]>)>,
} }
impl<'de> Deserializer<'de> { impl<'de> Deserializer<'de> {
@ -35,12 +36,17 @@ impl<'de> Deserializer<'de> {
pub fn from_bytes(input: &'de [u8]) -> Result<Self> { pub fn from_bytes(input: &'de [u8]) -> Result<Self> {
Ok(Deserializer { Ok(Deserializer {
bytes: Bytes::new(input)?, bytes: Bytes::new(input)?,
type_callback: None,
}) })
} }
pub fn remainder(&self) -> Cow<'_, str> { pub fn remainder(&self) -> Cow<'_, str> {
String::from_utf8_lossy(&self.bytes.bytes()) String::from_utf8_lossy(&self.bytes.bytes())
} }
pub fn set_callback(&mut self, callback: &'de mut dyn FnMut(&Option<&[u8]>)) {
self.type_callback = Some(callback);
}
} }
/// A convenience function for reading data from a reader /// A convenience function for reading data from a reader
@ -578,12 +584,20 @@ impl<'de, 'a> de::MapAccess<'de> for CommaSeparated<'a, 'de> {
K: DeserializeSeed<'de>, K: DeserializeSeed<'de>,
{ {
if self.has_element()? { if self.has_element()? {
if self.terminator == b')' { let result = if self.terminator == b')' {
seed.deserialize(&mut IdDeserializer::new(&mut *self.de)) seed.deserialize(&mut IdDeserializer::new(&mut *self.de))
.map(Some) .map(Some)
} else { } else {
seed.deserialize(&mut *self.de).map(Some) seed.deserialize(&mut *self.de).map(Some)
};
if let Some(ref mut callback) = self.de.type_callback {
let mut fast_forward_bytes = self.de.bytes.clone();
fast_forward_bytes.skip_ws()?;
fast_forward_bytes.consume(":");
fast_forward_bytes.skip_ws()?;
callback(&fast_forward_bytes.identifier().ok());
} }
result
} else { } else {
Ok(None) Ok(None)
} }

View File

@ -315,7 +315,7 @@ impl<'a> Bytes<'a> {
self.test_for(ident) && !self.check_ident_char(ident.len()) self.test_for(ident) && !self.check_ident_char(ident.len())
} }
fn check_ident_char(&self, index: usize) -> bool { pub fn check_ident_char(&self, index: usize) -> bool {
self.bytes self.bytes
.get(index) .get(index)
.map_or(false, |b| IDENT_CHAR.contains(b)) .map_or(false, |b| IDENT_CHAR.contains(b))

View File

@ -69,5 +69,4 @@ fn serialize_scene(world: &mut World, resources: &mut Resources) {
let pretty_config = ron::ser::PrettyConfig::default().with_decimal_floats(true); let pretty_config = ron::ser::PrettyConfig::default().with_decimal_floats(true);
let ron_string = ron::ser::to_string_pretty(&scene, pretty_config).unwrap(); let ron_string = ron::ser::to_string_pretty(&scene, pretty_config).unwrap();
println!("{}", ron_string); println!("{}", ron_string);
} }

View File

@ -1,8 +1,13 @@
use bevy::prelude::*; use bevy::prelude::*;
use bevy_property::ron::deserialize_dynamic_properties;
use bevy_scene::PropertyTypeRegistryContext;
use serde::{Deserialize, Serialize};
fn main() { fn main() {
App::build() App::build()
.add_default_plugins() .add_default_plugins()
// If you need to deserialize custom property types, register them like this:
.register_property_type::<CustomProperty>()
.add_startup_system(setup.system()) .add_startup_system(setup.system())
.run(); .run();
} }
@ -10,6 +15,7 @@ fn main() {
#[derive(Properties, Default)] #[derive(Properties, Default)]
pub struct Test { pub struct Test {
a: usize, a: usize,
hi: CustomProperty,
nested: Nested, nested: Nested,
} }
@ -18,9 +24,15 @@ pub struct Nested {
b: usize, b: usize,
} }
fn setup() { #[derive(Serialize, Deserialize, Default, Clone)]
pub struct CustomProperty {
a: usize,
}
fn setup(property_type_registry: Res<PropertyTypeRegistryContext>) {
let mut test = Test { let mut test = Test {
a: 1, a: 1,
hi: CustomProperty { a: 10 },
nested: Nested { b: 8 }, nested: Nested { b: 8 },
}; };
@ -43,17 +55,31 @@ fn setup() {
assert_eq!(test.a, 4); assert_eq!(test.a, 4);
// Properties implement the serde Serialize trait. You don't need to derive it yourself! // Properties implement the serde Serialize trait. You don't need to derive it yourself!
let pretty_config = ron::ser::PrettyConfig::default().with_decimal_floats(true);
let ron_string = ron::ser::to_string_pretty(&test, pretty_config.clone()).unwrap(); let ron_string = serialize_ron(&test).unwrap();
println!("{}\n", ron_string); println!("{}\n", ron_string);
// Dynamic properties can be deserialized // Dynamic properties can be deserialized
let dynamic_properties = ron::from_str::<DynamicProperties>(&ron_string).unwrap(); let dynamic_properties =
let round_tripped = ron::ser::to_string_pretty(&dynamic_properties, pretty_config).unwrap(); deserialize_dynamic_properties(&ron_string, &property_type_registry.value.read().unwrap())
.unwrap();
let round_tripped = serialize_ron(&dynamic_properties).unwrap();
println!("{}", round_tripped); println!("{}", round_tripped);
assert_eq!(ron_string, round_tripped); assert_eq!(ron_string, round_tripped);
// This means you can patch Properties with dynamic properties deserialized from a string // This means you can patch Properties with dynamic properties deserialized from a string
test.apply(&dynamic_properties); test.apply(&dynamic_properties);
} }
fn serialize_ron<T>(properties: &T) -> Result<String, ron::Error>
where
T: Serialize,
{
let pretty_config = ron::ser::PrettyConfig::default().with_decimal_floats(true);
let mut buf = Vec::new();
let mut serializer = ron::ser::Serializer::new(&mut buf, Some(pretty_config), true)?;
properties.serialize(&mut serializer)?;
let ron_string = String::from_utf8(buf).unwrap();
Ok(ron_string)
}