scene: type registry refactor. use short type names when possible
This commit is contained in:
parent
91af49ede3
commit
830565ae2b
@ -6,10 +6,10 @@ edition = "2018"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["headless", "wgpu", "winit"]
|
default = ["headless", "wgpu", "winit"]
|
||||||
headless = ["asset", "component_registry", "core", "derive", "diagnostic", "gltf", "input", "pbr", "property", "render", "scene", "text", "transform", "ui", "window"]
|
headless = ["asset", "type_registry", "core", "derive", "diagnostic", "gltf", "input", "pbr", "property", "render", "scene", "text", "transform", "ui", "window"]
|
||||||
asset = ["bevy_asset"]
|
asset = ["bevy_asset"]
|
||||||
core = ["bevy_core"]
|
core = ["bevy_core"]
|
||||||
component_registry = ["bevy_component_registry"]
|
type_registry = ["bevy_type_registry"]
|
||||||
derive = ["bevy_derive"]
|
derive = ["bevy_derive"]
|
||||||
diagnostic = ["bevy_diagnostic"]
|
diagnostic = ["bevy_diagnostic"]
|
||||||
gltf = ["bevy_gltf"]
|
gltf = ["bevy_gltf"]
|
||||||
@ -36,7 +36,7 @@ members = [
|
|||||||
# bevy
|
# bevy
|
||||||
bevy_app = { path = "crates/bevy_app" }
|
bevy_app = { path = "crates/bevy_app" }
|
||||||
bevy_asset = { path = "crates/bevy_asset", optional = true }
|
bevy_asset = { path = "crates/bevy_asset", optional = true }
|
||||||
bevy_component_registry = { path = "crates/bevy_component_registry", optional = true }
|
bevy_type_registry = { path = "crates/bevy_type_registry", optional = true }
|
||||||
bevy_core = { path = "crates/bevy_core", optional = true }
|
bevy_core = { path = "crates/bevy_core", optional = true }
|
||||||
bevy_derive = { path = "crates/bevy_derive", optional = true }
|
bevy_derive = { path = "crates/bevy_derive", optional = true }
|
||||||
bevy_diagnostic = { path = "crates/bevy_diagnostic", optional = true }
|
bevy_diagnostic = { path = "crates/bevy_diagnostic", optional = true }
|
||||||
|
|||||||
@ -11,7 +11,7 @@ filesystem_watcher = ["notify"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
bevy_app = { path = "../bevy_app" }
|
bevy_app = { path = "../bevy_app" }
|
||||||
bevy_core = { path = "../bevy_core" }
|
bevy_core = { path = "../bevy_core" }
|
||||||
bevy_component_registry = { path = "../bevy_component_registry" }
|
bevy_type_registry = { path = "../bevy_type_registry" }
|
||||||
bevy_property = { path = "../bevy_property" }
|
bevy_property = { path = "../bevy_property" }
|
||||||
legion = { path = "../bevy_legion" }
|
legion = { path = "../bevy_legion" }
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use crate::{
|
|||||||
Handle, HandleId,
|
Handle, HandleId,
|
||||||
};
|
};
|
||||||
use bevy_app::{AppBuilder, Events, FromResources};
|
use bevy_app::{AppBuilder, Events, FromResources};
|
||||||
use bevy_component_registry::RegisterComponent;
|
use bevy_type_registry::RegisterType;
|
||||||
use bevy_core::bytes::GetBytes;
|
use bevy_core::bytes::GetBytes;
|
||||||
use legion::prelude::*;
|
use legion::prelude::*;
|
||||||
use std::{
|
use std::{
|
||||||
|
|||||||
@ -13,7 +13,7 @@ pub use load_request::*;
|
|||||||
pub use loader::*;
|
pub use loader::*;
|
||||||
|
|
||||||
use bevy_app::{AppBuilder, AppPlugin};
|
use bevy_app::{AppBuilder, AppPlugin};
|
||||||
use bevy_component_registry::RegisterComponent;
|
use bevy_type_registry::RegisterType;
|
||||||
use legion::prelude::IntoSystem;
|
use legion::prelude::IntoSystem;
|
||||||
|
|
||||||
pub mod stage {
|
pub mod stage {
|
||||||
|
|||||||
@ -1,85 +0,0 @@
|
|||||||
use bevy_property::{Properties, Property, PropertyTypeRegistry};
|
|
||||||
use legion::{
|
|
||||||
prelude::{Entity, World, Resources},
|
|
||||||
storage::{Component, ComponentResourceSet, ComponentTypeId},
|
|
||||||
};
|
|
||||||
use std::{
|
|
||||||
collections::HashMap,
|
|
||||||
sync::{Arc, RwLock},
|
|
||||||
};
|
|
||||||
use bevy_app::FromResources;
|
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
|
||||||
pub struct PropertyTypeRegistryContext {
|
|
||||||
pub value: Arc<RwLock<PropertyTypeRegistry>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct ComponentRegistryContext {
|
|
||||||
pub value: Arc<RwLock<ComponentRegistry>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct ComponentRegistry {
|
|
||||||
pub registrations: HashMap<ComponentTypeId, ComponentRegistration>,
|
|
||||||
pub short_names: HashMap<String, ComponentTypeId>,
|
|
||||||
pub full_names: HashMap<String, ComponentTypeId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ComponentRegistry {
|
|
||||||
pub fn register<T>(&mut self)
|
|
||||||
where
|
|
||||||
T: Properties + Component + FromResources,
|
|
||||||
{
|
|
||||||
let registration = ComponentRegistration::of::<T>();
|
|
||||||
self.short_names
|
|
||||||
.insert(registration.short_name.to_string(), registration.ty);
|
|
||||||
self.full_names
|
|
||||||
.insert(registration.ty.0.to_string(), registration.ty);
|
|
||||||
self.registrations.insert(registration.ty, registration);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(&self, type_id: &ComponentTypeId) -> Option<&ComponentRegistration> {
|
|
||||||
self.registrations.get(type_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_with_full_name(&self, full_name: &str) -> Option<&ComponentRegistration> {
|
|
||||||
self.full_names
|
|
||||||
.get(full_name)
|
|
||||||
.and_then(|id| self.registrations.get(id))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_with_short_name(&self, short_name: &str) -> Option<&ComponentRegistration> {
|
|
||||||
self.short_names
|
|
||||||
.get(short_name)
|
|
||||||
.and_then(|id| self.registrations.get(id))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ComponentRegistration {
|
|
||||||
pub ty: ComponentTypeId,
|
|
||||||
pub component_add_fn: fn(&mut World, resources: &Resources, Entity, &dyn Property),
|
|
||||||
pub component_properties_fn: fn(&ComponentResourceSet, usize) -> &dyn Properties,
|
|
||||||
pub short_name: &'static str,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ComponentRegistration {
|
|
||||||
pub fn of<T: Properties + Component + FromResources>() -> Self {
|
|
||||||
let ty = ComponentTypeId::of::<T>();
|
|
||||||
Self {
|
|
||||||
ty,
|
|
||||||
component_add_fn: |world: &mut World, resources: &Resources, entity: Entity, property: &dyn Property| {
|
|
||||||
let mut component = T::from_resources(resources);
|
|
||||||
component.apply(property);
|
|
||||||
world.add_component(entity, component).unwrap();
|
|
||||||
},
|
|
||||||
component_properties_fn: |component_resource_set: &ComponentResourceSet,
|
|
||||||
index: usize| {
|
|
||||||
// the type has been looked up by the caller, so this is safe
|
|
||||||
unsafe { &component_resource_set.data_slice::<T>()[index] }
|
|
||||||
},
|
|
||||||
short_name: ty.0.split("::").last().unwrap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
mod component_registry;
|
|
||||||
mod register_component;
|
|
||||||
|
|
||||||
pub use component_registry::*;
|
|
||||||
pub use register_component::*;
|
|
||||||
|
|
||||||
use bevy_app::{AppBuilder, AppPlugin};
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct ComponentRegistryPlugin;
|
|
||||||
|
|
||||||
impl AppPlugin for ComponentRegistryPlugin {
|
|
||||||
fn build(&self, app: &mut AppBuilder) {
|
|
||||||
app.init_resource::<ComponentRegistryContext>()
|
|
||||||
.init_resource::<PropertyTypeRegistryContext>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -6,7 +6,7 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy_app = { path = "../bevy_app" }
|
bevy_app = { path = "../bevy_app" }
|
||||||
bevy_component_registry = { path = "../bevy_component_registry" }
|
bevy_type_registry = { path = "../bevy_type_registry" }
|
||||||
bevy_transform = { path = "../bevy_transform" }
|
bevy_transform = { path = "../bevy_transform" }
|
||||||
legion = { path = "../bevy_legion" }
|
legion = { path = "../bevy_legion" }
|
||||||
glam = { path = "../bevy_glam" }
|
glam = { path = "../bevy_glam" }
|
||||||
|
|||||||
@ -3,7 +3,7 @@ pub mod time;
|
|||||||
pub mod transform;
|
pub mod transform;
|
||||||
|
|
||||||
use bevy_app::{stage, AppBuilder, AppPlugin};
|
use bevy_app::{stage, AppBuilder, AppPlugin};
|
||||||
use bevy_component_registry::RegisterComponent;
|
use bevy_type_registry::RegisterType;
|
||||||
use bevy_transform::{
|
use bevy_transform::{
|
||||||
components::{
|
components::{
|
||||||
Children, LocalToParent, LocalToWorld, NonUniformScale, Rotation, Scale, Translation,
|
Children, LocalToParent, LocalToWorld, NonUniformScale, Rotation, Scale, Translation,
|
||||||
|
|||||||
@ -7,7 +7,7 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
bevy_app = { path = "../bevy_app" }
|
bevy_app = { path = "../bevy_app" }
|
||||||
bevy_asset = { path = "../bevy_asset" }
|
bevy_asset = { path = "../bevy_asset" }
|
||||||
bevy_component_registry = { path = "../bevy_component_registry" }
|
bevy_type_registry = { path = "../bevy_type_registry" }
|
||||||
bevy_core = { path = "../bevy_core" }
|
bevy_core = { path = "../bevy_core" }
|
||||||
bevy_derive = { path = "../bevy_derive" }
|
bevy_derive = { path = "../bevy_derive" }
|
||||||
bevy_render = { path = "../bevy_render" }
|
bevy_render = { path = "../bevy_render" }
|
||||||
|
|||||||
@ -9,7 +9,7 @@ pub use forward_pbr_render_graph::*;
|
|||||||
|
|
||||||
use bevy_app::{stage, AppBuilder, AppPlugin};
|
use bevy_app::{stage, AppBuilder, AppPlugin};
|
||||||
use bevy_asset::AddAsset;
|
use bevy_asset::AddAsset;
|
||||||
use bevy_component_registry::RegisterComponent;
|
use bevy_type_registry::RegisterType;
|
||||||
use bevy_render::{render_graph::RenderGraph, shader};
|
use bevy_render::{render_graph::RenderGraph, shader};
|
||||||
use legion::prelude::IntoSystem;
|
use legion::prelude::IntoSystem;
|
||||||
use light::Light;
|
use light::Light;
|
||||||
|
|||||||
@ -150,6 +150,18 @@ pub fn derive_properties(input: TokenStream) -> TokenStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl #impl_generics #bevy_property_path::DeserializeProperty for #struct_name#ty_generics {
|
||||||
|
fn deserialize(
|
||||||
|
deserializer: &mut dyn #bevy_property_path::erased_serde::Deserializer,
|
||||||
|
property_type_registry: &#bevy_property_path::PropertyTypeRegistry) ->
|
||||||
|
Result<Box<dyn #bevy_property_path::Property>, #bevy_property_path::erased_serde::Error> {
|
||||||
|
use #bevy_property_path::serde::de::DeserializeSeed;
|
||||||
|
let dynamic_properties_deserializer = #bevy_property_path::property_serde::DynamicPropertiesDeserializer::new(property_type_registry);
|
||||||
|
let dynamic_properties: #bevy_property_path::DynamicProperties = dynamic_properties_deserializer.deserialize(deserializer)?;
|
||||||
|
Ok(Box::new(dynamic_properties))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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]
|
#[inline]
|
||||||
fn type_name(&self) -> &str {
|
fn type_name(&self) -> &str {
|
||||||
@ -198,8 +210,8 @@ pub fn derive_properties(input: TokenStream) -> TokenStream {
|
|||||||
Some(self)
|
Some(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serializable(&self) -> #bevy_property_path::property_serde::Serializable {
|
fn serializable<'a>(&'a self, registry: &'a #bevy_property_path::PropertyTypeRegistry) -> #bevy_property_path::property_serde::Serializable<'a> {
|
||||||
#bevy_property_path::property_serde::Serializable::Owned(Box::new(#bevy_property_path::property_serde::MapSerializer::new(self)))
|
#bevy_property_path::property_serde::Serializable::Owned(Box::new(#bevy_property_path::property_serde::MapSerializer::new(self, registry)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn property_type(&self) -> #bevy_property_path::PropertyType {
|
fn property_type(&self) -> #bevy_property_path::PropertyType {
|
||||||
@ -258,10 +270,8 @@ pub fn derive_property(input: TokenStream) -> TokenStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn serializable(&self) -> #bevy_property_path::property_serde::Serializable {
|
fn serializable<'a>(&'a self, registry: &'a #bevy_property_path::PropertyTypeRegistry) -> #bevy_property_path::property_serde::Serializable<'a> {
|
||||||
#bevy_property_path::property_serde::Serializable::Owned(Box::new(#bevy_property_path::property_serde::PropertyValueSerializer {
|
#bevy_property_path::property_serde::Serializable::Owned(Box::new(#bevy_property_path::property_serde::PropertyValueSerializer::new(self, registry)))
|
||||||
property: self,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn property_type(&self) -> #bevy_property_path::PropertyType {
|
fn property_type(&self) -> #bevy_property_path::PropertyType {
|
||||||
@ -274,7 +284,7 @@ pub fn derive_property(input: TokenStream) -> TokenStream {
|
|||||||
deserializer: &mut dyn #bevy_property_path::erased_serde::Deserializer,
|
deserializer: &mut dyn #bevy_property_path::erased_serde::Deserializer,
|
||||||
property_type_registry: &#bevy_property_path::PropertyTypeRegistry) ->
|
property_type_registry: &#bevy_property_path::PropertyTypeRegistry) ->
|
||||||
Result<Box<dyn #bevy_property_path::Property>, #bevy_property_path::erased_serde::Error> {
|
Result<Box<dyn #bevy_property_path::Property>, #bevy_property_path::erased_serde::Error> {
|
||||||
let property = <#struct_name#ty_generics as Deserialize>::deserialize(deserializer)?;
|
let property = <#struct_name#ty_generics as #bevy_property_path::serde::Deserialize>::deserialize(deserializer)?;
|
||||||
Ok(Box::new(property))
|
Ok(Box::new(property))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -343,9 +353,7 @@ pub fn impl_property(input: TokenStream) -> TokenStream {
|
|||||||
quote! { #serialize_fn(self) }
|
quote! { #serialize_fn(self) }
|
||||||
} else {
|
} else {
|
||||||
quote! {
|
quote! {
|
||||||
#bevy_property_path::property_serde::Serializable::Owned(Box::new(#bevy_property_path::property_serde::PropertyValueSerializer {
|
#bevy_property_path::property_serde::Serializable::Owned(Box::new(#bevy_property_path::property_serde::PropertyValueSerializer::new(self, registry)))
|
||||||
property: self,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let deserialize_fn = if let Some(deserialize_fn) = property_def.deserialize_fn {
|
let deserialize_fn = if let Some(deserialize_fn) = property_def.deserialize_fn {
|
||||||
@ -395,7 +403,7 @@ pub fn impl_property(input: TokenStream) -> TokenStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn serializable(&self) -> #bevy_property_path::property_serde::Serializable {
|
fn serializable<'a>(&'a self, registry: &'a #bevy_property_path::PropertyTypeRegistry) -> #bevy_property_path::property_serde::Serializable<'a> {
|
||||||
#serialize_fn
|
#serialize_fn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use crate::{property_serde::Serializable, Properties, Property, PropertyIter, PropertyType};
|
use crate::{property_serde::{DynamicPropertiesSerializer, Serializable, DynamicPropertiesDeserializer}, Properties, Property, PropertyIter, PropertyType, PropertyTypeRegistry, DeserializeProperty};
|
||||||
use std::{any::Any, borrow::Cow, collections::HashMap};
|
use std::{any::Any, borrow::Cow, collections::HashMap};
|
||||||
|
use serde::de::DeserializeSeed;
|
||||||
|
|
||||||
pub struct DynamicProperties {
|
pub struct DynamicProperties {
|
||||||
pub type_name: String,
|
pub type_name: String,
|
||||||
@ -168,11 +169,23 @@ impl Property for DynamicProperties {
|
|||||||
Some(self)
|
Some(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serializable(&self) -> Serializable {
|
fn serializable<'a>(&'a self, registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
|
||||||
Serializable::Borrowed(self)
|
Serializable::Owned(Box::new(DynamicPropertiesSerializer::new(self, registry)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn property_type(&self) -> PropertyType {
|
fn property_type(&self) -> PropertyType {
|
||||||
self.property_type
|
self.property_type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DeserializeProperty for DynamicProperties {
|
||||||
|
fn deserialize(
|
||||||
|
deserializer: &mut dyn erased_serde::Deserializer,
|
||||||
|
property_type_registry: &PropertyTypeRegistry,
|
||||||
|
) -> Result<Box<dyn Property>, erased_serde::Error> {
|
||||||
|
let dynamic_properties_deserializer = DynamicPropertiesDeserializer::new(property_type_registry);
|
||||||
|
let dynamic_properties: DynamicProperties = dynamic_properties_deserializer.deserialize(deserializer)?;
|
||||||
|
Ok(Box::new(dynamic_properties))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use crate::{Property, PropertyType, property_serde::Serializable};
|
use crate::{Property, PropertyType, property_serde::Serializable, PropertyTypeRegistry};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use smallvec::{Array, SmallVec};
|
use smallvec::{Array, SmallVec};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
@ -40,7 +40,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serializable(&self) -> Serializable {
|
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
|
||||||
Serializable::Borrowed(self)
|
Serializable::Borrowed(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
impl_property,
|
impl_property,
|
||||||
property_serde::{SeqSerializer, Serializable},
|
property_serde::{SeqSerializer, Serializable},
|
||||||
Properties, Property, PropertyIter, PropertyType,
|
Properties, Property, PropertyIter, PropertyType, PropertyTypeRegistry,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
@ -79,8 +79,8 @@ where
|
|||||||
Some(self)
|
Some(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serializable(&self) -> Serializable {
|
fn serializable<'a>(&'a self, registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
|
||||||
Serializable::Owned(Box::new(SeqSerializer::new(self)))
|
Serializable::Owned(Box::new(SeqSerializer::new(self, registry)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn property_type(&self) -> PropertyType {
|
fn property_type(&self) -> PropertyType {
|
||||||
@ -134,7 +134,7 @@ impl Property for String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serializable(&self) -> Serializable {
|
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
|
||||||
Serializable::Borrowed(self)
|
Serializable::Borrowed(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,7 +174,7 @@ impl Property for bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serializable(&self) -> Serializable {
|
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
|
||||||
Serializable::Borrowed(self)
|
Serializable::Borrowed(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -232,7 +232,7 @@ impl Property for usize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serializable(&self) -> Serializable {
|
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
|
||||||
Serializable::Borrowed(self)
|
Serializable::Borrowed(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -290,7 +290,7 @@ impl Property for u64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serializable(&self) -> Serializable {
|
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
|
||||||
Serializable::Borrowed(self)
|
Serializable::Borrowed(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -348,7 +348,7 @@ impl Property for u32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serializable(&self) -> Serializable {
|
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
|
||||||
Serializable::Borrowed(self)
|
Serializable::Borrowed(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -406,7 +406,7 @@ impl Property for u16 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serializable(&self) -> Serializable {
|
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
|
||||||
Serializable::Borrowed(self)
|
Serializable::Borrowed(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -464,7 +464,7 @@ impl Property for u8 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serializable(&self) -> Serializable {
|
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
|
||||||
Serializable::Borrowed(self)
|
Serializable::Borrowed(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -522,7 +522,7 @@ impl Property for isize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serializable(&self) -> Serializable {
|
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
|
||||||
Serializable::Borrowed(self)
|
Serializable::Borrowed(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -580,7 +580,7 @@ impl Property for i64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serializable(&self) -> Serializable {
|
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
|
||||||
Serializable::Borrowed(self)
|
Serializable::Borrowed(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -638,7 +638,7 @@ impl Property for i32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serializable(&self) -> Serializable {
|
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
|
||||||
Serializable::Borrowed(self)
|
Serializable::Borrowed(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -696,7 +696,7 @@ impl Property for i16 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serializable(&self) -> Serializable {
|
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
|
||||||
Serializable::Borrowed(self)
|
Serializable::Borrowed(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -754,7 +754,7 @@ impl Property for i8 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serializable(&self) -> Serializable {
|
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
|
||||||
Serializable::Borrowed(self)
|
Serializable::Borrowed(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -796,7 +796,7 @@ impl Property for f32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serializable(&self) -> Serializable {
|
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
|
||||||
Serializable::Borrowed(self)
|
Serializable::Borrowed(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -838,7 +838,7 @@ impl Property for f64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serializable(&self) -> Serializable {
|
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
|
||||||
Serializable::Borrowed(self)
|
Serializable::Borrowed(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,7 @@ pub trait Property: Send + Sync + Any + 'static {
|
|||||||
fn as_properties(&self) -> Option<&dyn Properties> {
|
fn as_properties(&self) -> Option<&dyn Properties> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
fn serializable(&self) -> Serializable;
|
fn serializable<'a>(&'a self, registry: &'a PropertyTypeRegistry) -> Serializable<'a>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait DeserializeProperty {
|
pub trait DeserializeProperty {
|
||||||
|
|||||||
@ -29,14 +29,15 @@ where
|
|||||||
T: Property + Serialize,
|
T: Property + Serialize,
|
||||||
{
|
{
|
||||||
pub property: &'a T,
|
pub property: &'a T,
|
||||||
|
pub registry: &'a PropertyTypeRegistry,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> PropertyValueSerializer<'a, T>
|
impl<'a, T> PropertyValueSerializer<'a, T>
|
||||||
where
|
where
|
||||||
T: Property + Serialize,
|
T: Property + Serialize,
|
||||||
{
|
{
|
||||||
pub fn new(property: &'a T) -> Self {
|
pub fn new(property: &'a T, registry: &'a PropertyTypeRegistry) -> Self {
|
||||||
PropertyValueSerializer { property }
|
PropertyValueSerializer { property, registry }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,20 +50,41 @@ where
|
|||||||
S: serde::Serializer,
|
S: serde::Serializer,
|
||||||
{
|
{
|
||||||
let mut state = serializer.serialize_map(Some(2))?;
|
let mut state = serializer.serialize_map(Some(2))?;
|
||||||
state.serialize_entry(TYPE_FIELD, self.property.type_name())?;
|
state.serialize_entry(TYPE_FIELD, format_type_name(self.registry, self.property.type_name()))?;
|
||||||
state.serialize_entry(VALUE_FIELD, self.property)?;
|
state.serialize_entry(VALUE_FIELD, self.property)?;
|
||||||
state.end()
|
state.end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for DynamicProperties {
|
pub struct DynamicPropertiesSerializer<'a> {
|
||||||
|
pub dynamic_properties: &'a DynamicProperties,
|
||||||
|
pub registry: &'a PropertyTypeRegistry,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DynamicPropertiesSerializer<'a> {
|
||||||
|
pub fn new(
|
||||||
|
dynamic_properties: &'a DynamicProperties,
|
||||||
|
registry: &'a PropertyTypeRegistry,
|
||||||
|
) -> Self {
|
||||||
|
DynamicPropertiesSerializer {
|
||||||
|
dynamic_properties,
|
||||||
|
registry,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Serialize for DynamicPropertiesSerializer<'a> {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: serde::Serializer,
|
S: serde::Serializer,
|
||||||
{
|
{
|
||||||
match self.property_type {
|
match self.dynamic_properties.property_type {
|
||||||
PropertyType::Map => MapSerializer::new(self).serialize(serializer),
|
PropertyType::Map => {
|
||||||
PropertyType::Seq => SeqSerializer::new(self).serialize(serializer),
|
MapSerializer::new(self.dynamic_properties, self.registry).serialize(serializer)
|
||||||
|
}
|
||||||
|
PropertyType::Seq => {
|
||||||
|
SeqSerializer::new(self.dynamic_properties, self.registry).serialize(serializer)
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(serde::ser::Error::custom(
|
return Err(serde::ser::Error::custom(
|
||||||
"DynamicProperties cannot be Value type",
|
"DynamicProperties cannot be Value type",
|
||||||
@ -74,25 +96,40 @@ impl Serialize for DynamicProperties {
|
|||||||
|
|
||||||
pub struct MapSerializer<'a> {
|
pub struct MapSerializer<'a> {
|
||||||
pub properties: &'a dyn Properties,
|
pub properties: &'a dyn Properties,
|
||||||
|
pub registry: &'a PropertyTypeRegistry,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> MapSerializer<'a> {
|
impl<'a> MapSerializer<'a> {
|
||||||
pub fn new(properties: &'a dyn Properties) -> Self {
|
pub fn new(properties: &'a dyn Properties, registry: &'a PropertyTypeRegistry) -> Self {
|
||||||
MapSerializer { properties }
|
MapSerializer {
|
||||||
|
properties,
|
||||||
|
registry,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn format_type_name<'a>(registry: &'a PropertyTypeRegistry, type_name: &'a str) -> &'a str {
|
||||||
|
registry
|
||||||
|
.format_type_name(type_name)
|
||||||
|
.unwrap_or_else(|| type_name)
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Serialize for MapSerializer<'a> {
|
impl<'a> Serialize for MapSerializer<'a> {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: serde::Serializer,
|
S: serde::Serializer,
|
||||||
{
|
{
|
||||||
let mut state = serializer.serialize_map(Some(2))?;
|
let mut state = serializer.serialize_map(Some(2))?;
|
||||||
state.serialize_entry(TYPE_FIELD, self.properties.type_name())?;
|
|
||||||
|
state.serialize_entry(
|
||||||
|
TYPE_FIELD,
|
||||||
|
format_type_name(self.registry, self.properties.type_name()),
|
||||||
|
)?;
|
||||||
state.serialize_entry(
|
state.serialize_entry(
|
||||||
MAP_FIELD,
|
MAP_FIELD,
|
||||||
&MapValueSerializer {
|
&MapValueSerializer {
|
||||||
properties: self.properties,
|
properties: self.properties,
|
||||||
|
registry: self.registry,
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
state.end()
|
state.end()
|
||||||
@ -101,6 +138,7 @@ impl<'a> Serialize for MapSerializer<'a> {
|
|||||||
|
|
||||||
pub struct MapValueSerializer<'a> {
|
pub struct MapValueSerializer<'a> {
|
||||||
pub properties: &'a dyn Properties,
|
pub properties: &'a dyn Properties,
|
||||||
|
pub registry: &'a PropertyTypeRegistry,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Serialize for MapValueSerializer<'a> {
|
impl<'a> Serialize for MapValueSerializer<'a> {
|
||||||
@ -111,7 +149,7 @@ impl<'a> Serialize for MapValueSerializer<'a> {
|
|||||||
let mut state = serializer.serialize_map(Some(self.properties.prop_len()))?;
|
let mut state = serializer.serialize_map(Some(self.properties.prop_len()))?;
|
||||||
for (index, property) in self.properties.iter_props().enumerate() {
|
for (index, property) in self.properties.iter_props().enumerate() {
|
||||||
let name = self.properties.prop_name(index).unwrap();
|
let name = self.properties.prop_name(index).unwrap();
|
||||||
state.serialize_entry(name, property.serializable().borrow())?;
|
state.serialize_entry(name, property.serializable(self.registry).borrow())?;
|
||||||
}
|
}
|
||||||
state.end()
|
state.end()
|
||||||
}
|
}
|
||||||
@ -119,11 +157,15 @@ impl<'a> Serialize for MapValueSerializer<'a> {
|
|||||||
|
|
||||||
pub struct SeqSerializer<'a> {
|
pub struct SeqSerializer<'a> {
|
||||||
pub properties: &'a dyn Properties,
|
pub properties: &'a dyn Properties,
|
||||||
|
pub registry: &'a PropertyTypeRegistry,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SeqSerializer<'a> {
|
impl<'a> SeqSerializer<'a> {
|
||||||
pub fn new(properties: &'a dyn Properties) -> Self {
|
pub fn new(properties: &'a dyn Properties, registry: &'a PropertyTypeRegistry) -> Self {
|
||||||
SeqSerializer { properties }
|
SeqSerializer {
|
||||||
|
properties,
|
||||||
|
registry,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,11 +175,12 @@ impl<'a> Serialize for SeqSerializer<'a> {
|
|||||||
S: serde::Serializer,
|
S: serde::Serializer,
|
||||||
{
|
{
|
||||||
let mut state = serializer.serialize_map(Some(2))?;
|
let mut state = serializer.serialize_map(Some(2))?;
|
||||||
state.serialize_entry(TYPE_FIELD, self.properties.type_name())?;
|
state.serialize_entry(TYPE_FIELD, format_type_name(self.registry, self.properties.type_name()))?;
|
||||||
state.serialize_entry(
|
state.serialize_entry(
|
||||||
SEQ_FIELD,
|
SEQ_FIELD,
|
||||||
&SeqValueSerializer {
|
&SeqValueSerializer {
|
||||||
properties: self.properties,
|
properties: self.properties,
|
||||||
|
registry: self.registry,
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
state.end()
|
state.end()
|
||||||
@ -146,6 +189,7 @@ impl<'a> Serialize for SeqSerializer<'a> {
|
|||||||
|
|
||||||
pub struct SeqValueSerializer<'a> {
|
pub struct SeqValueSerializer<'a> {
|
||||||
pub properties: &'a dyn Properties,
|
pub properties: &'a dyn Properties,
|
||||||
|
pub registry: &'a PropertyTypeRegistry,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Serialize for SeqValueSerializer<'a> {
|
impl<'a> Serialize for SeqValueSerializer<'a> {
|
||||||
@ -155,13 +199,12 @@ impl<'a> Serialize for SeqValueSerializer<'a> {
|
|||||||
{
|
{
|
||||||
let mut state = serializer.serialize_seq(Some(self.properties.prop_len()))?;
|
let mut state = serializer.serialize_seq(Some(self.properties.prop_len()))?;
|
||||||
for prop in self.properties.iter_props() {
|
for prop in self.properties.iter_props() {
|
||||||
state.serialize_element(prop.serializable().borrow())?;
|
state.serialize_element(prop.serializable(self.registry).borrow())?;
|
||||||
}
|
}
|
||||||
state.end()
|
state.end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub struct DynamicPropertiesDeserializer<'a> {
|
pub struct DynamicPropertiesDeserializer<'a> {
|
||||||
registry: &'a PropertyTypeRegistry,
|
registry: &'a PropertyTypeRegistry,
|
||||||
}
|
}
|
||||||
@ -200,12 +243,11 @@ impl<'a, 'de> Visitor<'de> for DynamicPropertiesVisiter<'a> {
|
|||||||
{
|
{
|
||||||
match visit_map(map, self.registry)? {
|
match visit_map(map, self.registry)? {
|
||||||
DynamicPropertiesOrProperty::DynamicProperties(value) => Ok(value),
|
DynamicPropertiesOrProperty::DynamicProperties(value) => Ok(value),
|
||||||
_ => Err(de::Error::custom("Expected DynamicProperties"))
|
_ => Err(de::Error::custom("Expected DynamicProperties")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub struct PropertyDeserializer<'a> {
|
pub struct PropertyDeserializer<'a> {
|
||||||
type_name: Option<&'a str>,
|
type_name: Option<&'a str>,
|
||||||
registry: &'a PropertyTypeRegistry,
|
registry: &'a PropertyTypeRegistry,
|
||||||
@ -221,9 +263,7 @@ impl<'a, 'de> DeserializeSeed<'de> for PropertyDeserializer<'a> {
|
|||||||
let registration = self.registry.get(type_name).ok_or_else(|| {
|
let registration = self.registry.get(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);
|
registration.deserialize(deserializer, self.registry)
|
||||||
(registration.deserialize)(&mut erased, self.registry)
|
|
||||||
.map_err(<<D as serde::Deserializer<'de>>::Error as serde::de::Error>::custom)
|
|
||||||
} else {
|
} else {
|
||||||
deserializer.deserialize_any(AnyPropVisiter {
|
deserializer.deserialize_any(AnyPropVisiter {
|
||||||
registry: self.registry,
|
registry: self.registry,
|
||||||
|
|||||||
@ -1,10 +1,14 @@
|
|||||||
use crate::{DeserializeProperty, Property};
|
use crate::{DeserializeProperty, Property};
|
||||||
use std::{any::TypeId, collections::HashMap};
|
use std::{
|
||||||
|
any::TypeId,
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct PropertyTypeRegistry {
|
pub struct PropertyTypeRegistry {
|
||||||
pub registrations: HashMap<String, PropertyTypeRegistration>,
|
registrations: HashMap<String, PropertyTypeRegistration>,
|
||||||
pub short_names: HashMap<String, String>,
|
short_names: HashMap<String, String>,
|
||||||
|
ambigous_names: HashSet<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PropertyTypeRegistry {
|
impl PropertyTypeRegistry {
|
||||||
@ -13,44 +17,97 @@ impl PropertyTypeRegistry {
|
|||||||
T: Property + DeserializeProperty,
|
T: Property + DeserializeProperty,
|
||||||
{
|
{
|
||||||
let registration = PropertyTypeRegistration::of::<T>();
|
let registration = PropertyTypeRegistration::of::<T>();
|
||||||
self.short_names
|
self.add_registration(registration);
|
||||||
.insert(registration.short_name.to_string(), registration.name.to_string());
|
}
|
||||||
|
|
||||||
|
fn add_registration(&mut self, registration: PropertyTypeRegistration) {
|
||||||
|
let short_name = registration.short_name.to_string();
|
||||||
|
if self.short_names.contains_key(&short_name) || self.ambigous_names.contains(&short_name) {
|
||||||
|
// name is ambiguous. fall back to long names for all ambiguous types
|
||||||
|
self.short_names.remove(&short_name);
|
||||||
|
self.ambigous_names.insert(short_name);
|
||||||
|
} else {
|
||||||
|
self.short_names
|
||||||
|
.insert(short_name, registration.name.to_string());
|
||||||
|
}
|
||||||
self.registrations
|
self.registrations
|
||||||
.insert(registration.name.to_string(), registration);
|
.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)
|
if let Some(long_name) = self.short_names.get(type_name) {
|
||||||
|
self.registrations.get(long_name)
|
||||||
|
} else {
|
||||||
|
self.registrations.get(type_name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_short(&self, short_type_name: &str) -> Option<&PropertyTypeRegistration> {
|
pub fn format_type_name(&self, type_name: &str) -> Option<&str> {
|
||||||
|
self.get(type_name).map(|registration| {
|
||||||
|
if self.short_names.contains_key(®istration.short_name) {
|
||||||
|
®istration.short_name
|
||||||
|
} else {
|
||||||
|
registration.name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_with_short_name(&self, short_type_name: &str) -> Option<&PropertyTypeRegistration> {
|
||||||
self.short_names
|
self.short_names
|
||||||
.get(short_type_name)
|
.get(short_type_name)
|
||||||
.and_then(|name| self.registrations.get(name))
|
.and_then(|name| self.registrations.get(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_with_full_name(&self, type_name: &str) -> Option<&PropertyTypeRegistration> {
|
||||||
|
self.registrations.get(type_name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct PropertyTypeRegistration {
|
pub struct PropertyTypeRegistration {
|
||||||
pub ty: TypeId,
|
pub ty: TypeId,
|
||||||
pub deserialize: fn(
|
deserialize_fn: fn(
|
||||||
deserializer: &mut dyn erased_serde::Deserializer,
|
deserializer: &mut dyn erased_serde::Deserializer,
|
||||||
property_type_registry: &PropertyTypeRegistry,
|
property_type_registry: &PropertyTypeRegistry,
|
||||||
) -> Result<Box<dyn Property>, erased_serde::Error>,
|
) -> Result<Box<dyn Property>, erased_serde::Error>,
|
||||||
pub short_name: &'static str,
|
pub short_name: String,
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PropertyTypeRegistration {
|
impl PropertyTypeRegistration {
|
||||||
pub fn of<T: Property + DeserializeProperty>() -> Self {
|
pub fn of<T: Property + DeserializeProperty>() -> Self {
|
||||||
let ty = TypeId::of::<T>();
|
let ty = TypeId::of::<T>();
|
||||||
|
let type_name = std::any::type_name::<T>();
|
||||||
Self {
|
Self {
|
||||||
ty,
|
ty,
|
||||||
deserialize: |deserializer: &mut dyn erased_serde::Deserializer, property_type_registry: &PropertyTypeRegistry| {
|
deserialize_fn:
|
||||||
T::deserialize(deserializer, property_type_registry)
|
|deserializer: &mut dyn erased_serde::Deserializer,
|
||||||
},
|
property_type_registry: &PropertyTypeRegistry| {
|
||||||
name: std::any::type_name::<T>(),
|
T::deserialize(deserializer, property_type_registry)
|
||||||
short_name: std::any::type_name::<T>().split("::").last().unwrap(),
|
},
|
||||||
|
name: type_name,
|
||||||
|
short_name: Self::get_short_name(type_name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_short_name(full_name: &str) -> String {
|
||||||
|
full_name
|
||||||
|
.split("<")
|
||||||
|
.map(|p| p.split("::").last().unwrap().to_string())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join("<")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize<'de, D>(
|
||||||
|
&self,
|
||||||
|
deserializer: D,
|
||||||
|
registry: &PropertyTypeRegistry,
|
||||||
|
) -> Result<Box<dyn Property>, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let mut erased = erased_serde::Deserializer::erase(deserializer);
|
||||||
|
(self.deserialize_fn)(&mut erased, registry)
|
||||||
|
.map_err(<<D as serde::Deserializer<'de>>::Error as serde::de::Error>::custom)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ edition = "2018"
|
|||||||
# bevy
|
# bevy
|
||||||
bevy_app = { path = "../bevy_app" }
|
bevy_app = { path = "../bevy_app" }
|
||||||
bevy_asset = { path = "../bevy_asset" }
|
bevy_asset = { path = "../bevy_asset" }
|
||||||
bevy_component_registry = { path = "../bevy_component_registry" }
|
bevy_type_registry = { path = "../bevy_type_registry" }
|
||||||
bevy_core = { path = "../bevy_core" }
|
bevy_core = { path = "../bevy_core" }
|
||||||
bevy_derive = { path = "../bevy_derive" }
|
bevy_derive = { path = "../bevy_derive" }
|
||||||
bevy_property = { path = "../bevy_property" }
|
bevy_property = { path = "../bevy_property" }
|
||||||
|
|||||||
@ -42,7 +42,7 @@ 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_asset::AddAsset;
|
use bevy_asset::AddAsset;
|
||||||
use bevy_component_registry::RegisterComponent;
|
use bevy_type_registry::RegisterType;
|
||||||
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;
|
||||||
|
|||||||
@ -7,7 +7,7 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
bevy_app = { path = "../bevy_app" }
|
bevy_app = { path = "../bevy_app" }
|
||||||
bevy_asset = { path = "../bevy_asset" }
|
bevy_asset = { path = "../bevy_asset" }
|
||||||
bevy_component_registry = { path = "../bevy_component_registry" }
|
bevy_type_registry = { path = "../bevy_type_registry" }
|
||||||
bevy_property = { path = "../bevy_property" }
|
bevy_property = { path = "../bevy_property" }
|
||||||
legion = { path = "../bevy_legion", features = ["serialize"] }
|
legion = { path = "../bevy_legion", features = ["serialize"] }
|
||||||
serde = { version = "1.0", features = ["derive"]}
|
serde = { version = "1.0", features = ["derive"]}
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use bevy_component_registry::ComponentRegistry;
|
use bevy_type_registry::ComponentRegistry;
|
||||||
use bevy_property::DynamicProperties;
|
use bevy_property::{PropertyTypeRegistry, DynamicProperties};
|
||||||
use legion::prelude::{Resources, World};
|
use legion::prelude::{Resources, World};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::num::Wrapping;
|
use std::num::Wrapping;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
use crate::serde::SceneSerializer;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Scene {
|
pub struct Scene {
|
||||||
pub entities: Vec<Entity>,
|
pub entities: Vec<Entity>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
|
||||||
pub struct Entity {
|
pub struct Entity {
|
||||||
pub id: u32,
|
pub entity: u32,
|
||||||
pub components: Vec<DynamicProperties>,
|
pub components: Vec<DynamicProperties>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,12 +40,12 @@ impl Scene {
|
|||||||
for (index, entity) in component_storage.entities().iter().enumerate() {
|
for (index, entity) in component_storage.entities().iter().enumerate() {
|
||||||
if index == entities.len() {
|
if index == entities.len() {
|
||||||
entities.push(Entity {
|
entities.push(Entity {
|
||||||
id: entity.index(),
|
entity: entity.index(),
|
||||||
components: Vec::new(),
|
components: Vec::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let properties = (component_registration.component_properties_fn)(
|
let properties = component_registration.get_component_properties(
|
||||||
&component_resource_set,
|
&component_resource_set,
|
||||||
index,
|
index,
|
||||||
);
|
);
|
||||||
@ -72,18 +72,18 @@ impl Scene {
|
|||||||
world.entity_allocator.push_next_ids(
|
world.entity_allocator.push_next_ids(
|
||||||
self.entities
|
self.entities
|
||||||
.iter()
|
.iter()
|
||||||
.map(|e| legion::prelude::Entity::new(e.id, Wrapping(1))),
|
.map(|e| legion::prelude::Entity::new(e.entity, Wrapping(1))),
|
||||||
);
|
);
|
||||||
for scene_entity in self.entities.iter() {
|
for scene_entity in self.entities.iter() {
|
||||||
// TODO: use EntityEntry when legion refactor is finished
|
// TODO: use EntityEntry when legion refactor is finished
|
||||||
let entity = world.insert((), vec![()])[0];
|
let entity = world.insert((), vec![()])[0];
|
||||||
for component in scene_entity.components.iter() {
|
for component in scene_entity.components.iter() {
|
||||||
let component_registration = component_registry
|
let component_registration = component_registry
|
||||||
.get_with_full_name(&component.type_name)
|
.get_with_name(&component.type_name)
|
||||||
.ok_or_else(|| SceneAddError::UnregisteredComponent {
|
.ok_or_else(|| SceneAddError::UnregisteredComponent {
|
||||||
type_name: component.type_name.to_string(),
|
type_name: component.type_name.to_string(),
|
||||||
})?;
|
})?;
|
||||||
(component_registration.component_add_fn)(world, resources, entity, component);
|
component_registration.add_component_to_entity(world, resources, entity, component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,14 +91,15 @@ impl Scene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: move to AssetSaver when it is implemented
|
// TODO: move to AssetSaver when it is implemented
|
||||||
pub fn serialize_ron(&self) -> Result<String, ron::Error> {
|
pub fn serialize_ron(&self, registry: &PropertyTypeRegistry) -> Result<String, ron::Error> {
|
||||||
let pretty_config = ron::ser::PrettyConfig::default()
|
let pretty_config = ron::ser::PrettyConfig::default()
|
||||||
.with_decimal_floats(true)
|
.with_decimal_floats(true)
|
||||||
.with_indentor(" ".to_string())
|
.with_indentor(" ".to_string())
|
||||||
.with_new_line("\n".to_string());
|
.with_new_line("\n".to_string());
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
let mut serializer = ron::ser::Serializer::new(&mut buf, Some(pretty_config), true)?;
|
let mut serializer = ron::ser::Serializer::new(&mut buf, Some(pretty_config), false)?;
|
||||||
self.serialize(&mut serializer)?;
|
let scene_serializer = SceneSerializer::new(self, registry);
|
||||||
|
scene_serializer.serialize(&mut serializer)?;
|
||||||
Ok(String::from_utf8(buf).unwrap())
|
Ok(String::from_utf8(buf).unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,27 +2,28 @@ use crate::{serde::SceneDeserializer, Scene};
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use bevy_app::FromResources;
|
use bevy_app::FromResources;
|
||||||
use bevy_asset::AssetLoader;
|
use bevy_asset::AssetLoader;
|
||||||
use bevy_component_registry::PropertyTypeRegistryContext;
|
use bevy_property::PropertyTypeRegistry;
|
||||||
use legion::prelude::Resources;
|
use legion::prelude::Resources;
|
||||||
use serde::de::DeserializeSeed;
|
use serde::de::DeserializeSeed;
|
||||||
use std::path::Path;
|
use std::{sync::{Arc, RwLock}, path::Path};
|
||||||
|
use bevy_type_registry::TypeRegistry;
|
||||||
|
|
||||||
pub struct SceneLoader {
|
pub struct SceneLoader {
|
||||||
property_type_registry: PropertyTypeRegistryContext,
|
property_type_registry: Arc<RwLock<PropertyTypeRegistry>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromResources for SceneLoader {
|
impl FromResources for SceneLoader {
|
||||||
fn from_resources(resources: &Resources) -> Self {
|
fn from_resources(resources: &Resources) -> Self {
|
||||||
let property_type_registry = resources.get::<PropertyTypeRegistryContext>().unwrap();
|
let type_registry = resources.get::<TypeRegistry>().unwrap();
|
||||||
SceneLoader {
|
SceneLoader {
|
||||||
property_type_registry: property_type_registry.clone(),
|
property_type_registry: type_registry.property.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AssetLoader<Scene> for SceneLoader {
|
impl AssetLoader<Scene> for SceneLoader {
|
||||||
fn from_bytes(&self, _asset_path: &Path, bytes: Vec<u8>) -> Result<Scene> {
|
fn from_bytes(&self, _asset_path: &Path, bytes: Vec<u8>) -> Result<Scene> {
|
||||||
let registry = self.property_type_registry.value.read().unwrap();
|
let registry = self.property_type_registry.read().unwrap();
|
||||||
let mut deserializer = ron::de::Deserializer::from_bytes(&bytes).unwrap();
|
let mut deserializer = ron::de::Deserializer::from_bytes(&bytes).unwrap();
|
||||||
let scene_deserializer = SceneDeserializer {
|
let scene_deserializer = SceneDeserializer {
|
||||||
property_type_registry: ®istry,
|
property_type_registry: ®istry,
|
||||||
|
|||||||
@ -1,22 +1,84 @@
|
|||||||
use crate::{Entity, Scene};
|
use crate::{Entity, Scene};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use bevy_property::{
|
use bevy_property::{
|
||||||
property_serde::DynamicPropertiesDeserializer, DynamicProperties, PropertyTypeRegistry,
|
property_serde::{DynamicPropertiesSerializer, DynamicPropertiesDeserializer}, DynamicProperties, PropertyTypeRegistry,
|
||||||
};
|
};
|
||||||
use serde::{
|
use serde::{
|
||||||
de::{DeserializeSeed, Error, MapAccess, SeqAccess, Visitor},
|
de::{DeserializeSeed, Error, MapAccess, SeqAccess, Visitor},
|
||||||
|
ser::{SerializeSeq, SerializeStruct},
|
||||||
Deserialize, Serialize,
|
Deserialize, Serialize,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl Serialize for Scene {
|
pub struct SceneSerializer<'a> {
|
||||||
|
pub scene: &'a Scene,
|
||||||
|
pub registry: &'a PropertyTypeRegistry,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> SceneSerializer<'a> {
|
||||||
|
pub fn new(scene: &'a Scene, registry: &'a PropertyTypeRegistry) -> Self {
|
||||||
|
SceneSerializer {
|
||||||
|
scene,
|
||||||
|
registry,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Serialize for SceneSerializer<'a> {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: serde::Serializer,
|
S: serde::Serializer,
|
||||||
{
|
{
|
||||||
self.entities.serialize(serializer)
|
let mut state = serializer.serialize_seq(Some(self.scene.entities.len()))?;
|
||||||
|
for entity in self.scene.entities.iter() {
|
||||||
|
state.serialize_element(&EntitySerializer {
|
||||||
|
entity,
|
||||||
|
registry: self.registry,
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
state.end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct EntitySerializer<'a> {
|
||||||
|
pub entity: &'a Entity,
|
||||||
|
pub registry: &'a PropertyTypeRegistry,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Serialize for EntitySerializer<'a> {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
let mut state = serializer.serialize_struct(ENTITY_STRUCT, 2)?;
|
||||||
|
state.serialize_field(ENTITY_FIELD_ENTITY, &self.entity.entity)?;
|
||||||
|
state.serialize_field(ENTITY_FIELD_COMPONENTS, &ComponentsSerializer {
|
||||||
|
components: &self.entity.components,
|
||||||
|
registry: self.registry,
|
||||||
|
})?;
|
||||||
|
state.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct ComponentsSerializer<'a> {
|
||||||
|
pub components: &'a [DynamicProperties],
|
||||||
|
pub registry: &'a PropertyTypeRegistry,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Serialize for ComponentsSerializer<'a> {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
let mut state = serializer.serialize_seq(Some(self.components.len()))?;
|
||||||
|
for dynamic_properties in self.components.iter() {
|
||||||
|
state.serialize_element(&DynamicPropertiesSerializer::new(dynamic_properties, self.registry))?;
|
||||||
|
}
|
||||||
|
state.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pub struct SceneDeserializer<'a> {
|
pub struct SceneDeserializer<'a> {
|
||||||
pub property_type_registry: &'a PropertyTypeRegistry,
|
pub property_type_registry: &'a PropertyTypeRegistry,
|
||||||
}
|
}
|
||||||
@ -72,8 +134,8 @@ impl<'a, 'de> DeserializeSeed<'de> for SceneEntityDeserializer<'a> {
|
|||||||
D: serde::Deserializer<'de>,
|
D: serde::Deserializer<'de>,
|
||||||
{
|
{
|
||||||
deserializer.deserialize_struct(
|
deserializer.deserialize_struct(
|
||||||
"Entity",
|
ENTITY_STRUCT,
|
||||||
&["id", "components"],
|
&[ENTITY_FIELD_ENTITY, ENTITY_FIELD_COMPONENTS],
|
||||||
SceneEntityVisiter {
|
SceneEntityVisiter {
|
||||||
registry: self.property_type_registry,
|
registry: self.property_type_registry,
|
||||||
},
|
},
|
||||||
@ -84,11 +146,12 @@ impl<'a, 'de> DeserializeSeed<'de> for SceneEntityDeserializer<'a> {
|
|||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(field_identifier, rename_all = "lowercase")]
|
#[serde(field_identifier, rename_all = "lowercase")]
|
||||||
enum EntityField {
|
enum EntityField {
|
||||||
Id,
|
Entity,
|
||||||
Components,
|
Components,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ENTITY_FIELD_ID: &str = "id";
|
pub const ENTITY_STRUCT: &str = "Entity";
|
||||||
|
pub const ENTITY_FIELD_ENTITY: &str = "entity";
|
||||||
pub const ENTITY_FIELD_COMPONENTS: &str = "components";
|
pub const ENTITY_FIELD_COMPONENTS: &str = "components";
|
||||||
|
|
||||||
struct SceneEntityVisiter<'a> {
|
struct SceneEntityVisiter<'a> {
|
||||||
@ -109,9 +172,9 @@ impl<'a, 'de> Visitor<'de> for SceneEntityVisiter<'a> {
|
|||||||
let mut components = None;
|
let mut components = None;
|
||||||
while let Some(key) = map.next_key()? {
|
while let Some(key) = map.next_key()? {
|
||||||
match key {
|
match key {
|
||||||
EntityField::Id => {
|
EntityField::Entity => {
|
||||||
if id.is_some() {
|
if id.is_some() {
|
||||||
return Err(Error::duplicate_field(ENTITY_FIELD_ID));
|
return Err(Error::duplicate_field(ENTITY_FIELD_ENTITY));
|
||||||
}
|
}
|
||||||
id = Some(map.next_value::<u32>()?);
|
id = Some(map.next_value::<u32>()?);
|
||||||
}
|
}
|
||||||
@ -129,13 +192,13 @@ impl<'a, 'de> Visitor<'de> for SceneEntityVisiter<'a> {
|
|||||||
|
|
||||||
let entity = id
|
let entity = id
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.ok_or_else(|| Error::missing_field(ENTITY_FIELD_ID))?;
|
.ok_or_else(|| Error::missing_field(ENTITY_FIELD_ENTITY))?;
|
||||||
|
|
||||||
let components = components
|
let components = components
|
||||||
.take()
|
.take()
|
||||||
.ok_or_else(|| Error::missing_field(ENTITY_FIELD_COMPONENTS))?;
|
.ok_or_else(|| Error::missing_field(ENTITY_FIELD_COMPONENTS))?;
|
||||||
Ok(Entity {
|
Ok(Entity {
|
||||||
id: *entity,
|
entity: *entity,
|
||||||
components,
|
components,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "bevy_component_registry"
|
name = "bevy_type_registry"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Carter Anderson <mcanders1@gmail.com>"]
|
authors = ["Carter Anderson <mcanders1@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
18
crates/bevy_type_registry/src/lib.rs
Normal file
18
crates/bevy_type_registry/src/lib.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
mod type_registry;
|
||||||
|
mod register_type;
|
||||||
|
|
||||||
|
pub use type_registry::*;
|
||||||
|
pub use register_type::*;
|
||||||
|
|
||||||
|
use bevy_app::{AppBuilder, AppPlugin};
|
||||||
|
use bevy_property::DynamicProperties;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct TypeRegistryPlugin;
|
||||||
|
|
||||||
|
impl AppPlugin for TypeRegistryPlugin {
|
||||||
|
fn build(&self, app: &mut AppBuilder) {
|
||||||
|
app.init_resource::<TypeRegistry>()
|
||||||
|
.register_property_type::<DynamicProperties>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,43 +1,43 @@
|
|||||||
|
|
||||||
use bevy_property::{Property, Properties, DeserializeProperty};
|
use bevy_property::{Property, Properties, DeserializeProperty};
|
||||||
use legion::storage::Component;
|
use legion::storage::Component;
|
||||||
use crate::{PropertyTypeRegistryContext, ComponentRegistryContext};
|
|
||||||
use bevy_app::{FromResources, AppBuilder};
|
use bevy_app::{FromResources, AppBuilder};
|
||||||
|
use crate::TypeRegistry;
|
||||||
|
|
||||||
pub trait RegisterComponent {
|
pub trait RegisterType {
|
||||||
fn register_component<T>(&mut self) -> &mut Self
|
fn register_component<T>(&mut self) -> &mut Self
|
||||||
where
|
where
|
||||||
T: Properties + Component + FromResources;
|
T: Properties + DeserializeProperty + Component + FromResources;
|
||||||
fn register_property_type<T>(&mut self) -> &mut Self
|
fn register_property_type<T>(&mut self) -> &mut Self
|
||||||
where
|
where
|
||||||
T: Property + DeserializeProperty;
|
T: Property + DeserializeProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegisterComponent for AppBuilder {
|
impl RegisterType for AppBuilder {
|
||||||
fn register_component<T>(&mut self) -> &mut Self
|
fn register_component<T>(&mut self) -> &mut Self
|
||||||
where
|
where
|
||||||
T: Properties + Component + FromResources,
|
T: Properties + DeserializeProperty + Component + FromResources,
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
let registry_context = self
|
let type_registry = self
|
||||||
.resources()
|
.resources()
|
||||||
.get_mut::<ComponentRegistryContext>()
|
.get_mut::<TypeRegistry>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
registry_context.value.write().unwrap().register::<T>();
|
type_registry.component.write().unwrap().register::<T>();
|
||||||
|
type_registry.property.write().unwrap().register::<T>();
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_property_type<T>(&mut self) -> &mut Self
|
fn register_property_type<T>(&mut self) -> &mut Self
|
||||||
where
|
where
|
||||||
T: Property + DeserializeProperty,
|
T: Property + DeserializeProperty {
|
||||||
{
|
|
||||||
{
|
{
|
||||||
let registry_context = self
|
let type_registry = self
|
||||||
.resources()
|
.resources()
|
||||||
.get_mut::<PropertyTypeRegistryContext>()
|
.get_mut::<TypeRegistry>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
registry_context.value.write().unwrap().register::<T>();
|
type_registry.property.write().unwrap().register::<T>();
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
123
crates/bevy_type_registry/src/type_registry.rs
Normal file
123
crates/bevy_type_registry/src/type_registry.rs
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
use bevy_app::FromResources;
|
||||||
|
use bevy_property::{Properties, Property, PropertyTypeRegistration, PropertyTypeRegistry};
|
||||||
|
use legion::{
|
||||||
|
prelude::{Entity, Resources, World},
|
||||||
|
storage::{Component, ComponentResourceSet, ComponentTypeId},
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
|
sync::{Arc, RwLock},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct TypeRegistry {
|
||||||
|
pub property: Arc<RwLock<PropertyTypeRegistry>>,
|
||||||
|
pub component: Arc<RwLock<ComponentRegistry>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct ComponentRegistry {
|
||||||
|
pub registrations: HashMap<ComponentTypeId, ComponentRegistration>,
|
||||||
|
pub short_names: HashMap<String, ComponentTypeId>,
|
||||||
|
pub full_names: HashMap<String, ComponentTypeId>,
|
||||||
|
pub ambigous_names: HashSet<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ComponentRegistry {
|
||||||
|
pub fn register<T>(&mut self)
|
||||||
|
where
|
||||||
|
T: Properties + Component + FromResources,
|
||||||
|
{
|
||||||
|
let registration = ComponentRegistration::of::<T>();
|
||||||
|
let short_name = registration.short_name.to_string();
|
||||||
|
self.full_names
|
||||||
|
.insert(registration.ty.0.to_string(), registration.ty);
|
||||||
|
if self.short_names.contains_key(&short_name) || self.ambigous_names.contains(&short_name) {
|
||||||
|
// name is ambiguous. fall back to long names for all ambiguous types
|
||||||
|
self.short_names.remove(&short_name);
|
||||||
|
self.ambigous_names.insert(short_name);
|
||||||
|
} else {
|
||||||
|
self.short_names
|
||||||
|
.insert(short_name, registration.ty);
|
||||||
|
}
|
||||||
|
self.registrations.insert(registration.ty, registration);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, type_id: &ComponentTypeId) -> Option<&ComponentRegistration> {
|
||||||
|
self.registrations.get(type_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_with_full_name(&self, full_name: &str) -> Option<&ComponentRegistration> {
|
||||||
|
self.full_names
|
||||||
|
.get(full_name)
|
||||||
|
.and_then(|id| self.registrations.get(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_with_short_name(&self, short_name: &str) -> Option<&ComponentRegistration> {
|
||||||
|
self.short_names
|
||||||
|
.get(short_name)
|
||||||
|
.and_then(|id| self.registrations.get(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_with_name(&self, type_name: &str) -> Option<&ComponentRegistration> {
|
||||||
|
let mut registration = self.get_with_short_name(type_name);
|
||||||
|
if registration.is_none() {
|
||||||
|
registration = self.get_with_full_name(type_name);
|
||||||
|
if registration.is_none() {
|
||||||
|
if self.ambigous_names.contains(type_name) {
|
||||||
|
panic!("Type name is ambiguous: {}", type_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
registration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ComponentRegistration {
|
||||||
|
pub ty: ComponentTypeId,
|
||||||
|
component_add_fn: fn(&mut World, resources: &Resources, Entity, &dyn Property),
|
||||||
|
component_properties_fn: fn(&ComponentResourceSet, usize) -> &dyn Properties,
|
||||||
|
pub short_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ComponentRegistration {
|
||||||
|
pub fn of<T: Properties + Component + FromResources>() -> Self {
|
||||||
|
let ty = ComponentTypeId::of::<T>();
|
||||||
|
Self {
|
||||||
|
ty,
|
||||||
|
component_add_fn: |world: &mut World,
|
||||||
|
resources: &Resources,
|
||||||
|
entity: Entity,
|
||||||
|
property: &dyn Property| {
|
||||||
|
let mut component = T::from_resources(resources);
|
||||||
|
component.apply(property);
|
||||||
|
world.add_component(entity, component).unwrap();
|
||||||
|
},
|
||||||
|
component_properties_fn: |component_resource_set: &ComponentResourceSet,
|
||||||
|
index: usize| {
|
||||||
|
// the type has been looked up by the caller, so this is safe
|
||||||
|
unsafe { &component_resource_set.data_slice::<T>()[index] }
|
||||||
|
},
|
||||||
|
short_name: PropertyTypeRegistration::get_short_name(ty.0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_component_to_entity(
|
||||||
|
&self,
|
||||||
|
world: &mut World,
|
||||||
|
resources: &Resources,
|
||||||
|
entity: Entity,
|
||||||
|
property: &dyn Property,
|
||||||
|
) {
|
||||||
|
(self.component_add_fn)(world, resources, entity, property);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_component_properties<'a>(
|
||||||
|
&self,
|
||||||
|
component_resource_set: &'a ComponentResourceSet,
|
||||||
|
entity_index: usize,
|
||||||
|
) -> &'a dyn Properties {
|
||||||
|
(self.component_properties_fn)(component_resource_set, entity_index)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,7 +7,7 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
bevy_app = { path = "../bevy_app" }
|
bevy_app = { path = "../bevy_app" }
|
||||||
bevy_asset = { path = "../bevy_asset" }
|
bevy_asset = { path = "../bevy_asset" }
|
||||||
bevy_component_registry = { path = "../bevy_component_registry" }
|
bevy_type_registry = { path = "../bevy_type_registry" }
|
||||||
bevy_core = { path = "../bevy_core" }
|
bevy_core = { path = "../bevy_core" }
|
||||||
bevy_derive = { path = "../bevy_derive" }
|
bevy_derive = { path = "../bevy_derive" }
|
||||||
bevy_text = { path = "../bevy_text" }
|
bevy_text = { path = "../bevy_text" }
|
||||||
|
|||||||
@ -1,7 +1,4 @@
|
|||||||
use bevy::{
|
use bevy::{input::keyboard::KeyboardInput, prelude::*, type_registry::TypeRegistry};
|
||||||
component_registry::ComponentRegistryContext, input::keyboard::KeyboardInput, prelude::*,
|
|
||||||
};
|
|
||||||
use bevy_app::FromResources;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
App::build()
|
App::build()
|
||||||
@ -64,11 +61,16 @@ fn save_scene_system(world: &mut World, resources: &mut Resources) {
|
|||||||
.add(ComponentA { x: 3.0, y: 4.0 });
|
.add(ComponentA { x: 3.0, y: 4.0 });
|
||||||
|
|
||||||
// The component registry resource contains information about all registered components. This is used to construct scenes.
|
// The component registry resource contains information about all registered components. This is used to construct scenes.
|
||||||
let component_registry = resources.get::<ComponentRegistryContext>().unwrap();
|
let type_registry = resources.get::<TypeRegistry>().unwrap();
|
||||||
let scene = Scene::from_world(world, &component_registry.value.read().unwrap());
|
let scene = Scene::from_world(world, &type_registry.component.read().unwrap());
|
||||||
|
|
||||||
// Scenes can be serialized like this:
|
// Scenes can be serialized like this:
|
||||||
println!("{}", scene.serialize_ron().unwrap());
|
println!(
|
||||||
|
"{}",
|
||||||
|
scene
|
||||||
|
.serialize_ron(&type_registry.property.read().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
// TODO: save scene
|
// TODO: save scene
|
||||||
}
|
}
|
||||||
@ -76,16 +78,16 @@ fn save_scene_system(world: &mut World, resources: &mut Resources) {
|
|||||||
fn load_scene_system(world: &mut World, resources: &mut Resources) {
|
fn load_scene_system(world: &mut World, resources: &mut Resources) {
|
||||||
let asset_server = resources.get::<AssetServer>().unwrap();
|
let asset_server = resources.get::<AssetServer>().unwrap();
|
||||||
let mut scenes = resources.get_mut::<Assets<Scene>>().unwrap();
|
let mut scenes = resources.get_mut::<Assets<Scene>>().unwrap();
|
||||||
|
|
||||||
// Scenes are loaded just like any other asset.
|
// Scenes are loaded just like any other asset.
|
||||||
let scene_handle: Handle<Scene> = asset_server
|
let scene_handle: Handle<Scene> = asset_server
|
||||||
.load_sync(&mut scenes, "assets/scene/load_scene_example.scn")
|
.load_sync(&mut scenes, "assets/scene/load_scene_example.scn")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let scene = scenes.get(&scene_handle).unwrap();
|
let scene = scenes.get(&scene_handle).unwrap();
|
||||||
|
|
||||||
// Scenes can be added to any ECS World. Adding scenes also uses the component registry.
|
// Scenes can be added to any ECS World. Adding scenes also uses the component registry.
|
||||||
let component_registry = resources.get::<ComponentRegistryContext>().unwrap();
|
let type_registry = resources.get::<TypeRegistry>().unwrap();
|
||||||
scene
|
scene
|
||||||
.add_to_world(world, resources, &component_registry.value.read().unwrap())
|
.add_to_world(world, resources, &type_registry.component.read().unwrap())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use bevy::{
|
use bevy::{
|
||||||
component_registry::PropertyTypeRegistryContext,
|
|
||||||
prelude::*,
|
prelude::*,
|
||||||
property::{ron::deserialize_dynamic_properties},
|
property::{ron::deserialize_dynamic_properties, PropertyTypeRegistry},
|
||||||
|
type_registry::TypeRegistry,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@ -9,6 +9,8 @@ fn main() {
|
|||||||
App::build()
|
App::build()
|
||||||
.add_default_plugins()
|
.add_default_plugins()
|
||||||
// If you need to deserialize custom property types, register them like this:
|
// If you need to deserialize custom property types, register them like this:
|
||||||
|
.register_property_type::<Test>()
|
||||||
|
.register_property_type::<Nested>()
|
||||||
.register_property_type::<CustomProperty>()
|
.register_property_type::<CustomProperty>()
|
||||||
.add_startup_system(setup.system())
|
.add_startup_system(setup.system())
|
||||||
.run();
|
.run();
|
||||||
@ -31,7 +33,7 @@ pub struct CustomProperty {
|
|||||||
a: usize,
|
a: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup(property_type_registry: Res<PropertyTypeRegistryContext>) {
|
fn setup(type_registry: Res<TypeRegistry>) {
|
||||||
let mut test = Test {
|
let mut test = Test {
|
||||||
a: 1,
|
a: 1,
|
||||||
custom: CustomProperty { a: 10 },
|
custom: CustomProperty { a: 10 },
|
||||||
@ -58,15 +60,14 @@ fn setup(property_type_registry: Res<PropertyTypeRegistryContext>) {
|
|||||||
|
|
||||||
// All properties can be serialized.
|
// All properties can be serialized.
|
||||||
// If you #[derive(Properties)] your type doesn't even need to directly implement the Serde trait!
|
// If you #[derive(Properties)] your type doesn't even need to directly implement the Serde trait!
|
||||||
let ron_string = serialize_ron(&test.serializable().borrow()).unwrap();
|
let registry = type_registry.property.read().unwrap();
|
||||||
|
let ron_string = serialize_ron(&test, ®istry).unwrap();
|
||||||
println!("{}\n", ron_string);
|
println!("{}\n", ron_string);
|
||||||
|
|
||||||
// Dynamic properties can be deserialized
|
// Dynamic properties can be deserialized
|
||||||
let dynamic_properties =
|
let dynamic_properties = deserialize_dynamic_properties(&ron_string, ®istry).unwrap();
|
||||||
deserialize_dynamic_properties(&ron_string, &property_type_registry.value.read().unwrap())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let round_tripped = serialize_ron(&dynamic_properties).unwrap();
|
let round_tripped = serialize_ron(&dynamic_properties, ®istry).unwrap();
|
||||||
println!("{}", round_tripped);
|
println!("{}", round_tripped);
|
||||||
assert_eq!(ron_string, round_tripped);
|
assert_eq!(ron_string, round_tripped);
|
||||||
|
|
||||||
@ -81,23 +82,24 @@ fn setup(property_type_registry: Res<PropertyTypeRegistryContext>) {
|
|||||||
seq.apply(&patch);
|
seq.apply(&patch);
|
||||||
assert_eq!(seq[0], 3);
|
assert_eq!(seq[0], 3);
|
||||||
|
|
||||||
let ron_string = serialize_ron(&patch.serializable().borrow()).unwrap();
|
let ron_string = serialize_ron(&patch, ®istry).unwrap();
|
||||||
println!("{}\n", ron_string);
|
println!("{}\n", ron_string);
|
||||||
let dynamic_properties =
|
let dynamic_properties = deserialize_dynamic_properties(&ron_string, ®istry).unwrap();
|
||||||
deserialize_dynamic_properties(&ron_string, &property_type_registry.value.read().unwrap())
|
let round_tripped = serialize_ron(&dynamic_properties, ®istry).unwrap();
|
||||||
.unwrap();
|
|
||||||
let round_tripped = serialize_ron(&dynamic_properties).unwrap();
|
|
||||||
assert_eq!(ron_string, round_tripped);
|
assert_eq!(ron_string, round_tripped);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_ron<T>(properties: &T) -> Result<String, ron::Error>
|
fn serialize_ron<T>(property: &T, registry: &PropertyTypeRegistry) -> Result<String, ron::Error>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: Property,
|
||||||
{
|
{
|
||||||
let pretty_config = ron::ser::PrettyConfig::default().with_decimal_floats(true);
|
let pretty_config = ron::ser::PrettyConfig::default().with_decimal_floats(true);
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
let mut serializer = ron::ser::Serializer::new(&mut buf, Some(pretty_config), true)?;
|
let mut serializer = ron::ser::Serializer::new(&mut buf, Some(pretty_config), false)?;
|
||||||
properties.serialize(&mut serializer)?;
|
property
|
||||||
|
.serializable(registry)
|
||||||
|
.borrow()
|
||||||
|
.serialize(&mut serializer)?;
|
||||||
let ron_string = String::from_utf8(buf).unwrap();
|
let ron_string = String::from_utf8(buf).unwrap();
|
||||||
Ok(ron_string)
|
Ok(ron_string)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,8 +6,8 @@ pub trait AddDefaultPlugins {
|
|||||||
|
|
||||||
impl AddDefaultPlugins for AppBuilder {
|
impl AddDefaultPlugins for AppBuilder {
|
||||||
fn add_default_plugins(&mut self) -> &mut Self {
|
fn add_default_plugins(&mut self) -> &mut Self {
|
||||||
#[cfg(feature = "component_registry")]
|
#[cfg(feature = "type_registry")]
|
||||||
self.add_plugin(bevy_component_registry::ComponentRegistryPlugin::default());
|
self.add_plugin(bevy_type_registry::TypeRegistryPlugin::default());
|
||||||
|
|
||||||
#[cfg(feature = "core")]
|
#[cfg(feature = "core")]
|
||||||
self.add_plugin(bevy_core::CorePlugin::default());
|
self.add_plugin(bevy_core::CorePlugin::default());
|
||||||
|
|||||||
@ -49,8 +49,8 @@ pub use legion;
|
|||||||
|
|
||||||
#[cfg(feature = "asset")]
|
#[cfg(feature = "asset")]
|
||||||
pub use bevy_asset as asset;
|
pub use bevy_asset as asset;
|
||||||
#[cfg(feature = "component_registry")]
|
#[cfg(feature = "type_registry")]
|
||||||
pub use bevy_component_registry as component_registry;
|
pub use bevy_type_registry as type_registry;
|
||||||
#[cfg(feature = "core")]
|
#[cfg(feature = "core")]
|
||||||
pub use bevy_core as core;
|
pub use bevy_core as core;
|
||||||
#[cfg(feature = "derive")]
|
#[cfg(feature = "derive")]
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
|
pub use crate::app::FromResources;
|
||||||
#[cfg(feature = "asset")]
|
#[cfg(feature = "asset")]
|
||||||
pub use crate::asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle};
|
pub use crate::asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle};
|
||||||
#[cfg(feature = "component_registry")]
|
|
||||||
pub use crate::component_registry::RegisterComponent;
|
|
||||||
#[cfg(feature = "core")]
|
#[cfg(feature = "core")]
|
||||||
pub use crate::core::{
|
pub use crate::core::{
|
||||||
time::Time,
|
time::Time,
|
||||||
@ -39,6 +38,8 @@ pub use crate::scene::Scene;
|
|||||||
pub use crate::text::Font;
|
pub use crate::text::Font;
|
||||||
#[cfg(feature = "transform")]
|
#[cfg(feature = "transform")]
|
||||||
pub use crate::transform::prelude::*;
|
pub use crate::transform::prelude::*;
|
||||||
|
#[cfg(feature = "type_registry")]
|
||||||
|
pub use crate::type_registry::RegisterType;
|
||||||
#[cfg(feature = "ui")]
|
#[cfg(feature = "ui")]
|
||||||
pub use crate::ui::{
|
pub use crate::ui::{
|
||||||
entity::*, widget::Label, Anchors, ColorMaterial, Margins, Node, Rect, Sprite,
|
entity::*, widget::Label, Anchors, ColorMaterial, Margins, Node, Rect, Sprite,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user