Bevy Reflection (#926)

Bevy Reflection
This commit is contained in:
Carter Anderson 2020-11-27 16:39:59 -08:00 committed by GitHub
parent 01c4dd96cf
commit 72b2fc9843
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
138 changed files with 4931 additions and 3519 deletions

View file

@ -75,7 +75,7 @@ bevy_internal = {path = "crates/bevy_internal", version = "0.3.0", default-featu
[dev-dependencies]
anyhow = "1.0"
rand = "0.7.3"
ron = "0.6"
ron = "0.6.2"
serde = {version = "1", features = ["derive"]}
[[example]]
@ -255,12 +255,24 @@ name = "touch_input_events"
path = "examples/input/touch_input_events.rs"
[[example]]
name = "scene"
path = "examples/scene/scene.rs"
name = "reflection"
path = "examples/reflection/reflection.rs"
[[example]]
name = "properties"
path = "examples/scene/properties.rs"
name = "reflection_types"
path = "examples/reflection/reflection_types.rs"
[[example]]
name = "generic_reflection"
path = "examples/reflection/generic_reflection.rs"
[[example]]
name = "trait_reflection"
path = "examples/reflection/trait_reflection.rs"
[[example]]
name = "scene"
path = "examples/scene/scene.rs"
[[example]]
name = "mesh_custom_attribute"

View file

@ -3,16 +3,42 @@
entity: 0,
components: [
{
"type": "ComponentB",
"map": {
"value": "hello",
"type": "bevy_transform::components::transform::Transform",
"struct": {
"translation": {
"type": "glam::f32::vec3::Vec3",
"value": (0.0, 0.0, 0.0),
},
"rotation": {
"type": "glam::f32::quat::Quat",
"value": (0.0, 0.0, 0.0, 1.0),
},
"scale": {
"type": "glam::f32::vec3::Vec3",
"value": (1.0, 1.0, 1.0),
},
},
},
{
"type": "ComponentA",
"map": {
"x": 1.0,
"y": 2.0,
"type": "scene::ComponentB",
"struct": {
"value": {
"type": "alloc::string::String",
"value": "hello",
},
},
},
{
"type": "scene::ComponentA",
"struct": {
"x": {
"type": "f32",
"value": 1.0,
},
"y": {
"type": "f32",
"value": 2.0,
},
},
},
],
@ -21,10 +47,16 @@
entity: 1,
components: [
{
"type": "ComponentA",
"map": {
"x": 3.0,
"y": 4.0,
"type": "scene::ComponentA",
"struct": {
"x": {
"type": "f32",
"value": 3.0,
},
"y": {
"type": "f32",
"value": 4.0,
},
},
},
],

View file

@ -20,13 +20,11 @@ filesystem_watcher = ["notify"]
# bevy
bevy_app = { path = "../bevy_app", version = "0.3.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.3.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.3.0", features = ["bevy"] }
bevy_tasks = { path = "../bevy_tasks", version = "0.3.0" }
bevy_type_registry = { path = "../bevy_type_registry", version = "0.3.0" }
bevy_property = { path = "../bevy_property", version = "0.3.0" }
bevy_utils = { path = "../bevy_utils", version = "0.3.0" }
# other
uuid = { version = "0.8", features = ["v4", "serde"] }
serde = { version = "1", features = ["derive"] }
ron = "0.6.2"
crossbeam-channel = "0.4.4"

View file

@ -7,12 +7,11 @@ use crate::{
use anyhow::Result;
use bevy_ecs::Res;
use bevy_tasks::TaskPool;
use bevy_utils::HashMap;
use bevy_utils::{HashMap, Uuid};
use crossbeam_channel::TryRecvError;
use parking_lot::RwLock;
use std::{collections::hash_map::Entry, path::Path, sync::Arc};
use thiserror::Error;
use uuid::Uuid;
/// Errors that occur while loading assets with an AssetServer
#[derive(Error, Debug)]

View file

@ -3,7 +3,6 @@ use crate::{
};
use bevy_app::{prelude::Events, AppBuilder};
use bevy_ecs::{FromResources, ResMut};
use bevy_type_registry::RegisterType;
use bevy_utils::HashMap;
use crossbeam_channel::Sender;
use std::fmt::Debug;
@ -218,7 +217,6 @@ impl AddAsset for AppBuilder {
};
self.add_resource(assets)
.register_component::<Handle<T>>()
.add_system_to_stage(super::stage::ASSET_EVENTS, Assets::<T>::asset_event_system)
.add_system_to_stage(crate::stage::LOAD_ASSETS, update_asset_storage_system::<T>)
.add_event::<AssetEvent<T>>()

View file

@ -5,20 +5,20 @@ use std::{
marker::PhantomData,
};
use bevy_property::{Properties, Property};
use crossbeam_channel::{Receiver, Sender};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::{
path::{AssetPath, AssetPathId},
Asset, Assets,
};
use bevy_reflect::{Reflect, ReflectDeserialize};
use bevy_utils::Uuid;
use crossbeam_channel::{Receiver, Sender};
use serde::{Deserialize, Serialize};
/// A unique, stable asset id
#[derive(
Debug, Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize, Property,
Debug, Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize, Reflect,
)]
#[reflect_value(Serialize, Deserialize, PartialEq, Hash)]
pub enum HandleId {
Id(Uuid, u64),
AssetPathId(AssetPathId),
@ -56,15 +56,15 @@ impl HandleId {
/// A handle into a specific Asset of type `T`
///
/// Handles contain a unique id that corresponds to a specific asset in the [Assets](crate::Assets) collection.
#[derive(Properties)]
#[derive(Reflect)]
pub struct Handle<T>
where
T: 'static,
{
pub id: HandleId,
#[property(ignore)]
#[reflect(ignore)]
handle_type: HandleType,
#[property(ignore)]
#[reflect(ignore)]
marker: PhantomData<T>,
}
@ -184,7 +184,7 @@ impl<T> From<&Handle<T>> for HandleId {
impl<T> Hash for Handle<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
Hash::hash(&self.id, state);
}
}
@ -311,7 +311,7 @@ impl From<&HandleUntyped> for HandleId {
impl Hash for HandleUntyped {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
Hash::hash(&self.id, state);
}
}

View file

@ -1,8 +1,7 @@
use crate::{path::AssetPath, LabelId};
use bevy_utils::{HashMap, HashSet};
use bevy_utils::{HashMap, HashSet, Uuid};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use uuid::Uuid;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SourceMeta {

View file

@ -13,6 +13,7 @@ mod path;
pub use asset_server::*;
pub use assets::*;
use bevy_reflect::RegisterTypeBuilder;
use bevy_tasks::IoTaskPool;
pub use handle::*;
pub use info::*;
@ -31,7 +32,6 @@ pub mod prelude {
}
use bevy_app::{prelude::Plugin, AppBuilder};
use bevy_type_registry::RegisterType;
/// Adds support for Assets to an App. Assets are typed collections with change tracking, which are added as App Resources.
/// Examples of assets: textures, sounds, 3d models, maps, scenes
@ -76,7 +76,7 @@ impl Plugin for AssetPlugin {
app.add_stage_before(bevy_app::stage::PRE_UPDATE, stage::LOAD_ASSETS)
.add_stage_after(bevy_app::stage::POST_UPDATE, stage::ASSET_EVENTS)
.add_resource(asset_server)
.register_property::<HandleId>()
.register_type::<HandleId>()
.add_system_to_stage(
bevy_app::stage::PRE_UPDATE,
asset_server::free_unused_assets_system,

View file

@ -4,7 +4,7 @@ use crate::{
};
use anyhow::Result;
use bevy_ecs::{Res, ResMut, Resource};
use bevy_type_registry::{TypeUuid, TypeUuidDynamic};
use bevy_reflect::{TypeUuid, TypeUuidDynamic};
use bevy_utils::{BoxedFuture, HashMap};
use crossbeam_channel::{Receiver, Sender};
use downcast_rs::{impl_downcast, Downcast};

View file

@ -1,4 +1,4 @@
use bevy_property::Property;
use bevy_reflect::{Reflect, ReflectDeserialize};
use bevy_utils::AHasher;
use serde::{Deserialize, Serialize};
use std::{
@ -58,18 +58,21 @@ impl<'a> AssetPath<'a> {
}
#[derive(
Debug, Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize, Property,
Debug, Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize, Reflect,
)]
#[reflect_value(PartialEq, Hash, Serialize, Deserialize)]
pub struct AssetPathId(SourcePathId, LabelId);
#[derive(
Debug, Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize, Property,
Debug, Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize, Reflect,
)]
#[reflect_value(PartialEq, Hash, Serialize, Deserialize)]
pub struct SourcePathId(u64);
#[derive(
Debug, Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize, Property,
Debug, Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize, Reflect,
)]
#[reflect_value(PartialEq, Hash, Serialize, Deserialize)]
pub struct LabelId(u64);
impl<'a> From<&'a Path> for SourcePathId {

View file

@ -17,7 +17,7 @@ keywords = ["bevy"]
bevy_app = { path = "../bevy_app", version = "0.3.0" }
bevy_asset = { path = "../bevy_asset", version = "0.3.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.3.0" }
bevy_type_registry = { path = "../bevy_type_registry", version = "0.3.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.3.0", features = ["bevy"] }
bevy_utils = { path = "../bevy_utils", version = "0.3.0" }
# other

View file

@ -1,6 +1,6 @@
use anyhow::Result;
use bevy_asset::{AssetLoader, LoadContext, LoadedAsset};
use bevy_type_registry::TypeUuid;
use bevy_reflect::TypeUuid;
use bevy_utils::BoxedFuture;
use std::{io::Cursor, sync::Arc};

View file

@ -17,8 +17,7 @@ keywords = ["bevy"]
bevy_app = { path = "../bevy_app", version = "0.3.0" }
bevy_derive = { path = "../bevy_derive", version = "0.3.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.3.0" }
bevy_property = { path = "../bevy_property", version = "0.3.0" }
bevy_type_registry = { path = "../bevy_type_registry", version = "0.3.0" }
bevy_math = { path = "../bevy_math", version = "0.3.0" }
bevy_utils = { path = "../bevy_utils", version = "0.3.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.3.0", features = ["bevy"] }
bevy_tasks = { path = "../bevy_tasks", version = "0.3.0" }
bevy_utils = { path = "../bevy_utils", version = "0.3.0" }

View file

@ -1,5 +1,5 @@
use bevy_ecs::prelude::*;
use bevy_property::Properties;
use bevy_reflect::Reflect;
use bevy_utils::{HashMap, HashSet};
use std::{
borrow::Cow,
@ -8,7 +8,7 @@ use std::{
};
/// A collection of labels
#[derive(Default, Properties)]
#[derive(Default, Reflect)]
pub struct Labels {
labels: HashSet<Cow<'static, str>>,
}

View file

@ -4,6 +4,9 @@ mod label;
mod task_pool_options;
mod time;
use std::ops::Range;
use bevy_reflect::RegisterTypeBuilder;
pub use bytes::*;
pub use float_ord::*;
pub use label::*;
@ -15,8 +18,6 @@ pub mod prelude {
}
use bevy_app::prelude::*;
use bevy_math::{Mat3, Mat4, Quat, Vec2, Vec3};
use bevy_type_registry::RegisterType;
/// Adds core functionality to Apps.
#[derive(Default)]
@ -32,13 +33,9 @@ impl Plugin for CorePlugin {
app.init_resource::<Time>()
.init_resource::<EntityLabels>()
.register_component::<Timer>()
.register_property::<Vec2>()
.register_property::<Vec3>()
.register_property::<Mat3>()
.register_property::<Mat4>()
.register_property::<Quat>()
.register_property::<Option<String>>()
.register_type::<Option<String>>()
.register_type::<Range<f32>>()
.register_type::<Timer>()
.add_system_to_stage(stage::FIRST, time_system)
.add_system_to_stage(stage::PRE_UPDATE, entity_labels_system);
}

View file

@ -1,4 +1,4 @@
use bevy_property::Properties;
use bevy_reflect::{Reflect, ReflectComponent};
use bevy_utils::Duration;
/// Tracks elapsed time. Enters the finished state once `duration` is reached.
@ -7,7 +7,8 @@ use bevy_utils::Duration;
/// Repeating timers will only be in the finished state on each tick `duration` is reached or exceeded, and can still be reset at any given point.
///
/// Paused timers will not have elapsed time increased.
#[derive(Clone, Debug, Default, Properties)]
#[derive(Clone, Debug, Default, Reflect)]
#[reflect(Component)]
pub struct Timer {
elapsed: f32,
duration: f32,

View file

@ -21,4 +21,3 @@ find-crate = "0.6"
proc-macro2 = "1.0"
quote = "1.0"
syn = "1.0"
uuid = { version = "0.8", features = ["v4", "serde"] }

View file

@ -8,7 +8,6 @@ mod render_resource;
mod render_resources;
mod resource;
mod shader_defs;
mod type_uuid;
use proc_macro::TokenStream;
@ -51,17 +50,6 @@ pub fn derive_dynamic_plugin(input: TokenStream) -> TokenStream {
app_plugin::derive_dynamic_plugin(input)
}
// From https://github.com/randomPoison/type-uuid
#[proc_macro_derive(TypeUuid, attributes(uuid))]
pub fn type_uuid_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
type_uuid::type_uuid_derive(input)
}
#[proc_macro]
pub fn external_type_uuid(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
type_uuid::external_type_uuid(tokens)
}
#[proc_macro_attribute]
pub fn bevy_main(attr: TokenStream, item: TokenStream) -> TokenStream {
bevy_main::bevy_main(attr, item)

View file

@ -8,7 +8,6 @@ pub struct Modules {
pub bevy_asset: String,
pub bevy_core: String,
pub bevy_app: String,
pub bevy_type_registry: String,
}
impl Modules {
@ -18,7 +17,6 @@ impl Modules {
bevy_render: format!("{}::render", name),
bevy_core: format!("{}::core", name),
bevy_app: format!("{}::app", name),
bevy_type_registry: format!("{}::type_registry", name),
}
}
@ -28,7 +26,6 @@ impl Modules {
bevy_render: "bevy_render".to_string(),
bevy_core: "bevy_core".to_string(),
bevy_app: "bevy_app".to_string(),
bevy_type_registry: "bevy_type_registry".to_string(),
}
}
}

View file

@ -21,5 +21,4 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.3.0" }
bevy_utils = { path = "../bevy_utils", version = "0.3.0" }
# other
uuid = { version = "0.8", features = ["v4", "serde"] }
parking_lot = "0.11.0"

View file

@ -1,6 +1,5 @@
use bevy_utils::{Duration, HashMap, Instant};
use bevy_utils::{Duration, HashMap, Instant, Uuid};
use std::collections::VecDeque;
use uuid::Uuid;
/// Unique identifier for a [Diagnostic]
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]

View file

@ -1,7 +1,7 @@
// modified by Bevy contributors
use crate::Entity;
use serde::{Serialize, Serializer};
use serde::{de::Visitor, Deserialize, Serialize, Serializer};
impl Serialize for Entity {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@ -11,3 +11,29 @@ impl Serialize for Entity {
serializer.serialize_u32(self.id())
}
}
impl<'de> Deserialize<'de> for Entity {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Ok(deserializer.deserialize_u32(EntityVisitor)?)
}
}
struct EntityVisitor;
impl<'de> Visitor<'de> for EntityVisitor {
type Value = Entity;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("expected Entity")
}
fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Entity::new(v))
}
}

View file

@ -18,11 +18,11 @@ bevy_app = { path = "../bevy_app", version = "0.3.0" }
bevy_asset = { path = "../bevy_asset", version = "0.3.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.3.0" }
bevy_pbr = { path = "../bevy_pbr", version = "0.3.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.3.0", features = ["bevy"] }
bevy_render = { path = "../bevy_render", version = "0.3.0" }
bevy_transform = { path = "../bevy_transform", version = "0.3.0" }
bevy_math = { path = "../bevy_math", version = "0.3.0" }
bevy_scene = { path = "../bevy_scene", version = "0.3.0" }
bevy_type_registry = { path = "../bevy_type_registry", version = "0.3.0" }
# other
gltf = { version = "0.15.2", default-features = false, features = ["utils"] }

View file

@ -38,7 +38,6 @@ x11 = ["bevy_winit/x11"]
# bevy
bevy_app = { path = "../bevy_app", version = "0.3.0" }
bevy_asset = { path = "../bevy_asset", version = "0.3.0" }
bevy_type_registry = { path = "../bevy_type_registry", version = "0.3.0" }
bevy_core = { path = "../bevy_core", version = "0.3.0" }
bevy_derive = { path = "../bevy_derive", version = "0.3.0" }
bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.3.0" }
@ -46,7 +45,7 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.3.0" }
bevy_input = { path = "../bevy_input", version = "0.3.0" }
bevy_log = { path = "../bevy_log", version = "0.3.0" }
bevy_math = { path = "../bevy_math", version = "0.3.0" }
bevy_property = { path = "../bevy_property", version = "0.3.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.3.0", features = ["bevy"] }
bevy_scene = { path = "../bevy_scene", version = "0.3.0" }
bevy_transform = { path = "../bevy_transform", version = "0.3.0" }
bevy_utils = { path = "../bevy_utils", version = "0.3.0" }

View file

@ -5,7 +5,7 @@ pub struct DefaultPlugins;
impl PluginGroup for DefaultPlugins {
fn build(&mut self, group: &mut PluginGroupBuilder) {
group.add(bevy_log::LogPlugin::default());
group.add(bevy_type_registry::TypeRegistryPlugin::default());
group.add(bevy_reflect::ReflectPlugin::default());
group.add(bevy_core::CorePlugin::default());
group.add(bevy_transform::TransformPlugin::default());
group.add(bevy_diagnostic::DiagnosticsPlugin::default());
@ -50,7 +50,7 @@ pub struct MinimalPlugins;
impl PluginGroup for MinimalPlugins {
fn build(&mut self, group: &mut PluginGroupBuilder) {
group.add(bevy_type_registry::TypeRegistryPlugin::default());
group.add(bevy_reflect::ReflectPlugin::default());
group.add(bevy_core::CorePlugin::default());
group.add(bevy_app::ScheduleRunnerPlugin::default());
}

View file

@ -44,9 +44,12 @@ pub mod math {
pub use bevy_math::*;
}
pub mod property {
//! Dynamically interact with struct fields and names.
pub use bevy_property::*;
pub mod reflect {
// TODO: remove these renames once TypeRegistryArc is no longer required
//! Type reflection used for dynamically interacting with rust types.
pub use bevy_reflect::{
TypeRegistry as TypeRegistryInternal, TypeRegistryArc as TypeRegistry, *,
};
}
pub mod scene {
@ -64,11 +67,6 @@ pub mod transform {
pub use bevy_transform::*;
}
pub mod type_registry {
//! Registered types and components can be used when loading scenes.
pub use bevy_type_registry::*;
}
pub mod utils {
pub use bevy_utils::*;
}

View file

@ -1,8 +1,7 @@
pub use crate::{
app::prelude::*, asset::prelude::*, core::prelude::*, ecs::prelude::*, input::prelude::*,
log::prelude::*, math::prelude::*, property::prelude::*, scene::prelude::*,
transform::prelude::*, type_registry::RegisterType, window::prelude::*, DefaultPlugins,
MinimalPlugins,
log::prelude::*, math::prelude::*, reflect::prelude::*, scene::prelude::*,
transform::prelude::*, window::prelude::*, DefaultPlugins, MinimalPlugins,
};
pub use bevy_derive::bevy_main;

View file

@ -14,3 +14,4 @@ keywords = ["bevy"]
[dependencies]
glam = { version = "0.10.0", features = ["serde"] }
bevy_reflect = { path = "../bevy_reflect", version = "0.3.0", features = ["bevy"] }

View file

@ -1,20 +1,21 @@
use bevy_reflect::Reflect;
use glam::Vec2;
use std::ops::{Add, AddAssign};
/// A two dimensional "size" as defined by a width and height
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Size<T = f32> {
#[derive(Copy, Clone, PartialEq, Debug, Reflect)]
pub struct Size<T: Reflect = f32> {
pub width: T,
pub height: T,
}
impl<T> Size<T> {
impl<T: Reflect> Size<T> {
pub fn new(width: T, height: T) -> Self {
Size { width, height }
}
}
impl<T: Default> Default for Size<T> {
impl<T: Default + Reflect> Default for Size<T> {
fn default() -> Self {
Self {
width: Default::default(),
@ -24,15 +25,15 @@ impl<T: Default> Default for Size<T> {
}
/// A rect, as defined by its "side" locations
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Rect<T> {
#[derive(Copy, Clone, PartialEq, Debug, Reflect)]
pub struct Rect<T: Reflect> {
pub left: T,
pub right: T,
pub top: T,
pub bottom: T,
}
impl<T> Rect<T> {
impl<T: Reflect> Rect<T> {
pub fn all(value: T) -> Self
where
T: Clone,
@ -46,7 +47,7 @@ impl<T> Rect<T> {
}
}
impl<T: Default> Default for Rect<T> {
impl<T: Default + Reflect> Default for Rect<T> {
fn default() -> Self {
Self {
left: Default::default(),
@ -57,7 +58,7 @@ impl<T: Default> Default for Rect<T> {
}
}
impl<T> Add<Vec2> for Size<T>
impl<T: Reflect> Add<Vec2> for Size<T>
where
T: Add<f32, Output = T>,
{
@ -71,7 +72,7 @@ where
}
}
impl<T> AddAssign<Vec2> for Size<T>
impl<T: Reflect> AddAssign<Vec2> for Size<T>
where
T: AddAssign<f32>,
{

View file

@ -19,8 +19,7 @@ bevy_core = { path = "../bevy_core", version = "0.3.0" }
bevy_derive = { path = "../bevy_derive", version = "0.3.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.3.0" }
bevy_math = { path = "../bevy_math", version = "0.3.0" }
bevy_property = { path = "../bevy_property", version = "0.3.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.3.0", features = ["bevy"] }
bevy_render = { path = "../bevy_render", version = "0.3.0" }
bevy_transform = { path = "../bevy_transform", version = "0.3.0" }
bevy_type_registry = { path = "../bevy_type_registry", version = "0.3.0" }
bevy_window = { path = "../bevy_window", version = "0.3.0" }

View file

@ -14,9 +14,8 @@ pub mod prelude {
use bevy_app::prelude::*;
use bevy_asset::{AddAsset, Assets, Handle};
use bevy_reflect::RegisterTypeBuilder;
use bevy_render::{prelude::Color, render_graph::RenderGraph, shader};
use bevy_type_registry::RegisterType;
use light::Light;
use material::StandardMaterial;
use render_graph::add_pbr_graph;
@ -27,7 +26,7 @@ pub struct PbrPlugin;
impl Plugin for PbrPlugin {
fn build(&self, app: &mut AppBuilder) {
app.add_asset::<StandardMaterial>()
.register_component::<Light>()
.register_type::<Light>()
.add_system_to_stage(
stage::POST_UPDATE,
shader::asset_shader_defs_system::<StandardMaterial>,

View file

@ -1,5 +1,5 @@
use bevy_core::Byteable;
use bevy_property::Properties;
use bevy_reflect::{Reflect, ReflectComponent};
use bevy_render::{
camera::{CameraProjection, PerspectiveProjection},
color::Color,
@ -8,7 +8,8 @@ use bevy_transform::components::GlobalTransform;
use std::ops::Range;
/// A point light
#[derive(Debug, Properties)]
#[derive(Debug, Reflect)]
#[reflect(Component)]
pub struct Light {
pub color: Color,
pub fov: f32,

View file

@ -1,6 +1,6 @@
use bevy_asset::{self, Handle};
use bevy_reflect::TypeUuid;
use bevy_render::{color::Color, renderer::RenderResources, shader::ShaderDefs, texture::Texture};
use bevy_type_registry::TypeUuid;
/// A material with "standard" properties used in PBR lighting
#[derive(Debug, RenderResources, ShaderDefs, TypeUuid)]

View file

@ -1,4 +1,5 @@
use bevy_asset::{Assets, Handle};
use bevy_reflect::TypeUuid;
use bevy_render::{
pipeline::{
BlendDescriptor, BlendFactor, BlendOperation, ColorStateDescriptor, ColorWrite,
@ -8,7 +9,6 @@ use bevy_render::{
shader::{Shader, ShaderStage, ShaderStages},
texture::TextureFormat,
};
use bevy_type_registry::TypeUuid;
pub const FORWARD_PIPELINE_HANDLE: Handle<PipelineDescriptor> =
Handle::weak_from_u64(PipelineDescriptor::TYPE_UUID, 13148362314012771389);

View file

@ -1,26 +0,0 @@
[package]
name = "bevy_property"
version = "0.3.0"
edition = "2018"
authors = [
"Bevy Contributors <bevyengine@gmail.com>",
"Carter Anderson <mcanders1@gmail.com>",
]
description = "Dynamically interact with struct fields using their names"
homepage = "https://bevyengine.org"
repository = "https://github.com/bevyengine/bevy"
license = "MIT"
keywords = ["bevy"]
[dependencies]
# bevy
bevy_ecs = { path = "../bevy_ecs", version = "0.3.0" }
bevy_math = { path = "../bevy_math", version = "0.3.0" }
bevy_property_derive = { path = "bevy_property_derive", version = "0.3.0" }
bevy_utils = { path = "../bevy_utils", version = "0.3.0" }
# other
erased-serde = "0.3"
ron = "0.6.2"
serde = "1"
smallvec = { version = "1.4", features = ["serde"] }

View file

@ -1,431 +0,0 @@
extern crate proc_macro;
mod modules;
use find_crate::Manifest;
use modules::{get_modules, get_path};
use proc_macro::TokenStream;
use quote::quote;
use syn::{
parse::{Parse, ParseStream},
parse_macro_input,
punctuated::Punctuated,
token::{Comma, Where},
Data, DataStruct, DeriveInput, Field, Fields, Generics, Ident, Index, Member,
};
#[derive(Default)]
struct PropAttributeArgs {
pub ignore: Option<bool>,
}
static PROP_ATTRIBUTE_NAME: &str = "property";
#[proc_macro_derive(Properties, attributes(property, module))]
pub fn derive_properties(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let unit_struct_punctuated = Punctuated::new();
let fields = match &ast.data {
Data::Struct(DataStruct {
fields: Fields::Named(fields),
..
}) => &fields.named,
Data::Struct(DataStruct {
fields: Fields::Unnamed(fields),
..
}) => &fields.unnamed,
Data::Struct(DataStruct {
fields: Fields::Unit,
..
}) => &unit_struct_punctuated,
_ => panic!("expected a struct with named fields"),
};
let fields_and_args = fields
.iter()
.enumerate()
.map(|(i, f)| {
(
f,
f.attrs
.iter()
.find(|a| *a.path.get_ident().as_ref().unwrap() == PROP_ATTRIBUTE_NAME)
.map(|a| {
syn::custom_keyword!(ignore);
let mut attribute_args = PropAttributeArgs { ignore: None };
a.parse_args_with(|input: ParseStream| {
if input.parse::<Option<ignore>>()?.is_some() {
attribute_args.ignore = Some(true);
return Ok(());
}
Ok(())
})
.expect("invalid 'property' attribute format");
attribute_args
}),
i,
)
})
.collect::<Vec<(&Field, Option<PropAttributeArgs>, usize)>>();
let active_fields = fields_and_args
.iter()
.filter(|(_field, attrs, _i)| {
attrs.is_none()
|| match attrs.as_ref().unwrap().ignore {
Some(ignore) => !ignore,
None => true,
}
})
.map(|(f, _attr, i)| (*f, *i))
.collect::<Vec<(&Field, usize)>>();
let modules = get_modules();
let bevy_property_path = get_path(&modules.bevy_property);
let field_names = active_fields
.iter()
.map(|(field, index)| {
field
.ident
.as_ref()
.map(|i| i.to_string())
.unwrap_or_else(|| index.to_string())
})
.collect::<Vec<String>>();
let field_idents = active_fields
.iter()
.map(|(field, index)| {
field
.ident
.as_ref()
.map(|ident| Member::Named(ident.clone()))
.unwrap_or_else(|| Member::Unnamed(Index::from(*index)))
})
.collect::<Vec<_>>();
let field_count = active_fields.len();
let field_indices = (0..field_count).collect::<Vec<usize>>();
let generics = ast.generics;
let (impl_generics, ty_generics, _where_clause) = generics.split_for_impl();
let struct_name = &ast.ident;
TokenStream::from(quote! {
impl #impl_generics #bevy_property_path::Properties for #struct_name#ty_generics {
fn prop(&self, name: &str) -> Option<&dyn #bevy_property_path::Property> {
match name {
#(#field_names => Some(&self.#field_idents),)*
_ => None,
}
}
fn prop_mut(&mut self, name: &str) -> Option<&mut dyn #bevy_property_path::Property> {
match name {
#(#field_names => Some(&mut self.#field_idents),)*
_ => None,
}
}
fn prop_with_index(&self, index: usize) -> Option<&dyn #bevy_property_path::Property> {
match index {
#(#field_indices => Some(&self.#field_idents),)*
_ => None,
}
}
fn prop_with_index_mut(&mut self, index: usize) -> Option<&mut dyn #bevy_property_path::Property> {
match index {
#(#field_indices => Some(&mut self.#field_idents),)*
_ => None,
}
}
fn prop_name(&self, index: usize) -> Option<&str> {
match index {
#(#field_indices => Some(#field_names),)*
_ => None,
}
}
fn prop_len(&self) -> usize {
#field_count
}
fn iter_props(&self) -> #bevy_property_path::PropertyIter {
#bevy_property_path::PropertyIter::new(self)
}
}
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 {
#[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 #bevy_property_path::Property> {
Box::new(self.to_dynamic())
}
#[inline]
fn set(&mut self, value: &dyn #bevy_property_path::Property) {
// TODO: type check
self.apply(value);
}
#[inline]
fn apply(&mut self, value: &dyn #bevy_property_path::Property) {
if let Some(properties) = value.as_properties() {
if properties.property_type() != self.property_type() {
panic!(
"Properties type mismatch. This type is {:?} but the applied type is {:?}",
self.property_type(),
properties.property_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 {
panic!("attempted to apply non-Properties type to Properties type");
}
}
#[inline]
fn as_properties(&self) -> Option<&dyn #bevy_property_path::Properties> {
Some(self)
}
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, registry)))
}
fn property_type(&self) -> #bevy_property_path::PropertyType {
#bevy_property_path::PropertyType::Map
}
}
})
}
#[proc_macro_derive(Property)]
pub fn derive_property(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let modules = get_modules();
let bevy_property_path = get_path(&modules.bevy_property);
let generics = ast.generics;
let (impl_generics, ty_generics, _where_clause) = generics.split_for_impl();
let struct_name = &ast.ident;
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
}
#[inline]
fn any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
#[inline]
fn clone_prop(&self) -> Box<dyn #bevy_property_path::Property> {
Box::new(self.clone())
}
#[inline]
fn apply(&mut self, value: &dyn #bevy_property_path::Property) {
self.set(value);
}
#[inline]
fn set(&mut self, value: &dyn #bevy_property_path::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>());
}
}
#[inline]
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::new(self, registry)))
}
fn property_type(&self) -> #bevy_property_path::PropertyType {
#bevy_property_path::PropertyType::Value
}
}
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> {
let property = <#struct_name#ty_generics as #bevy_property_path::serde::Deserialize>::deserialize(deserializer)?;
Ok(Box::new(property))
}
}
})
}
struct PropertyDef {
type_name: Ident,
generics: Generics,
serialize_fn: Option<Ident>,
deserialize_fn: Option<Ident>,
}
impl Parse for PropertyDef {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let type_ident = input.parse::<Ident>()?;
let generics = input.parse::<Generics>()?;
let mut lookahead = input.lookahead1();
let mut where_clause = None;
if lookahead.peek(Where) {
where_clause = Some(input.parse()?);
lookahead = input.lookahead1();
}
let mut serialize_fn = None;
if lookahead.peek(Comma) {
input.parse::<Comma>()?;
serialize_fn = Some(input.parse::<Ident>()?);
lookahead = input.lookahead1();
}
let mut deserialize_fn = None;
if lookahead.peek(Comma) {
input.parse::<Comma>()?;
deserialize_fn = Some(input.parse::<Ident>()?);
}
Ok(PropertyDef {
type_name: type_ident,
generics: Generics {
where_clause,
..generics
},
serialize_fn,
deserialize_fn,
})
}
}
#[proc_macro]
pub fn impl_property(input: TokenStream) -> TokenStream {
let property_def = parse_macro_input!(input as PropertyDef);
let manifest = Manifest::new().unwrap();
let crate_path = if let Some(package) = manifest.find(|name| name == "bevy") {
format!("{}::property", package.name)
} else if let Some(package) = manifest.find(|name| name == "bevy_property") {
package.name
} else {
"crate".to_string()
};
let bevy_property_path = get_path(&crate_path);
let (impl_generics, ty_generics, where_clause) = property_def.generics.split_for_impl();
let ty = &property_def.type_name;
let serialize_fn = if let Some(serialize_fn) = property_def.serialize_fn {
quote! { #serialize_fn(self) }
} else {
quote! {
#bevy_property_path::property_serde::Serializable::Owned(Box::new(#bevy_property_path::property_serde::PropertyValueSerializer::new(self, registry)))
}
};
let deserialize_fn = if let Some(deserialize_fn) = property_def.deserialize_fn {
quote! { #deserialize_fn(deserializer, property_type_registry) }
} else {
quote! {
let property = <#ty#ty_generics as #bevy_property_path::serde::Deserialize>::deserialize(deserializer)?;
Ok(Box::new(property))
}
};
TokenStream::from(quote! {
impl #impl_generics #bevy_property_path::Property for #ty#ty_generics #where_clause {
#[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 #bevy_property_path::Property> {
Box::new(self.clone())
}
#[inline]
fn apply(&mut self, value: &dyn #bevy_property_path::Property) {
self.set(value);
}
#[inline]
fn set(&mut self, value: &dyn #bevy_property_path::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>());
}
}
#[inline]
fn serializable<'a>(&'a self, registry: &'a #bevy_property_path::PropertyTypeRegistry) -> #bevy_property_path::property_serde::Serializable<'a> {
#serialize_fn
}
fn property_type(&self) -> #bevy_property_path::PropertyType {
#bevy_property_path::PropertyType::Value
}
}
impl #impl_generics #bevy_property_path::DeserializeProperty for #ty#ty_generics #where_clause {
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> {
#deserialize_fn
}
}
})
}

View file

@ -1,223 +0,0 @@
use crate::{
property_serde::{DynamicPropertiesDeserializer, DynamicPropertiesSerializer, Serializable},
DeserializeProperty, Properties, Property, PropertyIter, PropertyType, PropertyTypeRegistry,
};
use bevy_utils::HashMap;
use serde::de::DeserializeSeed;
use std::{any::Any, borrow::Cow, fmt};
pub struct DynamicProperties {
pub type_name: String,
pub props: Vec<Box<dyn Property>>,
pub prop_names: Vec<Cow<'static, str>>,
pub prop_indices: HashMap<Cow<'static, str>, usize>,
pub property_type: PropertyType,
}
impl fmt::Debug for DynamicProperties {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let props = self
.props
.iter()
.map(|p| p.as_ref() as *const dyn Property)
.collect::<Vec<_>>();
f.debug_struct("DynamicProperties")
.field("type_name", &self.type_name)
.field("props", &props)
.field("prop_names", &self.prop_names)
.field("prop_indices", &self.prop_indices)
.field("property_type", &self.property_type)
.finish()
}
}
impl DynamicProperties {
pub fn map() -> Self {
DynamicProperties {
type_name: std::any::type_name::<Self>().to_string(),
props: Default::default(),
prop_names: Default::default(),
prop_indices: Default::default(),
property_type: PropertyType::Map,
}
}
pub fn seq() -> Self {
DynamicProperties {
type_name: std::any::type_name::<Self>().to_string(),
props: Default::default(),
prop_names: Default::default(),
prop_indices: Default::default(),
property_type: PropertyType::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] = Box::new(prop);
} else {
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] = prop;
} else {
self.push(prop, Some(name));
}
}
}
impl Properties for DynamicProperties {
#[inline]
fn prop(&self, name: &str) -> Option<&dyn Property> {
if let Some(index) = self.prop_indices.get(name) {
Some(&*self.props[*index])
} else {
None
}
}
#[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])
} else {
None
}
}
#[inline]
fn prop_with_index(&self, index: usize) -> Option<&dyn Property> {
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(|prop| &mut **prop)
}
#[inline]
fn prop_name(&self, index: usize) -> Option<&str> {
match self.property_type {
PropertyType::Seq => None,
PropertyType::Map => self.prop_names.get(index).map(|name| name.as_ref()),
_ => panic!("DynamicProperties cannot be Value types"),
}
}
#[inline]
fn prop_len(&self) -> usize {
self.props.len()
}
fn iter_props(&self) -> PropertyIter {
PropertyIter {
props: self,
index: 0,
}
}
}
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.property_type() != self.property_type {
panic!(
"Properties type mismatch. This type is {:?} but the applied type is {:?}",
self.property_type,
properties.property_type()
);
}
match self.property_type {
PropertyType::Map => {
for (i, prop) in properties.iter_props().enumerate() {
let name = properties.prop_name(i).unwrap();
if let Some(p) = self.prop_mut(name) {
p.apply(prop);
}
}
}
PropertyType::Seq => {
for (i, prop) in properties.iter_props().enumerate() {
if let Some(p) = self.prop_with_index_mut(i) {
p.apply(prop);
}
}
}
_ => panic!("DynamicProperties cannot be Value types"),
}
} else {
panic!("attempted to apply non-Properties type to Properties type");
}
}
fn as_properties(&self) -> Option<&dyn Properties> {
Some(self)
}
fn serializable<'a>(&'a self, registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
Serializable::Owned(Box::new(DynamicPropertiesSerializer::new(self, registry)))
}
fn property_type(&self) -> PropertyType {
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))
}
}

View file

@ -1,24 +0,0 @@
use crate::{impl_property, property_serde::Serializable, Property, PropertyTypeRegistry};
use bevy_ecs::Entity;
use erased_serde::Deserializer;
use serde::Deserialize;
impl_property!(Entity, serialize_entity, deserialize_entity);
mod private {
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub(super) struct Entity(pub(super) u32);
}
fn serialize_entity(entity: &Entity) -> Serializable {
Serializable::Owned(Box::new(private::Entity(entity.id())))
}
fn deserialize_entity(
deserializer: &mut dyn Deserializer,
_registry: &PropertyTypeRegistry,
) -> Result<Box<dyn Property>, erased_serde::Error> {
let entity = private::Entity::deserialize(deserializer)?;
Ok(Box::new(Entity::new(entity.0)))
}

View file

@ -1,8 +0,0 @@
use crate::impl_property;
use bevy_math::{Mat3, Mat4, Quat, Vec2, Vec3};
impl_property!(Vec2);
impl_property!(Vec3);
impl_property!(Mat3);
impl_property!(Mat4);
impl_property!(Quat);

View file

@ -1,50 +0,0 @@
use crate::{property_serde::Serializable, Property, PropertyType, PropertyTypeRegistry};
use serde::Serialize;
use smallvec::{Array, SmallVec};
use std::any::Any;
impl<T, I> Property for SmallVec<T>
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
}
#[inline]
fn any_mut(&mut self) -> &mut dyn 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();
}
}
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
Serializable::Borrowed(self)
}
fn property_type(&self) -> PropertyType {
PropertyType::Value
}
}

View file

@ -1,861 +0,0 @@
use crate::{
impl_property,
property_serde::{SeqSerializer, Serializable},
Properties, Property, PropertyIter, PropertyType, PropertyTypeRegistry,
};
use serde::{Deserialize, Serialize};
use std::{
any::Any,
collections::{BTreeMap, HashMap, HashSet},
hash::{BuildHasher, Hash},
ops::Range,
};
impl<T> Properties for Vec<T>
where
T: Property + Clone + Default,
{
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)
}
}
impl<T> Property for Vec<T>
where
T: Property + Clone + Default,
{
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() {
let len = properties.prop_len();
self.resize_with(len, T::default);
if properties.property_type() != self.property_type() {
panic!(
"Properties type mismatch. This type is {:?} but the applied type is {:?}",
self.property_type(),
properties.property_type()
);
}
for (i, prop) in properties.iter_props().enumerate() {
if let Some(p) = self.prop_with_index_mut(i) {
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 serializable<'a>(&'a self, registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
Serializable::Owned(Box::new(SeqSerializer::new(self, registry)))
}
fn property_type(&self) -> PropertyType {
PropertyType::Seq
}
}
// impl_property!(SEQUENCE, VecDeque<T> where T: Clone + Send + Sync + Serialize + 'static);
impl_property!(Option<T> where T: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de> + 'static);
impl_property!(HashSet<T, H> where T: Clone + Eq + Send + Sync + Hash + Serialize + for<'de> Deserialize<'de> + 'static, H: Clone + Send + Sync + Default + BuildHasher + 'static);
impl_property!(HashMap<K, V, H> where
K: Clone + Eq + Send + Sync + Hash + Serialize + for<'de> Deserialize<'de> + 'static,
V: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de> + 'static,
H: Clone + Send + Sync + Default + BuildHasher + 'static);
impl_property!(BTreeMap<K, V> where
K: Clone + Ord + Send + Sync + Serialize + for<'de> Deserialize<'de> + 'static,
V: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de> + 'static);
impl_property!(Range<T> where T: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de> + 'static);
// TODO: Implement lossless primitive types in RON and remove all of these primitive "cast checks"
impl Property for String {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[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.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 serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
Serializable::Borrowed(self)
}
}
impl Property for bool {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[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)
}
#[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;
} else {
panic!("prop value is not {}", std::any::type_name::<Self>());
}
}
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
Serializable::Borrowed(self)
}
}
impl Property for usize {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[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)
}
#[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;
} else if let Some(prop) = value.downcast_ref::<u64>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u32>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u16>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u8>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<isize>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i64>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i32>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i16>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i8>() {
*self = *prop as Self;
} else {
panic!("prop value is not {}", std::any::type_name::<Self>());
}
}
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
Serializable::Borrowed(self)
}
}
impl Property for u64 {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[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)
}
#[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;
} else if let Some(prop) = value.downcast_ref::<usize>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u32>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u16>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u8>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<isize>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i64>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i32>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i16>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i8>() {
*self = *prop as Self;
} else {
panic!("prop value is not {}", std::any::type_name::<Self>());
}
}
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
Serializable::Borrowed(self)
}
}
impl Property for u32 {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[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)
}
#[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;
} else if let Some(prop) = value.downcast_ref::<u64>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<usize>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u16>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u8>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<isize>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i64>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i32>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i16>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i8>() {
*self = *prop as Self;
} else {
panic!("prop value is not {}", std::any::type_name::<Self>());
}
}
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
Serializable::Borrowed(self)
}
}
impl Property for u16 {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[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)
}
#[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;
} else if let Some(prop) = value.downcast_ref::<u64>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u32>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<usize>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u8>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<isize>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i64>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i32>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i16>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i8>() {
*self = *prop as Self;
} else {
panic!("prop value is not {}", std::any::type_name::<Self>());
}
}
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
Serializable::Borrowed(self)
}
}
impl Property for u8 {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[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)
}
#[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;
} else if let Some(prop) = value.downcast_ref::<u64>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u32>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u16>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<usize>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<isize>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i64>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i32>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i16>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i8>() {
*self = *prop as Self;
} else {
panic!("prop value is not {}", std::any::type_name::<Self>());
}
}
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
Serializable::Borrowed(self)
}
}
impl Property for isize {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[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)
}
#[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;
} else if let Some(prop) = value.downcast_ref::<i64>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i32>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i16>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i8>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<usize>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u64>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u32>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u16>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u8>() {
*self = *prop as Self;
} else {
panic!("prop value is not {}", std::any::type_name::<Self>());
}
}
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
Serializable::Borrowed(self)
}
}
impl Property for i64 {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[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)
}
#[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;
} else if let Some(prop) = value.downcast_ref::<isize>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i32>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i16>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i8>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<usize>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u64>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u32>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u16>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u8>() {
*self = *prop as Self;
} else {
panic!("prop value is not {}", std::any::type_name::<Self>());
}
}
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
Serializable::Borrowed(self)
}
}
impl Property for i32 {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[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)
}
#[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;
} else if let Some(prop) = value.downcast_ref::<i64>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<isize>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i16>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i8>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<usize>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u64>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u32>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u16>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u8>() {
*self = *prop as Self;
} else {
panic!("prop value is not {}", std::any::type_name::<Self>());
}
}
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
Serializable::Borrowed(self)
}
}
impl Property for i16 {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[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)
}
#[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;
} else if let Some(prop) = value.downcast_ref::<i64>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i32>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<isize>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i8>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<usize>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u64>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u32>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u16>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u8>() {
*self = *prop as Self;
} else {
panic!("prop value is not {}", std::any::type_name::<Self>());
}
}
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
Serializable::Borrowed(self)
}
}
impl Property for i8 {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[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)
}
#[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;
} else if let Some(prop) = value.downcast_ref::<i64>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i32>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<i16>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<isize>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<usize>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u64>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u32>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u16>() {
*self = *prop as Self;
} else if let Some(prop) = value.downcast_ref::<u8>() {
*self = *prop as Self;
} else {
panic!("prop value is not {}", std::any::type_name::<Self>());
}
}
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
Serializable::Borrowed(self)
}
}
impl Property for f32 {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[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)
}
#[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;
} else if let Some(prop) = value.downcast_ref::<f64>() {
*self = *prop as Self;
} else {
panic!("prop value is not {}", std::any::type_name::<Self>());
}
}
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
Serializable::Borrowed(self)
}
}
impl Property for f64 {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[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)
}
#[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;
} else if let Some(prop) = value.downcast_ref::<f32>() {
*self = *prop as Self;
} else {
panic!("prop value is not {}", std::any::type_name::<Self>());
}
}
fn serializable<'a>(&'a self, _registry: &'a PropertyTypeRegistry) -> Serializable<'a> {
Serializable::Borrowed(self)
}
}

View file

@ -1,4 +0,0 @@
mod impl_property_bevy_ecs;
mod impl_property_glam;
mod impl_property_smallvec;
mod impl_property_std;

View file

@ -1,21 +0,0 @@
pub mod impl_property;
pub mod property_serde;
pub mod ron;
mod dynamic_properties;
mod properties;
mod property;
mod type_registry;
pub use dynamic_properties::*;
pub use properties::*;
pub use property::*;
pub use type_registry::*;
pub use bevy_property_derive::*;
pub use erased_serde;
pub use serde;
pub mod prelude {
pub use crate::{DynamicProperties, Properties, PropertiesVal, Property, PropertyVal};
}

View file

@ -1,92 +0,0 @@
use crate::{DynamicProperties, Property, PropertyType, PropertyVal};
pub trait Properties: Property {
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>;
fn prop_with_index_mut(&mut self, index: usize) -> Option<&mut dyn Property>;
fn prop_name(&self, index: usize) -> Option<&str>;
fn prop_len(&self) -> usize;
fn iter_props(&self) -> PropertyIter;
fn set_prop(&mut self, name: &str, value: &dyn Property) {
if let Some(prop) = self.prop_mut(name) {
prop.set(value);
} else {
panic!("prop does not exist: {}", name);
}
}
fn to_dynamic(&self) -> DynamicProperties {
let mut dynamic_props = match self.property_type() {
PropertyType::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
}
PropertyType::Seq => {
let mut dynamic_props = DynamicProperties::seq();
for prop in self.iter_props() {
dynamic_props.push(prop.clone_prop(), None);
}
dynamic_props
}
_ => panic!("Properties cannot be Value types"),
};
dynamic_props.type_name = self.type_name().to_string();
dynamic_props
}
}
pub struct PropertyIter<'a> {
pub(crate) props: &'a dyn Properties,
pub(crate) index: usize,
}
impl<'a> PropertyIter<'a> {
pub fn new(props: &'a dyn Properties) -> Self {
PropertyIter { props, index: 0 }
}
}
impl<'a> Iterator for PropertyIter<'a> {
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();
self.index += 1;
Some(prop)
} else {
None
}
}
}
pub trait PropertiesVal {
fn prop_val<T: 'static>(&self, name: &str) -> Option<&T>;
fn set_prop_val<T: 'static>(&mut self, name: &str, value: T);
}
impl<P> PropertiesVal for P
where
P: Properties,
{
#[inline]
fn prop_val<T: 'static>(&self, name: &str) -> Option<&T> {
self.prop(name).and_then(|p| p.any().downcast_ref::<T>())
}
#[inline]
fn set_prop_val<T: 'static>(&mut self, name: &str, value: T) {
if let Some(prop) = self.prop_mut(name) {
prop.set_val(value);
} else {
panic!("prop does not exist or is incorrect type: {}", name);
}
}
}

View file

@ -1,55 +0,0 @@
use crate::{property_serde::Serializable, Properties, PropertyTypeRegistry};
use erased_serde::Deserializer;
use std::any::Any;
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
pub enum PropertyType {
Map,
Seq,
Value,
}
// TODO: consider removing send + sync requirements
pub trait Property: 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>;
fn set(&mut self, value: &dyn Property);
fn apply(&mut self, value: &dyn Property);
fn property_type(&self) -> PropertyType {
PropertyType::Value
}
fn as_properties(&self) -> Option<&dyn Properties> {
None
}
fn serializable<'a>(&'a self, registry: &'a PropertyTypeRegistry) -> Serializable<'a>;
}
pub trait DeserializeProperty {
fn deserialize(
deserializer: &mut dyn Deserializer,
property_type_registry: &PropertyTypeRegistry,
) -> Result<Box<dyn Property>, erased_serde::Error>;
}
pub trait PropertyVal {
fn val<T: 'static>(&self) -> Option<&T>;
fn set_val<T: 'static>(&mut self, value: T);
}
impl PropertyVal for dyn Property {
#[inline]
fn val<T: 'static>(&self) -> Option<&T> {
self.any().downcast_ref::<T>()
}
#[inline]
fn set_val<T: 'static>(&mut self, value: T) {
if let Some(prop) = self.any_mut().downcast_mut::<T>() {
*prop = value;
} else {
panic!("prop value is not {}", std::any::type_name::<T>());
}
}
}

View file

@ -1,545 +0,0 @@
use crate::{DynamicProperties, Properties, Property, PropertyType, PropertyTypeRegistry};
use de::SeqAccess;
use serde::{
de::{self, DeserializeSeed, MapAccess, Visitor},
ser::{SerializeMap, SerializeSeq},
Serialize,
};
pub const TYPE_FIELD: &str = "type";
pub const MAP_FIELD: &str = "map";
pub const SEQ_FIELD: &str = "seq";
pub const VALUE_FIELD: &str = "value";
pub enum Serializable<'a> {
Owned(Box<dyn erased_serde::Serialize + 'a>),
Borrowed(&'a dyn erased_serde::Serialize),
}
impl<'a> Serializable<'a> {
#[allow(clippy::should_implement_trait)]
pub fn borrow(&self) -> &dyn erased_serde::Serialize {
match self {
Serializable::Borrowed(serialize) => serialize,
Serializable::Owned(serialize) => serialize,
}
}
}
pub struct PropertyValueSerializer<'a, T>
where
T: Property + Serialize,
{
pub property: &'a T,
pub registry: &'a PropertyTypeRegistry,
}
impl<'a, T> PropertyValueSerializer<'a, T>
where
T: Property + Serialize,
{
pub fn new(property: &'a T, registry: &'a PropertyTypeRegistry) -> Self {
PropertyValueSerializer { property, registry }
}
}
impl<'a, T> Serialize for PropertyValueSerializer<'a, T>
where
T: Property + Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_map(Some(2))?;
state.serialize_entry(
TYPE_FIELD,
format_type_name(self.registry, self.property.type_name()),
)?;
state.serialize_entry(VALUE_FIELD, self.property)?;
state.end()
}
}
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>
where
S: serde::Serializer,
{
match self.dynamic_properties.property_type {
PropertyType::Map => {
MapSerializer::new(self.dynamic_properties, self.registry).serialize(serializer)
}
PropertyType::Seq => {
SeqSerializer::new(self.dynamic_properties, self.registry).serialize(serializer)
}
_ => Err(serde::ser::Error::custom(
"DynamicProperties cannot be Value type",
)),
}
}
}
pub struct MapSerializer<'a> {
pub properties: &'a dyn Properties,
pub registry: &'a PropertyTypeRegistry,
}
impl<'a> MapSerializer<'a> {
pub fn new(properties: &'a dyn Properties, registry: &'a PropertyTypeRegistry) -> Self {
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(type_name)
}
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(2))?;
state.serialize_entry(
TYPE_FIELD,
format_type_name(self.registry, self.properties.type_name()),
)?;
state.serialize_entry(
MAP_FIELD,
&MapValueSerializer {
properties: self.properties,
registry: self.registry,
},
)?;
state.end()
}
}
pub struct MapValueSerializer<'a> {
pub properties: &'a dyn Properties,
pub registry: &'a PropertyTypeRegistry,
}
impl<'a> Serialize for MapValueSerializer<'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()))?;
for (index, property) in self.properties.iter_props().enumerate() {
let name = self.properties.prop_name(index).unwrap();
state.serialize_entry(name, property.serializable(self.registry).borrow())?;
}
state.end()
}
}
pub struct SeqSerializer<'a> {
pub properties: &'a dyn Properties,
pub registry: &'a PropertyTypeRegistry,
}
impl<'a> SeqSerializer<'a> {
pub fn new(properties: &'a dyn Properties, registry: &'a PropertyTypeRegistry) -> Self {
SeqSerializer {
properties,
registry,
}
}
}
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))?;
state.serialize_entry(
TYPE_FIELD,
format_type_name(self.registry, self.properties.type_name()),
)?;
state.serialize_entry(
SEQ_FIELD,
&SeqValueSerializer {
properties: self.properties,
registry: self.registry,
},
)?;
state.end()
}
}
pub struct SeqValueSerializer<'a> {
pub properties: &'a dyn Properties,
pub registry: &'a PropertyTypeRegistry,
}
impl<'a> Serialize for SeqValueSerializer<'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.serializable(self.registry).borrow())?;
}
state.end()
}
}
pub struct DynamicPropertiesDeserializer<'a> {
registry: &'a PropertyTypeRegistry,
}
impl<'a> DynamicPropertiesDeserializer<'a> {
pub fn new(registry: &'a PropertyTypeRegistry) -> Self {
DynamicPropertiesDeserializer { registry }
}
}
impl<'a, 'de> DeserializeSeed<'de> for DynamicPropertiesDeserializer<'a> {
type Value = DynamicProperties;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_map(DynamicPropertiesVisitor {
registry: self.registry,
})
}
}
struct DynamicPropertiesVisitor<'a> {
registry: &'a PropertyTypeRegistry,
}
impl<'a, 'de> Visitor<'de> for DynamicPropertiesVisitor<'a> {
type Value = DynamicProperties;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("dynamic property")
}
fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'de>,
{
match visit_map(map, self.registry)? {
DynamicPropertiesOrProperty::DynamicProperties(value) => Ok(value),
_ => Err(de::Error::custom("Expected DynamicProperties")),
}
}
}
pub struct PropertyDeserializer<'a> {
type_name: Option<&'a str>,
registry: &'a PropertyTypeRegistry,
}
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>,
{
if let Some(type_name) = self.type_name {
let registration = self.registry.get(type_name).ok_or_else(|| {
de::Error::custom(format!("TypeRegistration is missing for {}", type_name))
})?;
registration.deserialize(deserializer, self.registry)
} else {
deserializer.deserialize_any(AnyPropVisitor {
registry: self.registry,
})
}
}
}
pub struct SeqPropertyDeserializer<'a> {
registry: &'a PropertyTypeRegistry,
}
impl<'a, 'de> DeserializeSeed<'de> for SeqPropertyDeserializer<'a> {
type Value = DynamicProperties;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_seq(SeqPropertyVisitor {
registry: self.registry,
})
}
}
pub struct SeqPropertyVisitor<'a> {
registry: &'a PropertyTypeRegistry,
}
impl<'a, 'de> Visitor<'de> for SeqPropertyVisitor<'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 {
registry: self.registry,
type_name: None,
})? {
dynamic_properties.push(prop, None);
}
Ok(dynamic_properties)
}
}
pub struct MapPropertyDeserializer<'a> {
registry: &'a PropertyTypeRegistry,
}
impl<'a> MapPropertyDeserializer<'a> {
pub fn new(registry: &'a PropertyTypeRegistry) -> Self {
MapPropertyDeserializer { registry }
}
}
impl<'a, 'de> DeserializeSeed<'de> for MapPropertyDeserializer<'a> {
type Value = DynamicProperties;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_map(MapPropertyVisitor {
registry: self.registry,
})
}
}
struct MapPropertyVisitor<'a> {
registry: &'a PropertyTypeRegistry,
}
impl<'a, 'de> Visitor<'de> for MapPropertyVisitor<'a> {
type Value = DynamicProperties;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("map value")
}
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'de>,
{
let mut dynamic_properties = DynamicProperties::map();
while let Some(key) = map.next_key::<String>()? {
let property = map.next_value_seed(PropertyDeserializer {
registry: self.registry,
type_name: None,
})?;
dynamic_properties.set_box(&key, property);
}
Ok(dynamic_properties)
}
}
struct AnyPropVisitor<'a> {
registry: &'a PropertyTypeRegistry,
}
impl<'a, 'de> Visitor<'de> for AnyPropVisitor<'a> {
type Value = Box<dyn Property>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("property value")
}
fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
where
E: de::Error,
{
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,
{
Ok(Box::new(v))
}
fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Box::new(v.to_string()))
}
fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'de>,
{
Ok(match visit_map(map, self.registry)? {
DynamicPropertiesOrProperty::DynamicProperties(value) => Box::new(value),
DynamicPropertiesOrProperty::Property(value) => value,
})
}
}
enum DynamicPropertiesOrProperty {
DynamicProperties(DynamicProperties),
Property(Box<dyn Property>),
}
fn visit_map<'de, V>(
mut map: V,
registry: &PropertyTypeRegistry,
) -> Result<DynamicPropertiesOrProperty, V::Error>
where
V: MapAccess<'de>,
{
let mut type_name: Option<String> = None;
while let Some(key) = map.next_key::<String>()? {
match key.as_str() {
TYPE_FIELD => {
type_name = Some(map.next_value()?);
}
MAP_FIELD => {
let type_name = type_name
.take()
.ok_or_else(|| de::Error::missing_field(TYPE_FIELD))?;
let mut dynamic_properties =
map.next_value_seed(MapPropertyDeserializer { registry })?;
dynamic_properties.type_name = type_name;
return Ok(DynamicPropertiesOrProperty::DynamicProperties(
dynamic_properties,
));
}
SEQ_FIELD => {
let type_name = type_name
.take()
.ok_or_else(|| de::Error::missing_field(TYPE_FIELD))?;
let mut dynamic_properties =
map.next_value_seed(SeqPropertyDeserializer { registry })?;
dynamic_properties.type_name = type_name;
return Ok(DynamicPropertiesOrProperty::DynamicProperties(
dynamic_properties,
));
}
VALUE_FIELD => {
let type_name = type_name
.take()
.ok_or_else(|| de::Error::missing_field(TYPE_FIELD))?;
return Ok(DynamicPropertiesOrProperty::Property(map.next_value_seed(
PropertyDeserializer {
registry,
type_name: Some(&type_name),
},
)?));
}
_ => return Err(de::Error::unknown_field(key.as_str(), &[])),
}
}
Err(de::Error::custom("Maps in this location must have the \'type\' field and one of the following fields: \'map\', \'seq\', \'value\'"))
}

View file

@ -1,15 +0,0 @@
use crate::{
property_serde::DynamicPropertiesDeserializer, DynamicProperties, PropertyTypeRegistry,
};
use ron::de::Deserializer;
use serde::de::DeserializeSeed;
pub fn deserialize_dynamic_properties(
ron_string: &str,
property_type_registry: &PropertyTypeRegistry,
) -> Result<DynamicProperties, ron::Error> {
let mut deserializer = Deserializer::from_str(&ron_string).unwrap();
let dynamic_properties_deserializer =
DynamicPropertiesDeserializer::new(&property_type_registry);
dynamic_properties_deserializer.deserialize(&mut deserializer)
}

View file

@ -1,235 +0,0 @@
use crate::{DeserializeProperty, Property};
use bevy_utils::{HashMap, HashSet};
use std::{any::TypeId, fmt};
#[derive(Debug, Default)]
pub struct PropertyTypeRegistry {
registrations: HashMap<String, PropertyTypeRegistration>,
short_names: HashMap<String, String>,
ambiguous_names: HashSet<String>,
}
impl PropertyTypeRegistry {
pub fn register<T>(&mut self)
where
T: Property + DeserializeProperty,
{
let registration = PropertyTypeRegistration::of::<T>();
self.add_registration(registration);
}
fn add_registration(&mut self, registration: PropertyTypeRegistration) {
let short_name = registration.short_name.to_string();
if self.short_names.contains_key(&short_name) || self.ambiguous_names.contains(&short_name)
{
// name is ambiguous. fall back to long names for all ambiguous types
self.short_names.remove(&short_name);
self.ambiguous_names.insert(short_name);
} else {
self.short_names
.insert(short_name, registration.name.to_string());
}
self.registrations
.insert(registration.name.to_string(), registration);
}
pub fn get(&self, type_name: &str) -> Option<&PropertyTypeRegistration> {
if let Some(long_name) = self.short_names.get(type_name) {
self.registrations.get(long_name)
} else {
self.registrations.get(type_name)
}
}
pub fn format_type_name(&self, type_name: &str) -> Option<&str> {
self.get(type_name).map(|registration| {
if self.short_names.contains_key(&registration.short_name) {
&registration.short_name
} else {
registration.name
}
})
}
pub fn get_with_short_name(&self, short_type_name: &str) -> Option<&PropertyTypeRegistration> {
self.short_names
.get(short_type_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)]
pub struct PropertyTypeRegistration {
pub ty: TypeId,
deserialize_fn: fn(
deserializer: &mut dyn erased_serde::Deserializer,
property_type_registry: &PropertyTypeRegistry,
) -> Result<Box<dyn Property>, erased_serde::Error>,
pub short_name: String,
pub name: &'static str,
}
impl fmt::Debug for PropertyTypeRegistration {
fn fmt<'a>(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("PropertyTypeRegistration")
.field("ty", &self.ty)
.field(
"deserialize_fn",
&(self.deserialize_fn
as fn(
deserializer: &'a mut dyn erased_serde::Deserializer<'a>,
property_type_registry: &'a PropertyTypeRegistry,
) -> Result<Box<dyn Property>, erased_serde::Error>),
)
.field("short_name", &self.short_name)
.field("name", &self.name)
.finish()
}
}
impl PropertyTypeRegistration {
pub fn of<T: Property + DeserializeProperty>() -> Self {
let ty = TypeId::of::<T>();
let type_name = std::any::type_name::<T>();
Self {
ty,
deserialize_fn:
|deserializer: &mut dyn erased_serde::Deserializer,
property_type_registry: &PropertyTypeRegistry| {
T::deserialize(deserializer, property_type_registry)
},
name: type_name,
short_name: Self::get_short_name(type_name),
}
}
pub fn get_short_name(full_name: &str) -> String {
let mut short_name = String::new();
{
// A typename may be a composition of several other type names (e.g. generic parameters)
// separated by the characters that we try to find below.
// Then, each individual typename is shortened to its last path component.
//
// Note: Instead of `find`, `split_inclusive` would be nice but it's still unstable...
let mut remainder = full_name;
while let Some(index) = remainder.find(&['<', '>', '(', ')', '[', ']', ',', ';'][..]) {
let (path, new_remainder) = remainder.split_at(index);
// Push the shortened path in front of the found character
short_name.push_str(path.rsplit(':').next().unwrap());
// Push the character that was found
let character = new_remainder.chars().next().unwrap();
short_name.push(character);
// Advance the remainder
if character == ',' || character == ';' {
// A comma or semicolon is always followed by a space
short_name.push(' ');
remainder = &new_remainder[2..];
} else {
remainder = &new_remainder[1..];
}
}
// The remainder will only be non-empty if there were no matches at all
if !remainder.is_empty() {
// Then, the full typename is a path that has to be shortened
short_name.push_str(remainder.rsplit(':').next().unwrap());
}
}
short_name
}
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)
}
}
#[cfg(test)]
mod test {
use crate::PropertyTypeRegistration;
use std::collections::HashMap;
#[test]
fn test_get_short_name() {
assert_eq!(
PropertyTypeRegistration::get_short_name(std::any::type_name::<f64>()),
"f64"
);
assert_eq!(
PropertyTypeRegistration::get_short_name(std::any::type_name::<String>()),
"String"
);
assert_eq!(
PropertyTypeRegistration::get_short_name(std::any::type_name::<(u32, f64)>()),
"(u32, f64)"
);
assert_eq!(
PropertyTypeRegistration::get_short_name(std::any::type_name::<(String, String)>()),
"(String, String)"
);
assert_eq!(
PropertyTypeRegistration::get_short_name(std::any::type_name::<[f64]>()),
"[f64]"
);
assert_eq!(
PropertyTypeRegistration::get_short_name(std::any::type_name::<[String]>()),
"[String]"
);
assert_eq!(
PropertyTypeRegistration::get_short_name(std::any::type_name::<[f64; 16]>()),
"[f64; 16]"
);
assert_eq!(
PropertyTypeRegistration::get_short_name(std::any::type_name::<[String; 16]>()),
"[String; 16]"
);
}
#[test]
fn test_property_type_registration() {
assert_eq!(
PropertyTypeRegistration::of::<Option<f64>>().short_name,
"Option<f64>"
);
assert_eq!(
PropertyTypeRegistration::of::<HashMap<u32, String>>().short_name,
"HashMap<u32, String>"
);
assert_eq!(
PropertyTypeRegistration::of::<Option<HashMap<u32, String>>>().short_name,
"Option<HashMap<u32, String>>"
);
assert_eq!(
PropertyTypeRegistration::of::<Option<HashMap<u32, Option<String>>>>().short_name,
"Option<HashMap<u32, Option<String>>>"
);
assert_eq!(
PropertyTypeRegistration::of::<Option<HashMap<String, Option<String>>>>().short_name,
"Option<HashMap<String, Option<String>>>"
);
assert_eq!(
PropertyTypeRegistration::of::<Option<HashMap<Option<String>, Option<String>>>>()
.short_name,
"Option<HashMap<Option<String>, Option<String>>>"
);
assert_eq!(
PropertyTypeRegistration::of::<Option<HashMap<Option<String>, (String, Option<String>)>>>()
.short_name,
"Option<HashMap<Option<String>, (String, Option<String>)>>"
);
}
}

View file

@ -0,0 +1,36 @@
[package]
name = "bevy_reflect"
version = "0.3.0"
edition = "2018"
authors = [
"Bevy Contributors <bevyengine@gmail.com>",
"Carter Anderson <mcanders1@gmail.com>",
]
description = "Dynamically interact with rust types"
homepage = "https://bevyengine.org"
repository = "https://github.com/bevyengine/bevy"
license = "MIT"
keywords = ["bevy"]
readme = "README.md"
[features]
bevy = ["bevy_ecs", "bevy_app", "glam", "smallvec"]
[dependencies]
# bevy
bevy_reflect_derive = { path = "bevy_reflect_derive", version = "0.3.0" }
bevy_utils = { path = "../bevy_utils", version = "0.3.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.3.0", optional = true }
bevy_app = { path = "../bevy_app", version = "0.3.0", optional = true }
# other
erased-serde = "0.3"
downcast-rs = "1.2"
parking_lot = "0.11.0"
thiserror = "1.0"
serde = "1"
smallvec = { version = "1.4", features = ["serde"], optional = true }
glam = { version = "0.10.0", features = ["serde"], optional = true }
[dev-dependencies]
ron = "0.6.2"

View file

@ -0,0 +1,166 @@
# Bevy Reflect
This crate enables you to dynamically interact with Rust types:
* Derive the Reflect traits
* Interact with fields using their names (for named structs) or indices (for tuple structs)
* "Patch" your types with new values
* Look up nested fields using "path strings"
* Iterate over struct fields
* Automatically serialize and deserialize via Serde (without explicit serde impls)
* Trait "reflection"
## Features
### Derive the Reflect traits
```rust
// this will automatically implement the Reflect trait and the Struct trait (because the type is a struct)
#[derive(Reflect)]
struct Foo {
a: u32,
b: Bar
c: Vec<i32>,
d: Vec<Bar>,
}
// this will automatically implement the Reflect trait and the TupleStruct trait (because the type is a tuple struct)
#[derive(Reflect)]
struct Bar(String);
#[derive(Reflect)]
struct Baz {
value: f32,
};
// We will use this value to illustrate `bevy_reflect` features
let mut foo = Foo {
a: 1,
b: Bar("hello".to_string()),
c: vec![1, 2]
d: vec![Baz { value: 3.14 }]
};
```
### Interact with fields using their names
```rust
assert_eq!(*foo.get_field::<u32>("a").unwrap(), 1);
*foo.get_field_mut::<u32>("a").unwrap() = 2;
assert_eq!(foo.a, 2);
```
### "Patch" your types with new values
```rust
let mut dynamic_struct = DynamicStruct::default();
dynamic_struct.insert("a", 42u32);
dynamic_struct.insert("c", vec![3, 4, 5]);
foo.apply(&dynamic_struct);
assert_eq!(foo.a, 42);
assert_eq!(foo.c, vec![3, 4, 5]);
```
### Look up nested fields using "path strings"
```rust
let value = *foo.get_path::<f32>("d[0].value").unwrap();
assert_eq!(value, 3.14);
```
### Iterate over struct fields
```rust
for (i, value: &Reflect) in foo.iter_fields().enumerate() {
let field_name = foo.name_at(i).unwrap();
if let Ok(value) = value.downcast_ref::<u32>() {
println!("{} is a u32 with the value: {}", field_name, *value);
}
}
```
### Automatically serialize and deserialize via Serde (without explicit serde impls)
```rust
let mut registry = TypeRegistry::default();
registry.register::<u32>();
registry.register::<i32>();
registry.register::<f32>();
registry.register::<String>();
registry.register::<Bar>();
registry.register::<Baz>();
let serializer = ReflectSerializer::new(&foo, &registry);
let serialized = ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap();
let mut deserializer = ron::de::Deserializer::from_str(&serialized).unwrap();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let value = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let dynamic_struct = value.take::<DynamicStruct>().unwrap();
assert!(foo.partial_eq(&dynamic_struct).unwrap());
```
### Trait "reflection"
Call a trait on a given &dyn Reflect reference without knowing the underlying type!
```rust
#[derive(Reflect)]
#[reflect(DoThing)]
struct MyType {
value: String,
}
impl DoThing for MyType {
fn do_thing(&self) -> String {
format!("{} World!", self.value)
}
}
#[reflect_trait]
pub trait DoThing {
fn do_thing(&self) -> String;
}
// First, lets box our type as a Box<dyn Reflect>
let reflect_value: Box<dyn Reflect> = Box::new(MyType {
value: "Hello".to_string(),
});
// This means we no longer have direct access to MyType or its methods. We can only call Reflect methods on reflect_value.
// What if we want to call `do_thing` on our type? We could downcast using reflect_value.downcast_ref::<MyType>(), but what if we
// don't know the type at compile time?
// Normally in rust we would be out of luck at this point. Lets use our new reflection powers to do something cool!
let mut type_registry = TypeRegistry::default()
type_registry.register::<MyType>();
// The #[reflect] attribute we put on our DoThing trait generated a new `ReflectDoThing` struct, which implements TypeData.
// This was added to MyType's TypeRegistration.
let reflect_do_thing = type_registry
.get_type_data::<ReflectDoThing>(reflect_value.type_id())
.unwrap();
// We can use this generated type to convert our `&dyn Reflect` reference to a `&dyn DoThing` reference
let my_trait: &dyn DoThing = reflect_do_thing.get(&*reflect_value).unwrap();
// Which means we can now call do_thing(). Magic!
println!("{}", my_trait.do_thing());
// This works because the #[reflect(MyTrait)] we put on MyType informed the Reflect derive to insert a new instance
// of ReflectDoThing into MyType's registration. The instance knows how to cast &dyn Reflect to &dyn MyType, because it
// knows that &dyn Reflect should first be downcasted to &MyType, which can then be safely casted to &dyn MyType
```
## Why make this?
The whole point of Rust is static safety! Why build something that makes it easy to throw it all away?
* Some problems are inherently dynamic (scripting, some types of serialization / deserialization)
* Sometimes the dynamic way is easier
* Sometimes the dynamic way puts less burden on your users to derive a bunch of traits (this was a big motivator for the Bevy project)

View file

@ -1,12 +1,12 @@
[package]
name = "bevy_property_derive"
name = "bevy_reflect_derive"
version = "0.3.0"
edition = "2018"
authors = [
"Bevy Contributors <bevyengine@gmail.com>",
"Carter Anderson <mcanders1@gmail.com>",
]
description = "Derive implementations for bevy_property"
description = "Derive implementations for bevy_reflect"
homepage = "https://bevyengine.org"
repository = "https://github.com/bevyengine/bevy"
license = "MIT"
@ -20,3 +20,4 @@ syn = "1.0"
proc-macro2 = "1.0"
quote = "1.0"
find-crate = "0.5"
uuid = { version = "0.8", features = ["v4", "serde"] }

View file

@ -0,0 +1,751 @@
extern crate proc_macro;
mod modules;
mod reflect_trait;
mod type_uuid;
use find_crate::Manifest;
use modules::{get_modules, get_path};
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;
use syn::{
parenthesized,
parse::{Parse, ParseStream},
parse_macro_input,
punctuated::Punctuated,
token::{Comma, Paren, Where},
Data, DataStruct, DeriveInput, Field, Fields, Generics, Ident, Index, Member, Meta, NestedMeta,
Path,
};
#[derive(Default)]
struct PropAttributeArgs {
pub ignore: Option<bool>,
}
#[derive(Clone)]
enum TraitImpl {
NotImplemented,
Implemented,
Custom(Ident),
}
impl Default for TraitImpl {
fn default() -> Self {
Self::NotImplemented
}
}
enum DeriveType {
Struct,
TupleStruct,
UnitStruct,
Value,
}
static REFLECT_ATTRIBUTE_NAME: &str = "reflect";
static REFLECT_VALUE_ATTRIBUTE_NAME: &str = "reflect_value";
#[proc_macro_derive(Reflect, attributes(reflect, reflect_value, module))]
pub fn derive_reflect(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let unit_struct_punctuated = Punctuated::new();
let (fields, mut derive_type) = match &ast.data {
Data::Struct(DataStruct {
fields: Fields::Named(fields),
..
}) => (&fields.named, DeriveType::Struct),
Data::Struct(DataStruct {
fields: Fields::Unnamed(fields),
..
}) => (&fields.unnamed, DeriveType::TupleStruct),
Data::Struct(DataStruct {
fields: Fields::Unit,
..
}) => (&unit_struct_punctuated, DeriveType::UnitStruct),
_ => (&unit_struct_punctuated, DeriveType::Value),
};
let fields_and_args = fields
.iter()
.enumerate()
.map(|(i, f)| {
(
f,
f.attrs
.iter()
.find(|a| *a.path.get_ident().as_ref().unwrap() == REFLECT_ATTRIBUTE_NAME)
.map(|a| {
syn::custom_keyword!(ignore);
let mut attribute_args = PropAttributeArgs { ignore: None };
a.parse_args_with(|input: ParseStream| {
if input.parse::<Option<ignore>>()?.is_some() {
attribute_args.ignore = Some(true);
return Ok(());
}
Ok(())
})
.expect("invalid 'property' attribute format");
attribute_args
}),
i,
)
})
.collect::<Vec<(&Field, Option<PropAttributeArgs>, usize)>>();
let active_fields = fields_and_args
.iter()
.filter(|(_field, attrs, _i)| {
attrs.is_none()
|| match attrs.as_ref().unwrap().ignore {
Some(ignore) => !ignore,
None => true,
}
})
.map(|(f, _attr, i)| (*f, *i))
.collect::<Vec<(&Field, usize)>>();
let modules = get_modules();
let bevy_reflect_path = get_path(&modules.bevy_reflect);
let type_name = &ast.ident;
let mut reflect_attrs = ReflectAttrs::default();
for attribute in ast.attrs.iter().filter_map(|attr| attr.parse_meta().ok()) {
let meta_list = if let Meta::List(meta_list) = attribute {
meta_list
} else {
continue;
};
if let Some(ident) = meta_list.path.get_ident() {
if ident == REFLECT_ATTRIBUTE_NAME {
reflect_attrs = ReflectAttrs::from_nested_metas(&meta_list.nested);
} else if ident == REFLECT_VALUE_ATTRIBUTE_NAME {
derive_type = DeriveType::Value;
reflect_attrs = ReflectAttrs::from_nested_metas(&meta_list.nested);
}
}
}
let registration_data = &reflect_attrs.data;
let get_type_registration_impl = impl_get_type_registration(
type_name,
&bevy_reflect_path,
registration_data,
&ast.generics,
);
match derive_type {
DeriveType::Struct | DeriveType::UnitStruct => impl_struct(
type_name,
&ast.generics,
get_type_registration_impl,
&bevy_reflect_path,
&reflect_attrs,
&active_fields,
),
DeriveType::TupleStruct => impl_tuple_struct(
type_name,
&ast.generics,
get_type_registration_impl,
&bevy_reflect_path,
&reflect_attrs,
&active_fields,
),
DeriveType::Value => impl_value(
type_name,
&ast.generics,
get_type_registration_impl,
&bevy_reflect_path,
&reflect_attrs,
),
}
}
fn impl_struct(
struct_name: &Ident,
generics: &Generics,
get_type_registration_impl: proc_macro2::TokenStream,
bevy_reflect_path: &Path,
reflect_attrs: &ReflectAttrs,
active_fields: &[(&Field, usize)],
) -> TokenStream {
let field_names = active_fields
.iter()
.map(|(field, index)| {
field
.ident
.as_ref()
.map(|i| i.to_string())
.unwrap_or_else(|| index.to_string())
})
.collect::<Vec<String>>();
let field_idents = active_fields
.iter()
.map(|(field, index)| {
field
.ident
.as_ref()
.map(|ident| Member::Named(ident.clone()))
.unwrap_or_else(|| Member::Unnamed(Index::from(*index)))
})
.collect::<Vec<_>>();
let field_count = active_fields.len();
let field_indices = (0..field_count).collect::<Vec<usize>>();
let hash_fn = reflect_attrs.get_hash_impl(&bevy_reflect_path);
let serialize_fn = reflect_attrs.get_serialize_impl(&bevy_reflect_path);
let partial_eq_fn = match reflect_attrs.partial_eq {
TraitImpl::NotImplemented => quote! {
use #bevy_reflect_path::Struct;
#bevy_reflect_path::struct_partial_eq(self, value)
},
TraitImpl::Implemented | TraitImpl::Custom(_) => reflect_attrs.get_partial_eq_impl(),
};
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
TokenStream::from(quote! {
#get_type_registration_impl
impl #impl_generics #bevy_reflect_path::Struct for #struct_name#ty_generics #where_clause {
fn field(&self, name: &str) -> Option<&dyn #bevy_reflect_path::Reflect> {
match name {
#(#field_names => Some(&self.#field_idents),)*
_ => None,
}
}
fn field_mut(&mut self, name: &str) -> Option<&mut dyn #bevy_reflect_path::Reflect> {
match name {
#(#field_names => Some(&mut self.#field_idents),)*
_ => None,
}
}
fn field_at(&self, index: usize) -> Option<&dyn #bevy_reflect_path::Reflect> {
match index {
#(#field_indices => Some(&self.#field_idents),)*
_ => None,
}
}
fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn #bevy_reflect_path::Reflect> {
match index {
#(#field_indices => Some(&mut self.#field_idents),)*
_ => None,
}
}
fn name_at(&self, index: usize) -> Option<&str> {
match index {
#(#field_indices => Some(#field_names),)*
_ => None,
}
}
fn field_len(&self) -> usize {
#field_count
}
fn iter_fields(&self) -> #bevy_reflect_path::FieldIter {
#bevy_reflect_path::FieldIter::new(self)
}
fn clone_dynamic(&self) -> #bevy_reflect_path::DynamicStruct {
let mut dynamic = #bevy_reflect_path::DynamicStruct::default();
dynamic.set_name(self.type_name().to_string());
#(dynamic.insert_boxed(#field_names, self.#field_idents.clone_value());)*
dynamic
}
}
impl #impl_generics #bevy_reflect_path::Reflect for #struct_name#ty_generics #where_clause {
#[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_value(&self) -> Box<dyn #bevy_reflect_path::Reflect> {
use #bevy_reflect_path::Struct;
Box::new(self.clone_dynamic())
}
#[inline]
fn set(&mut self, value: Box<dyn #bevy_reflect_path::Reflect>) -> Result<(), Box<dyn #bevy_reflect_path::Reflect>> {
*self = value.take()?;
Ok(())
}
#[inline]
fn apply(&mut self, value: &dyn #bevy_reflect_path::Reflect) {
use #bevy_reflect_path::Struct;
if let #bevy_reflect_path::ReflectRef::Struct(struct_value) = value.reflect_ref() {
for (i, value) in struct_value.iter_fields().enumerate() {
let name = struct_value.name_at(i).unwrap();
self.field_mut(name).map(|v| v.apply(value));
}
} else {
panic!("attempted to apply non-struct type to struct type");
}
}
fn reflect_ref(&self) -> #bevy_reflect_path::ReflectRef {
#bevy_reflect_path::ReflectRef::Struct(self)
}
fn reflect_mut(&mut self) -> #bevy_reflect_path::ReflectMut {
#bevy_reflect_path::ReflectMut::Struct(self)
}
fn serializable(&self) -> Option<#bevy_reflect_path::serde::Serializable> {
#serialize_fn
}
fn hash(&self) -> Option<u64> {
#hash_fn
}
fn partial_eq(&self, value: &dyn #bevy_reflect_path::Reflect) -> Option<bool> {
#partial_eq_fn
}
}
})
}
fn impl_tuple_struct(
struct_name: &Ident,
generics: &Generics,
get_type_registration_impl: proc_macro2::TokenStream,
bevy_reflect_path: &Path,
reflect_attrs: &ReflectAttrs,
active_fields: &[(&Field, usize)],
) -> TokenStream {
let field_idents = active_fields
.iter()
.map(|(_field, index)| Member::Unnamed(Index::from(*index)))
.collect::<Vec<_>>();
let field_count = active_fields.len();
let field_indices = (0..field_count).collect::<Vec<usize>>();
let hash_fn = reflect_attrs.get_hash_impl(&bevy_reflect_path);
let serialize_fn = reflect_attrs.get_serialize_impl(&bevy_reflect_path);
let partial_eq_fn = match reflect_attrs.partial_eq {
TraitImpl::NotImplemented => quote! {
use #bevy_reflect_path::TupleStruct;
#bevy_reflect_path::tuple_struct_partial_eq(self, value)
},
TraitImpl::Implemented | TraitImpl::Custom(_) => reflect_attrs.get_partial_eq_impl(),
};
let (impl_generics, ty_generics, _where_clause) = generics.split_for_impl();
TokenStream::from(quote! {
#get_type_registration_impl
impl #impl_generics #bevy_reflect_path::TupleStruct for #struct_name#ty_generics {
fn field(&self, index: usize) -> Option<&dyn #bevy_reflect_path::Reflect> {
match index {
#(#field_indices => Some(&self.#field_idents),)*
_ => None,
}
}
fn field_mut(&mut self, index: usize) -> Option<&mut dyn #bevy_reflect_path::Reflect> {
match index {
#(#field_indices => Some(&mut self.#field_idents),)*
_ => None,
}
}
fn field_len(&self) -> usize {
#field_count
}
fn iter_fields(&self) -> #bevy_reflect_path::TupleStructFieldIter {
#bevy_reflect_path::TupleStructFieldIter::new(self)
}
fn clone_dynamic(&self) -> #bevy_reflect_path::DynamicTupleStruct {
let mut dynamic = #bevy_reflect_path::DynamicTupleStruct::default();
#(dynamic.insert_boxed(self.#field_idents.clone_value());)*
dynamic
}
}
impl #impl_generics #bevy_reflect_path::Reflect 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
}
#[inline]
fn any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
#[inline]
fn clone_value(&self) -> Box<dyn #bevy_reflect_path::Reflect> {
use #bevy_reflect_path::TupleStruct;
Box::new(self.clone_dynamic())
}
#[inline]
fn set(&mut self, value: Box<dyn #bevy_reflect_path::Reflect>) -> Result<(), Box<dyn #bevy_reflect_path::Reflect>> {
*self = value.take()?;
Ok(())
}
#[inline]
fn apply(&mut self, value: &dyn #bevy_reflect_path::Reflect) {
use #bevy_reflect_path::TupleStruct;
if let #bevy_reflect_path::ReflectRef::TupleStruct(struct_value) = value.reflect_ref() {
for (i, value) in struct_value.iter_fields().enumerate() {
self.field_mut(i).map(|v| v.apply(value));
}
} else {
panic!("attempted to apply non-TupleStruct type to TupleStruct type");
}
}
fn reflect_ref(&self) -> #bevy_reflect_path::ReflectRef {
#bevy_reflect_path::ReflectRef::TupleStruct(self)
}
fn reflect_mut(&mut self) -> #bevy_reflect_path::ReflectMut {
#bevy_reflect_path::ReflectMut::TupleStruct(self)
}
fn serializable(&self) -> Option<#bevy_reflect_path::serde::Serializable> {
#serialize_fn
}
fn hash(&self) -> Option<u64> {
#hash_fn
}
fn partial_eq(&self, value: &dyn #bevy_reflect_path::Reflect) -> Option<bool> {
#partial_eq_fn
}
}
})
}
fn impl_value(
type_name: &Ident,
generics: &Generics,
get_type_registration_impl: proc_macro2::TokenStream,
bevy_reflect_path: &Path,
reflect_attrs: &ReflectAttrs,
) -> TokenStream {
let hash_fn = reflect_attrs.get_hash_impl(&bevy_reflect_path);
let partial_eq_fn = reflect_attrs.get_partial_eq_impl();
let serialize_fn = reflect_attrs.get_serialize_impl(&bevy_reflect_path);
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
TokenStream::from(quote! {
#get_type_registration_impl
impl #impl_generics #bevy_reflect_path::Reflect for #type_name#ty_generics #where_clause {
#[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_value(&self) -> Box<dyn #bevy_reflect_path::Reflect> {
Box::new(self.clone())
}
#[inline]
fn apply(&mut self, value: &dyn #bevy_reflect_path::Reflect) {
let value = value.any();
if let Some(value) = value.downcast_ref::<Self>() {
*self = value.clone();
} else {
panic!("value is not {}", std::any::type_name::<Self>());
}
}
#[inline]
fn set(&mut self, value: Box<dyn #bevy_reflect_path::Reflect>) -> Result<(), Box<dyn #bevy_reflect_path::Reflect>> {
*self = value.take()?;
Ok(())
}
fn reflect_ref(&self) -> #bevy_reflect_path::ReflectRef {
#bevy_reflect_path::ReflectRef::Value(self)
}
fn reflect_mut(&mut self) -> #bevy_reflect_path::ReflectMut {
#bevy_reflect_path::ReflectMut::Value(self)
}
fn hash(&self) -> Option<u64> {
#hash_fn
}
fn partial_eq(&self, value: &dyn #bevy_reflect_path::Reflect) -> Option<bool> {
#partial_eq_fn
}
fn serializable(&self) -> Option<#bevy_reflect_path::serde::Serializable> {
#serialize_fn
}
}
})
}
struct ReflectDef {
type_name: Ident,
generics: Generics,
attrs: Option<ReflectAttrs>,
}
impl Parse for ReflectDef {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let type_ident = input.parse::<Ident>()?;
let generics = input.parse::<Generics>()?;
let mut lookahead = input.lookahead1();
let mut where_clause = None;
if lookahead.peek(Where) {
where_clause = Some(input.parse()?);
lookahead = input.lookahead1();
}
let mut attrs = None;
if lookahead.peek(Paren) {
let content;
parenthesized!(content in input);
attrs = Some(content.parse::<ReflectAttrs>()?);
}
Ok(ReflectDef {
type_name: type_ident,
generics: Generics {
where_clause,
..generics
},
attrs,
})
}
}
#[proc_macro]
pub fn impl_reflect_value(input: TokenStream) -> TokenStream {
let reflect_value_def = parse_macro_input!(input as ReflectDef);
let manifest = Manifest::new().unwrap();
let crate_path = if let Some(package) = manifest.find(|name| name == "bevy") {
format!("{}::reflect", package.name)
} else if let Some(package) = manifest.find(|name| name == "bevy_reflect") {
package.name
} else {
"crate".to_string()
};
let bevy_reflect_path = get_path(&crate_path);
let ty = &reflect_value_def.type_name;
let reflect_attrs = reflect_value_def
.attrs
.unwrap_or_else(ReflectAttrs::default);
let registration_data = &reflect_attrs.data;
let get_type_registration_impl = impl_get_type_registration(
ty,
&bevy_reflect_path,
registration_data,
&reflect_value_def.generics,
);
impl_value(
ty,
&reflect_value_def.generics,
get_type_registration_impl,
&bevy_reflect_path,
&reflect_attrs,
)
}
#[derive(Default)]
struct ReflectAttrs {
hash: TraitImpl,
partial_eq: TraitImpl,
serialize: TraitImpl,
data: Vec<Ident>,
}
impl ReflectAttrs {
fn from_nested_metas(nested_metas: &Punctuated<NestedMeta, Comma>) -> Self {
let mut attrs = ReflectAttrs::default();
for nested_meta in nested_metas.iter() {
match nested_meta {
NestedMeta::Lit(_) => {}
NestedMeta::Meta(meta) => match meta {
Meta::Path(path) => {
if let Some(segment) = path.segments.iter().next() {
let ident = segment.ident.to_string();
match ident.as_str() {
"PartialEq" => attrs.partial_eq = TraitImpl::Implemented,
"Hash" => attrs.hash = TraitImpl::Implemented,
"Serialize" => attrs.serialize = TraitImpl::Implemented,
_ => attrs.data.push(Ident::new(
&format!("Reflect{}", segment.ident),
Span::call_site(),
)),
}
}
}
Meta::List(list) => {
let ident = if let Some(segment) = list.path.segments.iter().next() {
segment.ident.to_string()
} else {
continue;
};
if let Some(list_nested) = list.nested.iter().next() {
match list_nested {
NestedMeta::Meta(list_nested_meta) => match list_nested_meta {
Meta::Path(path) => {
if let Some(segment) = path.segments.iter().next() {
match ident.as_str() {
"PartialEq" => {
attrs.partial_eq =
TraitImpl::Custom(segment.ident.clone())
}
"Hash" => {
attrs.hash =
TraitImpl::Custom(segment.ident.clone())
}
"Serialize" => {
attrs.serialize =
TraitImpl::Custom(segment.ident.clone())
}
_ => {}
}
}
}
Meta::List(_) => {}
Meta::NameValue(_) => {}
},
NestedMeta::Lit(_) => {}
}
}
}
Meta::NameValue(_) => {}
},
}
}
attrs
}
fn get_hash_impl(&self, path: &Path) -> proc_macro2::TokenStream {
match &self.hash {
TraitImpl::Implemented => quote! {
use std::hash::{Hash, Hasher};
let mut hasher = #path::ReflectHasher::default();
Hash::hash(&std::any::Any::type_id(self), &mut hasher);
Hash::hash(self, &mut hasher);
Some(hasher.finish())
},
TraitImpl::Custom(impl_fn) => quote! {
Some(#impl_fn(self))
},
TraitImpl::NotImplemented => quote! {
None
},
}
}
fn get_partial_eq_impl(&self) -> proc_macro2::TokenStream {
match &self.partial_eq {
TraitImpl::Implemented => quote! {
let value = value.any();
if let Some(value) = value.downcast_ref::<Self>() {
Some(std::cmp::PartialEq::eq(self, value))
} else {
Some(false)
}
},
TraitImpl::Custom(impl_fn) => quote! {
Some(#impl_fn(self, value))
},
TraitImpl::NotImplemented => quote! {
None
},
}
}
fn get_serialize_impl(&self, path: &Path) -> proc_macro2::TokenStream {
match &self.serialize {
TraitImpl::Implemented => quote! {
Some(#path::serde::Serializable::Borrowed(self))
},
TraitImpl::Custom(impl_fn) => quote! {
Some(#impl_fn(self))
},
TraitImpl::NotImplemented => quote! {
None
},
}
}
}
impl Parse for ReflectAttrs {
fn parse(input: ParseStream) -> syn::Result<Self> {
let result = Punctuated::<NestedMeta, Comma>::parse_terminated(input)?;
Ok(ReflectAttrs::from_nested_metas(&result))
}
}
fn impl_get_type_registration(
type_name: &Ident,
bevy_reflect_path: &Path,
registration_data: &[Ident],
generics: &Generics,
) -> proc_macro2::TokenStream {
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
quote! {
#[allow(unused_mut)]
impl #impl_generics #bevy_reflect_path::GetTypeRegistration for #type_name#ty_generics #where_clause {
fn get_type_registration() -> #bevy_reflect_path::TypeRegistration {
let mut registration = #bevy_reflect_path::TypeRegistration::of::<#type_name#ty_generics>();
#(registration.insert::<#registration_data>(#bevy_reflect_path::FromType::<#type_name#ty_generics>::from_type());)*
registration
}
}
}
}
// From https://github.com/randomPoison/type-uuid
#[proc_macro_derive(TypeUuid, attributes(uuid))]
pub fn type_uuid_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
type_uuid::type_uuid_derive(input)
}
#[proc_macro]
pub fn external_type_uuid(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
type_uuid::external_type_uuid(tokens)
}
#[proc_macro_attribute]
pub fn reflect_trait(args: TokenStream, input: TokenStream) -> TokenStream {
reflect_trait::reflect_trait(args, input)
}

View file

@ -4,38 +4,42 @@ use syn::Path;
#[derive(Debug)]
pub struct Modules {
pub bevy_property: String,
pub bevy_reflect: String,
}
impl Modules {
pub fn meta(name: &str) -> Modules {
Modules {
bevy_property: format!("{}::property", name),
bevy_reflect: format!("{}::reflect", name),
}
}
pub fn external() -> Modules {
Modules {
bevy_property: "bevy_property".to_string(),
bevy_reflect: "bevy_reflect".to_string(),
}
}
pub fn internal() -> Modules {
Modules {
bevy_reflect: "crate".to_string(),
}
}
}
fn get_meta() -> Option<Modules> {
pub fn get_modules() -> Modules {
let manifest = Manifest::new().unwrap();
if let Some(package) = manifest.find(|name| name == "bevy") {
Some(Modules::meta(&package.name))
Modules::meta(&package.name)
} else if let Some(package) = manifest.find(|name| name == "bevy_internal") {
Some(Modules::meta(&package.name))
Modules::meta(&package.name)
} else if let Some(_package) = manifest.find(|name| name == "bevy_reflect") {
Modules::external()
} else {
None
Modules::internal()
}
}
pub fn get_modules() -> Modules {
get_meta().unwrap_or_else(Modules::external)
}
pub fn get_path(path_str: &str) -> Path {
syn::parse(path_str.parse::<TokenStream>().unwrap()).unwrap()
}

View file

@ -0,0 +1,66 @@
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;
use syn::{parse::Parse, parse_macro_input, Attribute, Ident, ItemTrait, Token};
use crate::modules::{get_modules, get_path};
pub struct TraitInfo {
item_trait: ItemTrait,
}
impl Parse for TraitInfo {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let attrs = input.call(Attribute::parse_outer)?;
let lookahead = input.lookahead1();
if lookahead.peek(Token![pub]) || lookahead.peek(Token![trait]) {
let mut item_trait: ItemTrait = input.parse()?;
item_trait.attrs = attrs;
Ok(TraitInfo { item_trait })
} else {
Err(lookahead.error())
}
}
}
pub fn reflect_trait(_args: TokenStream, input: TokenStream) -> TokenStream {
let trait_info = parse_macro_input!(input as TraitInfo);
let item_trait = &trait_info.item_trait;
let trait_ident = &item_trait.ident;
let reflect_trait_ident =
Ident::new(&format!("Reflect{}", item_trait.ident), Span::call_site());
let modules = get_modules();
let bevy_reflect_path = get_path(&modules.bevy_reflect);
TokenStream::from(quote! {
#item_trait
#[derive(Clone)]
pub struct #reflect_trait_ident {
get_func: fn(&dyn #bevy_reflect_path::Reflect) -> Option<&dyn #trait_ident>,
get_mut_func: fn(&mut dyn #bevy_reflect_path::Reflect) -> Option<&mut dyn #trait_ident>,
}
impl #reflect_trait_ident {
fn get<'a>(&self, reflect_value: &'a dyn #bevy_reflect_path::Reflect) -> Option<&'a dyn #trait_ident> {
(self.get_func)(reflect_value)
}
fn get_mut<'a>(&self, reflect_value: &'a mut dyn #bevy_reflect_path::Reflect) -> Option<&'a mut dyn #trait_ident> {
(self.get_mut_func)(reflect_value)
}
}
impl<T: #trait_ident + #bevy_reflect_path::Reflect> #bevy_reflect_path::FromType<T> for #reflect_trait_ident {
fn from_type() -> Self {
Self {
get_func: |reflect_value| {
reflect_value.downcast_ref::<T>().map(|value| value as &dyn #trait_ident)
},
get_mut_func: |reflect_value| {
reflect_value.downcast_mut::<T>().map(|value| value as &mut dyn #trait_ident)
}
}
}
}
})
}

View file

@ -10,8 +10,8 @@ pub fn type_uuid_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStre
// Construct a representation of Rust code as a syntax tree
// that we can manipulate
let ast: DeriveInput = syn::parse(input).unwrap();
let modules = get_modules(&ast.attrs);
let bevy_type_registry_path: Path = get_path(&modules.bevy_type_registry);
let modules = get_modules();
let bevy_reflect_path: Path = get_path(&modules.bevy_reflect);
// Build the trait implementation
let name = &ast.ident;
@ -53,8 +53,8 @@ pub fn type_uuid_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStre
.map(|byte_str| syn::parse_str::<LitInt>(&byte_str).unwrap());
let gen = quote! {
impl #bevy_type_registry_path::TypeUuid for #name {
const TYPE_UUID: #bevy_type_registry_path::Uuid = #bevy_type_registry_path::Uuid::from_bytes([
impl #bevy_reflect_path::TypeUuid for #name {
const TYPE_UUID: #bevy_reflect_path::Uuid = #bevy_reflect_path::Uuid::from_bytes([
#( #bytes ),*
]);
}

View file

@ -0,0 +1,57 @@
use crate::{impl_reflect_value, GetTypeRegistration, ReflectDeserialize, TypeRegistryArc};
use bevy_app::{AppBuilder, Plugin};
use bevy_ecs::Entity;
#[derive(Default)]
pub struct ReflectPlugin;
impl Plugin for ReflectPlugin {
fn build(&self, app: &mut AppBuilder) {
app.init_resource::<TypeRegistryArc>()
.register_type::<bool>()
.register_type::<u8>()
.register_type::<u16>()
.register_type::<u32>()
.register_type::<u64>()
.register_type::<u128>()
.register_type::<usize>()
.register_type::<i8>()
.register_type::<i16>()
.register_type::<i32>()
.register_type::<i64>()
.register_type::<i128>()
.register_type::<isize>()
.register_type::<f32>()
.register_type::<f64>()
.register_type::<String>();
#[cfg(feature = "glam")]
{
app.register_type::<glam::Vec2>()
.register_type::<glam::Vec3>()
.register_type::<glam::Vec4>()
.register_type::<glam::Mat3>()
.register_type::<glam::Mat4>()
.register_type::<glam::Quat>();
}
#[cfg(feature = "bevy_ecs")]
{
app.register_type::<bevy_ecs::Entity>();
}
}
}
impl_reflect_value!(Entity(Hash, PartialEq, Serialize, Deserialize));
pub trait RegisterTypeBuilder {
fn register_type<T: GetTypeRegistration>(&mut self) -> &mut Self;
}
impl RegisterTypeBuilder for AppBuilder {
fn register_type<T: GetTypeRegistration>(&mut self) -> &mut Self {
{
let registry = self.resources().get_mut::<TypeRegistryArc>().unwrap();
registry.write().register::<T>();
}
self
}
}

View file

@ -0,0 +1,217 @@
use crate::{FromType, Reflect};
use bevy_ecs::{
Archetype, Component, Entity, EntityMap, FromResources, MapEntities, MapEntitiesError,
Resources, World,
};
use std::marker::PhantomData;
#[derive(Clone)]
pub struct ReflectComponent {
add_component: fn(&mut World, resources: &Resources, Entity, &dyn Reflect),
apply_component: fn(&mut World, Entity, &dyn Reflect),
reflect_component: unsafe fn(&Archetype, usize) -> &dyn Reflect,
copy_component: fn(&World, &mut World, &Resources, Entity, Entity),
}
impl ReflectComponent {
pub fn add_component(
&self,
world: &mut World,
resources: &Resources,
entity: Entity,
component: &dyn Reflect,
) {
(self.add_component)(world, resources, entity, component);
}
pub fn apply_component(&self, world: &mut World, entity: Entity, component: &dyn Reflect) {
(self.apply_component)(world, entity, component);
}
/// # Safety
/// This does not do bound checks on entity_index. You must make sure entity_index is within bounds before calling.
pub unsafe fn reflect_component<'a>(
&self,
archetype: &'a Archetype,
entity_index: usize,
) -> &'a dyn Reflect {
(self.reflect_component)(archetype, entity_index)
}
pub fn copy_component(
&self,
source_world: &World,
destination_world: &mut World,
resources: &Resources,
source_entity: Entity,
destination_entity: Entity,
) {
(self.copy_component)(
source_world,
destination_world,
resources,
source_entity,
destination_entity,
);
}
}
impl<C: Component + Reflect + FromResources> FromType<C> for ReflectComponent {
fn from_type() -> Self {
ReflectComponent {
add_component: |world, resources, entity, reflected_component| {
let mut component = C::from_resources(resources);
component.apply(reflected_component);
world.insert_one(entity, component).unwrap();
},
apply_component: |world, entity, reflected_component| {
let mut component = world.get_mut::<C>(entity).unwrap();
component.apply(reflected_component);
},
copy_component: |source_world,
destination_world,
resources,
source_entity,
destination_entity| {
let source_component = source_world.get::<C>(source_entity).unwrap();
let mut destination_component = C::from_resources(resources);
destination_component.apply(source_component);
destination_world
.insert_one(destination_entity, destination_component)
.unwrap();
},
reflect_component: |archetype, index| {
unsafe {
// the type has been looked up by the caller, so this is safe
let ptr = archetype.get::<C>().unwrap().as_ptr().add(index);
ptr.as_ref().unwrap()
}
},
}
}
}
#[derive(Clone)]
pub struct SceneComponent<Scene: Component, Runtime: Component> {
copy_scene_to_runtime: fn(&World, &mut World, &Resources, Entity, Entity),
marker: PhantomData<(Scene, Runtime)>,
}
impl<Scene: Component + IntoComponent<Runtime>, Runtime: Component> SceneComponent<Scene, Runtime> {
pub fn copy_scene_to_runtime(
&self,
scene_world: &World,
runtime_world: &mut World,
resources: &Resources,
scene_entity: Entity,
runtime_entity: Entity,
) {
(self.copy_scene_to_runtime)(
scene_world,
runtime_world,
resources,
scene_entity,
runtime_entity,
);
}
}
impl<Scene: Component + IntoComponent<Runtime>, Runtime: Component> FromType<Scene>
for SceneComponent<Scene, Runtime>
{
fn from_type() -> Self {
SceneComponent {
copy_scene_to_runtime: |scene_world,
runtime_world,
resources,
scene_entity,
runtime_entity| {
let scene_component = scene_world.get::<Scene>(scene_entity).unwrap();
let destination_component = scene_component.into_component(resources);
runtime_world
.insert_one(runtime_entity, destination_component)
.unwrap();
},
marker: Default::default(),
}
}
}
#[derive(Clone)]
pub struct RuntimeComponent<Runtime: Component, Scene: Component> {
copy_runtime_to_scene: fn(&World, &mut World, &Resources, Entity, Entity),
marker: PhantomData<(Runtime, Scene)>,
}
impl<Runtime: Component + IntoComponent<Scene>, Scene: Component> RuntimeComponent<Runtime, Scene> {
pub fn copy_runtime_to_scene(
&self,
runtime_world: &World,
scene_world: &mut World,
resources: &Resources,
runtime_entity: Entity,
scene_entity: Entity,
) {
(self.copy_runtime_to_scene)(
runtime_world,
scene_world,
resources,
runtime_entity,
scene_entity,
);
}
}
impl<Runtime: Component + IntoComponent<Scene>, Scene: Component> FromType<Runtime>
for RuntimeComponent<Runtime, Scene>
{
fn from_type() -> Self {
RuntimeComponent {
copy_runtime_to_scene: |runtime_world,
scene_world,
resources,
runtime_entity,
scene_entity| {
let runtime_component = runtime_world.get::<Runtime>(runtime_entity).unwrap();
let scene_component = runtime_component.into_component(resources);
scene_world
.insert_one(scene_entity, scene_component)
.unwrap();
},
marker: Default::default(),
}
}
}
#[derive(Clone)]
pub struct ReflectMapEntities {
map_entities: fn(&mut World, &EntityMap) -> Result<(), MapEntitiesError>,
}
impl ReflectMapEntities {
pub fn map_entities(
&self,
world: &mut World,
entity_map: &EntityMap,
) -> Result<(), MapEntitiesError> {
(self.map_entities)(world, entity_map)
}
}
impl<C: Component + MapEntities> FromType<C> for ReflectMapEntities {
fn from_type() -> Self {
ReflectMapEntities {
map_entities: |world, entity_map| {
for mut component in &mut world.query_mut::<&mut C>() {
component.map_entities(entity_map)?;
}
Ok(())
},
}
}
}
pub trait IntoComponent<ToComponent: Component> {
fn into_component(&self, resources: &Resources) -> ToComponent;
}

View file

@ -0,0 +1,10 @@
use crate::ReflectDeserialize;
use bevy_reflect_derive::impl_reflect_value;
use glam::{Mat3, Mat4, Quat, Vec2, Vec3, Vec4};
impl_reflect_value!(Vec2(PartialEq, Serialize, Deserialize));
impl_reflect_value!(Vec3(PartialEq, Serialize, Deserialize));
impl_reflect_value!(Vec4(PartialEq, Serialize, Deserialize));
impl_reflect_value!(Mat3(PartialEq, Serialize, Deserialize));
impl_reflect_value!(Mat4(PartialEq, Serialize, Deserialize));
impl_reflect_value!(Quat(PartialEq, Serialize, Deserialize));

View file

@ -0,0 +1,96 @@
use smallvec::{Array, SmallVec};
use std::any::Any;
use crate::{serde::Serializable, List, ListIter, Reflect, ReflectMut, ReflectRef};
impl<T: Array + Send + Sync + 'static> List for SmallVec<T>
where
T::Item: Reflect + Clone,
{
fn get(&self, index: usize) -> Option<&dyn Reflect> {
if index < SmallVec::len(self) {
Some(&self[index] as &dyn Reflect)
} else {
None
}
}
fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {
if index < SmallVec::len(self) {
Some(&mut self[index] as &mut dyn Reflect)
} else {
None
}
}
fn len(&self) -> usize {
<SmallVec<T>>::len(self)
}
fn push(&mut self, value: Box<dyn Reflect>) {
let value = value.take::<T::Item>().unwrap_or_else(|value| {
panic!(
"Attempted to push invalid value of type {}",
value.type_name()
)
});
SmallVec::push(self, value);
}
fn iter(&self) -> ListIter {
ListIter {
list: self,
index: 0,
}
}
}
impl<T: Array + Send + Sync + 'static> Reflect for SmallVec<T>
where
T::Item: Reflect + Clone,
{
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 apply(&mut self, value: &dyn Reflect) {
crate::list_apply(self, value);
}
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::List(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::List(self)
}
fn clone_value(&self) -> Box<dyn Reflect> {
Box::new(self.clone_dynamic())
}
fn hash(&self) -> Option<u64> {
None
}
fn partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
crate::list_partial_eq(self, value)
}
fn serializable(&self) -> Option<Serializable> {
None
}
}

View file

@ -0,0 +1,201 @@
use crate::{
map_partial_eq, serde::Serializable, DynamicMap, List, ListIter, Map, MapIter, Reflect,
ReflectDeserialize, ReflectMut, ReflectRef,
};
use bevy_reflect_derive::impl_reflect_value;
use bevy_utils::{HashMap, HashSet};
use serde::{Deserialize, Serialize};
use std::{any::Any, hash::Hash, ops::Range};
impl_reflect_value!(bool(Hash, PartialEq, Serialize, Deserialize));
impl_reflect_value!(u8(Hash, PartialEq, Serialize, Deserialize));
impl_reflect_value!(u16(Hash, PartialEq, Serialize, Deserialize));
impl_reflect_value!(u32(Hash, PartialEq, Serialize, Deserialize));
impl_reflect_value!(u64(Hash, PartialEq, Serialize, Deserialize));
impl_reflect_value!(u128(Hash, PartialEq, Serialize, Deserialize));
impl_reflect_value!(usize(Hash, PartialEq, Serialize, Deserialize));
impl_reflect_value!(i8(Hash, PartialEq, Serialize, Deserialize));
impl_reflect_value!(i16(Hash, PartialEq, Serialize, Deserialize));
impl_reflect_value!(i32(Hash, PartialEq, Serialize, Deserialize));
impl_reflect_value!(i64(Hash, PartialEq, Serialize, Deserialize));
impl_reflect_value!(i128(Hash, PartialEq, Serialize, Deserialize));
impl_reflect_value!(isize(Hash, PartialEq, Serialize, Deserialize));
impl_reflect_value!(f32(Serialize, Deserialize));
impl_reflect_value!(f64(Serialize, Deserialize));
impl_reflect_value!(String(Hash, PartialEq, Serialize, Deserialize));
impl_reflect_value!(Option<T: Serialize + Clone + for<'de> Deserialize<'de> + Reflect + 'static>(Serialize, Deserialize));
impl_reflect_value!(HashSet<T: Serialize + Hash + Eq + Clone + for<'de> Deserialize<'de> + Send + Sync + 'static>(Serialize, Deserialize));
impl_reflect_value!(Range<T: Serialize + Clone + for<'de> Deserialize<'de> + Send + Sync + 'static>(Serialize, Deserialize));
impl<T: Reflect> List for Vec<T> {
fn get(&self, index: usize) -> Option<&dyn Reflect> {
<[T]>::get(self, index).map(|value| value as &dyn Reflect)
}
fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {
<[T]>::get_mut(self, index).map(|value| value as &mut dyn Reflect)
}
fn len(&self) -> usize {
<[T]>::len(self)
}
fn iter(&self) -> ListIter {
ListIter {
list: self,
index: 0,
}
}
fn push(&mut self, value: Box<dyn Reflect>) {
let value = value.take::<T>().unwrap_or_else(|value| {
panic!(
"Attempted to push invalid value of type {}",
value.type_name()
)
});
Vec::push(self, value);
}
}
impl<T: Reflect> Reflect for Vec<T> {
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 apply(&mut self, value: &dyn Reflect) {
crate::list_apply(self, value);
}
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::List(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::List(self)
}
fn clone_value(&self) -> Box<dyn Reflect> {
Box::new(self.clone_dynamic())
}
fn hash(&self) -> Option<u64> {
None
}
fn partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
crate::list_partial_eq(self, value)
}
fn serializable(&self) -> Option<Serializable> {
None
}
}
impl<K: Reflect + Clone + Eq + Hash, V: Reflect + Clone> Map for HashMap<K, V> {
fn get(&self, key: &dyn Reflect) -> Option<&dyn Reflect> {
key.downcast_ref::<K>()
.and_then(|key| HashMap::get(self, key))
.map(|value| value as &dyn Reflect)
}
fn get_mut(&mut self, key: &dyn Reflect) -> Option<&mut dyn Reflect> {
key.downcast_ref::<K>()
.and_then(move |key| HashMap::get_mut(self, key))
.map(|value| value as &mut dyn Reflect)
}
fn get_at(&self, index: usize) -> Option<(&dyn Reflect, &dyn Reflect)> {
self.iter()
.nth(index)
.map(|(key, value)| (key as &dyn Reflect, value as &dyn Reflect))
}
fn len(&self) -> usize {
HashMap::len(self)
}
fn iter(&self) -> MapIter {
MapIter {
map: self,
index: 0,
}
}
fn clone_dynamic(&self) -> DynamicMap {
let mut dynamic_map = DynamicMap::default();
for (k, v) in HashMap::iter(self) {
dynamic_map.insert_boxed(k.clone_value(), v.clone_value());
}
dynamic_map
}
}
impl<K: Reflect + Clone + Eq + Hash, V: Reflect + Clone> Reflect for HashMap<K, V> {
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 apply(&mut self, value: &dyn Reflect) {
if let ReflectRef::Map(map_value) = value.reflect_ref() {
for (key, value) in map_value.iter() {
if let Some(v) = Map::get_mut(self, key) {
v.apply(value)
}
}
} else {
panic!("attempted to apply a non-map type to a map type");
}
}
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Map(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Map(self)
}
fn clone_value(&self) -> Box<dyn Reflect> {
Box::new(self.clone_dynamic())
}
fn hash(&self) -> Option<u64> {
None
}
fn partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
map_partial_eq(self, value)
}
fn serializable(&self) -> Option<Serializable> {
None
}
}

View file

@ -0,0 +1,323 @@
mod list;
mod map;
mod path;
mod reflect;
mod struct_trait;
mod tuple_struct;
mod type_registry;
mod type_uuid;
mod impls {
#[cfg(feature = "bevy_app")]
mod bevy_app;
#[cfg(feature = "bevy_ecs")]
mod bevy_ecs;
#[cfg(feature = "glam")]
mod glam;
#[cfg(feature = "smallvec")]
mod smallvec;
mod std;
#[cfg(feature = "bevy_app")]
pub use self::bevy_app::*;
#[cfg(feature = "bevy_ecs")]
pub use self::bevy_ecs::*;
#[cfg(feature = "glam")]
pub use self::glam::*;
#[cfg(feature = "smallvec")]
pub use self::smallvec::*;
pub use self::std::*;
}
pub mod serde;
pub mod prelude {
#[cfg(feature = "bevy_ecs")]
pub use crate::ReflectComponent;
#[cfg(feature = "bevy_app")]
pub use crate::RegisterTypeBuilder;
pub use crate::{
reflect_trait, GetField, GetTupleStructField, Reflect, ReflectDeserialize, Struct,
TupleStruct,
};
}
pub use impls::*;
pub use list::*;
pub use map::*;
pub use path::*;
pub use reflect::*;
pub use struct_trait::*;
pub use tuple_struct::*;
pub use type_registry::*;
pub use type_uuid::*;
pub use bevy_reflect_derive::*;
pub use erased_serde;
#[cfg(test)]
mod tests {
use ::serde::de::DeserializeSeed;
use bevy_utils::HashMap;
use ron::{
ser::{to_string_pretty, PrettyConfig},
Deserializer,
};
use crate::serde::{ReflectDeserializer, ReflectSerializer};
use super::*;
#[test]
fn reflect_struct() {
#[derive(Reflect)]
struct Foo {
a: u32,
b: f32,
c: Bar,
}
#[derive(Reflect)]
struct Bar {
x: u32,
}
let mut foo = Foo {
a: 42,
b: 3.14,
c: Bar { x: 1 },
};
let a = *foo.get_field::<u32>("a").unwrap();
assert_eq!(a, 42);
*foo.get_field_mut::<u32>("a").unwrap() += 1;
assert_eq!(foo.a, 43);
let bar = foo.get_field::<Bar>("c").unwrap();
assert_eq!(bar.x, 1);
// nested retrieval
let c = foo.field("c").unwrap();
if let ReflectRef::Struct(value) = c.reflect_ref() {
assert_eq!(*value.get_field::<u32>("x").unwrap(), 1);
} else {
panic!("expected a struct");
}
// patch Foo with a dynamic struct
let mut dynamic_struct = DynamicStruct::default();
dynamic_struct.insert("a", 123u32);
dynamic_struct.insert("should_be_ignored", 456);
foo.apply(&dynamic_struct);
assert_eq!(foo.a, 123);
}
#[test]
fn reflect_map() {
#[derive(Reflect, Hash)]
#[reflect(Hash)]
struct Foo {
a: u32,
b: String,
}
let key_a = Foo {
a: 1,
b: "k1".to_string(),
};
let key_b = Foo {
a: 1,
b: "k1".to_string(),
};
let key_c = Foo {
a: 3,
b: "k3".to_string(),
};
let mut map = DynamicMap::default();
map.insert(key_a, 10u32);
assert_eq!(10, *map.get(&key_b).unwrap().downcast_ref::<u32>().unwrap());
assert!(map.get(&key_c).is_none());
*map.get_mut(&key_b).unwrap().downcast_mut::<u32>().unwrap() = 20;
assert_eq!(20, *map.get(&key_b).unwrap().downcast_ref::<u32>().unwrap());
}
#[test]
fn reflect_unit_struct() {
#[derive(Reflect)]
struct Foo(u32, u64);
let mut foo = Foo(1, 2);
assert_eq!(1, *foo.get_field::<u32>(0).unwrap());
assert_eq!(2, *foo.get_field::<u64>(1).unwrap());
let mut patch = DynamicTupleStruct::default();
patch.insert(3u32);
patch.insert(4u64);
assert_eq!(3, *patch.field(0).unwrap().downcast_ref::<u32>().unwrap());
assert_eq!(4, *patch.field(1).unwrap().downcast_ref::<u64>().unwrap());
foo.apply(&patch);
assert_eq!(3, foo.0);
assert_eq!(4, foo.1);
let mut iter = patch.iter_fields();
assert_eq!(3, *iter.next().unwrap().downcast_ref::<u32>().unwrap());
assert_eq!(4, *iter.next().unwrap().downcast_ref::<u64>().unwrap());
}
#[test]
#[should_panic(expected = "the given key does not support hashing")]
fn reflect_map_no_hash() {
#[derive(Reflect)]
struct Foo {
a: u32,
}
let foo = Foo { a: 1 };
let mut map = DynamicMap::default();
map.insert(foo, 10u32);
}
#[test]
fn reflect_ignore() {
#[derive(Reflect)]
struct Foo {
a: u32,
#[reflect(ignore)]
_b: u32,
}
let foo = Foo { a: 1, _b: 2 };
let values: Vec<u32> = foo
.iter_fields()
.map(|value| *value.downcast_ref::<u32>().unwrap())
.collect();
assert_eq!(values, vec![1]);
}
#[test]
fn reflect_complex_patch() {
#[derive(Reflect, Eq, PartialEq, Debug)]
struct Foo {
a: u32,
#[reflect(ignore)]
_b: u32,
c: Vec<isize>,
d: HashMap<usize, i8>,
e: Bar,
}
#[derive(Reflect, Eq, PartialEq, Debug)]
struct Bar {
x: u32,
}
let mut hash_map = HashMap::default();
hash_map.insert(1, 1);
hash_map.insert(2, 2);
let mut foo = Foo {
a: 1,
_b: 1,
c: vec![1, 2],
d: hash_map,
e: Bar { x: 1 },
};
let mut foo_patch = DynamicStruct::default();
foo_patch.insert("a", 2u32);
foo_patch.insert("b", 2u32); // this should be ignored
let mut list = DynamicList::default();
list.push(3isize);
list.push(4isize);
list.push(5isize);
foo_patch.insert("c", list);
let mut map = DynamicMap::default();
map.insert(2usize, 3i8);
foo_patch.insert("d", map);
let mut bar_patch = DynamicStruct::default();
bar_patch.insert("x", 2u32);
foo_patch.insert("e", bar_patch);
foo.apply(&foo_patch);
let mut hash_map = HashMap::default();
hash_map.insert(1, 1);
hash_map.insert(2, 3);
let expected_foo = Foo {
a: 2,
_b: 1,
c: vec![3, 4, 5],
d: hash_map,
e: Bar { x: 2 },
};
assert_eq!(foo, expected_foo);
}
#[test]
fn reflect_serialize() {
#[derive(Reflect)]
struct Foo {
a: u32,
#[reflect(ignore)]
_b: u32,
c: Vec<isize>,
d: HashMap<usize, i8>,
e: Bar,
f: String,
}
#[derive(Reflect)]
struct Bar {
x: u32,
}
let mut hash_map = HashMap::default();
hash_map.insert(1, 1);
hash_map.insert(2, 2);
let foo = Foo {
a: 1,
_b: 1,
c: vec![1, 2],
d: hash_map,
e: Bar { x: 1 },
f: "hi".to_string(),
};
let mut registry = TypeRegistry::default();
registry.register::<u32>();
registry.register::<isize>();
registry.register::<usize>();
registry.register::<Bar>();
registry.register::<String>();
registry.register::<i8>();
let serializer = ReflectSerializer::new(&foo, &registry);
let serialized = to_string_pretty(&serializer, PrettyConfig::default()).unwrap();
let mut deserializer = Deserializer::from_str(&serialized).unwrap();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let value = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let dynamic_struct = value.take::<DynamicStruct>().unwrap();
assert!(foo.partial_eq(&dynamic_struct).unwrap());
}
#[test]
fn reflect_take() {
#[derive(Reflect, Debug, PartialEq)]
struct Bar {
x: u32,
}
let x: Box<dyn Reflect> = Box::new(Bar { x: 2 });
let y = x.take::<Bar>().unwrap();
assert_eq!(y, Bar { x: 2 });
}
}

View file

@ -0,0 +1,178 @@
use std::any::Any;
use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef};
/// An ordered, mutable list of [ReflectValue] items. This corresponds to types like [std::vec::Vec].
pub trait List: Reflect {
fn get(&self, index: usize) -> Option<&dyn Reflect>;
fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>;
fn push(&mut self, value: Box<dyn Reflect>);
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
fn iter(&self) -> ListIter;
fn clone_dynamic(&self) -> DynamicList {
DynamicList {
values: self.iter().map(|value| value.clone_value()).collect(),
}
}
}
#[derive(Default)]
pub struct DynamicList {
pub(crate) values: Vec<Box<dyn Reflect>>,
}
impl DynamicList {
pub fn push<T: Reflect>(&mut self, value: T) {
self.values.push(Box::new(value));
}
pub fn push_box(&mut self, value: Box<dyn Reflect>) {
self.values.push(value);
}
}
impl List for DynamicList {
fn get(&self, index: usize) -> Option<&dyn Reflect> {
self.values.get(index).map(|value| &**value)
}
fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {
self.values.get_mut(index).map(|value| &mut **value)
}
fn len(&self) -> usize {
self.values.len()
}
fn clone_dynamic(&self) -> DynamicList {
DynamicList {
values: self
.values
.iter()
.map(|value| value.clone_value())
.collect(),
}
}
fn iter(&self) -> ListIter {
ListIter {
list: self,
index: 0,
}
}
fn push(&mut self, value: Box<dyn Reflect>) {
DynamicList::push_box(self, value);
}
}
impl Reflect for DynamicList {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[inline]
fn any(&self) -> &dyn Any {
self
}
#[inline]
fn any_mut(&mut self) -> &mut dyn Any {
self
}
fn apply(&mut self, value: &dyn Reflect) {
list_apply(self, value);
}
#[inline]
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
#[inline]
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::List(self)
}
#[inline]
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::List(self)
}
#[inline]
fn clone_value(&self) -> Box<dyn Reflect> {
Box::new(self.clone_dynamic())
}
#[inline]
fn hash(&self) -> Option<u64> {
None
}
fn partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
list_partial_eq(self, value)
}
fn serializable(&self) -> Option<Serializable> {
None
}
}
pub struct ListIter<'a> {
pub(crate) list: &'a dyn List,
pub(crate) index: usize,
}
impl<'a> Iterator for ListIter<'a> {
type Item = &'a dyn Reflect;
fn next(&mut self) -> Option<Self::Item> {
let value = self.list.get(self.index);
self.index += 1;
value
}
}
#[inline]
pub fn list_apply<L: List>(a: &mut L, b: &dyn Reflect) {
if let ReflectRef::List(list_value) = b.reflect_ref() {
for (i, value) in list_value.iter().enumerate() {
if i < a.len() {
if let Some(v) = a.get_mut(i) {
v.apply(value);
}
} else {
List::push(a, value.clone_value());
}
}
} else {
panic!("attempted to apply a non-list type to a list type");
}
}
#[inline]
pub fn list_partial_eq<L: List>(a: &L, b: &dyn Reflect) -> Option<bool> {
let list = if let ReflectRef::List(list) = b.reflect_ref() {
list
} else {
return Some(false);
};
if a.len() != list.len() {
return Some(false);
}
for (a_value, b_value) in a.iter().zip(list.iter()) {
if let Some(false) | None = a_value.partial_eq(b_value) {
return Some(false);
}
}
Some(true)
}

View file

@ -0,0 +1,184 @@
use std::{any::Any, collections::hash_map::Entry};
use bevy_utils::HashMap;
use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef};
/// An ordered ReflectValue->ReflectValue mapping. ReflectValue Keys are assumed to return a non-None hash.
/// Ideally the ordering is stable across runs, but this is not required.
/// This corresponds to types like [std::collections::HashMap].
pub trait Map: Reflect {
fn get(&self, key: &dyn Reflect) -> Option<&dyn Reflect>;
fn get_mut(&mut self, key: &dyn Reflect) -> Option<&mut dyn Reflect>;
fn get_at(&self, index: usize) -> Option<(&dyn Reflect, &dyn Reflect)>;
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
fn iter(&self) -> MapIter;
fn clone_dynamic(&self) -> DynamicMap;
}
const HASH_ERROR: &str = "the given key does not support hashing";
#[derive(Default)]
pub struct DynamicMap {
pub values: Vec<(Box<dyn Reflect>, Box<dyn Reflect>)>,
pub indices: HashMap<u64, usize>,
}
impl DynamicMap {
pub fn insert<K: Reflect, V: Reflect>(&mut self, key: K, value: V) {
self.insert_boxed(Box::new(key), Box::new(value));
}
pub fn insert_boxed(&mut self, key: Box<dyn Reflect>, value: Box<dyn Reflect>) {
match self.indices.entry(key.hash().expect(HASH_ERROR)) {
Entry::Occupied(entry) => {
self.values[*entry.get()] = (key, value);
}
Entry::Vacant(entry) => {
entry.insert(self.values.len());
self.values.push((key, value));
}
}
}
}
impl Map for DynamicMap {
fn get(&self, key: &dyn Reflect) -> Option<&dyn Reflect> {
self.indices
.get(&key.hash().expect(HASH_ERROR))
.map(|index| &*self.values.get(*index).unwrap().1)
}
fn get_mut(&mut self, key: &dyn Reflect) -> Option<&mut dyn Reflect> {
self.indices
.get(&key.hash().expect(HASH_ERROR))
.cloned()
.map(move |index| &mut *self.values.get_mut(index).unwrap().1)
}
fn len(&self) -> usize {
self.values.len()
}
fn clone_dynamic(&self) -> DynamicMap {
DynamicMap {
values: self
.values
.iter()
.map(|(key, value)| (key.clone_value(), value.clone_value()))
.collect(),
indices: self.indices.clone(),
}
}
fn iter(&self) -> MapIter {
MapIter {
map: self,
index: 0,
}
}
fn get_at(&self, index: usize) -> Option<(&dyn Reflect, &dyn Reflect)> {
self.values
.get(index)
.map(|(key, value)| (&**key, &**value))
}
}
impl Reflect for DynamicMap {
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 apply(&mut self, value: &dyn Reflect) {
if let ReflectRef::Map(map_value) = value.reflect_ref() {
for (key, value) in map_value.iter() {
if let Some(v) = self.get_mut(key) {
v.apply(value)
}
}
} else {
panic!("attempted to apply a non-map type to a map type");
}
}
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Map(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Map(self)
}
fn clone_value(&self) -> Box<dyn Reflect> {
Box::new(self.clone_dynamic())
}
fn hash(&self) -> Option<u64> {
None
}
fn partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
map_partial_eq(self, value)
}
fn serializable(&self) -> Option<Serializable> {
None
}
}
pub struct MapIter<'a> {
pub(crate) map: &'a dyn Map,
pub(crate) index: usize,
}
impl<'a> Iterator for MapIter<'a> {
type Item = (&'a dyn Reflect, &'a dyn Reflect);
fn next(&mut self) -> Option<Self::Item> {
let value = self.map.get_at(self.index);
self.index += 1;
value
}
}
#[inline]
pub fn map_partial_eq<M: Map>(a: &M, b: &dyn Reflect) -> Option<bool> {
let map = if let ReflectRef::Map(map) = b.reflect_ref() {
map
} else {
return Some(false);
};
if a.len() != map.len() {
return Some(false);
}
for (key, value) in a.iter() {
if let Some(map_value) = map.get(key) {
if let Some(false) | None = value.partial_eq(map_value) {
return Some(false);
}
} else {
return Some(false);
}
}
Some(true)
}

View file

@ -0,0 +1,385 @@
use std::num::ParseIntError;
use crate::{Reflect, ReflectMut, ReflectRef};
use thiserror::Error;
#[derive(Debug, PartialEq, Eq, Error)]
pub enum ReflectPathError<'a> {
#[error("Expected an identifier at the given index")]
ExpectedIdent { index: usize },
#[error("The current struct doesn't have a field with the given name")]
InvalidField { index: usize, field: &'a str },
#[error("The current tuple struct doesn't have a field with the given index")]
InvalidTupleStructIndex {
index: usize,
tuple_struct_index: usize,
},
#[error("The current list doesn't have a value at the given index")]
InvalidListIndex { index: usize, list_index: usize },
#[error("Encountered an unexpected token")]
UnexpectedToken { index: usize, token: &'a str },
#[error("Expected a token, but it wasn't there.")]
ExpectedToken { index: usize, token: &'a str },
#[error("Expected a struct, but found a different reflect value")]
ExpectedStruct { index: usize },
#[error("Expected a list, but found a different reflect value")]
ExpectedList { index: usize },
#[error("Failed to parse a usize")]
IndexParseError(#[from] ParseIntError),
#[error("Failed to downcast to the path result to the given type")]
InvalidDowncast,
}
pub trait GetPath {
fn path<'r, 'p>(&'r self, path: &'p str) -> Result<&'r dyn Reflect, ReflectPathError<'p>>;
fn path_mut<'r, 'p>(
&'r mut self,
path: &'p str,
) -> Result<&'r mut dyn Reflect, ReflectPathError<'p>>;
fn get_path<'r, 'p, T: Reflect>(
&'r self,
path: &'p str,
) -> Result<&'r T, ReflectPathError<'p>> {
self.path(path).and_then(|p| {
p.downcast_ref::<T>()
.ok_or(ReflectPathError::InvalidDowncast)
})
}
fn get_path_mut<'r, 'p, T: Reflect>(
&'r mut self,
path: &'p str,
) -> Result<&'r mut T, ReflectPathError<'p>> {
self.path_mut(path).and_then(|p| {
p.downcast_mut::<T>()
.ok_or(ReflectPathError::InvalidDowncast)
})
}
}
impl<T: Reflect> GetPath for T {
fn path<'r, 'p>(&'r self, path: &'p str) -> Result<&'r dyn Reflect, ReflectPathError<'p>> {
(self as &dyn Reflect).path(path)
}
fn path_mut<'r, 'p>(
&'r mut self,
path: &'p str,
) -> Result<&'r mut dyn Reflect, ReflectPathError<'p>> {
(self as &mut dyn Reflect).path_mut(path)
}
}
impl GetPath for dyn Reflect {
fn path<'r, 'p>(&'r self, path: &'p str) -> Result<&'r dyn Reflect, ReflectPathError<'p>> {
let mut index = 0;
let mut current: &dyn Reflect = self;
while let Some(token) = next_token(path, &mut index) {
let current_index = index;
match token {
Token::Dot => {
if let Some(Token::Ident(value)) = next_token(path, &mut index) {
current = read_field(current, value, current_index)?;
} else {
return Err(ReflectPathError::ExpectedIdent {
index: current_index,
});
}
}
Token::OpenBracket => {
if let Some(Token::Ident(value)) = next_token(path, &mut index) {
match current.reflect_ref() {
ReflectRef::List(reflect_list) => {
let list_index = value.parse::<usize>()?;
let list_item = reflect_list.get(list_index).ok_or(
ReflectPathError::InvalidListIndex {
index: current_index,
list_index,
},
)?;
current = list_item;
}
_ => {
return Err(ReflectPathError::ExpectedList {
index: current_index,
})
}
}
} else {
return Err(ReflectPathError::ExpectedIdent {
index: current_index,
});
}
if let Some(Token::CloseBracket) = next_token(path, &mut index) {
} else {
return Err(ReflectPathError::ExpectedToken {
index: current_index,
token: "]",
});
}
}
Token::CloseBracket => {
return Err(ReflectPathError::UnexpectedToken {
index: current_index,
token: "]",
})
}
Token::Ident(value) => {
current = read_field(current, value, current_index)?;
}
}
}
Ok(current)
}
fn path_mut<'r, 'p>(
&'r mut self,
path: &'p str,
) -> Result<&'r mut dyn Reflect, ReflectPathError<'p>> {
let mut index = 0;
let mut current: &mut dyn Reflect = self;
while let Some(token) = next_token(path, &mut index) {
let current_index = index;
match token {
Token::Dot => {
if let Some(Token::Ident(value)) = next_token(path, &mut index) {
current = read_field_mut(current, value, current_index)?;
} else {
return Err(ReflectPathError::ExpectedIdent {
index: current_index,
});
}
}
Token::OpenBracket => {
if let Some(Token::Ident(value)) = next_token(path, &mut index) {
match current.reflect_mut() {
ReflectMut::List(reflect_list) => {
let list_index = value.parse::<usize>()?;
let list_item = reflect_list.get_mut(list_index).ok_or(
ReflectPathError::InvalidListIndex {
index: current_index,
list_index,
},
)?;
current = list_item;
}
_ => {
return Err(ReflectPathError::ExpectedStruct {
index: current_index,
})
}
}
} else {
return Err(ReflectPathError::ExpectedIdent {
index: current_index,
});
}
if let Some(Token::CloseBracket) = next_token(path, &mut index) {
} else {
return Err(ReflectPathError::ExpectedToken {
index: current_index,
token: "]",
});
}
}
Token::CloseBracket => {
return Err(ReflectPathError::UnexpectedToken {
index: current_index,
token: "]",
})
}
Token::Ident(value) => {
current = read_field_mut(current, value, current_index)?;
}
}
}
Ok(current)
}
}
fn read_field<'r, 'p>(
current: &'r dyn Reflect,
field: &'p str,
current_index: usize,
) -> Result<&'r dyn Reflect, ReflectPathError<'p>> {
match current.reflect_ref() {
ReflectRef::Struct(reflect_struct) => {
Ok(reflect_struct
.field(field)
.ok_or(ReflectPathError::InvalidField {
index: current_index,
field,
})?)
}
ReflectRef::TupleStruct(reflect_struct) => {
let tuple_index = field.parse::<usize>()?;
Ok(reflect_struct.field(tuple_index).ok_or(
ReflectPathError::InvalidTupleStructIndex {
index: current_index,
tuple_struct_index: tuple_index,
},
)?)
}
_ => Err(ReflectPathError::ExpectedStruct {
index: current_index,
}),
}
}
fn read_field_mut<'r, 'p>(
current: &'r mut dyn Reflect,
field: &'p str,
current_index: usize,
) -> Result<&'r mut dyn Reflect, ReflectPathError<'p>> {
match current.reflect_mut() {
ReflectMut::Struct(reflect_struct) => {
Ok(reflect_struct
.field_mut(field)
.ok_or(ReflectPathError::InvalidField {
index: current_index,
field,
})?)
}
ReflectMut::TupleStruct(reflect_struct) => {
let tuple_index = field.parse::<usize>()?;
Ok(reflect_struct.field_mut(tuple_index).ok_or(
ReflectPathError::InvalidTupleStructIndex {
index: current_index,
tuple_struct_index: tuple_index,
},
)?)
}
_ => Err(ReflectPathError::ExpectedStruct {
index: current_index,
}),
}
}
enum Token<'a> {
Dot,
OpenBracket,
CloseBracket,
Ident(&'a str),
}
fn next_token<'a>(path: &'a str, index: &mut usize) -> Option<Token<'a>> {
if *index >= path.len() {
return None;
}
match path[*index..].chars().next().unwrap() {
'.' => {
*index += 1;
return Some(Token::Dot);
}
'[' => {
*index += 1;
return Some(Token::OpenBracket);
}
']' => {
*index += 1;
return Some(Token::CloseBracket);
}
_ => {}
}
// we can assume we are parsing an ident now
for (char_index, character) in path[*index..].chars().enumerate() {
match character {
'.' | '[' | ']' => {
let ident = Token::Ident(&path[*index..*index + char_index]);
*index += char_index;
return Some(ident);
}
_ => {}
}
}
let ident = Token::Ident(&path[*index..]);
*index = path.len();
Some(ident)
}
#[cfg(test)]
mod tests {
use super::GetPath;
use crate::*;
#[test]
fn reflect_path() {
#[derive(Reflect)]
struct A {
w: usize,
x: B,
y: Vec<C>,
z: D,
}
#[derive(Reflect)]
struct B {
foo: usize,
bar: C,
}
#[derive(Reflect)]
struct C {
baz: f32,
}
#[derive(Reflect)]
struct D(E);
#[derive(Reflect)]
struct E(f32, usize);
let mut a = A {
w: 1,
x: B {
foo: 10,
bar: C { baz: 3.14 },
},
y: vec![C { baz: 1.0 }, C { baz: 2.0 }],
z: D(E(10.0, 42)),
};
assert_eq!(*a.get_path::<usize>("w").unwrap(), 1);
assert_eq!(*a.get_path::<usize>("x.foo").unwrap(), 10);
assert_eq!(*a.get_path::<f32>("x.bar.baz").unwrap(), 3.14);
assert_eq!(*a.get_path::<f32>("y[1].baz").unwrap(), 2.0);
assert_eq!(*a.get_path::<usize>("z.0.1").unwrap(), 42);
*a.get_path_mut::<f32>("y[1].baz").unwrap() = 3.0;
assert_eq!(a.y[1].baz, 3.0);
assert_eq!(
a.path("x.notreal").err().unwrap(),
ReflectPathError::InvalidField {
index: 2,
field: "notreal"
}
);
assert_eq!(
a.path("x..").err().unwrap(),
ReflectPathError::ExpectedIdent { index: 2 }
);
assert_eq!(
a.path("x[0]").err().unwrap(),
ReflectPathError::ExpectedList { index: 2 }
);
assert_eq!(
a.path("y.x").err().unwrap(),
ReflectPathError::ExpectedStruct { index: 2 }
);
assert!(matches!(
a.path("y[badindex]"),
Err(ReflectPathError::IndexParseError(_))
));
}
}

View file

@ -0,0 +1,77 @@
use crate::{serde::Serializable, List, Map, Struct, TupleStruct};
use std::{any::Any, fmt::Debug};
pub use bevy_utils::AHasher as ReflectHasher;
pub enum ReflectRef<'a> {
Struct(&'a dyn Struct),
TupleStruct(&'a dyn TupleStruct),
List(&'a dyn List),
Map(&'a dyn Map),
Value(&'a dyn Reflect),
}
pub enum ReflectMut<'a> {
Struct(&'a mut dyn Struct),
TupleStruct(&'a mut dyn TupleStruct),
List(&'a mut dyn List),
Map(&'a mut dyn Map),
Value(&'a mut dyn Reflect),
}
/// A reflected rust type.
pub trait Reflect: Any + Send + Sync {
fn type_name(&self) -> &str;
fn any(&self) -> &dyn Any;
fn any_mut(&mut self) -> &mut dyn Any;
fn apply(&mut self, value: &dyn Reflect);
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>>;
fn reflect_ref(&self) -> ReflectRef;
fn reflect_mut(&mut self) -> ReflectMut;
fn clone_value(&self) -> Box<dyn Reflect>;
/// Returns a hash of the value (which includes the type) if hashing is supported. Otherwise `None` will be returned.
fn hash(&self) -> Option<u64>;
/// Returns a "partial equal" comparison result if comparison is supported. Otherwise `None` will be returned.
fn partial_eq(&self, _value: &dyn Reflect) -> Option<bool>;
/// Returns a serializable value, if serialization is supported. Otherwise `None` will be returned.
fn serializable(&self) -> Option<Serializable>;
}
impl Debug for dyn Reflect {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&format!("Reflect({})", self.type_name()))
}
}
impl dyn Reflect {
pub fn downcast<T: Reflect>(self: Box<dyn Reflect>) -> Result<Box<T>, Box<dyn Reflect>> {
// SAFE?: Same approach used by std::any::Box::downcast. ReflectValue is always Any and type has been checked.
if self.is::<T>() {
unsafe {
let raw: *mut dyn Reflect = Box::into_raw(self);
Ok(Box::from_raw(raw as *mut T))
}
} else {
Err(self)
}
}
pub fn take<T: Reflect>(self: Box<dyn Reflect>) -> Result<T, Box<dyn Reflect>> {
self.downcast::<T>().map(|value| *value)
}
#[inline]
pub fn is<T: Reflect>(&self) -> bool {
self.any().is::<T>()
}
#[inline]
pub fn downcast_ref<T: Reflect>(&self) -> Option<&T> {
self.any().downcast_ref::<T>()
}
#[inline]
pub fn downcast_mut<T: Reflect>(&mut self) -> Option<&mut T> {
self.any_mut().downcast_mut::<T>()
}
}

View file

@ -0,0 +1,403 @@
use crate::{
serde::type_fields, DynamicList, DynamicMap, DynamicStruct, DynamicTupleStruct, Reflect,
ReflectDeserialize, TypeRegistry,
};
use erased_serde::Deserializer;
use serde::de::{self, DeserializeSeed, MapAccess, SeqAccess, Visitor};
pub trait DeserializeValue {
fn deserialize(
deserializer: &mut dyn Deserializer,
type_registry: &TypeRegistry,
) -> Result<Box<dyn Reflect>, erased_serde::Error>;
}
pub struct ReflectDeserializer<'a> {
registry: &'a TypeRegistry,
}
impl<'a> ReflectDeserializer<'a> {
pub fn new(registry: &'a TypeRegistry) -> Self {
ReflectDeserializer { registry }
}
}
impl<'a, 'de> DeserializeSeed<'de> for ReflectDeserializer<'a> {
type Value = Box<dyn Reflect>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_any(ReflectVisitor {
registry: self.registry,
})
}
}
struct ReflectVisitor<'a> {
registry: &'a TypeRegistry,
}
impl<'a, 'de> Visitor<'de> for ReflectVisitor<'a> {
type Value = Box<dyn Reflect>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("reflect value")
}
fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
where
E: de::Error,
{
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,
{
Ok(Box::new(v))
}
fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Box::new(v))
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Box::new(v.to_string()))
}
fn visit_map<V>(self, mut 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>()? {
match key.as_str() {
type_fields::TYPE => {
type_name = Some(map.next_value()?);
}
type_fields::MAP => {
let _type_name = type_name
.take()
.ok_or_else(|| de::Error::missing_field(type_fields::TYPE))?;
let map = map.next_value_seed(MapDeserializer {
registry: self.registry,
})?;
return Ok(Box::new(map));
}
type_fields::STRUCT => {
let type_name = type_name
.take()
.ok_or_else(|| de::Error::missing_field(type_fields::TYPE))?;
let mut dynamic_struct = map.next_value_seed(StructDeserializer {
registry: self.registry,
})?;
dynamic_struct.set_name(type_name);
return Ok(Box::new(dynamic_struct));
}
type_fields::TUPLE_STRUCT => {
let type_name = type_name
.take()
.ok_or_else(|| de::Error::missing_field(type_fields::TYPE))?;
let mut tuple_struct = map.next_value_seed(TupleStructDeserializer {
registry: self.registry,
})?;
tuple_struct.set_name(type_name);
return Ok(Box::new(tuple_struct));
}
type_fields::LIST => {
let _type_name = type_name
.take()
.ok_or_else(|| de::Error::missing_field(type_fields::TYPE))?;
let list = map.next_value_seed(ListDeserializer {
registry: self.registry,
})?;
return Ok(Box::new(list));
}
type_fields::VALUE => {
let type_name = type_name
.take()
.ok_or_else(|| de::Error::missing_field(type_fields::TYPE))?;
let registration =
self.registry.get_with_name(&type_name).ok_or_else(|| {
de::Error::custom(format!("No registration found for {}", type_name))
})?;
let deserialize_reflect =
registration.data::<ReflectDeserialize>().ok_or_else(|| {
de::Error::custom(format!(
"The TypeRegistration for {} doesn't have DeserializeReflect",
type_name
))
})?;
let value = map.next_value_seed(DeserializeReflectDeserializer {
reflect_deserialize: deserialize_reflect,
})?;
return Ok(value);
}
_ => return Err(de::Error::unknown_field(key.as_str(), &[])),
}
}
Err(de::Error::custom("Maps in this location must have the \'type\' field and one of the following fields: \'map\', \'seq\', \'value\'"))
}
}
struct DeserializeReflectDeserializer<'a> {
reflect_deserialize: &'a ReflectDeserialize,
}
impl<'a, 'de> DeserializeSeed<'de> for DeserializeReflectDeserializer<'a> {
type Value = Box<dyn Reflect>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
self.reflect_deserialize.deserialize(deserializer)
}
}
struct ListDeserializer<'a> {
registry: &'a TypeRegistry,
}
impl<'a, 'de> DeserializeSeed<'de> for ListDeserializer<'a> {
type Value = DynamicList;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_seq(ListVisitor {
registry: self.registry,
})
}
}
struct ListVisitor<'a> {
registry: &'a TypeRegistry,
}
impl<'a, 'de> Visitor<'de> for ListVisitor<'a> {
type Value = DynamicList;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("list value")
}
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
let mut list = DynamicList::default();
while let Some(value) = seq.next_element_seed(ReflectDeserializer {
registry: self.registry,
})? {
list.push_box(value);
}
Ok(list)
}
}
struct MapDeserializer<'a> {
registry: &'a TypeRegistry,
}
impl<'a, 'de> DeserializeSeed<'de> for MapDeserializer<'a> {
type Value = DynamicMap;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_map(MapVisitor {
registry: self.registry,
})
}
}
struct MapVisitor<'a> {
registry: &'a TypeRegistry,
}
impl<'a, 'de> Visitor<'de> for MapVisitor<'a> {
type Value = DynamicMap;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("map value")
}
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'de>,
{
let mut dynamic_map = DynamicMap::default();
while let Some(key) = map.next_key_seed(ReflectDeserializer {
registry: self.registry,
})? {
let value = map.next_value_seed(ReflectDeserializer {
registry: self.registry,
})?;
dynamic_map.insert_boxed(key, value);
}
Ok(dynamic_map)
}
}
struct StructDeserializer<'a> {
registry: &'a TypeRegistry,
}
impl<'a, 'de> DeserializeSeed<'de> for StructDeserializer<'a> {
type Value = DynamicStruct;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_map(StructVisitor {
registry: self.registry,
})
}
}
struct StructVisitor<'a> {
registry: &'a TypeRegistry,
}
impl<'a, 'de> Visitor<'de> for StructVisitor<'a> {
type Value = DynamicStruct;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("struct value")
}
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'de>,
{
let mut dynamic_struct = DynamicStruct::default();
while let Some(key) = map.next_key::<String>()? {
let value = map.next_value_seed(ReflectDeserializer {
registry: self.registry,
})?;
dynamic_struct.insert_boxed(&key, value);
}
Ok(dynamic_struct)
}
}
struct TupleStructDeserializer<'a> {
registry: &'a TypeRegistry,
}
impl<'a, 'de> DeserializeSeed<'de> for TupleStructDeserializer<'a> {
type Value = DynamicTupleStruct;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_seq(TupleStructVisitor {
registry: self.registry,
})
}
}
struct TupleStructVisitor<'a> {
registry: &'a TypeRegistry,
}
impl<'a, 'de> Visitor<'de> for TupleStructVisitor<'a> {
type Value = DynamicTupleStruct;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("tuple struct value")
}
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
let mut tuple_struct = DynamicTupleStruct::default();
while let Some(value) = seq.next_element_seed(ReflectDeserializer {
registry: self.registry,
})? {
tuple_struct.insert_boxed(value);
}
Ok(tuple_struct)
}
}

View file

@ -0,0 +1,14 @@
mod de;
mod ser;
pub use de::*;
pub use ser::*;
pub(crate) mod type_fields {
pub const TYPE: &str = "type";
pub const MAP: &str = "map";
pub const STRUCT: &str = "struct";
pub const TUPLE_STRUCT: &str = "tuple_struct";
pub const LIST: &str = "list";
pub const VALUE: &str = "value";
}

View file

@ -0,0 +1,268 @@
use crate::{
serde::type_fields, List, Map, Reflect, ReflectRef, Struct, TupleStruct, TypeRegistry,
};
use serde::{
ser::{SerializeMap, SerializeSeq},
Serialize,
};
pub enum Serializable<'a> {
Owned(Box<dyn erased_serde::Serialize + 'a>),
Borrowed(&'a dyn erased_serde::Serialize),
}
impl<'a> Serializable<'a> {
#[allow(clippy::should_implement_trait)]
pub fn borrow(&self) -> &dyn erased_serde::Serialize {
match self {
Serializable::Borrowed(serialize) => serialize,
Serializable::Owned(serialize) => serialize,
}
}
}
fn get_serializable<E: serde::ser::Error>(reflect_value: &dyn Reflect) -> Result<Serializable, E> {
reflect_value.serializable().ok_or_else(|| {
serde::ser::Error::custom(&format!(
"Type '{}' does not support ReflectValue serialization",
reflect_value.type_name()
))
})
}
pub struct ReflectSerializer<'a> {
pub value: &'a dyn Reflect,
pub registry: &'a TypeRegistry,
}
impl<'a> ReflectSerializer<'a> {
pub fn new(value: &'a dyn Reflect, registry: &'a TypeRegistry) -> Self {
ReflectSerializer { value, registry }
}
}
impl<'a> Serialize for ReflectSerializer<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self.value.reflect_ref() {
ReflectRef::Struct(value) => StructSerializer {
struct_value: value,
registry: self.registry,
}
.serialize(serializer),
ReflectRef::TupleStruct(value) => TupleStructSerializer {
tuple_struct: value,
registry: self.registry,
}
.serialize(serializer),
ReflectRef::List(value) => ListSerializer {
list: value,
registry: self.registry,
}
.serialize(serializer),
ReflectRef::Map(value) => MapSerializer {
map: value,
registry: self.registry,
}
.serialize(serializer),
ReflectRef::Value(value) => ReflectValueSerializer {
registry: self.registry,
value,
}
.serialize(serializer),
}
}
}
pub struct ReflectValueSerializer<'a> {
pub registry: &'a TypeRegistry,
pub value: &'a dyn Reflect,
}
impl<'a> Serialize for ReflectValueSerializer<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_map(Some(2))?;
state.serialize_entry(type_fields::TYPE, self.value.type_name())?;
state.serialize_entry(
type_fields::VALUE,
get_serializable::<S::Error>(self.value)?.borrow(),
)?;
state.end()
}
}
pub struct StructSerializer<'a> {
pub struct_value: &'a dyn Struct,
pub registry: &'a TypeRegistry,
}
impl<'a> Serialize for StructSerializer<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_map(Some(2))?;
state.serialize_entry(type_fields::TYPE, self.struct_value.type_name())?;
state.serialize_entry(
type_fields::STRUCT,
&StructValueSerializer {
struct_value: self.struct_value,
registry: self.registry,
},
)?;
state.end()
}
}
pub struct StructValueSerializer<'a> {
pub struct_value: &'a dyn Struct,
pub registry: &'a TypeRegistry,
}
impl<'a> Serialize for StructValueSerializer<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_map(Some(self.struct_value.field_len()))?;
for (index, value) in self.struct_value.iter_fields().enumerate() {
let key = self.struct_value.name_at(index).unwrap();
state.serialize_entry(key, &ReflectSerializer::new(value, self.registry))?;
}
state.end()
}
}
pub struct TupleStructSerializer<'a> {
pub tuple_struct: &'a dyn TupleStruct,
pub registry: &'a TypeRegistry,
}
impl<'a> Serialize for TupleStructSerializer<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_map(Some(2))?;
state.serialize_entry(type_fields::TYPE, self.tuple_struct.type_name())?;
state.serialize_entry(
type_fields::TUPLE_STRUCT,
&TupleStructValueSerializer {
tuple_struct: self.tuple_struct,
registry: self.registry,
},
)?;
state.end()
}
}
pub struct TupleStructValueSerializer<'a> {
pub tuple_struct: &'a dyn TupleStruct,
pub registry: &'a TypeRegistry,
}
impl<'a> Serialize for TupleStructValueSerializer<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_seq(Some(self.tuple_struct.field_len()))?;
for value in self.tuple_struct.iter_fields() {
state.serialize_element(&ReflectSerializer::new(value, self.registry))?;
}
state.end()
}
}
pub struct MapSerializer<'a> {
pub map: &'a dyn Map,
pub registry: &'a TypeRegistry,
}
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(2))?;
state.serialize_entry(type_fields::TYPE, self.map.type_name())?;
state.serialize_entry(
type_fields::MAP,
&MapValueSerializer {
map: self.map,
registry: self.registry,
},
)?;
state.end()
}
}
pub struct MapValueSerializer<'a> {
pub map: &'a dyn Map,
pub registry: &'a TypeRegistry,
}
impl<'a> Serialize for MapValueSerializer<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_map(Some(self.map.len()))?;
for (key, value) in self.map.iter() {
state.serialize_entry(
&ReflectSerializer::new(key, self.registry),
&ReflectSerializer::new(value, self.registry),
)?;
}
state.end()
}
}
pub struct ListSerializer<'a> {
pub list: &'a dyn List,
pub registry: &'a TypeRegistry,
}
impl<'a> Serialize for ListSerializer<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_map(Some(2))?;
state.serialize_entry(type_fields::TYPE, self.list.type_name())?;
state.serialize_entry(
type_fields::LIST,
&ListValueSerializer {
list: self.list,
registry: self.registry,
},
)?;
state.end()
}
}
pub struct ListValueSerializer<'a> {
pub list: &'a dyn List,
pub registry: &'a TypeRegistry,
}
impl<'a> Serialize for ListValueSerializer<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_seq(Some(self.list.len()))?;
for value in self.list.iter() {
state.serialize_element(&ReflectSerializer::new(value, self.registry))?;
}
state.end()
}
}

View file

@ -0,0 +1,256 @@
use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef};
use bevy_utils::HashMap;
use std::{any::Any, borrow::Cow, collections::hash_map::Entry};
/// An ordered &str->ReflectValue mapping where &str is a "field".
/// This corresponds to rust struct types.
pub trait Struct: Reflect {
fn field(&self, name: &str) -> Option<&dyn Reflect>;
fn field_mut(&mut self, name: &str) -> Option<&mut dyn Reflect>;
fn field_at(&self, index: usize) -> Option<&dyn Reflect>;
fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>;
fn name_at(&self, index: usize) -> Option<&str>;
fn field_len(&self) -> usize;
fn iter_fields(&self) -> FieldIter;
fn clone_dynamic(&self) -> DynamicStruct;
}
pub struct FieldIter<'a> {
pub(crate) struct_val: &'a dyn Struct,
pub(crate) index: usize,
}
impl<'a> FieldIter<'a> {
pub fn new(value: &'a dyn Struct) -> Self {
FieldIter {
struct_val: value,
index: 0,
}
}
}
impl<'a> Iterator for FieldIter<'a> {
type Item = &'a dyn Reflect;
fn next(&mut self) -> Option<Self::Item> {
let value = self.struct_val.field_at(self.index);
self.index += 1;
value
}
}
pub trait GetField {
fn get_field<T: Reflect>(&self, name: &str) -> Option<&T>;
fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T>;
}
impl<S: Struct> GetField for S {
fn get_field<T: Reflect>(&self, name: &str) -> Option<&T> {
self.field(name).and_then(|value| value.downcast_ref::<T>())
}
fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T> {
self.field_mut(name)
.and_then(|value| value.downcast_mut::<T>())
}
}
impl GetField for dyn Struct {
fn get_field<T: Reflect>(&self, name: &str) -> Option<&T> {
self.field(name).and_then(|value| value.downcast_ref::<T>())
}
fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T> {
self.field_mut(name)
.and_then(|value| value.downcast_mut::<T>())
}
}
#[derive(Default)]
pub struct DynamicStruct {
name: String,
fields: Vec<Box<dyn Reflect>>,
field_names: Vec<Cow<'static, str>>,
field_indices: HashMap<Cow<'static, str>, usize>,
}
impl DynamicStruct {
pub fn name(&self) -> &str {
&self.name
}
pub fn set_name(&mut self, name: String) {
self.name = name;
}
pub fn insert_boxed(&mut self, name: &str, value: Box<dyn Reflect>) {
let name = Cow::Owned(name.to_string());
match self.field_indices.entry(name) {
Entry::Occupied(entry) => {
self.fields[*entry.get()] = value;
}
Entry::Vacant(entry) => {
self.fields.push(value);
self.field_names.push(entry.key().clone());
entry.insert(self.fields.len() - 1);
}
}
}
pub fn insert<T: Reflect>(&mut self, name: &str, value: T) {
if let Some(index) = self.field_indices.get(name) {
self.fields[*index] = Box::new(value);
} else {
self.insert_boxed(name, Box::new(value));
}
}
}
impl Struct for DynamicStruct {
#[inline]
fn field(&self, name: &str) -> Option<&dyn Reflect> {
if let Some(index) = self.field_indices.get(name) {
Some(&*self.fields[*index])
} else {
None
}
}
#[inline]
fn field_mut(&mut self, name: &str) -> Option<&mut dyn Reflect> {
if let Some(index) = self.field_indices.get(name) {
Some(&mut *self.fields[*index])
} else {
None
}
}
#[inline]
fn field_at(&self, index: usize) -> Option<&dyn Reflect> {
self.fields.get(index).map(|value| &**value)
}
#[inline]
fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {
self.fields.get_mut(index).map(|value| &mut **value)
}
#[inline]
fn name_at(&self, index: usize) -> Option<&str> {
self.field_names.get(index).map(|name| name.as_ref())
}
#[inline]
fn field_len(&self) -> usize {
self.fields.len()
}
#[inline]
fn iter_fields(&self) -> FieldIter {
FieldIter {
struct_val: self,
index: 0,
}
}
fn clone_dynamic(&self) -> DynamicStruct {
DynamicStruct {
name: self.name.clone(),
field_names: self.field_names.clone(),
field_indices: self.field_indices.clone(),
fields: self
.fields
.iter()
.map(|value| value.clone_value())
.collect(),
}
}
}
impl Reflect for DynamicStruct {
#[inline]
fn type_name(&self) -> &str {
&self.name
}
#[inline]
fn any(&self) -> &dyn Any {
self
}
#[inline]
fn any_mut(&mut self) -> &mut dyn Any {
self
}
#[inline]
fn clone_value(&self) -> Box<dyn Reflect> {
Box::new(self.clone_dynamic())
}
#[inline]
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Struct(self)
}
#[inline]
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Struct(self)
}
fn apply(&mut self, value: &dyn Reflect) {
if let ReflectRef::Struct(struct_value) = value.reflect_ref() {
for (i, value) in struct_value.iter_fields().enumerate() {
let name = struct_value.name_at(i).unwrap();
if let Some(v) = self.field_mut(name) {
v.apply(value)
}
}
} else {
panic!("attempted to apply non-struct type to struct type");
}
}
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
fn hash(&self) -> Option<u64> {
None
}
fn partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
struct_partial_eq(self, value)
}
fn serializable(&self) -> Option<Serializable> {
None
}
}
#[inline]
pub fn struct_partial_eq<S: Struct>(a: &S, b: &dyn Reflect) -> Option<bool> {
let struct_value = if let ReflectRef::Struct(struct_value) = b.reflect_ref() {
struct_value
} else {
return Some(false);
};
if a.field_len() != struct_value.field_len() {
return Some(false);
}
for (i, value) in struct_value.iter_fields().enumerate() {
let name = struct_value.name_at(i).unwrap();
if let Some(field_value) = a.field(name) {
if let Some(false) | None = field_value.partial_eq(value) {
return Some(false);
}
} else {
return Some(false);
}
}
Some(true)
}

View file

@ -0,0 +1,210 @@
use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef};
use std::any::Any;
/// A rust "tuple struct" reflection
pub trait TupleStruct: Reflect {
fn field(&self, index: usize) -> Option<&dyn Reflect>;
fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>;
fn field_len(&self) -> usize;
fn iter_fields(&self) -> TupleStructFieldIter;
fn clone_dynamic(&self) -> DynamicTupleStruct;
}
pub struct TupleStructFieldIter<'a> {
pub(crate) tuple_struct: &'a dyn TupleStruct,
pub(crate) index: usize,
}
impl<'a> TupleStructFieldIter<'a> {
pub fn new(value: &'a dyn TupleStruct) -> Self {
TupleStructFieldIter {
tuple_struct: value,
index: 0,
}
}
}
impl<'a> Iterator for TupleStructFieldIter<'a> {
type Item = &'a dyn Reflect;
fn next(&mut self) -> Option<Self::Item> {
let value = self.tuple_struct.field(self.index);
self.index += 1;
value
}
}
pub trait GetTupleStructField {
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T>;
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T>;
}
impl<S: TupleStruct> GetTupleStructField for S {
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T> {
self.field(index)
.and_then(|value| value.downcast_ref::<T>())
}
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T> {
self.field_mut(index)
.and_then(|value| value.downcast_mut::<T>())
}
}
impl GetTupleStructField for dyn TupleStruct {
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T> {
self.field(index)
.and_then(|value| value.downcast_ref::<T>())
}
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T> {
self.field_mut(index)
.and_then(|value| value.downcast_mut::<T>())
}
}
#[derive(Default)]
pub struct DynamicTupleStruct {
name: String,
fields: Vec<Box<dyn Reflect>>,
}
impl DynamicTupleStruct {
pub fn name(&self) -> &str {
&self.name
}
pub fn set_name(&mut self, name: String) {
self.name = name;
}
pub fn insert_boxed(&mut self, value: Box<dyn Reflect>) {
self.fields.push(value);
}
pub fn insert<T: Reflect>(&mut self, value: T) {
self.insert_boxed(Box::new(value));
}
}
impl TupleStruct for DynamicTupleStruct {
#[inline]
fn field(&self, index: usize) -> Option<&dyn Reflect> {
self.fields.get(index).map(|field| &**field)
}
#[inline]
fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {
self.fields.get_mut(index).map(|field| &mut **field)
}
#[inline]
fn field_len(&self) -> usize {
self.fields.len()
}
#[inline]
fn iter_fields(&self) -> TupleStructFieldIter {
TupleStructFieldIter {
tuple_struct: self,
index: 0,
}
}
fn clone_dynamic(&self) -> DynamicTupleStruct {
DynamicTupleStruct {
name: self.name.clone(),
fields: self
.fields
.iter()
.map(|value| value.clone_value())
.collect(),
}
}
}
impl Reflect for DynamicTupleStruct {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[inline]
fn any(&self) -> &dyn Any {
self
}
#[inline]
fn any_mut(&mut self) -> &mut dyn Any {
self
}
#[inline]
fn clone_value(&self) -> Box<dyn Reflect> {
Box::new(self.clone_dynamic())
}
#[inline]
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::TupleStruct(self)
}
#[inline]
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::TupleStruct(self)
}
fn apply(&mut self, value: &dyn Reflect) {
if let ReflectRef::TupleStruct(tuple_struct) = value.reflect_ref() {
for (i, value) in tuple_struct.iter_fields().enumerate() {
if let Some(v) = self.field_mut(i) {
v.apply(value)
}
}
} else {
panic!("attempted to apply non-TupleStruct type to TupleStruct type");
}
}
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
fn hash(&self) -> Option<u64> {
None
}
fn partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
tuple_struct_partial_eq(self, value)
}
fn serializable(&self) -> Option<Serializable> {
None
}
}
#[inline]
pub fn tuple_struct_partial_eq<S: TupleStruct>(a: &S, b: &dyn Reflect) -> Option<bool> {
let tuple_struct = if let ReflectRef::TupleStruct(tuple_struct) = b.reflect_ref() {
tuple_struct
} else {
return Some(false);
};
if a.field_len() != tuple_struct.field_len() {
return Some(false);
}
for (i, value) in tuple_struct.iter_fields().enumerate() {
if let Some(field_value) = a.field(i) {
if let Some(false) | None = field_value.partial_eq(value) {
return Some(false);
}
} else {
return Some(false);
}
}
Some(true)
}

View file

@ -0,0 +1,324 @@
use crate::Reflect;
use bevy_utils::{HashMap, HashSet};
use downcast_rs::{impl_downcast, Downcast};
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use serde::Deserialize;
use std::{any::TypeId, fmt::Debug, sync::Arc};
#[derive(Default)]
pub struct TypeRegistry {
registrations: HashMap<TypeId, TypeRegistration>,
short_name_to_id: HashMap<String, TypeId>,
full_name_to_id: HashMap<String, TypeId>,
ambiguous_names: HashSet<String>,
}
// TODO: remove this wrapper once we migrate to Atelier Assets and the Scene AssetLoader doesn't need a TypeRegistry ref
#[derive(Clone, Default)]
pub struct TypeRegistryArc {
pub internal: Arc<RwLock<TypeRegistry>>,
}
impl Debug for TypeRegistryArc {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.internal.read().full_name_to_id.keys().fmt(f)
}
}
pub trait GetTypeRegistration {
fn get_type_registration() -> TypeRegistration;
}
impl TypeRegistry {
pub fn register<T>(&mut self)
where
T: GetTypeRegistration,
{
self.add_registration(T::get_type_registration());
}
pub fn add_registration(&mut self, registration: TypeRegistration) {
let short_name = registration.short_name.to_string();
if self.short_name_to_id.contains_key(&short_name)
|| self.ambiguous_names.contains(&short_name)
{
// name is ambiguous. fall back to long names for all ambiguous types
self.short_name_to_id.remove(&short_name);
self.ambiguous_names.insert(short_name);
} else {
self.short_name_to_id
.insert(short_name, registration.type_id);
}
self.full_name_to_id
.insert(registration.name.to_string(), registration.type_id);
self.registrations
.insert(registration.type_id, registration);
}
pub fn get(&self, type_id: TypeId) -> Option<&TypeRegistration> {
self.registrations.get(&type_id)
}
pub fn get_mut(&mut self, type_id: TypeId) -> Option<&mut TypeRegistration> {
self.registrations.get_mut(&type_id)
}
pub fn get_with_name(&self, type_name: &str) -> Option<&TypeRegistration> {
self.full_name_to_id
.get(type_name)
.and_then(|id| self.get(*id))
}
pub fn get_with_name_mut(&mut self, type_name: &str) -> Option<&mut TypeRegistration> {
self.full_name_to_id
.get(type_name)
.cloned()
.and_then(move |id| self.get_mut(id))
}
pub fn get_with_short_name(&self, short_type_name: &str) -> Option<&TypeRegistration> {
self.short_name_to_id
.get(short_type_name)
.and_then(|id| self.registrations.get(id))
}
pub fn get_type_data<T: TypeData>(&self, type_id: TypeId) -> Option<&T> {
self.get(type_id)
.and_then(|registration| registration.data::<T>())
}
pub fn iter(&self) -> impl Iterator<Item = &TypeRegistration> {
self.registrations.values()
}
}
impl TypeRegistryArc {
pub fn read(&self) -> RwLockReadGuard<'_, TypeRegistry> {
self.internal.read()
}
pub fn write(&self) -> RwLockWriteGuard<'_, TypeRegistry> {
self.internal.write()
}
}
pub struct TypeRegistration {
type_id: TypeId,
short_name: String,
name: &'static str,
data: HashMap<TypeId, Box<dyn TypeData>>,
}
impl TypeRegistration {
#[inline]
pub fn type_id(&self) -> TypeId {
self.type_id
}
pub fn data<T: TypeData>(&self) -> Option<&T> {
self.data
.get(&TypeId::of::<T>())
.and_then(|value| value.downcast_ref())
}
pub fn data_mut<T: TypeData>(&mut self) -> Option<&mut T> {
self.data
.get_mut(&TypeId::of::<T>())
.and_then(|value| value.downcast_mut())
}
pub fn insert<T: TypeData>(&mut self, data: T) {
self.data.insert(TypeId::of::<T>(), Box::new(data));
}
pub fn of<T: Reflect>() -> Self {
let ty = TypeId::of::<T>();
let type_name = std::any::type_name::<T>();
Self {
type_id: ty,
data: HashMap::default(),
name: type_name,
short_name: Self::get_short_name(type_name),
}
}
pub fn short_name(&self) -> &str {
&self.short_name
}
pub fn name(&self) -> &'static str {
self.name
}
fn get_short_name(full_name: &str) -> String {
let mut short_name = String::new();
{
// A typename may be a composition of several other type names (e.g. generic parameters)
// separated by the characters that we try to find below.
// Then, each individual typename is shortened to its last path component.
//
// Note: Instead of `find`, `split_inclusive` would be nice but it's still unstable...
let mut remainder = full_name;
while let Some(index) = remainder.find(&['<', '>', '(', ')', '[', ']', ',', ';'][..]) {
let (path, new_remainder) = remainder.split_at(index);
// Push the shortened path in front of the found character
short_name.push_str(path.rsplit(':').next().unwrap());
// Push the character that was found
let character = new_remainder.chars().next().unwrap();
short_name.push(character);
// Advance the remainder
if character == ',' || character == ';' {
// A comma or semicolon is always followed by a space
short_name.push(' ');
remainder = &new_remainder[2..];
} else {
remainder = &new_remainder[1..];
}
}
// The remainder will only be non-empty if there were no matches at all
if !remainder.is_empty() {
// Then, the full typename is a path that has to be shortened
short_name.push_str(remainder.rsplit(':').next().unwrap());
}
}
short_name
}
}
impl Clone for TypeRegistration {
fn clone(&self) -> Self {
let mut data = HashMap::default();
for (id, type_data) in self.data.iter() {
data.insert(*id, (*type_data).clone_type_data());
}
TypeRegistration {
data,
name: self.name,
short_name: self.short_name.clone(),
type_id: self.type_id,
}
}
}
pub trait TypeData: Downcast + Send + Sync {
fn clone_type_data(&self) -> Box<dyn TypeData>;
}
impl_downcast!(TypeData);
impl<T: 'static + Send + Sync> TypeData for T
where
T: Clone,
{
fn clone_type_data(&self) -> Box<dyn TypeData> {
Box::new(self.clone())
}
}
pub trait FromType<T> {
fn from_type() -> Self;
}
#[derive(Clone)]
pub struct ReflectDeserialize {
pub func: fn(
deserializer: &mut dyn erased_serde::Deserializer,
) -> Result<Box<dyn Reflect>, erased_serde::Error>,
}
impl ReflectDeserialize {
pub fn deserialize<'de, D>(&self, deserializer: D) -> Result<Box<dyn Reflect>, D::Error>
where
D: serde::Deserializer<'de>,
{
let mut erased = erased_serde::Deserializer::erase(deserializer);
(self.func)(&mut erased)
.map_err(<<D as serde::Deserializer<'de>>::Error as serde::de::Error>::custom)
}
}
impl<T: for<'a> Deserialize<'a> + Reflect> FromType<T> for ReflectDeserialize {
fn from_type() -> Self {
ReflectDeserialize {
func: |deserializer| Ok(Box::new(T::deserialize(deserializer)?)),
}
}
}
#[cfg(test)]
mod test {
use crate::TypeRegistration;
#[test]
fn test_get_short_name() {
assert_eq!(
TypeRegistration::get_short_name(std::any::type_name::<f64>()),
"f64"
);
assert_eq!(
TypeRegistration::get_short_name(std::any::type_name::<String>()),
"String"
);
assert_eq!(
TypeRegistration::get_short_name(std::any::type_name::<(u32, f64)>()),
"(u32, f64)"
);
assert_eq!(
TypeRegistration::get_short_name(std::any::type_name::<(String, String)>()),
"(String, String)"
);
assert_eq!(
TypeRegistration::get_short_name(std::any::type_name::<[f64]>()),
"[f64]"
);
assert_eq!(
TypeRegistration::get_short_name(std::any::type_name::<[String]>()),
"[String]"
);
assert_eq!(
TypeRegistration::get_short_name(std::any::type_name::<[f64; 16]>()),
"[f64; 16]"
);
assert_eq!(
TypeRegistration::get_short_name(std::any::type_name::<[String; 16]>()),
"[String; 16]"
);
}
// TODO: re-enable
// #[test]
// fn test_property_type_registration() {
// assert_eq!(
// TypeRegistration::of::<Option<f64>>().short_name,
// "Option<f64>"
// );
// assert_eq!(
// TypeRegistration::of::<HashMap<u32, String>>().short_name,
// "HashMap<u32, String>"
// );
// assert_eq!(
// TypeRegistration::of::<Option<HashMap<u32, String>>>().short_name,
// "Option<HashMap<u32, String>>"
// );
// assert_eq!(
// TypeRegistration::of::<Option<HashMap<u32, Option<String>>>>().short_name,
// "Option<HashMap<u32, Option<String>>>"
// );
// assert_eq!(
// TypeRegistration::of::<Option<HashMap<String, Option<String>>>>().short_name,
// "Option<HashMap<String, Option<String>>>"
// );
// assert_eq!(
// TypeRegistration::of::<Option<HashMap<Option<String>, Option<String>>>>().short_name,
// "Option<HashMap<Option<String>, Option<String>>>"
// );
// assert_eq!(
// TypeRegistration::of::<Option<HashMap<Option<String>, (String, Option<String>)>>>()
// .short_name,
// "Option<HashMap<Option<String>, (String, Option<String>)>>"
// );
// }
}

View file

@ -1,5 +1,5 @@
pub use bevy_derive::TypeUuid;
use uuid::Uuid;
pub use bevy_reflect_derive::TypeUuid;
pub use bevy_utils::Uuid;
pub trait TypeUuid {
const TYPE_UUID: Uuid;

View file

@ -20,9 +20,8 @@ bevy_core = { path = "../bevy_core", version = "0.3.0" }
bevy_derive = { path = "../bevy_derive", version = "0.3.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.3.0" }
bevy_math = { path = "../bevy_math", version = "0.3.0" }
bevy_property = { path = "../bevy_property", version = "0.3.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.3.0", features = ["bevy"] }
bevy_transform = { path = "../bevy_transform", version = "0.3.0" }
bevy_type_registry = { path = "../bevy_type_registry", version = "0.3.0" }
bevy_window = { path = "../bevy_window", version = "0.3.0" }
bevy_utils = { path = "../bevy_utils", version = "0.3.0" }
@ -30,7 +29,6 @@ bevy_utils = { path = "../bevy_utils", version = "0.3.0" }
image = { version = "0.23.12", default-features = false }
# misc
uuid = { version = "0.8", features = ["v4", "serde"] }
serde = { version = "1", features = ["derive"] }
bitflags = "1.2.1"
smallvec = "1.4.2"

View file

@ -2,16 +2,16 @@ use super::CameraProjection;
use bevy_app::prelude::{EventReader, Events};
use bevy_ecs::{Added, Component, Entity, Local, Query, QuerySet, Res};
use bevy_math::Mat4;
use bevy_property::Properties;
use bevy_reflect::Reflect;
use bevy_window::{WindowCreated, WindowId, WindowResized, Windows};
#[derive(Default, Debug, Properties)]
#[derive(Default, Debug, Reflect)]
pub struct Camera {
pub projection_matrix: Mat4,
pub name: Option<String>,
#[property(ignore)]
#[reflect(ignore)]
pub window: WindowId,
#[property(ignore)]
#[reflect(ignore)]
pub depth_calculation: DepthCalculation,
}

View file

@ -1,6 +1,6 @@
use super::DepthCalculation;
use bevy_math::Mat4;
use bevy_property::{Properties, Property};
use bevy_reflect::{Reflect, ReflectDeserialize};
use serde::{Deserialize, Serialize};
pub trait CameraProjection {
@ -9,7 +9,7 @@ pub trait CameraProjection {
fn depth_calculation(&self) -> DepthCalculation;
}
#[derive(Debug, Clone, Properties)]
#[derive(Debug, Clone, Reflect)]
pub struct PerspectiveProjection {
pub fov: f32,
pub aspect_ratio: f32,
@ -43,13 +43,14 @@ impl Default for PerspectiveProjection {
}
// TODO: make this a component instead of a property
#[derive(Debug, Clone, Property, Serialize, Deserialize)]
#[derive(Debug, Clone, Reflect, Serialize, Deserialize)]
#[reflect_value(Serialize, Deserialize)]
pub enum WindowOrigin {
Center,
BottomLeft,
}
#[derive(Debug, Clone, Properties)]
#[derive(Debug, Clone, Reflect)]
pub struct OrthographicProjection {
pub left: f32,
pub right: f32,

View file

@ -2,7 +2,7 @@ use super::{Camera, DepthCalculation};
use crate::Draw;
use bevy_core::FloatOrd;
use bevy_ecs::{Entity, Query, With};
use bevy_property::Properties;
use bevy_reflect::Reflect;
use bevy_transform::prelude::GlobalTransform;
#[derive(Debug)]
@ -11,9 +11,9 @@ pub struct VisibleEntity {
pub order: FloatOrd,
}
#[derive(Default, Debug, Properties)]
#[derive(Default, Debug, Reflect)]
pub struct VisibleEntities {
#[property(ignore)]
#[reflect(ignore)]
pub value: Vec<VisibleEntity>,
}

View file

@ -7,7 +7,7 @@ use crate::{
use bevy_asset::Handle;
use bevy_core::{Byteable, Bytes};
use bevy_math::{Vec3, Vec4};
use bevy_property::Property;
use bevy_reflect::Reflect;
use serde::{Deserialize, Serialize};
use std::ops::{Add, AddAssign, Mul, MulAssign};
@ -15,7 +15,7 @@ use std::ops::{Add, AddAssign, Mul, MulAssign};
// see comment on bevy issue #688 https://github.com/bevyengine/bevy/pull/688#issuecomment-711414011
/// RGBA color in the Linear sRGB colorspace (often colloquially referred to as "linear", "RGB", or "linear RGB").
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Property)]
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Reflect)]
pub struct Color {
red: f32,
green: f32,

View file

@ -1,5 +1,3 @@
// sRGB
//==================================================================================================
pub trait SrgbColorSpace {
fn linear_to_nonlinear_srgb(self) -> Self;
fn nonlinear_to_linear_srgb(self) -> Self;
@ -47,4 +45,3 @@ fn test_srgb_full_roundtrip() {
);
}
}
//==================================================================================================

View file

@ -8,7 +8,7 @@ use crate::{
};
use bevy_asset::{Assets, Handle};
use bevy_ecs::{Query, Res, ResMut, SystemParam};
use bevy_property::Properties;
use bevy_reflect::Reflect;
use std::{ops::Range, sync::Arc};
use thiserror::Error;
@ -44,11 +44,11 @@ pub enum RenderCommand {
}
/// A component that indicates how to draw an entity.
#[derive(Debug, Properties, Clone)]
#[derive(Debug, Clone, Reflect)]
pub struct Draw {
pub is_visible: bool,
pub is_transparent: bool,
#[property(ignore)]
#[reflect(ignore)]
pub render_commands: Vec<RenderCommand>,
}

View file

@ -11,7 +11,7 @@ pub mod renderer;
pub mod shader;
pub mod texture;
use bevy_type_registry::RegisterType;
use bevy_reflect::RegisterTypeBuilder;
pub use once_cell;
pub mod prelude {
@ -29,7 +29,7 @@ pub mod prelude {
}
use crate::prelude::*;
use base::{MainPass, Msaa};
use base::Msaa;
use bevy_app::prelude::*;
use bevy_asset::AddAsset;
use camera::{
@ -40,11 +40,10 @@ use pipeline::{
ShaderSpecialization,
};
use render_graph::{
base::{self, BaseRenderGraphBuilder, BaseRenderGraphConfig},
base::{self, BaseRenderGraphBuilder, BaseRenderGraphConfig, MainPass},
RenderGraph,
};
use renderer::{AssetRenderResourceBindings, RenderResourceBindings};
use std::ops::Range;
#[cfg(feature = "hdr")]
use texture::HdrTextureLoader;
#[cfg(feature = "png")]
@ -101,19 +100,18 @@ impl Plugin for RenderPlugin {
.add_asset::<Texture>()
.add_asset::<Shader>()
.add_asset::<PipelineDescriptor>()
.register_component::<Camera>()
.register_component::<Draw>()
.register_component::<RenderPipelines>()
.register_component::<OrthographicProjection>()
.register_component::<PerspectiveProjection>()
.register_component::<MainPass>()
.register_component::<VisibleEntities>()
.register_property::<Color>()
.register_property::<Range<f32>>()
.register_property::<ShaderSpecialization>()
.register_property::<PrimitiveTopology>()
.register_property::<IndexFormat>()
.register_properties::<PipelineSpecialization>()
.register_type::<Camera>()
.register_type::<Draw>()
.register_type::<RenderPipelines>()
.register_type::<OrthographicProjection>()
.register_type::<PerspectiveProjection>()
.register_type::<MainPass>()
.register_type::<VisibleEntities>()
.register_type::<Color>()
.register_type::<ShaderSpecialization>()
.register_type::<PrimitiveTopology>()
.register_type::<IndexFormat>()
.register_type::<PipelineSpecialization>()
.init_resource::<RenderGraph>()
.init_resource::<PipelineCompiler>()
.init_resource::<RenderResourceBindings>()

View file

@ -7,7 +7,7 @@ use bevy_asset::{AssetEvent, Assets, Handle};
use bevy_core::AsBytes;
use bevy_ecs::{Local, Query, Res};
use bevy_math::*;
use bevy_type_registry::TypeUuid;
use bevy_reflect::TypeUuid;
use std::borrow::Cow;
use crate::pipeline::{InputStepMode, VertexAttributeDescriptor, VertexBufferDescriptor};

View file

@ -7,7 +7,7 @@ use super::{
PipelineLayout, StencilStateDescriptor,
};
use crate::{shader::ShaderStages, texture::TextureFormat};
use bevy_type_registry::TypeUuid;
use bevy_reflect::TypeUuid;
#[derive(Clone, Debug, TypeUuid)]
#[uuid = "ebfc1d11-a2a4-44cb-8f12-c49cc631146c"]

View file

@ -5,12 +5,12 @@ use crate::{
shader::{Shader, ShaderSource},
};
use bevy_asset::{Assets, Handle};
use bevy_property::{Properties, Property};
use bevy_reflect::Reflect;
use bevy_utils::{HashMap, HashSet};
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
#[derive(Clone, Eq, PartialEq, Debug, Properties)]
#[derive(Clone, Eq, PartialEq, Debug, Reflect)]
pub struct PipelineSpecialization {
pub shader_specialization: ShaderSpecialization,
pub primitive_topology: PrimitiveTopology,
@ -40,7 +40,7 @@ impl PipelineSpecialization {
}
}
#[derive(Clone, Eq, PartialEq, Debug, Default, Property, Serialize, Deserialize)]
#[derive(Clone, Eq, PartialEq, Debug, Default, Reflect, Serialize, Deserialize)]
pub struct ShaderSpecialization {
pub shader_defs: HashSet<String>,
}

View file

@ -7,10 +7,9 @@ use crate::{
};
use bevy_asset::{Assets, Handle};
use bevy_ecs::{Query, Res, ResMut};
use bevy_property::Properties;
use bevy_reflect::Reflect;
#[derive(Debug, Properties, Default, Clone)]
#[non_exhaustive]
#[derive(Debug, Default, Clone, Reflect)]
pub struct RenderPipeline {
pub pipeline: Handle<PipelineDescriptor>,
pub specialization: PipelineSpecialization,
@ -39,10 +38,10 @@ impl RenderPipeline {
}
}
#[derive(Debug, Properties, Clone)]
#[derive(Debug, Clone, Reflect)]
pub struct RenderPipelines {
pub pipelines: Vec<RenderPipeline>,
#[property(ignore)]
#[reflect(ignore)]
pub bindings: RenderResourceBindings,
}

View file

@ -1,5 +1,5 @@
use crate::texture::TextureFormat;
use bevy_property::Property;
use bevy_reflect::Reflect;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug)]
@ -59,7 +59,7 @@ pub enum CompareFunction {
Always = 7,
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize, Property)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize, Reflect)]
pub enum PrimitiveTopology {
PointList = 0,
LineList = 1,
@ -182,7 +182,7 @@ impl Default for BlendOperation {
}
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize, Property)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize, Reflect)]
pub enum IndexFormat {
Uint16 = 0,
Uint32 = 1,

View file

@ -1,12 +1,13 @@
use super::VertexFormat;
use bevy_property::Property;
use bevy_reflect::{Reflect, ReflectDeserialize};
use serde::{Deserialize, Serialize};
use std::{
borrow::Cow,
hash::{Hash, Hasher},
};
#[derive(Clone, Debug, Eq, PartialEq, Default, Property, Serialize, Deserialize)]
#[derive(Clone, Debug, Eq, PartialEq, Default, Reflect, Serialize, Deserialize)]
#[reflect_value(Serialize, Deserialize, PartialEq)]
pub struct VertexBufferDescriptor {
pub name: Cow<'static, str>,
pub stride: u64,

View file

@ -10,11 +10,11 @@ use crate::{
texture::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsage},
Color,
};
use bevy_property::Properties;
use bevy_reflect::Reflect;
use bevy_window::WindowId;
/// A component that indicates that an entity should be drawn in the "main pass"
#[derive(Default, Properties)]
#[derive(Default, Reflect)]
pub struct MainPass;
#[derive(Debug)]

View file

@ -1,9 +1,9 @@
use super::{Edge, RenderGraphError, ResourceSlotInfo, ResourceSlots};
use crate::renderer::RenderContext;
use bevy_ecs::{Commands, Resources, System, World};
use bevy_utils::Uuid;
use downcast_rs::{impl_downcast, Downcast};
use std::{borrow::Cow, fmt::Debug};
use uuid::Uuid;
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct NodeId(Uuid);

View file

@ -1,4 +1,4 @@
use uuid::Uuid;
use bevy_utils::Uuid;
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
pub struct BufferId(Uuid);

View file

@ -1,4 +1,4 @@
use uuid::Uuid;
use bevy_utils::Uuid;
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TextureId(Uuid);

View file

@ -1,6 +1,6 @@
use super::ShaderLayout;
use bevy_asset::Handle;
use bevy_type_registry::TypeUuid;
use bevy_reflect::TypeUuid;
use std::marker::Copy;
/// The stage of a shader

View file

@ -5,7 +5,7 @@ use crate::renderer::{
use bevy_app::prelude::{EventReader, Events};
use bevy_asset::{AssetEvent, Assets, Handle};
use bevy_ecs::{Res, ResMut};
use bevy_type_registry::TypeUuid;
use bevy_reflect::TypeUuid;
use bevy_utils::HashSet;
pub const TEXTURE_ASSET_INDEX: u64 = 0;

View file

@ -17,8 +17,7 @@ keywords = ["bevy"]
bevy_app = { path = "../bevy_app", version = "0.3.0" }
bevy_asset = { path = "../bevy_asset", version = "0.3.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.3.0" }
bevy_property = { path = "../bevy_property", version = "0.3.0" }
bevy_type_registry = { path = "../bevy_type_registry", version = "0.3.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.3.0", features = ["bevy"] }
bevy_utils = { path = "../bevy_utils", version = "0.3.0" }
# other

View file

@ -1,8 +1,7 @@
use crate::{serde::SceneSerializer, Scene};
use anyhow::Result;
use bevy_ecs::{EntityMap, Resources, World};
use bevy_property::{DynamicProperties, PropertyTypeRegistry};
use bevy_type_registry::{ComponentRegistry, TypeRegistry, TypeUuid};
use bevy_reflect::{Reflect, ReflectComponent, ReflectMapEntities, TypeRegistryArc, TypeUuid};
use serde::Serialize;
use thiserror::Error;
@ -20,16 +19,17 @@ pub struct DynamicScene {
pub struct Entity {
pub entity: u32,
pub components: Vec<DynamicProperties>,
pub components: Vec<Box<dyn Reflect>>,
}
impl DynamicScene {
pub fn from_scene(scene: &Scene, component_registry: &ComponentRegistry) -> Self {
Self::from_world(&scene.world, component_registry)
pub fn from_scene(scene: &Scene, type_registry: &TypeRegistryArc) -> Self {
Self::from_world(&scene.world, type_registry)
}
pub fn from_world(world: &World, component_registry: &ComponentRegistry) -> Self {
pub fn from_world(world: &World, type_registry: &TypeRegistryArc) -> Self {
let mut scene = DynamicScene::default();
let type_registry = type_registry.read();
for archetype in world.archetypes() {
let mut entities = Vec::new();
for (index, entity) in archetype.iter_entities().enumerate() {
@ -40,11 +40,15 @@ impl DynamicScene {
})
}
for type_info in archetype.types() {
if let Some(component_registration) = component_registry.get(&type_info.id()) {
let properties =
component_registration.get_component_properties(&archetype, index);
entities[index].components.push(properties.to_dynamic());
if let Some(registration) = type_registry.get(type_info.id()) {
if let Some(reflect_component) = registration.data::<ReflectComponent>() {
// SAFE: the index comes directly from a currently live component
unsafe {
let component =
reflect_component.reflect_component(&archetype, index);
entities[index].components.push(component.clone_value());
}
}
}
}
}
@ -60,38 +64,45 @@ impl DynamicScene {
world: &mut World,
resources: &Resources,
) -> Result<(), DynamicSceneToWorldError> {
let type_registry = resources.get::<TypeRegistry>().unwrap();
let component_registry = type_registry.component.read();
let type_registry = resources.get::<TypeRegistryArc>().unwrap();
let type_registry = type_registry.read();
let mut entity_map = EntityMap::default();
for scene_entity in self.entities.iter() {
let new_entity = world.reserve_entity();
entity_map.insert(bevy_ecs::Entity::new(scene_entity.entity), new_entity);
for component in scene_entity.components.iter() {
let component_registration = component_registry
.get_with_name(&component.type_name)
let registration = type_registry
.get_with_name(component.type_name())
.ok_or_else(|| DynamicSceneToWorldError::UnregisteredComponent {
type_name: component.type_name.to_string(),
type_name: component.type_name().to_string(),
})?;
if world.has_component_type(new_entity, component_registration.ty) {
component_registration.apply_property_to_entity(world, new_entity, component);
let reflect_component =
registration.data::<ReflectComponent>().ok_or_else(|| {
DynamicSceneToWorldError::UnregisteredComponent {
type_name: component.type_name().to_string(),
}
})?;
if world.has_component_type(new_entity, registration.type_id()) {
reflect_component.apply_component(world, new_entity, &**component);
} else {
component_registration
.add_property_to_entity(world, resources, new_entity, component);
reflect_component.add_component(world, resources, new_entity, &**component);
}
}
}
for component_registration in component_registry.iter() {
component_registration
.map_entities(world, &entity_map)
.unwrap();
for registration in type_registry.iter() {
if let Some(map_entities_reflect) = registration.data::<ReflectMapEntities>() {
map_entities_reflect
.map_entities(world, &entity_map)
.unwrap();
}
}
Ok(())
}
// TODO: move to AssetSaver when it is implemented
pub fn serialize_ron(&self, registry: &PropertyTypeRegistry) -> Result<String, ron::Error> {
pub fn serialize_ron(&self, registry: &TypeRegistryArc) -> Result<String, ron::Error> {
serialize_ron(SceneSerializer::new(self, registry))
}

View file

@ -1,5 +1,5 @@
use bevy_ecs::World;
use bevy_type_registry::TypeUuid;
use bevy_reflect::TypeUuid;
#[derive(Debug, TypeUuid)]
#[uuid = "c156503c-edd9-4ec7-8d33-dab392df03cd"]

View file

@ -2,23 +2,20 @@ use crate::serde::SceneDeserializer;
use anyhow::Result;
use bevy_asset::{AssetLoader, LoadContext, LoadedAsset};
use bevy_ecs::{FromResources, Resources};
use bevy_property::PropertyTypeRegistry;
use bevy_type_registry::TypeRegistry;
use bevy_reflect::TypeRegistryArc;
use bevy_utils::BoxedFuture;
use parking_lot::RwLock;
use serde::de::DeserializeSeed;
use std::sync::Arc;
#[derive(Debug)]
pub struct SceneLoader {
property_type_registry: Arc<RwLock<PropertyTypeRegistry>>,
type_registry: TypeRegistryArc,
}
impl FromResources for SceneLoader {
fn from_resources(resources: &Resources) -> Self {
let type_registry = resources.get::<TypeRegistry>().unwrap();
let type_registry = resources.get::<TypeRegistryArc>().unwrap();
SceneLoader {
property_type_registry: type_registry.property.clone(),
type_registry: (&*type_registry).clone(),
}
}
}
@ -30,10 +27,9 @@ impl AssetLoader for SceneLoader {
load_context: &'a mut LoadContext,
) -> BoxedFuture<'a, Result<()>> {
Box::pin(async move {
let registry = self.property_type_registry.read();
let mut deserializer = ron::de::Deserializer::from_bytes(&bytes)?;
let scene_deserializer = SceneDeserializer {
property_type_registry: &registry,
type_registry: &*self.type_registry.read(),
};
let scene = scene_deserializer.deserialize(&mut deserializer)?;
load_context.set_default_asset(LoadedAsset::new(scene));

View file

@ -2,7 +2,7 @@ use crate::{DynamicScene, Scene};
use bevy_app::prelude::*;
use bevy_asset::{AssetEvent, Assets, Handle};
use bevy_ecs::{EntityMap, Resources, World};
use bevy_type_registry::TypeRegistry;
use bevy_reflect::{ReflectComponent, ReflectMapEntities, TypeRegistryArc};
use bevy_utils::HashMap;
use thiserror::Error;
use uuid::Uuid;
@ -100,8 +100,8 @@ impl SceneSpawner {
scene_handle: &Handle<DynamicScene>,
instance_info: &mut InstanceInfo,
) -> Result<(), SceneSpawnError> {
let type_registry = resources.get::<TypeRegistry>().unwrap();
let component_registry = type_registry.component.read();
let type_registry = resources.get::<TypeRegistryArc>().unwrap();
let type_registry = type_registry.read();
let scenes = resources.get::<Assets<DynamicScene>>().unwrap();
let scene = scenes
.get(scene_handle)
@ -116,18 +116,23 @@ impl SceneSpawner {
.entry(bevy_ecs::Entity::new(scene_entity.entity))
.or_insert_with(|| world.reserve_entity());
for component in scene_entity.components.iter() {
let component_registration = component_registry
.get_with_name(&component.type_name)
.ok_or(SceneSpawnError::UnregisteredComponent {
type_name: component.type_name.to_string(),
let registration = type_registry
.get_with_name(component.type_name())
.ok_or_else(|| SceneSpawnError::UnregisteredComponent {
type_name: component.type_name().to_string(),
})?;
if world.has_component_type(entity, component_registration.ty) {
if component.type_name != "Camera" {
component_registration.apply_property_to_entity(world, entity, component);
let reflect_component =
registration.data::<ReflectComponent>().ok_or_else(|| {
SceneSpawnError::UnregisteredComponent {
type_name: component.type_name().to_string(),
}
})?;
if world.has_component_type(entity, registration.type_id()) {
if registration.short_name() != "Camera" {
reflect_component.apply_component(world, entity, &**component);
}
} else {
component_registration
.add_property_to_entity(world, resources, entity, component);
reflect_component.add_component(world, resources, entity, &**component);
}
}
}
@ -144,8 +149,8 @@ impl SceneSpawner {
let mut instance_info = InstanceInfo {
entity_map: EntityMap::default(),
};
let type_registry = resources.get::<TypeRegistry>().unwrap();
let component_registry = type_registry.component.read();
let type_registry = resources.get::<TypeRegistryArc>().unwrap();
let type_registry = type_registry.read();
let scenes = resources.get::<Assets<Scene>>().unwrap();
let scene =
scenes
@ -161,22 +166,26 @@ impl SceneSpawner {
.entry(*scene_entity)
.or_insert_with(|| world.reserve_entity());
for type_info in archetype.types() {
if let Some(component_registration) = component_registry.get(&type_info.id()) {
component_registration.component_copy(
&scene.world,
world,
resources,
*scene_entity,
entity,
);
if let Some(registration) = type_registry.get(type_info.id()) {
if let Some(component_reflect) = registration.data::<ReflectComponent>() {
component_reflect.copy_component(
&scene.world,
world,
resources,
*scene_entity,
entity,
);
}
}
}
}
}
for component_registration in component_registry.iter() {
component_registration
.map_entities(world, &instance_info.entity_map)
.unwrap();
for registration in type_registry.iter() {
if let Some(map_entities_reflect) = registration.data::<ReflectMapEntities>() {
map_entities_reflect
.map_entities(world, &instance_info.entity_map)
.unwrap();
}
}
self.spawned_instances.insert(instance_id, instance_info);
let spawned = self

View file

@ -1,8 +1,8 @@
use crate::{DynamicScene, Entity};
use anyhow::Result;
use bevy_property::{
property_serde::{DynamicPropertiesDeserializer, DynamicPropertiesSerializer},
DynamicProperties, PropertyTypeRegistry,
use bevy_reflect::{
serde::{ReflectDeserializer, ReflectSerializer},
Reflect, TypeRegistry, TypeRegistryArc,
};
use serde::{
de::{DeserializeSeed, Error, MapAccess, SeqAccess, Visitor},
@ -12,11 +12,11 @@ use serde::{
pub struct SceneSerializer<'a> {
pub scene: &'a DynamicScene,
pub registry: &'a PropertyTypeRegistry,
pub registry: &'a TypeRegistryArc,
}
impl<'a> SceneSerializer<'a> {
pub fn new(scene: &'a DynamicScene, registry: &'a PropertyTypeRegistry) -> Self {
pub fn new(scene: &'a DynamicScene, registry: &'a TypeRegistryArc) -> Self {
SceneSerializer { scene, registry }
}
}
@ -39,7 +39,7 @@ impl<'a> Serialize for SceneSerializer<'a> {
pub struct EntitySerializer<'a> {
pub entity: &'a Entity,
pub registry: &'a PropertyTypeRegistry,
pub registry: &'a TypeRegistryArc,
}
impl<'a> Serialize for EntitySerializer<'a> {
@ -61,8 +61,8 @@ impl<'a> Serialize for EntitySerializer<'a> {
}
pub struct ComponentsSerializer<'a> {
pub components: &'a [DynamicProperties],
pub registry: &'a PropertyTypeRegistry,
pub components: &'a [Box<dyn Reflect>],
pub registry: &'a TypeRegistryArc,
}
impl<'a> Serialize for ComponentsSerializer<'a> {
@ -71,10 +71,10 @@ impl<'a> Serialize for ComponentsSerializer<'a> {
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,
for component in self.components.iter() {
state.serialize_element(&ReflectSerializer::new(
&**component,
&*self.registry.read(),
))?;
}
state.end()
@ -82,7 +82,7 @@ impl<'a> Serialize for ComponentsSerializer<'a> {
}
pub struct SceneDeserializer<'a> {
pub property_type_registry: &'a PropertyTypeRegistry,
pub type_registry: &'a TypeRegistry,
}
impl<'a, 'de> DeserializeSeed<'de> for SceneDeserializer<'a> {
@ -94,14 +94,14 @@ impl<'a, 'de> DeserializeSeed<'de> for SceneDeserializer<'a> {
{
Ok(DynamicScene {
entities: deserializer.deserialize_seq(SceneEntitySeqVisitor {
property_type_registry: self.property_type_registry,
type_registry: self.type_registry,
})?,
})
}
}
struct SceneEntitySeqVisitor<'a> {
pub property_type_registry: &'a PropertyTypeRegistry,
pub type_registry: &'a TypeRegistry,
}
impl<'a, 'de> Visitor<'de> for SceneEntitySeqVisitor<'a> {
@ -117,7 +117,7 @@ impl<'a, 'de> Visitor<'de> for SceneEntitySeqVisitor<'a> {
{
let mut entities = Vec::new();
while let Some(entity) = seq.next_element_seed(SceneEntityDeserializer {
property_type_registry: self.property_type_registry,
type_registry: self.type_registry,
})? {
entities.push(entity);
}
@ -127,7 +127,7 @@ impl<'a, 'de> Visitor<'de> for SceneEntitySeqVisitor<'a> {
}
pub struct SceneEntityDeserializer<'a> {
pub property_type_registry: &'a PropertyTypeRegistry,
pub type_registry: &'a TypeRegistry,
}
impl<'a, 'de> DeserializeSeed<'de> for SceneEntityDeserializer<'a> {
@ -141,7 +141,7 @@ impl<'a, 'de> DeserializeSeed<'de> for SceneEntityDeserializer<'a> {
ENTITY_STRUCT,
&[ENTITY_FIELD_ENTITY, ENTITY_FIELD_COMPONENTS],
SceneEntityVisitor {
registry: self.property_type_registry,
registry: self.type_registry,
},
)
}
@ -158,9 +158,8 @@ pub const ENTITY_STRUCT: &str = "Entity";
pub const ENTITY_FIELD_ENTITY: &str = "entity";
pub const ENTITY_FIELD_COMPONENTS: &str = "components";
#[derive(Debug)]
struct SceneEntityVisitor<'a> {
pub registry: &'a PropertyTypeRegistry,
pub registry: &'a TypeRegistry,
}
impl<'a, 'de> Visitor<'de> for SceneEntityVisitor<'a> {
@ -211,11 +210,11 @@ impl<'a, 'de> Visitor<'de> for SceneEntityVisitor<'a> {
}
pub struct ComponentVecDeserializer<'a> {
pub registry: &'a PropertyTypeRegistry,
pub registry: &'a TypeRegistry,
}
impl<'a, 'de> DeserializeSeed<'de> for ComponentVecDeserializer<'a> {
type Value = Vec<DynamicProperties>;
type Value = Vec<Box<dyn Reflect>>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
@ -228,11 +227,11 @@ impl<'a, 'de> DeserializeSeed<'de> for ComponentVecDeserializer<'a> {
}
struct ComponentSeqVisitor<'a> {
pub registry: &'a PropertyTypeRegistry,
pub registry: &'a TypeRegistry,
}
impl<'a, 'de> Visitor<'de> for ComponentSeqVisitor<'a> {
type Value = Vec<DynamicProperties>;
type Value = Vec<Box<dyn Reflect>>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("list of components")
@ -243,9 +242,7 @@ impl<'a, 'de> Visitor<'de> for ComponentSeqVisitor<'a> {
A: SeqAccess<'de>,
{
let mut dynamic_properties = Vec::new();
while let Some(entity) =
seq.next_element_seed(DynamicPropertiesDeserializer::new(self.registry))?
{
while let Some(entity) = seq.next_element_seed(ReflectDeserializer::new(self.registry))? {
dynamic_properties.push(entity);
}

View file

@ -19,12 +19,13 @@ bevy_asset = { path = "../bevy_asset", version = "0.3.0" }
bevy_core = { path = "../bevy_core", version = "0.3.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.3.0" }
bevy_math = { path = "../bevy_math", version = "0.3.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.3.0", features = ["bevy"] }
bevy_render = { path = "../bevy_render", version = "0.3.0" }
bevy_transform = { path = "../bevy_transform", version = "0.3.0" }
bevy_type_registry = { path = "../bevy_type_registry", version = "0.3.0" }
bevy_utils = { path = "../bevy_utils", version = "0.3.0" }
# other
rectangle-pack = "0.2"
thiserror = "1.0"
guillotiere = "0.6.0"
serde = { version = "1", features = ["derive"] }

View file

@ -1,6 +1,6 @@
use bevy_asset::{self, Handle};
use bevy_reflect::TypeUuid;
use bevy_render::{color::Color, renderer::RenderResources, shader::ShaderDefs, texture::Texture};
use bevy_type_registry::TypeUuid;
#[derive(Debug, RenderResources, ShaderDefs, TypeUuid)]
#[uuid = "506cff92-a9f3-4543-862d-6851c7fdfc99"]

Some files were not shown because too many files have changed in this diff Show more