Skip to content

Commit

Permalink
use Reflect in more places
Browse files Browse the repository at this point in the history
  • Loading branch information
soqb committed Feb 5, 2023
1 parent ecf4c52 commit 9f10455
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 69 deletions.
2 changes: 1 addition & 1 deletion crates/bevy_app/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1082,7 +1082,7 @@ impl App {
/// See [`bevy_reflect::TypeRegistry::register_type_data`].
#[cfg(feature = "bevy_reflect")]
pub fn register_type_data<
T: bevy_reflect::PartialReflect + 'static,
T: bevy_reflect::Reflect + 'static,
D: bevy_reflect::TypeData + bevy_reflect::FromType<T>,
>(
&mut self,
Expand Down
83 changes: 43 additions & 40 deletions crates/bevy_asset/src/reflect.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::any::{Any, TypeId};

use bevy_ecs::world::{unsafe_world_cell::UnsafeWorldCell, World};
use bevy_reflect::{FromReflect, FromType, PartialReflect, Uuid};
use bevy_reflect::{FromReflect, FromType, Reflect, Uuid};

use crate::{Asset, Assets, Handle, HandleId, HandleUntyped};

Expand All @@ -17,17 +17,16 @@ pub struct ReflectAsset {
handle_type_id: TypeId,
assets_resource_type_id: TypeId,

get: fn(&World, HandleUntyped) -> Option<&dyn PartialReflect>,
get: fn(&World, HandleUntyped) -> Option<&dyn Reflect>,
// SAFETY:
// - may only be called with a [`IteriorMutableWorld`] which can be used to access the corresponding `Assets<T>` resource mutably
// - may only be used to access **at most one** access at once
get_unchecked_mut:
unsafe fn(UnsafeWorldCell<'_>, HandleUntyped) -> Option<&mut dyn PartialReflect>,
add: fn(&mut World, &dyn PartialReflect) -> HandleUntyped,
set: fn(&mut World, HandleUntyped, &dyn PartialReflect) -> HandleUntyped,
get_unchecked_mut: unsafe fn(UnsafeWorldCell<'_>, HandleUntyped) -> Option<&mut dyn Reflect>,
add: fn(&mut World, Box<dyn Reflect>) -> HandleUntyped,
set: fn(&mut World, HandleUntyped, Box<dyn Reflect>) -> HandleUntyped,
len: fn(&World) -> usize,
ids: for<'w> fn(&'w World) -> Box<dyn Iterator<Item = HandleId> + 'w>,
remove: fn(&mut World, HandleUntyped) -> Option<Box<dyn PartialReflect>>,
remove: fn(&mut World, HandleUntyped) -> Option<Box<dyn Reflect>>,
}

impl ReflectAsset {
Expand All @@ -47,11 +46,7 @@ impl ReflectAsset {
}

/// Equivalent of [`Assets::get`]
pub fn get<'w>(
&self,
world: &'w World,
handle: HandleUntyped,
) -> Option<&'w dyn PartialReflect> {
pub fn get<'w>(&self, world: &'w World, handle: HandleUntyped) -> Option<&'w dyn Reflect> {
(self.get)(world, handle)
}

Expand All @@ -60,7 +55,7 @@ impl ReflectAsset {
&self,
world: &'w mut World,
handle: HandleUntyped,
) -> Option<&'w mut dyn PartialReflect> {
) -> Option<&'w mut dyn Reflect> {
// SAFETY: unique world access
unsafe { (self.get_unchecked_mut)(world.as_unsafe_world_cell(), handle) }
}
Expand Down Expand Up @@ -96,31 +91,27 @@ impl ReflectAsset {
&self,
world: UnsafeWorldCell<'w>,
handle: HandleUntyped,
) -> Option<&'w mut dyn PartialReflect> {
) -> Option<&'w mut dyn Reflect> {
// SAFETY: requirements are deferred to the caller
(self.get_unchecked_mut)(world, handle)
}

/// Equivalent of [`Assets::add`]
pub fn add(&self, world: &mut World, value: &dyn PartialReflect) -> HandleUntyped {
pub fn add(&self, world: &mut World, value: Box<dyn Reflect>) -> HandleUntyped {
(self.add)(world, value)
}
/// Equivalent of [`Assets::set`]
pub fn set(
&self,
world: &mut World,
handle: HandleUntyped,
value: &dyn PartialReflect,
value: Box<dyn Reflect>,
) -> HandleUntyped {
(self.set)(world, handle, value)
}

/// Equivalent of [`Assets::remove`]
pub fn remove(
&self,
world: &mut World,
handle: HandleUntyped,
) -> Option<Box<dyn PartialReflect>> {
pub fn remove(&self, world: &mut World, handle: HandleUntyped) -> Option<Box<dyn Reflect>> {
(self.remove)(world, handle)
}

Expand Down Expand Up @@ -150,26 +141,41 @@ impl<A: Asset + FromReflect> FromType<A> for ReflectAsset {
get: |world, handle| {
let assets = world.resource::<Assets<A>>();
let asset = assets.get(&handle.typed());
asset.map(|asset| asset as &dyn PartialReflect)
asset.map(|asset| asset as &dyn Reflect)
},
get_unchecked_mut: |world, handle| {
// SAFETY: `get_unchecked_mut` must be callied with `UnsafeWorldCell` having access to `Assets<A>`,
// and must ensure to only have at most one reference to it live at all times.
let assets = unsafe { world.get_resource_mut::<Assets<A>>().unwrap().into_inner() };
let asset = assets.get_mut(&handle.typed());
asset.map(|asset| asset as &mut dyn PartialReflect)
asset.map(|asset| asset as &mut dyn Reflect)
},
add: |world, value| {
let mut assets = world.resource_mut::<Assets<A>>();
let value: A = FromReflect::from_reflect(value)
.expect("could not call `FromReflect::from_reflect` in `ReflectAsset::add`");
assets.add(value).into()
assets
.add(value.take::<A>().unwrap_or_else(|value| {
panic!(
"ReflectAsset::add called with type `{}`, even though it was created for `{}`",
value.type_name(),
std::any::type_name::<A>()
)
}))
.into()
},
set: |world, handle, value| {
let mut assets = world.resource_mut::<Assets<A>>();
let value: A = FromReflect::from_reflect(value)
.expect("could not call `FromReflect::from_reflect` in `ReflectAsset::set`");
assets.set(handle, value).into()
assets
.set(
handle,
value.take::<A>().unwrap_or_else(|value| {
panic!(
"ReflectAsset::set called with type `{}`, even though it was created for `{}`",
value.type_name(),
std::any::type_name::<A>()
)
}),
)
.into()
},
len: |world| {
let assets = world.resource::<Assets<A>>();
Expand All @@ -182,15 +188,15 @@ impl<A: Asset + FromReflect> FromType<A> for ReflectAsset {
remove: |world, handle| {
let mut assets = world.resource_mut::<Assets<A>>();
let value = assets.remove(handle);
value.map(|value| Box::new(value) as Box<dyn PartialReflect>)
value.map(|value| Box::new(value) as Box<dyn Reflect>)
},
}
}
}

/// Reflect type data struct relating a [`Handle<T>`] back to the `T` asset type.
///
/// Say you want to look up the asset values of a list of handles when you have access to their `&dyn PartialReflect` form.
/// Say you want to look up the asset values of a list of handles when you have access to their `&dyn Reflect` form.
/// Assets can be looked up in the world using [`ReflectAsset`], but how do you determine which [`ReflectAsset`] to use when
/// only looking at the handle? [`ReflectHandle`] is stored in the type registry on each `Handle<T>` type, so you can use [`ReflectHandle::asset_type_id`] to look up
/// the [`ReflectAsset`] type data on the corresponding `T` asset type:
Expand All @@ -203,7 +209,7 @@ impl<A: Asset + FromReflect> FromType<A> for ReflectAsset {
///
/// # let world: &World = unimplemented!();
/// # let type_registry: TypeRegistry = unimplemented!();
/// let handles: Vec<&dyn PartialReflect> = unimplemented!();
/// let handles: Vec<&dyn Reflect> = unimplemented!();
/// for handle in handles {
/// let reflect_handle = type_registry.get_type_data::<ReflectHandle>(handle.type_id()).unwrap();
/// let reflect_asset = type_registry.get_type_data::<ReflectAsset>(reflect_handle.asset_type_id()).unwrap();
Expand All @@ -218,7 +224,7 @@ pub struct ReflectHandle {
type_uuid: Uuid,
asset_type_id: TypeId,
downcast_handle_untyped: fn(&dyn Any) -> Option<HandleUntyped>,
typed: fn(HandleUntyped) -> Box<dyn PartialReflect>,
typed: fn(HandleUntyped) -> Box<dyn Reflect>,
}
impl ReflectHandle {
/// The [`bevy_reflect::TypeUuid`] of the asset
Expand All @@ -235,9 +241,9 @@ impl ReflectHandle {
(self.downcast_handle_untyped)(handle)
}

/// A way to go from a [`HandleUntyped`] to a [`Handle<T>`] in a `Box<dyn PartialReflect>`.
/// A way to go from a [`HandleUntyped`] to a [`Handle<T>`] in a `Box<dyn Reflect>`.
/// Equivalent of [`HandleUntyped::typed`].
pub fn typed(&self, handle: HandleUntyped) -> Box<dyn PartialReflect> {
pub fn typed(&self, handle: HandleUntyped) -> Box<dyn Reflect> {
(self.typed)(handle)
}
}
Expand Down Expand Up @@ -293,7 +299,7 @@ mod tests {
field: "test".into(),
};

let handle = reflect_asset.add(&mut app.world, &value);
let handle = reflect_asset.add(&mut app.world, Box::new(value));
let strukt = match reflect_asset
.get_mut(&mut app.world, handle)
.unwrap()
Expand All @@ -315,10 +321,7 @@ mod tests {
let asset = reflect_asset
.get(&app.world, fetched_handle.clone_weak())
.unwrap();
assert_eq!(
asset.try_downcast_ref::<AssetType>().unwrap().field,
"edited"
);
assert_eq!(asset.downcast_ref::<AssetType>().unwrap().field, "edited");

reflect_asset
.remove(&mut app.world, fetched_handle)
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_core_pipeline/src/bloom/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use bevy_ecs::{
world::{FromWorld, World},
};
use bevy_math::{UVec2, UVec4, Vec4};
use bevy_reflect::{PartialReflect, Reflect, TypeUuid};
use bevy_reflect::{Reflect, TypeUuid};
use bevy_render::{
camera::ExtractedCamera,
extract_component::{
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_pbr/src/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
};
use bevy_asset::Handle;
use bevy_ecs::{bundle::Bundle, component::Component, prelude::Entity, reflect::ReflectComponent};
use bevy_reflect::{PartialReflect, Reflect};
use bevy_reflect::Reflect;
use bevy_render::{
mesh::Mesh,
primitives::{CascadesFrusta, CubemapFrusta, Frustum},
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_reflect/src/serde/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> {
// Handle both Value case and types that have a custom `ReflectDeserialize`
if let Some(deserialize_reflect) = self.registration.data::<ReflectDeserialize>() {
let value = deserialize_reflect.deserialize(deserializer)?;
return Ok(value);
return Ok(value.into_partial());
}

match self.registration.type_info() {
Expand Down
10 changes: 8 additions & 2 deletions crates/bevy_reflect/src/serde/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,21 @@ fn get_serializable<'a, E: serde::ser::Error>(
reflect_value: &'a dyn PartialReflect,
type_registry: &TypeRegistry,
) -> Result<Serializable<'a>, E> {
let full_reflect = reflect_value.as_full().ok_or_else(|| {
serde::ser::Error::custom(format_args!(
"Type '{}' does not implement Reflect",
reflect_value.type_name(),
))
})?;
let reflect_serialize = type_registry
.get_type_data::<ReflectSerialize>(reflect_value.type_id())
.get_type_data::<ReflectSerialize>(full_reflect.type_id())
.ok_or_else(|| {
serde::ser::Error::custom(format_args!(
"Type '{}' did not register ReflectSerialize",
reflect_value.type_name()
))
})?;
Ok(reflect_serialize.get_serializable(reflect_value))
Ok(reflect_serialize.get_serializable(full_reflect))
}

/// Get the underlying [`TypeInfo`] of a given type.
Expand Down
Loading

0 comments on commit 9f10455

Please sign in to comment.