mirror of
https://github.com/bevyengine/bevy
synced 2024-11-24 21:53:07 +00:00
props: add type peeking to ron, support arbitrary property types
This commit is contained in:
parent
c5ab7df98f
commit
1cd3b4c987
13 changed files with 453 additions and 45 deletions
|
@ -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",
|
||||
|
|
|
@ -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" }
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
19
crates/bevy_property/src/ron.rs
Normal file
19
crates/bevy_property/src/ron.rs
Normal 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)
|
||||
}
|
43
crates/bevy_property/src/type_registry.rs
Normal file
43
crates/bevy_property/src/type_registry.rs
Normal 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(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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: ®istry,
|
||||
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"];
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue