mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
props: "Seq" properties
This commit is contained in:
parent
e337ff59b8
commit
d2d02f63f6
16 changed files with 656 additions and 213 deletions
6
.vscode/launch.json
vendored
6
.vscode/launch.json
vendored
|
@ -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"
|
||||
}
|
||||
},
|
||||
|
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -16,5 +16,6 @@
|
|||
"rspirv",
|
||||
"rustc",
|
||||
"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 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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::{impl_property, Property};
|
||||
use legion::prelude::Entity;
|
||||
use std::any::Any;
|
||||
|
||||
impl_property!(Entity);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)*] }
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>()
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue