diff --git a/crates/bevy_reflect/src/list.rs b/crates/bevy_reflect/src/list.rs index da7cf72ac1920..d9572cd1b42db 100644 --- a/crates/bevy_reflect/src/list.rs +++ b/crates/bevy_reflect/src/list.rs @@ -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); + + /// 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(&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) { 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(a: &mut L, b: &dyn Reflect) { if let ReflectRef::List(list_value) = b.reflect_ref() { @@ -175,6 +208,12 @@ pub fn list_apply(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(a: &L, b: &dyn Reflect) -> Option { let list = if let ReflectRef::List(list) = b.reflect_ref() { diff --git a/crates/bevy_reflect/src/map.rs b/crates/bevy_reflect/src/map.rs index ddb74d8e177c0..f2ad17d6671c1 100644 --- a/crates/bevy_reflect/src/map.rs +++ b/crates/bevy_reflect/src/map.rs @@ -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(&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, value: Box) { 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(a: &M, b: &dyn Reflect) -> Option { let map = if let ReflectRef::Map(map) = b.reflect_ref() { diff --git a/crates/bevy_reflect/src/path.rs b/crates/bevy_reflect/src/path.rs index 44b4450c0dd82..2b749d2efa080 100644 --- a/crates/bevy_reflect/src/path.rs +++ b/crates/bevy_reflect/src/path.rs @@ -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, diff --git a/crates/bevy_reflect/src/reflect.rs b/crates/bevy_reflect/src/reflect.rs index ae9dbb168d89a..4362068df918e 100644 --- a/crates/bevy_reflect/src/reflect.rs +++ b/crates/bevy_reflect/src/reflect.rs @@ -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) -> Result<(), Box>; + + /// 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; - /// 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; - /// 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; - /// 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; } +/// 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`) 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; } @@ -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(self: Box) -> Result, Box> { // 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(self: Box) -> Result> { self.downcast::().map(|value| *value) } + /// Returns `true` if the underlying value is of type `T`, or `false` + /// otherwise. #[inline] pub fn is(&self) -> bool { self.any().is::() } + /// Downcasts the value to type `T` by reference. + /// + /// If the underlying value is not of type `T`, returns `None`. #[inline] pub fn downcast_ref(&self) -> Option<&T> { self.any().downcast_ref::() } + /// 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(&mut self) -> Option<&mut T> { self.any_mut().downcast_mut::() diff --git a/crates/bevy_reflect/src/struct_trait.rs b/crates/bevy_reflect/src/struct_trait.rs index bbad3ea81d85f..40d3ed3d1995b 100644 --- a/crates/bevy_reflect/src/struct_trait.rs +++ b/crates/bevy_reflect/src/struct_trait.rs @@ -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(a: &S, b: &dyn Reflect) -> Option { let struct_value = if let ReflectRef::Struct(struct_value) = b.reflect_ref() { diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs index ba0d614de4e74..44423c3099cfb 100644 --- a/crates/bevy_reflect/src/tuple.rs +++ b/crates/bevy_reflect/src/tuple.rs @@ -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(a: &mut T, b: &dyn Reflect) { if let ReflectRef::Tuple(tuple) = b.reflect_ref() { @@ -272,6 +277,12 @@ pub fn tuple_apply(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(a: &T, b: &dyn Reflect) -> Option { let b = if let ReflectRef::Tuple(tuple) = b.reflect_ref() { diff --git a/crates/bevy_reflect/src/tuple_struct.rs b/crates/bevy_reflect/src/tuple_struct.rs index f16752ddadff1..dd053932cadbb 100644 --- a/crates/bevy_reflect/src/tuple_struct.rs +++ b/crates/bevy_reflect/src/tuple_struct.rs @@ -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(a: &S, b: &dyn Reflect) -> Option { let tuple_struct = if let ReflectRef::TupleStruct(tuple_struct) = b.reflect_ref() { diff --git a/crates/bevy_reflect/src/type_registry.rs b/crates/bevy_reflect/src/type_registry.rs index 48c7e95ea7a9f..d0ae8c412bc76 100644 --- a/crates/bevy_reflect/src/type_registry.rs +++ b/crates/bevy_reflect/src/type_registry.rs @@ -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, @@ -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>, @@ -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(&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(&self, type_id: TypeId) -> Option<&T> { self.get(type_id) .and_then(|registration| registration.data::()) } + /// Returns an iterator overed the [`TypeRegistration`]s of the registered + /// types. pub fn iter(&self) -> impl Iterator { 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(&self) -> Option<&T> { self.data .get(&TypeId::of::()) .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(&mut self) -> Option<&mut T> { self.data .get_mut(&TypeId::of::()) .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(&mut self, data: T) { self.data.insert(TypeId::of::(), Box::new(data)); } + /// Creates type registration information for `T`. pub fn of() -> Self { let ty = TypeId::of::(); let type_name = std::any::type_name::(); @@ -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>` + /// would be `Vec>`. 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; } @@ -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 { 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, D::Error> where D: serde::Deserializer<'de>, diff --git a/crates/bevy_reflect/src/type_uuid.rs b/crates/bevy_reflect/src/type_uuid.rs index ec71f13639ecc..545ab97bb594b 100644 --- a/crates/bevy_reflect/src/type_uuid.rs +++ b/crates/bevy_reflect/src/type_uuid.rs @@ -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 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::() }