document more of bevy_reflect (#3655)

This adds documentation for:

- The trait methods of `Reflect` and its subtraits
- The `partial_eq` and `apply` functions for `Map` et al.
- `DynamicList` and `DynamicMap`
- `TypeRegistry` and related types & traits
- `GetPath`, including an explanation of path string syntax

among other things.

Still to be documented are the various macros and `bevy_reflect::serde`.
This commit is contained in:
dataphract 2022-01-14 19:09:44 +00:00
parent 3e8e6c5671
commit f073b2d7f3
9 changed files with 363 additions and 18 deletions

View file

@ -4,14 +4,27 @@ use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef};
/// An ordered, mutable list of [Reflect] items. This corresponds to types like [`std::vec::Vec`].
pub trait List: Reflect {
/// Returns a reference to the element at `index`, or `None` if out of bounds.
fn get(&self, index: usize) -> Option<&dyn Reflect>;
/// Returns a mutable reference to the element at `index`, or `None` if out of bounds.
fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>;
/// Appends an element to the list.
fn push(&mut self, value: Box<dyn Reflect>);
/// Returns the number of elements in the list.
fn len(&self) -> usize;
/// Returns `true` if the list contains no elements.
fn is_empty(&self) -> bool {
self.len() == 0
}
/// Returns an iterator over the list.
fn iter(&self) -> ListIter;
/// Clones the list, producing a [`DynamicList`].
fn clone_dynamic(&self) -> DynamicList {
DynamicList {
name: self.type_name().to_string(),
@ -20,6 +33,7 @@ pub trait List: Reflect {
}
}
/// A list of reflected values.
#[derive(Default)]
pub struct DynamicList {
name: String,
@ -27,18 +41,28 @@ pub struct DynamicList {
}
impl DynamicList {
/// Returns the type name of the list.
///
/// The value returned by this method is the same value returned by
/// [`Reflect::type_name`].
pub fn name(&self) -> &str {
&self.name
}
/// Sets the type name of the list.
///
/// The value set by this method is the value returned by
/// [`Reflect::type_name`].
pub fn set_name(&mut self, name: String) {
self.name = name;
}
/// Appends a typed value to the list.
pub fn push<T: Reflect>(&mut self, value: T) {
self.values.push(Box::new(value));
}
/// Appends a [`Reflect`] trait object to the list.
pub fn push_box(&mut self, value: Box<dyn Reflect>) {
self.values.push(value);
}
@ -136,6 +160,7 @@ unsafe impl Reflect for DynamicList {
}
}
/// An iterator over the elements of a [`List`].
pub struct ListIter<'a> {
pub(crate) list: &'a dyn List,
pub(crate) index: usize,
@ -158,6 +183,14 @@ impl<'a> Iterator for ListIter<'a> {
impl<'a> ExactSizeIterator for ListIter<'a> {}
/// Applies the elements of `b` to the corresponding elements of `a`.
///
/// If the length of `b` is greater than that of `a`, the excess elements of `b`
/// are cloned and appended to `a`.
///
/// # Panics
///
/// This function panics if `b` is not a list.
#[inline]
pub fn list_apply<L: List>(a: &mut L, b: &dyn Reflect) {
if let ReflectRef::List(list_value) = b.reflect_ref() {
@ -175,6 +208,12 @@ pub fn list_apply<L: List>(a: &mut L, b: &dyn Reflect) {
}
}
/// Compares a [`List`] with a [`Reflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is a list;
/// - `b` is the same length as `a`;
/// - [`Reflect::reflect_partial_eq`] returns `Some(true)` for pairwise elements of `a` and `b`.
#[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() {

View file

@ -4,23 +4,48 @@ 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`].
/// An ordered mapping between [`Reflect`] values.
///
/// Because the values are reflected, the underlying types of keys and values
/// may differ between entries.
///
///`ReflectValue` `Keys` are assumed to return a non-`None` hash. The ordering
/// of `Map` entries is not guaranteed to be stable across runs or between
/// instances.
///
/// This trait corresponds to types like [`std::collections::HashMap`].
pub trait Map: Reflect {
/// Returns a reference to the value associated with the given key.
///
/// If no value is associated with `key`, returns `None`.
fn get(&self, key: &dyn Reflect) -> Option<&dyn Reflect>;
/// Returns a mutable reference to the value associated with the given key.
///
/// If no value is associated with `key`, returns `None`.
fn get_mut(&mut self, key: &dyn Reflect) -> Option<&mut dyn Reflect>;
/// Returns the key-value pair at `index` by reference, or `None` if out of bounds.
fn get_at(&self, index: usize) -> Option<(&dyn Reflect, &dyn Reflect)>;
/// Returns the number of elements in the map.
fn len(&self) -> usize;
/// Returns `true` if the list contains no elements.
fn is_empty(&self) -> bool {
self.len() == 0
}
/// Returns an iterator over the key-value pairs of the map.
fn iter(&self) -> MapIter;
/// Clones the map, producing a [`DynamicMap`].
fn clone_dynamic(&self) -> DynamicMap;
}
const HASH_ERROR: &str = "the given key does not support hashing";
/// An ordered mapping between reflected values.
#[derive(Default)]
pub struct DynamicMap {
name: String,
@ -29,18 +54,28 @@ pub struct DynamicMap {
}
impl DynamicMap {
/// Returns the type name of the map.
///
/// The value returned by this method is the same value returned by
/// [`Reflect::type_name`].
pub fn name(&self) -> &str {
&self.name
}
/// Sets the type name of the map.
///
/// The value set by this method is the same value returned by
/// [`Reflect::type_name`].
pub fn set_name(&mut self, name: String) {
self.name = name;
}
/// Inserts a typed key-value pair into the map.
pub fn insert<K: Reflect, V: Reflect>(&mut self, key: K, value: V) {
self.insert_boxed(Box::new(key), Box::new(value));
}
/// Inserts a key-value pair of [`Reflect`] values into the map.
pub fn insert_boxed(&mut self, key: Box<dyn Reflect>, value: Box<dyn Reflect>) {
match self.indices.entry(key.reflect_hash().expect(HASH_ERROR)) {
Entry::Occupied(entry) => {
@ -154,6 +189,7 @@ unsafe impl Reflect for DynamicMap {
}
}
/// An iterator over the key-value pairs of a [`Map`].
pub struct MapIter<'a> {
pub(crate) map: &'a dyn Map,
pub(crate) index: usize,
@ -176,6 +212,13 @@ impl<'a> Iterator for MapIter<'a> {
impl<'a> ExactSizeIterator for MapIter<'a> {}
/// Compares a [`Map`] with a [`Reflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is a map;
/// - `b` is the same length as `a`;
/// - For each key-value pair in `a`, `b` contains a value for the given key,
/// and [`Reflect::reflect_partial_eq`] returns `Some(true)` for the two values.
#[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() {

View file

@ -3,6 +3,7 @@ use std::num::ParseIntError;
use crate::{Reflect, ReflectMut, ReflectRef};
use thiserror::Error;
/// An error returned from a failed path string query.
#[derive(Debug, PartialEq, Eq, Error)]
pub enum ReflectPathError<'a> {
#[error("expected an identifier at the given index")]
@ -30,13 +31,41 @@ pub enum ReflectPathError<'a> {
InvalidDowncast,
}
/// A trait which allows nested values to be retrieved with path strings.
///
/// Path strings use Rust syntax:
/// - [`Struct`] items are accessed with a dot and a field name: `.field_name`
/// - [`TupleStruct`] and [`Tuple`] items are accessed with a dot and a number: `.0`
/// - [`List`] items are accessed with brackets: `[0]`
///
/// If the initial path element is a field of a struct, tuple struct, or tuple,
/// the initial '.' may be omitted.
///
/// For example, given a struct with a field `foo` which is a reflected list of
/// 2-tuples (like a `Vec<(T, U)>`), the path string `foo[3].0` would access tuple
/// element 0 of element 3 of `foo`.
///
/// [`Struct`]: crate::Struct
/// [`TupleStruct`]: crate::TupleStruct
/// [`Tuple`]: crate::Tuple
/// [`List`]: crate::List
pub trait GetPath {
/// Returns a reference to the value specified by `path`.
///
/// To retrieve a statically typed reference, use
/// [`get_path`][GetPath::get_path].
fn path<'r, 'p>(&'r self, path: &'p str) -> Result<&'r dyn Reflect, ReflectPathError<'p>>;
/// Returns a mutable reference to the value specified by `path`.
///
/// To retrieve a statically typed mutable reference, use
/// [`get_path_mut`][GetPath::get_path_mut].
fn path_mut<'r, 'p>(
&'r mut self,
path: &'p str,
) -> Result<&'r mut dyn Reflect, ReflectPathError<'p>>;
/// Returns a statically typed reference to the value specified by `path`.
fn get_path<'r, 'p, T: Reflect>(
&'r self,
path: &'p str,
@ -47,6 +76,8 @@ pub trait GetPath {
})
}
/// Returns a statically typed mutable reference to the value specified by
/// `path`.
fn get_path_mut<'r, 'p, T: Reflect>(
&'r mut self,
path: &'p str,

View file

@ -3,6 +3,12 @@ use std::{any::Any, fmt::Debug};
pub use bevy_utils::AHasher as ReflectHasher;
/// An immutable enumeration of "kinds" of reflected type.
///
/// Each variant contains a trait object with methods specific to a kind of
/// type.
///
/// A `ReflectRef` is obtained via [`Reflect::reflect_ref`].
pub enum ReflectRef<'a> {
Struct(&'a dyn Struct),
TupleStruct(&'a dyn TupleStruct),
@ -12,6 +18,12 @@ pub enum ReflectRef<'a> {
Value(&'a dyn Reflect),
}
/// A mutable enumeration of "kinds" of reflected type.
///
/// Each variant contains a trait object with methods specific to a kind of
/// type.
///
/// A `ReflectMut` is obtained via [`Reflect::reflect_mut`].
pub enum ReflectMut<'a> {
Struct(&'a mut dyn Struct),
TupleStruct(&'a mut dyn TupleStruct),
@ -34,27 +46,107 @@ pub enum ReflectMut<'a> {
/// value passed in. If this is not done, [`Reflect::downcast`](trait.Reflect.html#method.downcast)
/// will be UB (and also just logically broken).
pub unsafe trait Reflect: Any + Send + Sync {
/// Returns the [type name] of the underlying type.
///
/// [type name]: std::any::type_name
fn type_name(&self) -> &str;
/// Returns the value as a [`&dyn Any`][std::any::Any].
fn any(&self) -> &dyn Any;
/// Returns the value as a [`&mut dyn Any`][std::any::Any].
fn any_mut(&mut self) -> &mut dyn Any;
/// Applies a reflected value to this value.
///
/// If a type implements a subtrait of `Reflect`, then the semantics of this
/// method are as follows:
/// - If `T` is a [`Struct`], then the value of each named field of `value` is
/// applied to the corresponding named field of `self`. Fields which are
/// not present in both structs are ignored.
/// - If `T` is a [`TupleStruct`] or [`Tuple`], then the value of each
/// numbered field is applied to the corresponding numbered field of
/// `self.` Fields which are not present in both values are ignored.
/// - If `T` is a [`List`], then each element of `value` is applied to the
/// corresponding element of `self`. Up to `self.len()` items are applied,
/// and excess elements in `value` are appended to `self`.
/// - If `T` is a [`Map`], then for each key in `value`, the associated
/// value is applied to the value associated with the same key in `self`.
/// Keys which are not present in both maps are ignored.
/// - If `T` is none of these, then `value` is downcast to `T`, cloned, and
/// assigned to `self`.
///
/// Note that `Reflect` must be implemented manually for [`List`]s and
/// [`Map`]s in order to achieve the correct semantics, as derived
/// implementations will have the semantics for [`Struct`], [`TupleStruct`]
/// or none of the above depending on the kind of type. For lists, use the
/// [`list_apply`] helper function when implementing this method.
///
/// [`list_apply`]: crate::list_apply
///
/// # Panics
///
/// Derived implementations of this method will panic:
/// - If the type of `value` is not of the same kind as `T` (e.g. if `T` is
/// a `List`, while `value` is a `Struct`).
/// - If `T` is any complex type and the corresponding fields or elements of
/// `self` and `value` are not of the same type.
/// - If `T` is a value type and `self` cannot be downcast to `T`
fn apply(&mut self, value: &dyn Reflect);
/// Performs a type-checked assignment of a reflected value to this value.
///
/// If `value` does not contain a value of type `T`, returns an `Err`
/// containing the trait object.
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>>;
/// Returns an enumeration of "kinds" of type.
///
/// See [`ReflectRef`].
fn reflect_ref(&self) -> ReflectRef;
/// Returns a mutable enumeration of "kinds" of type.
///
/// See [`ReflectMut`].
fn reflect_mut(&mut self) -> ReflectMut;
/// Clones the value as a `Reflect` trait object.
///
/// When deriving `Reflect` for a struct or struct tuple, the value is
/// cloned via [`Struct::clone_dynamic`] (resp.
/// [`TupleStruct::clone_dynamic`]). Implementors of other `Reflect`
/// subtraits (e.g. [`List`], [`Map`]) should use those subtraits'
/// respective `clone_dynamic` methods.
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.
/// Returns a hash of the value (which includes the type).
///
/// If the underlying type does not support hashing, returns `None`.
fn reflect_hash(&self) -> Option<u64>;
/// Returns a "partial equal" comparison result if comparison is supported. Otherwise `None`
/// will be returned.
/// Returns a "partial equality" comparison result.
///
/// If the underlying type does not support equality testing, returns `None`.
fn reflect_partial_eq(&self, _value: &dyn Reflect) -> Option<bool>;
/// Returns a serializable value, if serialization is supported. Otherwise `None` will be
/// returned.
/// Returns a serializable version of the value.
///
/// If the underlying type does not support serialization, returns `None`.
fn serializable(&self) -> Option<Serializable>;
}
/// A trait for types which can be constructed from a reflected type.
///
/// This trait can be derived on types which implement [`Reflect`]. Some complex
/// types (such as `Vec<T>`) may only be reflected if their element types
/// implement this trait.
///
/// For structs and tuple structs, fields marked with the `#[reflect(ignore)]`
/// attribute will be constructed using the `Default` implementation of the
/// field type, rather than the corresponding field value (if any) of the
/// reflected value.
pub trait FromReflect: Reflect + Sized {
/// Creates a clone of a reflected value, converting it to a concrete type if it was a dynamic types (e.g. [`DynamicStruct`](crate::DynamicStruct))
/// Constructs a concrete instance of `Self` from a reflected value.
fn from_reflect(reflect: &dyn Reflect) -> Option<Self>;
}
@ -65,6 +157,9 @@ impl Debug for dyn Reflect {
}
impl dyn Reflect {
/// Downcasts the value to type `T`, consuming the trait object.
///
/// If the underlying value is not of type `T`, returns `Err(self)`.
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.
@ -78,20 +173,31 @@ impl dyn Reflect {
}
}
/// Downcasts the value to type `T`, unboxing and consuming the trait object.
///
/// If the underlying value is not of type `T`, returns `Err(self)`.
pub fn take<T: Reflect>(self: Box<dyn Reflect>) -> Result<T, Box<dyn Reflect>> {
self.downcast::<T>().map(|value| *value)
}
/// Returns `true` if the underlying value is of type `T`, or `false`
/// otherwise.
#[inline]
pub fn is<T: Reflect>(&self) -> bool {
self.any().is::<T>()
}
/// Downcasts the value to type `T` by reference.
///
/// If the underlying value is not of type `T`, returns `None`.
#[inline]
pub fn downcast_ref<T: Reflect>(&self) -> Option<&T> {
self.any().downcast_ref::<T>()
}
/// Downcasts the value to type `T` by mutable reference.
///
/// If the underlying value is not of type `T`, returns `None`.
#[inline]
pub fn downcast_mut<T: Reflect>(&mut self) -> Option<&mut T> {
self.any_mut().downcast_mut::<T>()

View file

@ -154,12 +154,12 @@ pub struct DynamicStruct {
}
impl DynamicStruct {
/// Returns the name of the struct.
/// Returns the type name of the struct.
pub fn name(&self) -> &str {
&self.name
}
/// Sets the name of the struct.
/// Sets the type name of the struct.
pub fn set_name(&mut self, name: String) {
self.name = name;
}
@ -315,6 +315,13 @@ unsafe impl Reflect for DynamicStruct {
}
}
/// Compares a [`Struct`] with a [`Reflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is a struct;
/// - For each field in `a`, `b` contains a field with the same name and
/// [`Reflect::reflect_partial_eq`] returns `Some(true)` for the two field
/// values.
#[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() {

View file

@ -128,14 +128,14 @@ pub struct DynamicTuple {
}
impl DynamicTuple {
/// Returns the name of the tuple.
/// Returns the type name of the tuple.
///
/// The tuple's name is automatically generated from its element types.
pub fn name(&self) -> &str {
&self.name
}
/// Manually sets the name of the tuple.
/// Manually sets the type name of the tuple.
///
/// Note that the tuple name will be overwritten when elements are added.
pub fn set_name(&mut self, name: String) {
@ -259,6 +259,11 @@ unsafe impl Reflect for DynamicTuple {
}
}
/// Applies the elements of `b` to the corresponding elements of `a`.
///
/// # Panics
///
/// This function panics if `b` is not a tuple.
#[inline]
pub fn tuple_apply<T: Tuple>(a: &mut T, b: &dyn Reflect) {
if let ReflectRef::Tuple(tuple) = b.reflect_ref() {
@ -272,6 +277,12 @@ pub fn tuple_apply<T: Tuple>(a: &mut T, b: &dyn Reflect) {
}
}
/// Compares a [`Tuple`] with a [`Reflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is a tuple;
/// - `b` has the same number of elements as `a`;
/// - [`Reflect::reflect_partial_eq`] returns `Some(true)` for pairwise elements of `a` and `b`.
#[inline]
pub fn tuple_partial_eq<T: Tuple>(a: &T, b: &dyn Reflect) -> Option<bool> {
let b = if let ReflectRef::Tuple(tuple) = b.reflect_ref() {

View file

@ -135,12 +135,12 @@ pub struct DynamicTupleStruct {
}
impl DynamicTupleStruct {
/// Returns the name of the tuple struct.
/// Returns the type name of the tuple struct.
pub fn name(&self) -> &str {
&self.name
}
/// Sets the name of the tuple struct.
/// Sets the type name of the tuple struct.
pub fn set_name(&mut self, name: String) {
self.name = name;
}
@ -254,6 +254,12 @@ unsafe impl Reflect for DynamicTupleStruct {
}
}
/// Compares a [`TupleStruct`] with a [`Reflect`] value.
///
/// Returns true if and only if all of the following are true:
/// - `b` is a tuple struct;
/// - `b` has the same number of fields as `a`;
/// - [`Reflect::reflect_partial_eq`] returns `Some(true)` for pairwise fields of `a` and `b`.
#[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() {

View file

@ -5,6 +5,7 @@ use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use serde::Deserialize;
use std::{any::TypeId, fmt::Debug, sync::Arc};
/// A registry of reflected types.
#[derive(Default)]
pub struct TypeRegistry {
registrations: HashMap<TypeId, TypeRegistration>,
@ -15,6 +16,7 @@ pub struct TypeRegistry {
// TODO: remove this wrapper once we migrate to Atelier Assets and the Scene AssetLoader doesn't
// need a TypeRegistry ref
/// A synchronized wrapper around a [`TypeRegistry`].
#[derive(Clone, Default)]
pub struct TypeRegistryArc {
pub internal: Arc<RwLock<TypeRegistry>>,
@ -26,11 +28,15 @@ impl Debug for TypeRegistryArc {
}
}
/// A trait which allows a type to generate its [`TypeRegistration`].
///
/// This trait is automatically implemented for types which derive [`Reflect`].
pub trait GetTypeRegistration {
fn get_type_registration() -> TypeRegistration;
}
impl TypeRegistry {
/// Registers the type `T`.
pub fn register<T>(&mut self)
where
T: GetTypeRegistration,
@ -38,6 +44,7 @@ impl TypeRegistry {
self.add_registration(T::get_type_registration());
}
/// Registers the type described by `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)
@ -56,20 +63,40 @@ impl TypeRegistry {
.insert(registration.type_id, registration);
}
/// Returns a reference to the [`TypeRegistration`] of the type with the
/// given [`TypeId`].
///
/// If the specified type has not been registered, returns `None`.
///
/// [`TypeId`]: std::any::TypeId
pub fn get(&self, type_id: TypeId) -> Option<&TypeRegistration> {
self.registrations.get(&type_id)
}
/// Returns a mutable reference to the [`TypeRegistration`] of the type with
/// the given [`TypeId`].
///
/// If the specified type has not been registered, returns `None`.
///
/// [`TypeId`]: std::any::TypeId
pub fn get_mut(&mut self, type_id: TypeId) -> Option<&mut TypeRegistration> {
self.registrations.get_mut(&type_id)
}
/// Returns a reference to the [`TypeRegistration`] of the type with the
/// given name.
///
/// If no type with the given name has been registered, returns `None`.
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))
}
/// Returns a mutable reference to the [`TypeRegistration`] of the type with
/// the given name.
///
/// If no type with the given name has been registered, returns `None`.
pub fn get_with_name_mut(&mut self, type_name: &str) -> Option<&mut TypeRegistration> {
self.full_name_to_id
.get(type_name)
@ -77,32 +104,64 @@ impl TypeRegistry {
.and_then(move |id| self.get_mut(id))
}
/// Returns a mutable reference to the [`TypeRegistration`] of the type with
/// the given short name.
///
/// If the short name is ambiguous, or if no type with the given short name
/// has been registered, returns `None`.
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))
}
/// Returns the [`TypeData`] of type `T` associated with the given `TypeId`.
///
/// The returned value may be used to downcast [`Reflect`] trait objects to
/// trait objects of the trait used to generate `T`, provided that the
/// underlying reflected type has the proper `#[reflect(DoThing)]`
/// attribute.
///
/// If the specified type has not been registered, or if `T` is not present
/// in its type registration, returns `None`.
pub fn get_type_data<T: TypeData>(&self, type_id: TypeId) -> Option<&T> {
self.get(type_id)
.and_then(|registration| registration.data::<T>())
}
/// Returns an iterator overed the [`TypeRegistration`]s of the registered
/// types.
pub fn iter(&self) -> impl Iterator<Item = &TypeRegistration> {
self.registrations.values()
}
}
impl TypeRegistryArc {
/// Takes a read lock on the underlying [`TypeRegistry`].
pub fn read(&self) -> RwLockReadGuard<'_, TypeRegistry> {
self.internal.read()
}
/// Takes a write lock on the underlying [`TypeRegistry`].
pub fn write(&self) -> RwLockWriteGuard<'_, TypeRegistry> {
self.internal.write()
}
}
/// A record of data about a type.
///
/// This contains the [`TypeId`], [name], and [short name] of the type.
///
/// For each trait specified by the [`#[reflect(_)]`][0] attribute of
/// [`#[derive(Reflect)]`][1] on the registered type, this record also contains
/// a [`TypeData`] which can be used to downcast [`Reflect`] trait objects of
/// this type to trait objects of the relevant trait.
///
/// [`TypeId`]: std::any::TypeId
/// [name]: std::any::type_name
/// [short name]: TypeRegistration::get_short_name
/// [0]: crate::Reflect
/// [1]: crate::Reflect
pub struct TypeRegistration {
type_id: TypeId,
short_name: String,
@ -111,27 +170,42 @@ pub struct TypeRegistration {
}
impl TypeRegistration {
/// Returns the [`TypeId`] of the type.
///
/// [`TypeId`]: std::any::TypeId
#[inline]
pub fn type_id(&self) -> TypeId {
self.type_id
}
/// Returns a reference to the value of type `T` in this registration's type
/// data.
///
/// Returns `None` if no such value exists.
pub fn data<T: TypeData>(&self) -> Option<&T> {
self.data
.get(&TypeId::of::<T>())
.and_then(|value| value.downcast_ref())
}
/// Returns a mutable reference to the value of type `T` in this
/// registration's type data.
///
/// Returns `None` if no such value exists.
pub fn data_mut<T: TypeData>(&mut self) -> Option<&mut T> {
self.data
.get_mut(&TypeId::of::<T>())
.and_then(|value| value.downcast_mut())
}
/// Inserts an instance of `T` into this registration's type data.
///
/// If another instance of `T` was previously inserted, it is replaced.
pub fn insert<T: TypeData>(&mut self, data: T) {
self.data.insert(TypeId::of::<T>(), Box::new(data));
}
/// Creates type registration information for `T`.
pub fn of<T: Reflect>() -> Self {
let ty = TypeId::of::<T>();
let type_name = std::any::type_name::<T>();
@ -143,14 +217,24 @@ impl TypeRegistration {
}
}
/// Returns the [short name] of the type.
///
/// [short name]: TypeRegistration::get_short_name
pub fn short_name(&self) -> &str {
&self.short_name
}
/// Returns the name of the type.
pub fn name(&self) -> &'static str {
self.name
}
/// Calculates the short name of a type.
///
/// The short name of a type is its full name as returned by
/// [`std::any::type_name`], but with the prefix of all paths removed. For
/// example, the short name of `alloc::vec::Vec<core::option::Option<u32>>`
/// would be `Vec<Option<u32>>`.
pub fn get_short_name(full_name: &str) -> String {
let mut short_name = String::new();
@ -205,6 +289,9 @@ impl Clone for TypeRegistration {
}
}
/// A trait for types generated by the [`#[reflect_trait]`][0] attribute macro.
///
/// [0]: crate::reflect_trait
pub trait TypeData: Downcast + Send + Sync {
fn clone_type_data(&self) -> Box<dyn TypeData>;
}
@ -221,12 +308,16 @@ where
/// Trait used to generate [`TypeData`] for trait reflection.
///
/// This is used by the `#[derive(Reflect)]` macro to generate an implementation of [`TypeData`]
/// to pass to [`TypeRegistration::insert`].
/// This is used by the `#[derive(Reflect)]` macro to generate an implementation
/// of [`TypeData`] to pass to [`TypeRegistration::insert`].
pub trait FromType<T> {
fn from_type() -> Self;
}
/// A struct used to deserialize reflected instances of a type.
///
/// A `ReflectDeserialize` for type `T` can be obtained via
/// [`FromType::from_type`].
#[derive(Clone)]
pub struct ReflectDeserialize {
#[allow(clippy::type_complexity)]
@ -236,6 +327,11 @@ pub struct ReflectDeserialize {
}
impl ReflectDeserialize {
/// Deserializes a reflected value.
///
/// The underlying type of the reflected value, and thus the expected
/// structure of the serialized data, is determined by the type used to
/// construct this `ReflectDeserialize` value.
pub fn deserialize<'de, D>(&self, deserializer: D) -> Result<Box<dyn Reflect>, D::Error>
where
D: serde::Deserializer<'de>,

View file

@ -1,10 +1,12 @@
pub use bevy_reflect_derive::TypeUuid;
pub use bevy_utils::Uuid;
/// A trait for types with a statically associated UUID.
pub trait TypeUuid {
const TYPE_UUID: Uuid;
}
/// A trait for types with an associated UUID.
pub trait TypeUuidDynamic {
fn type_uuid(&self) -> Uuid;
fn type_name(&self) -> &'static str;
@ -14,10 +16,14 @@ impl<T> TypeUuidDynamic for T
where
T: TypeUuid,
{
/// Returns the UUID associated with this value's type.
fn type_uuid(&self) -> Uuid {
Self::TYPE_UUID
}
/// Returns the [type name] of this value's type.
///
/// [type name]: std::any::type_name
fn type_name(&self) -> &'static str {
std::any::type_name::<Self>()
}