mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 04:33:37 +00:00
parent
01c4dd96cf
commit
72b2fc9843
138 changed files with 4931 additions and 3519 deletions
22
Cargo.toml
22
Cargo.toml
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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>>()
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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>>,
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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::*;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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>,
|
||||
{
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"] }
|
|
@ -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
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
|
@ -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))
|
||||
}
|
||||
}
|
|
@ -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)))
|
||||
}
|
|
@ -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);
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
mod impl_property_bevy_ecs;
|
||||
mod impl_property_glam;
|
||||
mod impl_property_smallvec;
|
||||
mod impl_property_std;
|
|
@ -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};
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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\'"))
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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(®istration.short_name) {
|
||||
®istration.short_name
|
||||
} else {
|
||||
registration.name
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_with_short_name(&self, short_type_name: &str) -> Option<&PropertyTypeRegistration> {
|
||||
self.short_names
|
||||
.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>)>>"
|
||||
);
|
||||
}
|
||||
}
|
36
crates/bevy_reflect/Cargo.toml
Normal file
36
crates/bevy_reflect/Cargo.toml
Normal 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"
|
166
crates/bevy_reflect/README.md
Normal file
166
crates/bevy_reflect/README.md
Normal 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, ®istry);
|
||||
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(®istry);
|
||||
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)
|
|
@ -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"] }
|
751
crates/bevy_reflect/bevy_reflect_derive/src/lib.rs
Normal file
751
crates/bevy_reflect/bevy_reflect_derive/src/lib.rs
Normal 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)
|
||||
}
|
|
@ -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()
|
||||
}
|
66
crates/bevy_reflect/bevy_reflect_derive/src/reflect_trait.rs
Normal file
66
crates/bevy_reflect/bevy_reflect_derive/src/reflect_trait.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
|
@ -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 ),*
|
||||
]);
|
||||
}
|
57
crates/bevy_reflect/src/impls/bevy_app.rs
Normal file
57
crates/bevy_reflect/src/impls/bevy_app.rs
Normal 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
|
||||
}
|
||||
}
|
217
crates/bevy_reflect/src/impls/bevy_ecs.rs
Normal file
217
crates/bevy_reflect/src/impls/bevy_ecs.rs
Normal 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;
|
||||
}
|
10
crates/bevy_reflect/src/impls/glam.rs
Normal file
10
crates/bevy_reflect/src/impls/glam.rs
Normal 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));
|
96
crates/bevy_reflect/src/impls/smallvec.rs
Normal file
96
crates/bevy_reflect/src/impls/smallvec.rs
Normal 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
|
||||
}
|
||||
}
|
201
crates/bevy_reflect/src/impls/std.rs
Normal file
201
crates/bevy_reflect/src/impls/std.rs
Normal 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
|
||||
}
|
||||
}
|
323
crates/bevy_reflect/src/lib.rs
Normal file
323
crates/bevy_reflect/src/lib.rs
Normal 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, ®istry);
|
||||
let serialized = to_string_pretty(&serializer, PrettyConfig::default()).unwrap();
|
||||
|
||||
let mut deserializer = Deserializer::from_str(&serialized).unwrap();
|
||||
let reflect_deserializer = ReflectDeserializer::new(®istry);
|
||||
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 });
|
||||
}
|
||||
}
|
178
crates/bevy_reflect/src/list.rs
Normal file
178
crates/bevy_reflect/src/list.rs
Normal 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)
|
||||
}
|
184
crates/bevy_reflect/src/map.rs
Normal file
184
crates/bevy_reflect/src/map.rs
Normal 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)
|
||||
}
|
385
crates/bevy_reflect/src/path.rs
Normal file
385
crates/bevy_reflect/src/path.rs
Normal 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(_))
|
||||
));
|
||||
}
|
||||
}
|
77
crates/bevy_reflect/src/reflect.rs
Normal file
77
crates/bevy_reflect/src/reflect.rs
Normal 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>()
|
||||
}
|
||||
}
|
403
crates/bevy_reflect/src/serde/de.rs
Normal file
403
crates/bevy_reflect/src/serde/de.rs
Normal 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)
|
||||
}
|
||||
}
|
14
crates/bevy_reflect/src/serde/mod.rs
Normal file
14
crates/bevy_reflect/src/serde/mod.rs
Normal 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";
|
||||
}
|
268
crates/bevy_reflect/src/serde/ser.rs
Normal file
268
crates/bevy_reflect/src/serde/ser.rs
Normal 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()
|
||||
}
|
||||
}
|
256
crates/bevy_reflect/src/struct_trait.rs
Normal file
256
crates/bevy_reflect/src/struct_trait.rs
Normal 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)
|
||||
}
|
210
crates/bevy_reflect/src/tuple_struct.rs
Normal file
210
crates/bevy_reflect/src/tuple_struct.rs
Normal 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)
|
||||
}
|
324
crates/bevy_reflect/src/type_registry.rs
Normal file
324
crates/bevy_reflect/src/type_registry.rs
Normal 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>)>>"
|
||||
// );
|
||||
// }
|
||||
}
|
|
@ -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;
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>,
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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() {
|
|||
);
|
||||
}
|
||||
}
|
||||
//==================================================================================================
|
||||
|
|
|
@ -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>,
|
||||
}
|
||||
|
||||
|
|
|
@ -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>()
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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>,
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use uuid::Uuid;
|
||||
use bevy_utils::Uuid;
|
||||
|
||||
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
|
||||
pub struct BufferId(Uuid);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use uuid::Uuid;
|
||||
use bevy_utils::Uuid;
|
||||
|
||||
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
|
||||
pub struct TextureId(Uuid);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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: ®istry,
|
||||
type_registry: &*self.type_registry.read(),
|
||||
};
|
||||
let scene = scene_deserializer.deserialize(&mut deserializer)?;
|
||||
load_context.set_default_asset(LoadedAsset::new(scene));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue