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: [
{
"type": "load_scene::Test",
@ -10,7 +10,7 @@
],
),
(
entity: 3949176536,
entity: 1639302665,
components: [
{
"type": "load_scene::Test",

View file

@ -9,4 +9,5 @@ edition = "2018"
[dependencies]
serde = "1"
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 serde::{
de::{self, MapAccess, Visitor},
ser::SerializeMap,
Deserialize, Serialize,
use crate::{
AsProperties, Properties, Property, PropertyIter, PropertyTypeRegistration,
PropertyTypeRegistry, PropertyVal,
};
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)]
pub struct DynamicProperties {
@ -100,14 +103,22 @@ impl Serialize for DynamicProperties {
}
}
impl<'de> Deserialize<'de> for DynamicProperties {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
pub struct DynamicPropertiesDeserializer<'a> {
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
D: serde::Deserializer<'de>,
{
let mut dynamic_properties = DynamicProperties::default();
deserializer.deserialize_map(PropMapVisiter {
dynamic_properties: &mut dynamic_properties,
property_type_registry: self.property_type_registry,
current_type_name: self.current_type_name,
})?;
Ok(dynamic_properties)
@ -116,6 +127,8 @@ impl<'de> Deserialize<'de> for DynamicProperties {
struct PropMapVisiter<'a> {
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> {
@ -133,7 +146,10 @@ impl<'a, 'de> Visitor<'de> for PropMapVisiter<'a> {
if &key == "type" {
type_name = Some(map.next_value()?);
} 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);
}
}
@ -144,18 +160,50 @@ impl<'a, 'de> Visitor<'de> for PropMapVisiter<'a> {
}
}
impl<'de> Deserialize<'de> for Box<dyn Property> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
pub struct MapValueDeserializer<'a> {
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
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>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("property value")
@ -251,7 +299,10 @@ impl<'de> Visitor<'de> for AnyPropVisiter {
{
let mut dynamic_properties = DynamicProperties::default();
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" {
dynamic_properties.type_name = prop
.val::<String>()
@ -261,10 +312,27 @@ impl<'de> Visitor<'de> for AnyPropVisiter {
dynamic_properties.set_box(key, prop);
}
}
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 {
#[inline]
fn any(&self) -> &dyn Any {

View file

@ -3,10 +3,13 @@
mod property;
mod properties;
mod dynamic_properties;
mod type_registry;
pub mod ron;
pub use property::*;
pub use properties::*;
pub use dynamic_properties::*;
pub use type_registry::*;
pub use bevy_property_derive::*;
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_property::{Properties, Property};
use bevy_property::{Properties, Property, PropertyTypeRegistry};
use legion::{
prelude::{Entity, World},
storage::{Component, ComponentTypeId, ComponentResourceSet},
storage::{Component, ComponentResourceSet, ComponentTypeId},
};
use serde::Deserialize;
use std::{
collections::HashMap,
sync::{Arc, RwLock},
};
#[derive(Clone, Default)]
pub struct PropertyTypeRegistryContext {
pub value: Arc<RwLock<PropertyTypeRegistry>>,
}
#[derive(Default)]
pub struct ComponentRegistryContext {
pub value: Arc<RwLock<ComponentRegistry>>,
@ -69,9 +75,10 @@ impl ComponentRegistration {
component.apply(property);
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
unsafe { &component_resource_set.data_slice::<T>()[index] }
unsafe { &component_resource_set.data_slice::<T>()[index] }
},
short_name: ty.0.split("::").last().unwrap(),
}
@ -82,6 +89,9 @@ pub trait RegisterComponent {
fn register_component<T>(&mut self) -> &mut Self
where
T: Properties + Component + Default;
fn register_property_type<T>(&mut self) -> &mut Self
where
T: Property + for<'de> Deserialize<'de>;
}
impl RegisterComponent for AppBuilder {
@ -98,4 +108,18 @@ impl RegisterComponent for AppBuilder {
}
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 {
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 bevy_app::FromResources;
use bevy_asset::AssetLoader;
use bevy_property::DynamicProperties;
use legion::prelude::{Entity, World};
use serde::{Deserialize, Serialize};
use std::{num::Wrapping, path::Path};
use bevy_property::{DynamicProperties, PropertyTypeRegistry, DynamicPropertiesDeserializer};
use legion::prelude::{Entity, Resources, World};
use serde::{
de::{DeserializeSeed, SeqAccess, Visitor, MapAccess, Error},
Serialize,
Deserialize
};
use std::{cell::RefCell, num::Wrapping, path::Path, rc::Rc};
use thiserror::Error;
#[derive(Serialize, Deserialize, Default)]
#[derive(Default)]
pub struct Scene {
pub entities: Vec<SceneEntity>,
}
#[derive(Serialize)]
pub struct SceneEntity {
pub entity: u32,
pub components: Vec<DynamicProperties>,
}
#[derive(Error, Debug)]
pub enum SceneAddError {
#[error("Scene contains an unregistered component.")]
@ -85,20 +96,219 @@ impl Scene {
}
}
#[derive(Serialize, Deserialize)]
pub struct SceneEntity {
pub entity: u32,
pub components: Vec<DynamicProperties>,
impl Serialize for Scene {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.entities.serialize(serializer)
}
}
#[derive(Default)]
pub struct SceneLoader;
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> {
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 {
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 entities = Vec::<SceneEntity>::deserialize(&mut deserializer).unwrap();
Ok(Scene { entities })
let current_type_name = Rc::new(RefCell::new(None));
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] {
static EXTENSIONS: &[&str] = &["scn"];

View file

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

View file

@ -315,7 +315,7 @@ impl<'a> Bytes<'a> {
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
.get(index)
.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 ron_string = ron::ser::to_string_pretty(&scene, pretty_config).unwrap();
println!("{}", ron_string);
}

View file

@ -1,8 +1,13 @@
use bevy::prelude::*;
use bevy_property::ron::deserialize_dynamic_properties;
use bevy_scene::PropertyTypeRegistryContext;
use serde::{Deserialize, Serialize};
fn main() {
App::build()
.add_default_plugins()
// If you need to deserialize custom property types, register them like this:
.register_property_type::<CustomProperty>()
.add_startup_system(setup.system())
.run();
}
@ -10,6 +15,7 @@ fn main() {
#[derive(Properties, Default)]
pub struct Test {
a: usize,
hi: CustomProperty,
nested: Nested,
}
@ -18,9 +24,15 @@ pub struct Nested {
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 {
a: 1,
hi: CustomProperty { a: 10 },
nested: Nested { b: 8 },
};
@ -43,17 +55,31 @@ fn setup() {
assert_eq!(test.a, 4);
// 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);
// Dynamic properties can be deserialized
let dynamic_properties = ron::from_str::<DynamicProperties>(&ron_string).unwrap();
let round_tripped = ron::ser::to_string_pretty(&dynamic_properties, pretty_config).unwrap();
let dynamic_properties =
deserialize_dynamic_properties(&ron_string, &property_type_registry.value.read().unwrap())
.unwrap();
let round_tripped = serialize_ron(&dynamic_properties).unwrap();
println!("{}", round_tripped);
assert_eq!(ron_string, round_tripped);
// This means you can patch Properties with dynamic properties deserialized from a string
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)
}