mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 20:53:53 +00:00
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:
parent
3e8e6c5671
commit
f073b2d7f3
9 changed files with 363 additions and 18 deletions
|
@ -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() {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>()
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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>()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue