props: "Seq" properties

This commit is contained in:
Carter Anderson 2020-05-26 19:47:33 -07:00
parent e337ff59b8
commit d2d02f63f6
16 changed files with 656 additions and 213 deletions

6
.vscode/launch.json vendored
View file

@ -1104,15 +1104,15 @@
{
"type": "lldb",
"request": "launch",
"name": "Debug example 'scene'",
"name": "Debug example '3d_scene'",
"cargo": {
"args": [
"build",
"--example=scene",
"--example=3d_scene",
"--package=bevy"
],
"filter": {
"name": "scene",
"name": "3d_scene",
"kind": "example"
}
},

View file

@ -16,5 +16,6 @@
"rspirv",
"rustc",
"spirv"
]
],
"rust-analyzer.checkOnSave.extraArgs": ["--target-dir", "target/rust-analyzer"],
}

View file

@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
use std::{any::TypeId, marker::PhantomData};
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 const DEFAULT_HANDLE_ID: HandleId =
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)]
pub struct Handle<T>
where

View file

@ -4,7 +4,13 @@ pub mod transform;
use bevy_app::{stage, AppBuilder, AppPlugin};
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 time::{start_timer_system, stop_timer_system, Time};
@ -25,6 +31,11 @@ impl AppPlugin for CorePlugin {
.register_component::<Rotation>()
.register_component::<Scale>()
.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::LAST, stop_timer_system.system());
}

View file

@ -99,9 +99,6 @@ pub fn derive_properties(input: TokenStream) -> TokenStream {
TokenStream::from(quote! {
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> {
match name {
#(#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 {
#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 {
@ -152,16 +153,17 @@ pub fn derive_properties(input: TokenStream) -> TokenStream {
S: #bevy_property_path::serde::ser::Serializer,
{
use #bevy_property_path::serde::ser::SerializeMap;
let mut state = serializer.serialize_map(Some(self.prop_len()))?;
state.serialize_entry("type", self.type_name())?;
for (name, prop) in self.iter_props() {
state.serialize_entry(name, prop)?;
}
state.end()
use #bevy_property_path::serde::Serialize;
#bevy_property_path::MapSerializer::new(self).serialize(serializer)
}
}
impl #impl_generics #bevy_property_path::Property for #struct_name#ty_generics {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[inline]
fn any(&self) -> &dyn std::any::Any {
self
@ -183,7 +185,15 @@ pub fn derive_properties(input: TokenStream) -> TokenStream {
#[inline]
fn apply(&mut self, value: &dyn #bevy_property_path::Property) {
if let Some(properties) = value.as_properties() {
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));
}
} else {
@ -212,6 +222,11 @@ pub fn derive_property(input: TokenStream) -> TokenStream {
TokenStream::from(quote! {
impl #impl_generics #bevy_property_path::Property for #struct_name#ty_generics {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[inline]
fn any(&self) -> &dyn std::any::Any {
self

View file

@ -1,52 +1,76 @@
use crate::{
Properties, Property, PropertyIter, PropertyTypeRegistration,
PropertyTypeRegistry, PropertyVal,
Properties, PropertiesType, Property, PropertyIter, PropertyTypeRegistration,
PropertyTypeRegistry,
};
use de::SeqAccess;
use serde::{
de::{self, DeserializeSeed, MapAccess, Visitor},
ser::SerializeMap,
ser::{SerializeMap, SerializeSeq},
Serialize,
};
use std::{any::Any, borrow::Cow, cell::RefCell, collections::HashMap, rc::Rc};
#[derive(Default)]
pub struct DynamicProperties {
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 properties_type: PropertiesType,
}
impl DynamicProperties {
fn push(&mut self, name: &str, prop: Box<dyn Property>) {
let name: Cow<'static, str> = Cow::Owned(name.to_string());
self.props.push((name.clone(), prop));
self.prop_indices.insert(name, self.props.len());
pub fn map() -> Self {
DynamicProperties {
type_name: Default::default(),
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) {
// TODO: validate map / seq operations
if let Some(index) = self.prop_indices.get(name) {
self.props[*index].1 = Box::new(prop);
self.props[*index] = Box::new(prop);
} 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>) {
// TODO: validate map / seq operations
if let Some(index) = self.prop_indices.get(name) {
self.props[*index].1 = prop;
self.props[*index] = prop;
} else {
self.push(name, prop);
self.push(prop, Some(name));
}
}
}
impl Properties for DynamicProperties {
#[inline]
fn type_name(&self) -> &str {
&self.type_name
}
#[inline]
fn prop(&self, name: &str) -> Option<&dyn Property> {
if let Some(index) = self.prop_indices.get(name) {
Some(&*self.props[*index].1)
Some(&*self.props[*index])
} else {
None
}
@ -55,7 +79,7 @@ impl Properties for DynamicProperties {
#[inline]
fn prop_mut(&mut self, name: &str) -> Option<&mut dyn Property> {
if let Some(index) = self.prop_indices.get(name) {
Some(&mut *self.props[*index].1)
Some(&mut *self.props[*index])
} else {
None
}
@ -63,17 +87,20 @@ impl Properties for DynamicProperties {
#[inline]
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]
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]
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]
@ -87,6 +114,75 @@ impl Properties for DynamicProperties {
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 {
@ -94,10 +190,82 @@ impl Serialize for DynamicProperties {
where
S: serde::Serializer,
{
let mut state = serializer.serialize_map(Some(self.props.len()))?;
state.serialize_entry("type", self.type_name())?;
for (name, prop) in self.iter_props() {
state.serialize_entry(name, prop)?;
match self.properties_type {
PropertiesType::Map => MapSerializer::new(self).serialize(serializer),
PropertiesType::Seq => SeqSerializer::new(self).serialize(serializer),
}
}
}
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()
}
@ -114,49 +282,90 @@ impl<'a, 'de> DeserializeSeed<'de> for DynamicPropertiesDeserializer<'a> {
where
D: serde::Deserializer<'de>,
{
let mut dynamic_properties = DynamicProperties::default();
deserializer.deserialize_map(PropMapVisiter {
dynamic_properties: &mut dynamic_properties,
deserializer.deserialize_map(DynamicPropertyMapVisiter {
property_type_registry: self.property_type_registry,
current_type_name: self.current_type_name,
})?;
Ok(dynamic_properties)
})
}
}
struct PropMapVisiter<'a> {
dynamic_properties: &'a mut DynamicProperties,
pub struct DynamicPropertyMapVisiter<'a> {
property_type_registry: &'a PropertyTypeRegistry,
current_type_name: Rc<RefCell<Option<String>>>,
}
impl<'a, 'de> Visitor<'de> for PropMapVisiter<'a> {
type Value = ();
impl<'a, 'de> Visitor<'de> for DynamicPropertyMapVisiter<'a> {
type Value = DynamicProperties;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("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
V: MapAccess<'de>,
{
let mut type_name: Option<String> = None;
while let Some(key) = map.next_key::<String>()? {
if &key == "type" {
type_name = Some(map.next_value()?);
} else {
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);
}
}
visit_map(map, self.property_type_registry, self.current_type_name)
}
}
pub struct PropertyDeserializer<'a> {
pub property_type_registry: &'a PropertyTypeRegistry,
pub current_type_name: Rc<RefCell<Option<String>>>,
}
let type_name = type_name.ok_or_else(|| de::Error::missing_field("type"))?;
self.dynamic_properties.type_name = type_name.to_string();
Ok(())
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,
current_type_name: self.current_type_name.clone(),
})
}
}
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")
}
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
where
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,23 +382,18 @@ impl<'a, 'de> DeserializeSeed<'de> for MapValueDeserializer<'a> {
{
if self.current_type_name.borrow().is_some() {
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();
self
.property_type_registry
.get(type_name)
self.property_type_registry
.get_short(type_name)
.ok_or_else(|| {
de::Error::custom(format!(
"TypeRegistration is missing for {}",
type_name
))
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 {
(registration.deserialize)(&mut erased)
.map_err(<<D as serde::Deserializer<'de>>::Error as serde::de::Error>::custom)
} else {
deserializer.deserialize_any(AnyPropVisiter {
property_type_registry: self.property_type_registry,
current_type_name: self.current_type_name,
@ -216,6 +420,13 @@ impl<'a, 'de> Visitor<'de> for AnyPropVisiter<'a> {
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>
where
E: de::Error,
@ -293,30 +504,57 @@ impl<'a, 'de> Visitor<'de> for AnyPropVisiter<'a> {
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
V: MapAccess<'de>,
{
let mut dynamic_properties = DynamicProperties::default();
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(),
})?;
if key == "type" {
dynamic_properties.type_name = prop
.val::<String>()
.map(|s| s.clone())
.ok_or_else(|| de::Error::custom("type must be a string"))?;
} else {
dynamic_properties.set_box(key, prop);
}
}
Ok(Box::new(dynamic_properties))
Ok(Box::new(visit_map(map, self.property_type_registry, self.current_type_name)?))
}
}
fn visit_map<'a, 'de, V>(
mut map: V,
property_type_registry: &'a PropertyTypeRegistry,
current_type_name: Rc<RefCell<Option<String>>>,
) -> Result<DynamicProperties, V::Error>
where
V: MapAccess<'de>,
{
let mut dynamic_properties = DynamicProperties::map();
let mut type_name: Option<String> = None;
let mut is_seq = false;
// TODO: support seq_value_type
while let Some(key) = map.next_key::<String>()? {
if key == "type" {
type_name = Some(map.next_value()?);
} else if key == "seq_type" {
type_name = Some(map.next_value()?);
is_seq = true;
} else if is_seq {
if key != "data" {
return Err(de::Error::custom(
"seq_type must be immediately followed by a data field",
));
}
dynamic_properties = map.next_value_seed(PropSeqDeserializer {
property_type_registry: property_type_registry,
current_type_name: current_type_name.clone(),
})?;
break;
} else {
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);
}
}
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> {
registration: &'a PropertyTypeRegistration,
}
@ -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)
}
}
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)
}
}

View file

@ -1,6 +1,5 @@
use crate::{impl_property, Property};
use glam::{Mat3, Mat4, Quat, Vec2, Vec3};
use std::any::Any;
impl_property!(Vec2);
impl_property!(Vec3);

View file

@ -1,5 +1,4 @@
use crate::{impl_property, Property};
use legion::prelude::Entity;
use std::any::Any;
impl_property!(Entity);

View file

@ -8,6 +8,11 @@ where
T: Clone + Send + Sync + Serialize + 'static + Array<Item = I>,
I: Send + Sync + Clone + Serialize + 'static,
{
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[inline]
fn any(&self) -> &dyn Any {
self

View file

@ -1,15 +1,91 @@
use crate::{Property, impl_property};
use crate::{impl_property, Properties, PropertiesType, Property, PropertyIter};
use serde::Serialize;
use std::{
any::Any,
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!(bool);
impl_property!(Vec<T> where T: Clone + Send + Sync + Serialize + 'static);
impl_property!(VecDeque<T> where T: Clone + Send + Sync + Serialize + 'static);
impl_property!(SEQUENCE, VecDeque<T> where T: Clone + Send + Sync + Serialize + 'static);
impl_property!(HashSet<T> where T: Clone + Eq + Send + Sync + Hash + Serialize + 'static);
impl_property!(HashMap<K, V> where
K: Clone + Eq + Send + Sync + Hash + Serialize + 'static,
@ -19,7 +95,15 @@ impl_property!(BTreeMap<K, V> where
V: 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 {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[inline]
fn any(&self) -> &dyn Any {
self
@ -69,6 +153,11 @@ impl Property for usize {
}
impl Property for u64 {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[inline]
fn any(&self) -> &dyn Any {
self
@ -118,6 +207,11 @@ impl Property for u64 {
}
impl Property for u32 {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[inline]
fn any(&self) -> &dyn Any {
self
@ -167,6 +261,11 @@ impl Property for u32 {
}
impl Property for u16 {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[inline]
fn any(&self) -> &dyn Any {
self
@ -216,6 +315,11 @@ impl Property for u16 {
}
impl Property for u8 {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[inline]
fn any(&self) -> &dyn Any {
self
@ -265,6 +369,11 @@ impl Property for u8 {
}
impl Property for isize {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[inline]
fn any(&self) -> &dyn Any {
self
@ -314,6 +423,11 @@ impl Property for isize {
}
impl Property for i64 {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[inline]
fn any(&self) -> &dyn Any {
self
@ -363,6 +477,11 @@ impl Property for i64 {
}
impl Property for i32 {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[inline]
fn any(&self) -> &dyn Any {
self
@ -411,8 +530,12 @@ impl Property for i32 {
}
}
impl Property for i16 {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[inline]
fn any(&self) -> &dyn Any {
self
@ -462,6 +585,11 @@ impl Property for i16 {
}
impl Property for i8 {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[inline]
fn any(&self) -> &dyn Any {
self
@ -511,6 +639,11 @@ impl Property for i8 {
}
impl Property for f32 {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[inline]
fn any(&self) -> &dyn Any {
self
@ -544,6 +677,11 @@ impl Property for f32 {
}
impl Property for f64 {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[inline]
fn any(&self) -> &dyn Any {
self
@ -574,4 +712,4 @@ impl Property for f64 {
panic!("prop value is not {}", std::any::type_name::<Self>());
}
}
}
}

View file

@ -1,7 +1,12 @@
use crate::{DynamicProperties, Property, PropertyVal};
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
pub enum PropertiesType {
Map,
Seq,
}
pub trait Properties: Property {
fn type_name(&self) -> &str;
fn prop(&self, name: &str) -> Option<&dyn Property>;
fn prop_mut(&mut self, name: &str) -> Option<&mut 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_len(&self) -> usize;
fn iter_props(&self) -> PropertyIter;
fn properties_type(&self) -> PropertiesType;
fn set_prop(&mut self, name: &str, value: &dyn Property) {
if let Some(prop) = self.prop_mut(name) {
prop.set(value);
@ -18,12 +24,25 @@ pub trait Properties: Property {
}
fn to_dynamic(&self) -> DynamicProperties
{
let mut dynamic_props = DynamicProperties::default();
for (name, prop) in self.iter_props() {
dynamic_props.set_box(name, prop.clone_prop());
}
let mut dynamic_props = match self.properties_type() {
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
},
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
}
}
@ -40,13 +59,12 @@ impl<'a> 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> {
if self.index < self.props.prop_len() {
let prop = self.props.prop_with_index(self.index).unwrap();
let name = self.props.prop_name(self.index).unwrap();
self.index += 1;
Some((name, prop))
Some(prop)
} else {
None
}

View file

@ -2,6 +2,7 @@ use crate::Properties;
use std::any::Any;
pub trait Property: erased_serde::Serialize + Send + Sync + Any + 'static {
fn type_name(&self) -> &str;
fn any(&self) -> &dyn Any;
fn any_mut(&mut self) -> &mut dyn Any;
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> {
None
}
fn is_sequence(&self) -> bool {
false
}
}
erased_serde::serialize_trait_object!(Property);
@ -48,12 +52,17 @@ macro_rules! impl_property {
($ty:ident) => {
impl Property for $ty {
#[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
}
#[inline]
fn any_mut(&mut self) -> &mut dyn Any {
fn any_mut(&mut self) -> &mut dyn std::any::Any {
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)+]) => {
impl_property! {
@as_item
impl<$($args),*> Property for $trait_<$($args),*> where $($args: ::std::any::Any + 'static,)*
$($preds)* {
#[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
}
#[inline]
fn any_mut(&mut self) -> &mut dyn Any {
fn any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
@ -115,10 +174,16 @@ macro_rules! impl_property {
};
(@as_item $i:item) => { $i };
(
SEQUENCE, $trait_:ident < $($args:ident),* $(,)* >
where $($preds:tt)+
) => {
impl_property! {SEQUENCE, @$trait_ [$($args,)*] where [$($preds)*] }
};
(
$trait_:ident < $($args:ident),* $(,)* >
where $($preds:tt)+
) => {
impl_property! { @$trait_ [$($args,)*] where [$($preds)*] }
};
}
}

View file

@ -5,6 +5,7 @@ use std::{any::TypeId, collections::HashMap};
#[derive(Default)]
pub struct PropertyTypeRegistry {
pub registrations: HashMap<String, PropertyTypeRegistration>,
pub short_names: HashMap<String, String>,
}
impl PropertyTypeRegistry {
@ -13,19 +14,31 @@ impl PropertyTypeRegistry {
T: Property + for<'de> Deserialize<'de>,
{
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> {
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)]
pub struct PropertyTypeRegistration {
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 name: &'static str,
}
impl PropertyTypeRegistration {
@ -37,7 +50,8 @@ impl PropertyTypeRegistration {
let property = <T as Deserialize>::deserialize(deserializer)?;
Ok(Box::new(property))
},
name: std::any::type_name::<T>(),
short_name: std::any::type_name::<T>().split("::").last().unwrap(),
}
}
}
}

View file

@ -41,8 +41,8 @@ use self::{
use base_render_graph::{BaseRenderGraphBuilder, BaseRenderGraphConfig};
use bevy_app::{stage, AppBuilder, AppPlugin};
use bevy_component_registry::RegisterComponent;
use bevy_asset::AddAsset;
use bevy_component_registry::RegisterComponent;
use legion::prelude::IntoSystem;
use mesh::mesh_resource_provider_system;
use render_graph::RenderGraph;
@ -78,6 +78,7 @@ impl AppPlugin for RenderPlugin {
.register_component::<Renderable>()
.register_component::<ActiveCamera>()
.register_component::<ActiveCamera2d>()
.register_property_type::<Color>()
.init_resource::<RenderGraph>()
.init_resource::<PipelineAssignments>()
.init_resource::<PipelineCompiler>()

View file

@ -595,7 +595,14 @@ impl<'de, 'a> de::MapAccess<'de> for CommaSeparated<'a, 'de> {
fast_forward_bytes.skip_ws()?;
fast_forward_bytes.consume(":");
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
} else {

View file

@ -4,6 +4,7 @@ use bevy::{
property::{ron::deserialize_dynamic_properties},
};
use serde::{Deserialize, Serialize};
use bevy_property::{PropertiesSeqSerializer, SeqSerializer};
fn main() {
App::build()
@ -26,34 +27,11 @@ pub struct Nested {
b: usize,
}
#[derive(Serialize, Deserialize, Default, Clone)]
#[derive(Serialize, Deserialize, Default, Clone, Property)]
pub struct CustomProperty {
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>) {
let mut test = Test {
a: 1,
@ -71,7 +49,7 @@ fn setup(property_type_registry: Res<PropertyTypeRegistryContext>) {
assert_eq!(test.a, 3);
// DynamicProperties also implements the Properties trait.
let mut patch = DynamicProperties::default();
let mut patch = DynamicProperties::map();
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.
@ -80,7 +58,6 @@ fn setup(property_type_registry: Res<PropertyTypeRegistryContext>) {
assert_eq!(test.a, 4);
// Properties implement the serde Serialize trait. You don't need to derive it yourself!
let ron_string = serialize_ron(&test).unwrap();
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
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>