props: "Seq" properties
This commit is contained in:
parent
e337ff59b8
commit
d2d02f63f6
6
.vscode/launch.json
vendored
6
.vscode/launch.json
vendored
@ -1104,15 +1104,15 @@
|
|||||||
{
|
{
|
||||||
"type": "lldb",
|
"type": "lldb",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "Debug example 'scene'",
|
"name": "Debug example '3d_scene'",
|
||||||
"cargo": {
|
"cargo": {
|
||||||
"args": [
|
"args": [
|
||||||
"build",
|
"build",
|
||||||
"--example=scene",
|
"--example=3d_scene",
|
||||||
"--package=bevy"
|
"--package=bevy"
|
||||||
],
|
],
|
||||||
"filter": {
|
"filter": {
|
||||||
"name": "scene",
|
"name": "3d_scene",
|
||||||
"kind": "example"
|
"kind": "example"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -16,5 +16,6 @@
|
|||||||
"rspirv",
|
"rspirv",
|
||||||
"rustc",
|
"rustc",
|
||||||
"spirv"
|
"spirv"
|
||||||
]
|
],
|
||||||
|
"rust-analyzer.checkOnSave.extraArgs": ["--target-dir", "target/rust-analyzer"],
|
||||||
}
|
}
|
||||||
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use std::{any::TypeId, marker::PhantomData};
|
use std::{any::TypeId, marker::PhantomData};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, Property)]
|
||||||
pub struct HandleId(pub Uuid);
|
pub struct HandleId(pub Uuid);
|
||||||
pub const DEFAULT_HANDLE_ID: HandleId =
|
pub const DEFAULT_HANDLE_ID: HandleId =
|
||||||
HandleId(Uuid::from_u128(240940089166493627844978703213080810552));
|
HandleId(Uuid::from_u128(240940089166493627844978703213080810552));
|
||||||
@ -19,29 +19,6 @@ impl HandleId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Property for HandleId {
|
|
||||||
fn any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
fn clone_prop(&self) -> Box<dyn Property> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
fn set(&mut self, value: &dyn Property) {
|
|
||||||
let value = value.any();
|
|
||||||
if let Some(prop) = value.downcast_ref::<Self>() {
|
|
||||||
*self = *prop;
|
|
||||||
} else {
|
|
||||||
panic!("prop value is not {}", std::any::type_name::<Self>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn apply(&mut self, value: &dyn Property) {
|
|
||||||
self.set(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Properties)]
|
#[derive(Properties)]
|
||||||
pub struct Handle<T>
|
pub struct Handle<T>
|
||||||
where
|
where
|
||||||
|
|||||||
@ -4,7 +4,13 @@ pub mod transform;
|
|||||||
|
|
||||||
use bevy_app::{stage, AppBuilder, AppPlugin};
|
use bevy_app::{stage, AppBuilder, AppPlugin};
|
||||||
use bevy_component_registry::RegisterComponent;
|
use bevy_component_registry::RegisterComponent;
|
||||||
use bevy_transform::{transform_system_bundle, components::{Children, LocalToParent, LocalToWorld, Translation, Rotation, Scale, NonUniformScale}};
|
use bevy_transform::{
|
||||||
|
components::{
|
||||||
|
Children, LocalToParent, LocalToWorld, NonUniformScale, Rotation, Scale, Translation,
|
||||||
|
},
|
||||||
|
transform_system_bundle,
|
||||||
|
};
|
||||||
|
use glam::{Mat3, Mat4, Quat, Vec2, Vec3};
|
||||||
use legion::prelude::IntoSystem;
|
use legion::prelude::IntoSystem;
|
||||||
use time::{start_timer_system, stop_timer_system, Time};
|
use time::{start_timer_system, stop_timer_system, Time};
|
||||||
|
|
||||||
@ -25,6 +31,11 @@ impl AppPlugin for CorePlugin {
|
|||||||
.register_component::<Rotation>()
|
.register_component::<Rotation>()
|
||||||
.register_component::<Scale>()
|
.register_component::<Scale>()
|
||||||
.register_component::<NonUniformScale>()
|
.register_component::<NonUniformScale>()
|
||||||
|
.register_property_type::<Vec2>()
|
||||||
|
.register_property_type::<Vec3>()
|
||||||
|
.register_property_type::<Mat3>()
|
||||||
|
.register_property_type::<Mat4>()
|
||||||
|
.register_property_type::<Quat>()
|
||||||
.add_system_to_stage(stage::FIRST, start_timer_system.system())
|
.add_system_to_stage(stage::FIRST, start_timer_system.system())
|
||||||
.add_system_to_stage(stage::LAST, stop_timer_system.system());
|
.add_system_to_stage(stage::LAST, stop_timer_system.system());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -99,9 +99,6 @@ pub fn derive_properties(input: TokenStream) -> TokenStream {
|
|||||||
|
|
||||||
TokenStream::from(quote! {
|
TokenStream::from(quote! {
|
||||||
impl #impl_generics #bevy_property_path::Properties for #struct_name#ty_generics {
|
impl #impl_generics #bevy_property_path::Properties for #struct_name#ty_generics {
|
||||||
fn type_name(&self) -> &str {
|
|
||||||
std::any::type_name::<Self>()
|
|
||||||
}
|
|
||||||
fn prop(&self, name: &str) -> Option<&dyn #bevy_property_path::Property> {
|
fn prop(&self, name: &str) -> Option<&dyn #bevy_property_path::Property> {
|
||||||
match name {
|
match name {
|
||||||
#(#field_names => Some(&self.#field_idents),)*
|
#(#field_names => Some(&self.#field_idents),)*
|
||||||
@ -144,6 +141,10 @@ pub fn derive_properties(input: TokenStream) -> TokenStream {
|
|||||||
fn iter_props(&self) -> #bevy_property_path::PropertyIter {
|
fn iter_props(&self) -> #bevy_property_path::PropertyIter {
|
||||||
#bevy_property_path::PropertyIter::new(self)
|
#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::serde::ser::Serialize for #struct_name#ty_generics {
|
impl #impl_generics #bevy_property_path::serde::ser::Serialize for #struct_name#ty_generics {
|
||||||
@ -152,16 +153,17 @@ pub fn derive_properties(input: TokenStream) -> TokenStream {
|
|||||||
S: #bevy_property_path::serde::ser::Serializer,
|
S: #bevy_property_path::serde::ser::Serializer,
|
||||||
{
|
{
|
||||||
use #bevy_property_path::serde::ser::SerializeMap;
|
use #bevy_property_path::serde::ser::SerializeMap;
|
||||||
let mut state = serializer.serialize_map(Some(self.prop_len()))?;
|
use #bevy_property_path::serde::Serialize;
|
||||||
state.serialize_entry("type", self.type_name())?;
|
#bevy_property_path::MapSerializer::new(self).serialize(serializer)
|
||||||
for (name, prop) in self.iter_props() {
|
|
||||||
state.serialize_entry(name, prop)?;
|
|
||||||
}
|
|
||||||
state.end()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl #impl_generics #bevy_property_path::Property for #struct_name#ty_generics {
|
impl #impl_generics #bevy_property_path::Property for #struct_name#ty_generics {
|
||||||
|
#[inline]
|
||||||
|
fn type_name(&self) -> &str {
|
||||||
|
std::any::type_name::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn any(&self) -> &dyn std::any::Any {
|
fn any(&self) -> &dyn std::any::Any {
|
||||||
self
|
self
|
||||||
@ -183,7 +185,15 @@ pub fn derive_properties(input: TokenStream) -> TokenStream {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn apply(&mut self, value: &dyn #bevy_property_path::Property) {
|
fn apply(&mut self, value: &dyn #bevy_property_path::Property) {
|
||||||
if let Some(properties) = value.as_properties() {
|
if let Some(properties) = value.as_properties() {
|
||||||
for (name, prop) in properties.iter_props() {
|
if properties.properties_type() != self.properties_type() {
|
||||||
|
panic!(
|
||||||
|
"Properties type mismatch. This type is {:?} but the applied type is {:?}",
|
||||||
|
self.properties_type(),
|
||||||
|
properties.properties_type()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for (i, prop) in properties.iter_props().enumerate() {
|
||||||
|
let name = properties.prop_name(i).unwrap();
|
||||||
self.prop_mut(name).map(|p| p.apply(prop));
|
self.prop_mut(name).map(|p| p.apply(prop));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -212,6 +222,11 @@ pub fn derive_property(input: TokenStream) -> TokenStream {
|
|||||||
|
|
||||||
TokenStream::from(quote! {
|
TokenStream::from(quote! {
|
||||||
impl #impl_generics #bevy_property_path::Property for #struct_name#ty_generics {
|
impl #impl_generics #bevy_property_path::Property for #struct_name#ty_generics {
|
||||||
|
#[inline]
|
||||||
|
fn type_name(&self) -> &str {
|
||||||
|
std::any::type_name::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn any(&self) -> &dyn std::any::Any {
|
fn any(&self) -> &dyn std::any::Any {
|
||||||
self
|
self
|
||||||
|
|||||||
@ -1,52 +1,76 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
Properties, Property, PropertyIter, PropertyTypeRegistration,
|
Properties, PropertiesType, Property, PropertyIter, PropertyTypeRegistration,
|
||||||
PropertyTypeRegistry, PropertyVal,
|
PropertyTypeRegistry,
|
||||||
};
|
};
|
||||||
|
use de::SeqAccess;
|
||||||
use serde::{
|
use serde::{
|
||||||
de::{self, DeserializeSeed, MapAccess, Visitor},
|
de::{self, DeserializeSeed, MapAccess, Visitor},
|
||||||
ser::SerializeMap,
|
ser::{SerializeMap, SerializeSeq},
|
||||||
Serialize,
|
Serialize,
|
||||||
};
|
};
|
||||||
use std::{any::Any, borrow::Cow, cell::RefCell, collections::HashMap, rc::Rc};
|
use std::{any::Any, borrow::Cow, cell::RefCell, collections::HashMap, rc::Rc};
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct DynamicProperties {
|
pub struct DynamicProperties {
|
||||||
pub type_name: String,
|
pub type_name: String,
|
||||||
pub props: Vec<(Cow<'static, str>, Box<dyn Property>)>,
|
pub props: Vec<Box<dyn Property>>,
|
||||||
|
pub prop_names: Vec<Cow<'static, str>>,
|
||||||
pub prop_indices: HashMap<Cow<'static, str>, usize>,
|
pub prop_indices: HashMap<Cow<'static, str>, usize>,
|
||||||
|
pub properties_type: PropertiesType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DynamicProperties {
|
impl DynamicProperties {
|
||||||
fn push(&mut self, name: &str, prop: Box<dyn Property>) {
|
pub fn map() -> Self {
|
||||||
let name: Cow<'static, str> = Cow::Owned(name.to_string());
|
DynamicProperties {
|
||||||
self.props.push((name.clone(), prop));
|
type_name: Default::default(),
|
||||||
self.prop_indices.insert(name, self.props.len());
|
props: Default::default(),
|
||||||
|
prop_names: Default::default(),
|
||||||
|
prop_indices: Default::default(),
|
||||||
|
properties_type: PropertiesType::Map,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn seq() -> Self {
|
||||||
|
DynamicProperties {
|
||||||
|
type_name: Default::default(),
|
||||||
|
props: Default::default(),
|
||||||
|
prop_names: Default::default(),
|
||||||
|
prop_indices: Default::default(),
|
||||||
|
properties_type: PropertiesType::Seq,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, prop: Box<dyn Property>, name: Option<&str>) {
|
||||||
|
// TODO: validate map / seq operations
|
||||||
|
self.props.push(prop);
|
||||||
|
if let Some(name) = name {
|
||||||
|
let cow_name: Cow<'static, str> = Cow::Owned(name.to_string()); // moo
|
||||||
|
self.prop_names.push(cow_name.clone());
|
||||||
|
self.prop_indices.insert(cow_name, self.props.len() - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn set<T: Property>(&mut self, name: &str, prop: T) {
|
pub fn set<T: Property>(&mut self, name: &str, prop: T) {
|
||||||
|
// TODO: validate map / seq operations
|
||||||
if let Some(index) = self.prop_indices.get(name) {
|
if let Some(index) = self.prop_indices.get(name) {
|
||||||
self.props[*index].1 = Box::new(prop);
|
self.props[*index] = Box::new(prop);
|
||||||
} else {
|
} else {
|
||||||
self.push(name, Box::new(prop));
|
self.push(Box::new(prop), Some(name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn set_box(&mut self, name: &str, prop: Box<dyn Property>) {
|
pub fn set_box(&mut self, name: &str, prop: Box<dyn Property>) {
|
||||||
|
// TODO: validate map / seq operations
|
||||||
if let Some(index) = self.prop_indices.get(name) {
|
if let Some(index) = self.prop_indices.get(name) {
|
||||||
self.props[*index].1 = prop;
|
self.props[*index] = prop;
|
||||||
} else {
|
} else {
|
||||||
self.push(name, prop);
|
self.push(prop, Some(name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Properties for DynamicProperties {
|
impl Properties for DynamicProperties {
|
||||||
#[inline]
|
|
||||||
fn type_name(&self) -> &str {
|
|
||||||
&self.type_name
|
|
||||||
}
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn prop(&self, name: &str) -> Option<&dyn Property> {
|
fn prop(&self, name: &str) -> Option<&dyn Property> {
|
||||||
if let Some(index) = self.prop_indices.get(name) {
|
if let Some(index) = self.prop_indices.get(name) {
|
||||||
Some(&*self.props[*index].1)
|
Some(&*self.props[*index])
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -55,7 +79,7 @@ impl Properties for DynamicProperties {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn prop_mut(&mut self, name: &str) -> Option<&mut dyn Property> {
|
fn prop_mut(&mut self, name: &str) -> Option<&mut dyn Property> {
|
||||||
if let Some(index) = self.prop_indices.get(name) {
|
if let Some(index) = self.prop_indices.get(name) {
|
||||||
Some(&mut *self.props[*index].1)
|
Some(&mut *self.props[*index])
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -63,17 +87,20 @@ impl Properties for DynamicProperties {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn prop_with_index(&self, index: usize) -> Option<&dyn Property> {
|
fn prop_with_index(&self, index: usize) -> Option<&dyn Property> {
|
||||||
self.props.get(index).map(|(_i, prop)| &**prop)
|
self.props.get(index).map(|prop| &**prop)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn prop_with_index_mut(&mut self, index: usize) -> Option<&mut dyn Property> {
|
fn prop_with_index_mut(&mut self, index: usize) -> Option<&mut dyn Property> {
|
||||||
self.props.get_mut(index).map(|(_i, prop)| &mut **prop)
|
self.props.get_mut(index).map(|prop| &mut **prop)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn prop_name(&self, index: usize) -> Option<&str> {
|
fn prop_name(&self, index: usize) -> Option<&str> {
|
||||||
self.props.get(index).map(|(name, _)| name.as_ref())
|
match self.properties_type {
|
||||||
|
PropertiesType::Seq => None,
|
||||||
|
PropertiesType::Map => self.prop_names.get(index).map(|name| name.as_ref()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -87,6 +114,75 @@ impl Properties for DynamicProperties {
|
|||||||
index: 0,
|
index: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn properties_type(&self) -> PropertiesType {
|
||||||
|
self.properties_type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Property for DynamicProperties {
|
||||||
|
#[inline]
|
||||||
|
fn type_name(&self) -> &str {
|
||||||
|
&self.type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn any_mut(&mut self) -> &mut dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn clone_prop(&self) -> Box<dyn Property> {
|
||||||
|
Box::new(self.to_dynamic())
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn set(&mut self, value: &dyn Property) {
|
||||||
|
if let Some(properties) = value.as_properties() {
|
||||||
|
*self = properties.to_dynamic();
|
||||||
|
} else {
|
||||||
|
panic!("attempted to apply non-Properties type to Properties type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn apply(&mut self, value: &dyn Property) {
|
||||||
|
if let Some(properties) = value.as_properties() {
|
||||||
|
if properties.properties_type() != self.properties_type {
|
||||||
|
panic!(
|
||||||
|
"Properties type mismatch. This type is {:?} but the applied type is {:?}",
|
||||||
|
self.properties_type,
|
||||||
|
properties.properties_type()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
match self.properties_type {
|
||||||
|
PropertiesType::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 => {
|
||||||
|
for (i, prop) in properties.iter_props().enumerate() {
|
||||||
|
self.prop_with_index_mut(i).map(|p| p.apply(prop));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("attempted to apply non-Properties type to Properties type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_properties(&self) -> Option<&dyn Properties> {
|
||||||
|
Some(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_sequence(&self) -> bool {
|
||||||
|
self.properties_type == PropertiesType::Seq
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for DynamicProperties {
|
impl Serialize for DynamicProperties {
|
||||||
@ -94,10 +190,82 @@ impl Serialize for DynamicProperties {
|
|||||||
where
|
where
|
||||||
S: serde::Serializer,
|
S: serde::Serializer,
|
||||||
{
|
{
|
||||||
let mut state = serializer.serialize_map(Some(self.props.len()))?;
|
match self.properties_type {
|
||||||
state.serialize_entry("type", self.type_name())?;
|
PropertiesType::Map => MapSerializer::new(self).serialize(serializer),
|
||||||
for (name, prop) in self.iter_props() {
|
PropertiesType::Seq => SeqSerializer::new(self).serialize(serializer),
|
||||||
state.serialize_entry(name, prop)?;
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MapSerializer<'a> {
|
||||||
|
pub properties: &'a dyn Properties,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> MapSerializer<'a> {
|
||||||
|
pub fn new(properties: &'a dyn Properties) -> Self {
|
||||||
|
MapSerializer { properties }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(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)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: maybe you can return this as a type erased serializer as Prop::get_serializer()? This would remove the need for explicit Serialize impls
|
||||||
|
pub struct SeqSerializer<'a> {
|
||||||
|
pub property: &'a dyn Property,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> SeqSerializer<'a> {
|
||||||
|
pub fn new(property: &'a dyn Property) -> Self {
|
||||||
|
SeqSerializer { property }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Serialize for SeqSerializer<'a> {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
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)?;
|
||||||
|
}
|
||||||
|
state.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PropertiesSeqSerializer<'a> {
|
||||||
|
pub properties: &'a dyn Properties,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Serialize for PropertiesSeqSerializer<'a> {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
let mut state = serializer.serialize_seq(Some(self.properties.prop_len()))?;
|
||||||
|
for prop in self.properties.iter_props() {
|
||||||
|
state.serialize_element(prop)?;
|
||||||
}
|
}
|
||||||
state.end()
|
state.end()
|
||||||
}
|
}
|
||||||
@ -114,49 +282,90 @@ impl<'a, 'de> DeserializeSeed<'de> for DynamicPropertiesDeserializer<'a> {
|
|||||||
where
|
where
|
||||||
D: serde::Deserializer<'de>,
|
D: serde::Deserializer<'de>,
|
||||||
{
|
{
|
||||||
let mut dynamic_properties = DynamicProperties::default();
|
deserializer.deserialize_map(DynamicPropertyMapVisiter {
|
||||||
deserializer.deserialize_map(PropMapVisiter {
|
|
||||||
dynamic_properties: &mut dynamic_properties,
|
|
||||||
property_type_registry: self.property_type_registry,
|
property_type_registry: self.property_type_registry,
|
||||||
current_type_name: self.current_type_name,
|
current_type_name: self.current_type_name,
|
||||||
})?;
|
})
|
||||||
|
|
||||||
Ok(dynamic_properties)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PropMapVisiter<'a> {
|
pub struct DynamicPropertyMapVisiter<'a> {
|
||||||
dynamic_properties: &'a mut DynamicProperties,
|
|
||||||
property_type_registry: &'a PropertyTypeRegistry,
|
property_type_registry: &'a PropertyTypeRegistry,
|
||||||
current_type_name: Rc<RefCell<Option<String>>>,
|
current_type_name: Rc<RefCell<Option<String>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'de> Visitor<'de> for PropMapVisiter<'a> {
|
impl<'a, 'de> Visitor<'de> for DynamicPropertyMapVisiter<'a> {
|
||||||
type Value = ();
|
type Value = DynamicProperties;
|
||||||
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("map of properties")
|
formatter.write_str("properties map")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_map<V>(self, mut map: V) -> Result<(), V::Error>
|
fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
|
||||||
where
|
where
|
||||||
V: MapAccess<'de>,
|
V: MapAccess<'de>,
|
||||||
{
|
{
|
||||||
let mut type_name: Option<String> = None;
|
visit_map(map, self.property_type_registry, self.current_type_name)
|
||||||
while let Some(key) = map.next_key::<String>()? {
|
}
|
||||||
if &key == "type" {
|
}
|
||||||
type_name = Some(map.next_value()?);
|
pub struct PropertyDeserializer<'a> {
|
||||||
} else {
|
pub property_type_registry: &'a PropertyTypeRegistry,
|
||||||
let prop = map.next_value_seed(MapValueDeserializer {
|
pub current_type_name: Rc<RefCell<Option<String>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'de> DeserializeSeed<'de> for PropertyDeserializer<'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 {
|
||||||
|
property_type_registry: self.property_type_registry,
|
||||||
|
current_type_name: self.current_type_name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PropSeqDeserializer<'a> {
|
||||||
|
property_type_registry: &'a PropertyTypeRegistry,
|
||||||
|
current_type_name: Rc<RefCell<Option<String>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'de> DeserializeSeed<'de> for PropSeqDeserializer<'a> {
|
||||||
|
type Value = DynamicProperties;
|
||||||
|
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserializer.deserialize_seq(PropSeqVisiter {
|
||||||
property_type_registry: self.property_type_registry,
|
property_type_registry: self.property_type_registry,
|
||||||
current_type_name: self.current_type_name.clone(),
|
current_type_name: self.current_type_name.clone(),
|
||||||
})?;
|
})
|
||||||
self.dynamic_properties.set_box(&key, prop);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PropSeqVisiter<'a> {
|
||||||
|
property_type_registry: &'a PropertyTypeRegistry,
|
||||||
|
current_type_name: Rc<RefCell<Option<String>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'de> Visitor<'de> for PropSeqVisiter<'a> {
|
||||||
|
type Value = DynamicProperties;
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
formatter.write_str("property value")
|
||||||
}
|
}
|
||||||
|
|
||||||
let type_name = type_name.ok_or_else(|| de::Error::missing_field("type"))?;
|
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
|
||||||
self.dynamic_properties.type_name = type_name.to_string();
|
where
|
||||||
Ok(())
|
V: SeqAccess<'de>,
|
||||||
|
{
|
||||||
|
let mut dynamic_properties = DynamicProperties::seq();
|
||||||
|
while let Some(prop) = seq.next_element_seed(PropertyDeserializer {
|
||||||
|
property_type_registry: self.property_type_registry,
|
||||||
|
current_type_name: self.current_type_name.clone(),
|
||||||
|
})? {
|
||||||
|
dynamic_properties.push(prop, None);
|
||||||
|
}
|
||||||
|
Ok(dynamic_properties)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,22 +382,17 @@ impl<'a, 'de> DeserializeSeed<'de> for MapValueDeserializer<'a> {
|
|||||||
{
|
{
|
||||||
if self.current_type_name.borrow().is_some() {
|
if self.current_type_name.borrow().is_some() {
|
||||||
let registration = {
|
let registration = {
|
||||||
let current_type_name= self.current_type_name.borrow();
|
let current_type_name = self.current_type_name.borrow();
|
||||||
let type_name = current_type_name.as_ref().unwrap();
|
let type_name = current_type_name.as_ref().unwrap();
|
||||||
self
|
self.property_type_registry
|
||||||
.property_type_registry
|
.get_short(type_name)
|
||||||
.get(type_name)
|
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
de::Error::custom(format!(
|
de::Error::custom(format!("TypeRegistration is missing for {}", type_name))
|
||||||
"TypeRegistration is missing for {}",
|
|
||||||
type_name
|
|
||||||
))
|
|
||||||
})?
|
})?
|
||||||
};
|
};
|
||||||
let mut erased = erased_serde::Deserializer::erase(deserializer);
|
let mut erased = erased_serde::Deserializer::erase(deserializer);
|
||||||
let res = (registration.deserialize)(&mut erased)
|
(registration.deserialize)(&mut erased)
|
||||||
.map_err(<<D as serde::Deserializer<'de>>::Error as serde::de::Error>::custom);
|
.map_err(<<D as serde::Deserializer<'de>>::Error as serde::de::Error>::custom)
|
||||||
res
|
|
||||||
} else {
|
} else {
|
||||||
deserializer.deserialize_any(AnyPropVisiter {
|
deserializer.deserialize_any(AnyPropVisiter {
|
||||||
property_type_registry: self.property_type_registry,
|
property_type_registry: self.property_type_registry,
|
||||||
@ -216,6 +420,13 @@ impl<'a, 'de> Visitor<'de> for AnyPropVisiter<'a> {
|
|||||||
Ok(Box::new(v))
|
Ok(Box::new(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
Ok(Box::new(v))
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E>
|
fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E>
|
||||||
where
|
where
|
||||||
E: de::Error,
|
E: de::Error,
|
||||||
@ -293,28 +504,55 @@ impl<'a, 'de> Visitor<'de> for AnyPropVisiter<'a> {
|
|||||||
Ok(Box::new(v.to_string()))
|
Ok(Box::new(v.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
|
fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
|
||||||
where
|
where
|
||||||
V: MapAccess<'de>,
|
V: MapAccess<'de>,
|
||||||
{
|
{
|
||||||
let mut dynamic_properties = DynamicProperties::default();
|
Ok(Box::new(visit_map(map, self.property_type_registry, self.current_type_name)?))
|
||||||
while let Some(key) = map.next_key()? {
|
}
|
||||||
let prop = map.next_value_seed(MapValueDeserializer {
|
}
|
||||||
property_type_registry: self.property_type_registry,
|
|
||||||
current_type_name: self.current_type_name.clone(),
|
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" {
|
if key == "type" {
|
||||||
dynamic_properties.type_name = prop
|
type_name = Some(map.next_value()?);
|
||||||
.val::<String>()
|
} else if key == "seq_type" {
|
||||||
.map(|s| s.clone())
|
type_name = Some(map.next_value()?);
|
||||||
.ok_or_else(|| de::Error::custom("type must be a string"))?;
|
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",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
dynamic_properties = map.next_value_seed(PropSeqDeserializer {
|
||||||
|
property_type_registry: property_type_registry,
|
||||||
|
current_type_name: current_type_name.clone(),
|
||||||
|
})?;
|
||||||
|
break;
|
||||||
} else {
|
} else {
|
||||||
dynamic_properties.set_box(key, prop);
|
let prop = map.next_value_seed(MapValueDeserializer {
|
||||||
|
property_type_registry: property_type_registry,
|
||||||
|
current_type_name: current_type_name.clone(),
|
||||||
|
})?;
|
||||||
|
dynamic_properties.set_box(&key, prop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Box::new(dynamic_properties))
|
let type_name = type_name.ok_or_else(|| de::Error::missing_field("type"))?;
|
||||||
}
|
dynamic_properties.type_name = type_name.to_string();
|
||||||
|
Ok(dynamic_properties)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PropertyTypeDeserializer<'a> {
|
struct PropertyTypeDeserializer<'a> {
|
||||||
@ -332,41 +570,3 @@ impl<'a, 'de> DeserializeSeed<'de> for PropertyTypeDeserializer<'a> {
|
|||||||
.map_err(<<D as serde::Deserializer<'de>>::Error as serde::de::Error>::custom)
|
.map_err(<<D as serde::Deserializer<'de>>::Error as serde::de::Error>::custom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Property for DynamicProperties {
|
|
||||||
#[inline]
|
|
||||||
fn any(&self) -> &dyn Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn any_mut(&mut self) -> &mut dyn Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn clone_prop(&self) -> Box<dyn Property> {
|
|
||||||
Box::new(self.to_dynamic())
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn set(&mut self, value: &dyn Property) {
|
|
||||||
if let Some(properties) = value.as_properties() {
|
|
||||||
*self = properties.to_dynamic();
|
|
||||||
} else {
|
|
||||||
panic!("attempted to apply non-Properties type to Properties type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn apply(&mut self, value: &dyn Property) {
|
|
||||||
if let Some(properties) = value.as_properties() {
|
|
||||||
for (name, prop) in properties.iter_props() {
|
|
||||||
self.prop_mut(name).map(|p| p.apply(prop));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
panic!("attempted to apply non-Properties type to Properties type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_properties(&self) -> Option<&dyn Properties> {
|
|
||||||
Some(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,6 +1,5 @@
|
|||||||
use crate::{impl_property, Property};
|
use crate::{impl_property, Property};
|
||||||
use glam::{Mat3, Mat4, Quat, Vec2, Vec3};
|
use glam::{Mat3, Mat4, Quat, Vec2, Vec3};
|
||||||
use std::any::Any;
|
|
||||||
|
|
||||||
impl_property!(Vec2);
|
impl_property!(Vec2);
|
||||||
impl_property!(Vec3);
|
impl_property!(Vec3);
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
use crate::{impl_property, Property};
|
use crate::{impl_property, Property};
|
||||||
use legion::prelude::Entity;
|
use legion::prelude::Entity;
|
||||||
use std::any::Any;
|
|
||||||
|
|
||||||
impl_property!(Entity);
|
impl_property!(Entity);
|
||||||
|
|||||||
@ -8,6 +8,11 @@ where
|
|||||||
T: Clone + Send + Sync + Serialize + 'static + Array<Item = I>,
|
T: Clone + Send + Sync + Serialize + 'static + Array<Item = I>,
|
||||||
I: Send + Sync + Clone + Serialize + 'static,
|
I: Send + Sync + Clone + Serialize + 'static,
|
||||||
{
|
{
|
||||||
|
#[inline]
|
||||||
|
fn type_name(&self) -> &str {
|
||||||
|
std::any::type_name::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn any(&self) -> &dyn Any {
|
fn any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
|
|||||||
@ -1,15 +1,91 @@
|
|||||||
use crate::{Property, impl_property};
|
use crate::{impl_property, Properties, PropertiesType, Property, PropertyIter};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
collections::{BTreeMap, HashMap, HashSet, VecDeque},
|
collections::{BTreeMap, HashMap, HashSet, VecDeque},
|
||||||
hash::Hash, ops::Range,
|
hash::Hash,
|
||||||
|
ops::Range,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
impl<T> Properties for Vec<T>
|
||||||
|
where
|
||||||
|
T: Property + Clone + Serialize,
|
||||||
|
{
|
||||||
|
fn prop(&self, _name: &str) -> Option<&dyn Property> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn prop_mut(&mut self, _name: &str) -> Option<&mut dyn Property> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn prop_with_index(&self, index: usize) -> Option<&dyn Property> {
|
||||||
|
Some(&self[index])
|
||||||
|
}
|
||||||
|
fn prop_with_index_mut(&mut self, index: usize) -> Option<&mut dyn Property> {
|
||||||
|
Some(&mut self[index])
|
||||||
|
}
|
||||||
|
fn prop_name(&self, _index: usize) -> Option<&str> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn prop_len(&self) -> usize {
|
||||||
|
self.len()
|
||||||
|
}
|
||||||
|
fn iter_props(&self) -> PropertyIter {
|
||||||
|
PropertyIter::new(self)
|
||||||
|
}
|
||||||
|
fn properties_type(&self) -> PropertiesType {
|
||||||
|
PropertiesType::Seq
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Property for Vec<T>
|
||||||
|
where
|
||||||
|
T: Property + Clone + Serialize,
|
||||||
|
{
|
||||||
|
fn type_name(&self) -> &str {
|
||||||
|
std::any::type_name::<Self>()
|
||||||
|
}
|
||||||
|
fn any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
fn any_mut(&mut self) -> &mut dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clone_prop(&self) -> Box<dyn Property> {
|
||||||
|
Box::new(self.clone())
|
||||||
|
}
|
||||||
|
fn set(&mut self, value: &dyn Property) {
|
||||||
|
if let Some(properties) = value.as_properties() {
|
||||||
|
if properties.properties_type() != self.properties_type() {
|
||||||
|
panic!(
|
||||||
|
"Properties type mismatch. This type is {:?} but the applied type is {:?}",
|
||||||
|
self.properties_type(),
|
||||||
|
properties.properties_type()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for (i, prop) in properties.iter_props().enumerate() {
|
||||||
|
self.prop_with_index_mut(i).map(|p| p.apply(prop));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("attempted to apply non-Properties type to Properties type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn apply(&mut self, value: &dyn Property) {
|
||||||
|
self.set(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_properties(&self) -> Option<&dyn Properties> {
|
||||||
|
Some(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_sequence(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl_property!(String);
|
impl_property!(String);
|
||||||
impl_property!(bool);
|
impl_property!(bool);
|
||||||
impl_property!(Vec<T> where T: Clone + Send + Sync + Serialize + 'static);
|
impl_property!(SEQUENCE, VecDeque<T> where T: Clone + Send + Sync + Serialize + 'static);
|
||||||
impl_property!(VecDeque<T> where T: Clone + Send + Sync + Serialize + 'static);
|
|
||||||
impl_property!(HashSet<T> where T: Clone + Eq + Send + Sync + Hash + Serialize + 'static);
|
impl_property!(HashSet<T> where T: Clone + Eq + Send + Sync + Hash + Serialize + 'static);
|
||||||
impl_property!(HashMap<K, V> where
|
impl_property!(HashMap<K, V> where
|
||||||
K: Clone + Eq + Send + Sync + Hash + Serialize + 'static,
|
K: Clone + Eq + Send + Sync + Hash + Serialize + 'static,
|
||||||
@ -19,7 +95,15 @@ impl_property!(BTreeMap<K, V> where
|
|||||||
V: Clone + Send + Sync + Serialize + 'static);
|
V: Clone + Send + Sync + Serialize + 'static);
|
||||||
impl_property!(Range<T> where T: Clone + Send + Sync + Serialize + 'static);
|
impl_property!(Range<T> where T: Clone + Send + Sync + Serialize + 'static);
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Implement lossless primitive types in RON and remove all of these primitive "cast checks"
|
||||||
|
|
||||||
impl Property for usize {
|
impl Property for usize {
|
||||||
|
#[inline]
|
||||||
|
fn type_name(&self) -> &str {
|
||||||
|
std::any::type_name::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn any(&self) -> &dyn Any {
|
fn any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
@ -69,6 +153,11 @@ impl Property for usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Property for u64 {
|
impl Property for u64 {
|
||||||
|
#[inline]
|
||||||
|
fn type_name(&self) -> &str {
|
||||||
|
std::any::type_name::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn any(&self) -> &dyn Any {
|
fn any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
@ -118,6 +207,11 @@ impl Property for u64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Property for u32 {
|
impl Property for u32 {
|
||||||
|
#[inline]
|
||||||
|
fn type_name(&self) -> &str {
|
||||||
|
std::any::type_name::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn any(&self) -> &dyn Any {
|
fn any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
@ -167,6 +261,11 @@ impl Property for u32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Property for u16 {
|
impl Property for u16 {
|
||||||
|
#[inline]
|
||||||
|
fn type_name(&self) -> &str {
|
||||||
|
std::any::type_name::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn any(&self) -> &dyn Any {
|
fn any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
@ -216,6 +315,11 @@ impl Property for u16 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Property for u8 {
|
impl Property for u8 {
|
||||||
|
#[inline]
|
||||||
|
fn type_name(&self) -> &str {
|
||||||
|
std::any::type_name::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn any(&self) -> &dyn Any {
|
fn any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
@ -265,6 +369,11 @@ impl Property for u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Property for isize {
|
impl Property for isize {
|
||||||
|
#[inline]
|
||||||
|
fn type_name(&self) -> &str {
|
||||||
|
std::any::type_name::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn any(&self) -> &dyn Any {
|
fn any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
@ -314,6 +423,11 @@ impl Property for isize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Property for i64 {
|
impl Property for i64 {
|
||||||
|
#[inline]
|
||||||
|
fn type_name(&self) -> &str {
|
||||||
|
std::any::type_name::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn any(&self) -> &dyn Any {
|
fn any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
@ -363,6 +477,11 @@ impl Property for i64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Property for i32 {
|
impl Property for i32 {
|
||||||
|
#[inline]
|
||||||
|
fn type_name(&self) -> &str {
|
||||||
|
std::any::type_name::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn any(&self) -> &dyn Any {
|
fn any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
@ -411,8 +530,12 @@ impl Property for i32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Property for i16 {
|
impl Property for i16 {
|
||||||
|
#[inline]
|
||||||
|
fn type_name(&self) -> &str {
|
||||||
|
std::any::type_name::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn any(&self) -> &dyn Any {
|
fn any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
@ -462,6 +585,11 @@ impl Property for i16 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Property for i8 {
|
impl Property for i8 {
|
||||||
|
#[inline]
|
||||||
|
fn type_name(&self) -> &str {
|
||||||
|
std::any::type_name::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn any(&self) -> &dyn Any {
|
fn any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
@ -511,6 +639,11 @@ impl Property for i8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Property for f32 {
|
impl Property for f32 {
|
||||||
|
#[inline]
|
||||||
|
fn type_name(&self) -> &str {
|
||||||
|
std::any::type_name::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn any(&self) -> &dyn Any {
|
fn any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
@ -544,6 +677,11 @@ impl Property for f32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Property for f64 {
|
impl Property for f64 {
|
||||||
|
#[inline]
|
||||||
|
fn type_name(&self) -> &str {
|
||||||
|
std::any::type_name::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn any(&self) -> &dyn Any {
|
fn any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
|
|||||||
@ -1,7 +1,12 @@
|
|||||||
use crate::{DynamicProperties, Property, PropertyVal};
|
use crate::{DynamicProperties, Property, PropertyVal};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
|
||||||
|
pub enum PropertiesType {
|
||||||
|
Map,
|
||||||
|
Seq,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Properties: Property {
|
pub trait Properties: Property {
|
||||||
fn type_name(&self) -> &str;
|
|
||||||
fn prop(&self, name: &str) -> Option<&dyn Property>;
|
fn prop(&self, name: &str) -> Option<&dyn Property>;
|
||||||
fn prop_mut(&mut self, name: &str) -> Option<&mut dyn Property>;
|
fn prop_mut(&mut self, name: &str) -> Option<&mut dyn Property>;
|
||||||
fn prop_with_index(&self, index: usize) -> Option<&dyn Property>;
|
fn prop_with_index(&self, index: usize) -> Option<&dyn Property>;
|
||||||
@ -9,6 +14,7 @@ pub trait Properties: Property {
|
|||||||
fn prop_name(&self, index: usize) -> Option<&str>;
|
fn prop_name(&self, index: usize) -> Option<&str>;
|
||||||
fn prop_len(&self) -> usize;
|
fn prop_len(&self) -> usize;
|
||||||
fn iter_props(&self) -> PropertyIter;
|
fn iter_props(&self) -> PropertyIter;
|
||||||
|
fn properties_type(&self) -> PropertiesType;
|
||||||
fn set_prop(&mut self, name: &str, value: &dyn Property) {
|
fn set_prop(&mut self, name: &str, value: &dyn Property) {
|
||||||
if let Some(prop) = self.prop_mut(name) {
|
if let Some(prop) = self.prop_mut(name) {
|
||||||
prop.set(value);
|
prop.set(value);
|
||||||
@ -18,12 +24,25 @@ pub trait Properties: Property {
|
|||||||
}
|
}
|
||||||
fn to_dynamic(&self) -> DynamicProperties
|
fn to_dynamic(&self) -> DynamicProperties
|
||||||
{
|
{
|
||||||
let mut dynamic_props = DynamicProperties::default();
|
let mut dynamic_props = match self.properties_type() {
|
||||||
for (name, prop) in self.iter_props() {
|
PropertiesType::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");
|
||||||
dynamic_props.set_box(name, prop.clone_prop());
|
dynamic_props.set_box(name, prop.clone_prop());
|
||||||
}
|
}
|
||||||
|
dynamic_props
|
||||||
|
},
|
||||||
|
PropertiesType::Seq => {
|
||||||
|
let mut dynamic_props = DynamicProperties::seq();
|
||||||
|
for prop in self.iter_props() {
|
||||||
|
dynamic_props.push(prop.clone_prop(), None);
|
||||||
|
}
|
||||||
|
dynamic_props
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
dynamic_props.type_name = std::any::type_name::<Self>().to_string();
|
dynamic_props.type_name = self.type_name().to_string();
|
||||||
dynamic_props
|
dynamic_props
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -40,13 +59,12 @@ impl<'a> PropertyIter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for PropertyIter<'a> {
|
impl<'a> Iterator for PropertyIter<'a> {
|
||||||
type Item = (&'a str, &'a dyn Property);
|
type Item = &'a dyn Property;
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
if self.index < self.props.prop_len() {
|
if self.index < self.props.prop_len() {
|
||||||
let prop = self.props.prop_with_index(self.index).unwrap();
|
let prop = self.props.prop_with_index(self.index).unwrap();
|
||||||
let name = self.props.prop_name(self.index).unwrap();
|
|
||||||
self.index += 1;
|
self.index += 1;
|
||||||
Some((name, prop))
|
Some(prop)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ use crate::Properties;
|
|||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|
||||||
pub trait Property: erased_serde::Serialize + Send + Sync + Any + 'static {
|
pub trait Property: erased_serde::Serialize + Send + Sync + Any + 'static {
|
||||||
|
fn type_name(&self) -> &str;
|
||||||
fn any(&self) -> &dyn Any;
|
fn any(&self) -> &dyn Any;
|
||||||
fn any_mut(&mut self) -> &mut dyn Any;
|
fn any_mut(&mut self) -> &mut dyn Any;
|
||||||
fn clone_prop(&self) -> Box<dyn Property>;
|
fn clone_prop(&self) -> Box<dyn Property>;
|
||||||
@ -10,6 +11,9 @@ pub trait Property: erased_serde::Serialize + Send + Sync + Any + 'static {
|
|||||||
fn as_properties(&self) -> Option<&dyn Properties> {
|
fn as_properties(&self) -> Option<&dyn Properties> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
fn is_sequence(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
erased_serde::serialize_trait_object!(Property);
|
erased_serde::serialize_trait_object!(Property);
|
||||||
@ -48,12 +52,17 @@ macro_rules! impl_property {
|
|||||||
($ty:ident) => {
|
($ty:ident) => {
|
||||||
impl Property for $ty {
|
impl Property for $ty {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn any(&self) -> &dyn Any {
|
fn type_name(&self) -> &str {
|
||||||
|
std::any::type_name::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn any(&self) -> &dyn std::any::Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn any_mut(&mut self) -> &mut dyn Any {
|
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,18 +86,68 @@ macro_rules! impl_property {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
(SEQUENCE, @$trait_:ident [$($args:ident,)*] where [$($preds:tt)+]) => {
|
||||||
|
impl_property! {
|
||||||
|
@as_item
|
||||||
|
impl<$($args),*> Property for $trait_<$($args),*> where $($args: ::std::any::Any + 'static,)*
|
||||||
|
$($preds)* {
|
||||||
|
#[inline]
|
||||||
|
fn type_name(&self) -> &str {
|
||||||
|
std::any::type_name::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn clone_prop(&self) -> Box<dyn Property> {
|
||||||
|
Box::new(self.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn apply(&mut self, value: &dyn Property) {
|
||||||
|
self.set(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set(&mut self, value: &dyn Property) {
|
||||||
|
let value = value.any();
|
||||||
|
if let Some(prop) = value.downcast_ref::<Self>() {
|
||||||
|
*self = prop.clone();
|
||||||
|
} else {
|
||||||
|
panic!("prop value is not {}", std::any::type_name::<Self>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_sequence(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
(@$trait_:ident [$($args:ident,)*] where [$($preds:tt)+]) => {
|
(@$trait_:ident [$($args:ident,)*] where [$($preds:tt)+]) => {
|
||||||
impl_property! {
|
impl_property! {
|
||||||
@as_item
|
@as_item
|
||||||
impl<$($args),*> Property for $trait_<$($args),*> where $($args: ::std::any::Any + 'static,)*
|
impl<$($args),*> Property for $trait_<$($args),*> where $($args: ::std::any::Any + 'static,)*
|
||||||
$($preds)* {
|
$($preds)* {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn any(&self) -> &dyn Any {
|
fn type_name(&self) -> &str {
|
||||||
|
std::any::type_name::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn any(&self) -> &dyn std::any::Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn any_mut(&mut self) -> &mut dyn Any {
|
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,6 +174,12 @@ macro_rules! impl_property {
|
|||||||
};
|
};
|
||||||
(@as_item $i:item) => { $i };
|
(@as_item $i:item) => { $i };
|
||||||
|
|
||||||
|
(
|
||||||
|
SEQUENCE, $trait_:ident < $($args:ident),* $(,)* >
|
||||||
|
where $($preds:tt)+
|
||||||
|
) => {
|
||||||
|
impl_property! {SEQUENCE, @$trait_ [$($args,)*] where [$($preds)*] }
|
||||||
|
};
|
||||||
(
|
(
|
||||||
$trait_:ident < $($args:ident),* $(,)* >
|
$trait_:ident < $($args:ident),* $(,)* >
|
||||||
where $($preds:tt)+
|
where $($preds:tt)+
|
||||||
|
|||||||
@ -5,6 +5,7 @@ use std::{any::TypeId, collections::HashMap};
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct PropertyTypeRegistry {
|
pub struct PropertyTypeRegistry {
|
||||||
pub registrations: HashMap<String, PropertyTypeRegistration>,
|
pub registrations: HashMap<String, PropertyTypeRegistration>,
|
||||||
|
pub short_names: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PropertyTypeRegistry {
|
impl PropertyTypeRegistry {
|
||||||
@ -13,19 +14,31 @@ impl PropertyTypeRegistry {
|
|||||||
T: Property + for<'de> Deserialize<'de>,
|
T: Property + for<'de> Deserialize<'de>,
|
||||||
{
|
{
|
||||||
let registration = PropertyTypeRegistration::of::<T>();
|
let registration = PropertyTypeRegistration::of::<T>();
|
||||||
self.registrations.insert(registration.short_name.to_string(), registration);
|
self.short_names
|
||||||
|
.insert(registration.short_name.to_string(), registration.name.to_string());
|
||||||
|
self.registrations
|
||||||
|
.insert(registration.name.to_string(), registration);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, type_name: &str) -> Option<&PropertyTypeRegistration> {
|
pub fn get(&self, type_name: &str) -> Option<&PropertyTypeRegistration> {
|
||||||
self.registrations.get(type_name)
|
self.registrations.get(type_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_short(&self, short_type_name: &str) -> Option<&PropertyTypeRegistration> {
|
||||||
|
self.short_names
|
||||||
|
.get(short_type_name)
|
||||||
|
.and_then(|name| self.registrations.get(name))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct PropertyTypeRegistration {
|
pub struct PropertyTypeRegistration {
|
||||||
pub ty: TypeId,
|
pub ty: TypeId,
|
||||||
pub deserialize: fn(deserializer: &mut dyn erased_serde::Deserializer) -> Result<Box<dyn Property>, erased_serde::Error>,
|
pub deserialize: fn(
|
||||||
|
deserializer: &mut dyn erased_serde::Deserializer,
|
||||||
|
) -> Result<Box<dyn Property>, erased_serde::Error>,
|
||||||
pub short_name: &'static str,
|
pub short_name: &'static str,
|
||||||
|
pub name: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PropertyTypeRegistration {
|
impl PropertyTypeRegistration {
|
||||||
@ -37,6 +50,7 @@ impl PropertyTypeRegistration {
|
|||||||
let property = <T as Deserialize>::deserialize(deserializer)?;
|
let property = <T as Deserialize>::deserialize(deserializer)?;
|
||||||
Ok(Box::new(property))
|
Ok(Box::new(property))
|
||||||
},
|
},
|
||||||
|
name: std::any::type_name::<T>(),
|
||||||
short_name: std::any::type_name::<T>().split("::").last().unwrap(),
|
short_name: std::any::type_name::<T>().split("::").last().unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,8 +41,8 @@ use self::{
|
|||||||
|
|
||||||
use base_render_graph::{BaseRenderGraphBuilder, BaseRenderGraphConfig};
|
use base_render_graph::{BaseRenderGraphBuilder, BaseRenderGraphConfig};
|
||||||
use bevy_app::{stage, AppBuilder, AppPlugin};
|
use bevy_app::{stage, AppBuilder, AppPlugin};
|
||||||
use bevy_component_registry::RegisterComponent;
|
|
||||||
use bevy_asset::AddAsset;
|
use bevy_asset::AddAsset;
|
||||||
|
use bevy_component_registry::RegisterComponent;
|
||||||
use legion::prelude::IntoSystem;
|
use legion::prelude::IntoSystem;
|
||||||
use mesh::mesh_resource_provider_system;
|
use mesh::mesh_resource_provider_system;
|
||||||
use render_graph::RenderGraph;
|
use render_graph::RenderGraph;
|
||||||
@ -78,6 +78,7 @@ impl AppPlugin for RenderPlugin {
|
|||||||
.register_component::<Renderable>()
|
.register_component::<Renderable>()
|
||||||
.register_component::<ActiveCamera>()
|
.register_component::<ActiveCamera>()
|
||||||
.register_component::<ActiveCamera2d>()
|
.register_component::<ActiveCamera2d>()
|
||||||
|
.register_property_type::<Color>()
|
||||||
.init_resource::<RenderGraph>()
|
.init_resource::<RenderGraph>()
|
||||||
.init_resource::<PipelineAssignments>()
|
.init_resource::<PipelineAssignments>()
|
||||||
.init_resource::<PipelineCompiler>()
|
.init_resource::<PipelineCompiler>()
|
||||||
|
|||||||
@ -595,7 +595,14 @@ impl<'de, 'a> de::MapAccess<'de> for CommaSeparated<'a, 'de> {
|
|||||||
fast_forward_bytes.skip_ws()?;
|
fast_forward_bytes.skip_ws()?;
|
||||||
fast_forward_bytes.consume(":");
|
fast_forward_bytes.consume(":");
|
||||||
fast_forward_bytes.skip_ws()?;
|
fast_forward_bytes.skip_ws()?;
|
||||||
callback(&fast_forward_bytes.identifier().ok());
|
let identifier = &fast_forward_bytes.identifier().ok();
|
||||||
|
fast_forward_bytes.skip_ws()?;
|
||||||
|
// only run callback from structs
|
||||||
|
if fast_forward_bytes.consume("(") {
|
||||||
|
callback(identifier);
|
||||||
|
} else {
|
||||||
|
callback(&None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -4,6 +4,7 @@ use bevy::{
|
|||||||
property::{ron::deserialize_dynamic_properties},
|
property::{ron::deserialize_dynamic_properties},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use bevy_property::{PropertiesSeqSerializer, SeqSerializer};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
App::build()
|
App::build()
|
||||||
@ -26,34 +27,11 @@ pub struct Nested {
|
|||||||
b: usize,
|
b: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Default, Clone)]
|
#[derive(Serialize, Deserialize, Default, Clone, Property)]
|
||||||
pub struct CustomProperty {
|
pub struct CustomProperty {
|
||||||
a: usize,
|
a: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Property for CustomProperty {
|
|
||||||
fn any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
fn any_mut(&mut self) -> &mut dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
fn clone_prop(&self) -> Box<dyn Property> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
fn set(&mut self, value: &dyn Property) {
|
|
||||||
let value = value.any();
|
|
||||||
if let Some(prop) = value.downcast_ref::<Self>() {
|
|
||||||
*self = prop.clone();
|
|
||||||
} else {
|
|
||||||
panic!("prop value is not {}", std::any::type_name::<Self>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn apply(&mut self, value: &dyn Property) {
|
|
||||||
self.set(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup(property_type_registry: Res<PropertyTypeRegistryContext>) {
|
fn setup(property_type_registry: Res<PropertyTypeRegistryContext>) {
|
||||||
let mut test = Test {
|
let mut test = Test {
|
||||||
a: 1,
|
a: 1,
|
||||||
@ -71,7 +49,7 @@ fn setup(property_type_registry: Res<PropertyTypeRegistryContext>) {
|
|||||||
assert_eq!(test.a, 3);
|
assert_eq!(test.a, 3);
|
||||||
|
|
||||||
// DynamicProperties also implements the Properties trait.
|
// DynamicProperties also implements the Properties trait.
|
||||||
let mut patch = DynamicProperties::default();
|
let mut patch = DynamicProperties::map();
|
||||||
patch.set::<usize>("a", 4);
|
patch.set::<usize>("a", 4);
|
||||||
|
|
||||||
// You can "apply" Properties on top of other Properties. This will only set properties with the same name and type.
|
// You can "apply" Properties on top of other Properties. This will only set properties with the same name and type.
|
||||||
@ -80,7 +58,6 @@ fn setup(property_type_registry: Res<PropertyTypeRegistryContext>) {
|
|||||||
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 ron_string = serialize_ron(&test).unwrap();
|
let ron_string = serialize_ron(&test).unwrap();
|
||||||
println!("{}\n", ron_string);
|
println!("{}\n", ron_string);
|
||||||
|
|
||||||
@ -95,6 +72,22 @@ fn setup(property_type_registry: Res<PropertyTypeRegistryContext>) {
|
|||||||
|
|
||||||
// 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);
|
||||||
|
|
||||||
|
// Properties can also be sequences. Std sequences (Vec, VecDeque) already implement the Properties trait
|
||||||
|
let mut seq = vec![1u32, 2u32];
|
||||||
|
let mut patch = DynamicProperties::seq();
|
||||||
|
patch.push(Box::new(3u32), None);
|
||||||
|
seq.apply(&patch);
|
||||||
|
assert_eq!(seq[0], 3);
|
||||||
|
|
||||||
|
let ron_string = serialize_ron(&SeqSerializer { property: &patch} ).unwrap();
|
||||||
|
println!("{}\n", ron_string);
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_ron<T>(properties: &T) -> Result<String, ron::Error>
|
fn serialize_ron<T>(properties: &T) -> Result<String, ron::Error>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user