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
@ -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`].
|
/// An ordered, mutable list of [Reflect] items. This corresponds to types like [`std::vec::Vec`].
|
||||||
pub trait List: Reflect {
|
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>;
|
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>;
|
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>);
|
fn push(&mut self, value: Box<dyn Reflect>);
|
||||||
|
|
||||||
|
/// Returns the number of elements in the list.
|
||||||
fn len(&self) -> usize;
|
fn len(&self) -> usize;
|
||||||
|
|
||||||
|
/// Returns `true` if the list contains no elements.
|
||||||
fn is_empty(&self) -> bool {
|
fn is_empty(&self) -> bool {
|
||||||
self.len() == 0
|
self.len() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over the list.
|
||||||
fn iter(&self) -> ListIter;
|
fn iter(&self) -> ListIter;
|
||||||
|
|
||||||
|
/// Clones the list, producing a [`DynamicList`].
|
||||||
fn clone_dynamic(&self) -> DynamicList {
|
fn clone_dynamic(&self) -> DynamicList {
|
||||||
DynamicList {
|
DynamicList {
|
||||||
name: self.type_name().to_string(),
|
name: self.type_name().to_string(),
|
||||||
@ -20,6 +33,7 @@ pub trait List: Reflect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A list of reflected values.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct DynamicList {
|
pub struct DynamicList {
|
||||||
name: String,
|
name: String,
|
||||||
@ -27,18 +41,28 @@ pub struct DynamicList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
pub fn name(&self) -> &str {
|
||||||
&self.name
|
&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) {
|
pub fn set_name(&mut self, name: String) {
|
||||||
self.name = name;
|
self.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Appends a typed value to the list.
|
||||||
pub fn push<T: Reflect>(&mut self, value: T) {
|
pub fn push<T: Reflect>(&mut self, value: T) {
|
||||||
self.values.push(Box::new(value));
|
self.values.push(Box::new(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Appends a [`Reflect`] trait object to the list.
|
||||||
pub fn push_box(&mut self, value: Box<dyn Reflect>) {
|
pub fn push_box(&mut self, value: Box<dyn Reflect>) {
|
||||||
self.values.push(value);
|
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 struct ListIter<'a> {
|
||||||
pub(crate) list: &'a dyn List,
|
pub(crate) list: &'a dyn List,
|
||||||
pub(crate) index: usize,
|
pub(crate) index: usize,
|
||||||
@ -158,6 +183,14 @@ impl<'a> Iterator for ListIter<'a> {
|
|||||||
|
|
||||||
impl<'a> ExactSizeIterator 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]
|
#[inline]
|
||||||
pub fn list_apply<L: List>(a: &mut L, b: &dyn Reflect) {
|
pub fn list_apply<L: List>(a: &mut L, b: &dyn Reflect) {
|
||||||
if let ReflectRef::List(list_value) = b.reflect_ref() {
|
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]
|
#[inline]
|
||||||
pub fn list_partial_eq<L: List>(a: &L, b: &dyn Reflect) -> Option<bool> {
|
pub fn list_partial_eq<L: List>(a: &L, b: &dyn Reflect) -> Option<bool> {
|
||||||
let list = if let ReflectRef::List(list) = b.reflect_ref() {
|
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};
|
use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef};
|
||||||
|
|
||||||
/// An ordered `ReflectValue->ReflectValue` mapping. `ReflectValue` `Keys` are assumed to return a
|
/// An ordered mapping between [`Reflect`] values.
|
||||||
/// non-`None` hash. Ideally the ordering is stable across runs, but this is not required.
|
///
|
||||||
/// This corresponds to types like [`std::collections::HashMap`].
|
/// 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 {
|
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>;
|
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>;
|
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)>;
|
fn get_at(&self, index: usize) -> Option<(&dyn Reflect, &dyn Reflect)>;
|
||||||
|
|
||||||
|
/// Returns the number of elements in the map.
|
||||||
fn len(&self) -> usize;
|
fn len(&self) -> usize;
|
||||||
|
|
||||||
|
/// Returns `true` if the list contains no elements.
|
||||||
fn is_empty(&self) -> bool {
|
fn is_empty(&self) -> bool {
|
||||||
self.len() == 0
|
self.len() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over the key-value pairs of the map.
|
||||||
fn iter(&self) -> MapIter;
|
fn iter(&self) -> MapIter;
|
||||||
|
|
||||||
|
/// Clones the map, producing a [`DynamicMap`].
|
||||||
fn clone_dynamic(&self) -> DynamicMap;
|
fn clone_dynamic(&self) -> DynamicMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
const HASH_ERROR: &str = "the given key does not support hashing";
|
const HASH_ERROR: &str = "the given key does not support hashing";
|
||||||
|
|
||||||
|
/// An ordered mapping between reflected values.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct DynamicMap {
|
pub struct DynamicMap {
|
||||||
name: String,
|
name: String,
|
||||||
@ -29,18 +54,28 @@ pub struct DynamicMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
pub fn name(&self) -> &str {
|
||||||
&self.name
|
&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) {
|
pub fn set_name(&mut self, name: String) {
|
||||||
self.name = name;
|
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) {
|
pub fn insert<K: Reflect, V: Reflect>(&mut self, key: K, value: V) {
|
||||||
self.insert_boxed(Box::new(key), Box::new(value));
|
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>) {
|
pub fn insert_boxed(&mut self, key: Box<dyn Reflect>, value: Box<dyn Reflect>) {
|
||||||
match self.indices.entry(key.reflect_hash().expect(HASH_ERROR)) {
|
match self.indices.entry(key.reflect_hash().expect(HASH_ERROR)) {
|
||||||
Entry::Occupied(entry) => {
|
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 struct MapIter<'a> {
|
||||||
pub(crate) map: &'a dyn Map,
|
pub(crate) map: &'a dyn Map,
|
||||||
pub(crate) index: usize,
|
pub(crate) index: usize,
|
||||||
@ -176,6 +212,13 @@ impl<'a> Iterator for MapIter<'a> {
|
|||||||
|
|
||||||
impl<'a> ExactSizeIterator 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]
|
#[inline]
|
||||||
pub fn map_partial_eq<M: Map>(a: &M, b: &dyn Reflect) -> Option<bool> {
|
pub fn map_partial_eq<M: Map>(a: &M, b: &dyn Reflect) -> Option<bool> {
|
||||||
let map = if let ReflectRef::Map(map) = b.reflect_ref() {
|
let map = if let ReflectRef::Map(map) = b.reflect_ref() {
|
||||||
|
|||||||
@ -3,6 +3,7 @@ use std::num::ParseIntError;
|
|||||||
use crate::{Reflect, ReflectMut, ReflectRef};
|
use crate::{Reflect, ReflectMut, ReflectRef};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// An error returned from a failed path string query.
|
||||||
#[derive(Debug, PartialEq, Eq, Error)]
|
#[derive(Debug, PartialEq, Eq, Error)]
|
||||||
pub enum ReflectPathError<'a> {
|
pub enum ReflectPathError<'a> {
|
||||||
#[error("expected an identifier at the given index")]
|
#[error("expected an identifier at the given index")]
|
||||||
@ -30,13 +31,41 @@ pub enum ReflectPathError<'a> {
|
|||||||
InvalidDowncast,
|
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 {
|
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>>;
|
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>(
|
fn path_mut<'r, 'p>(
|
||||||
&'r mut self,
|
&'r mut self,
|
||||||
path: &'p str,
|
path: &'p str,
|
||||||
) -> Result<&'r mut dyn Reflect, ReflectPathError<'p>>;
|
) -> 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>(
|
fn get_path<'r, 'p, T: Reflect>(
|
||||||
&'r self,
|
&'r self,
|
||||||
path: &'p str,
|
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>(
|
fn get_path_mut<'r, 'p, T: Reflect>(
|
||||||
&'r mut self,
|
&'r mut self,
|
||||||
path: &'p str,
|
path: &'p str,
|
||||||
|
|||||||
@ -3,6 +3,12 @@ use std::{any::Any, fmt::Debug};
|
|||||||
|
|
||||||
pub use bevy_utils::AHasher as ReflectHasher;
|
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> {
|
pub enum ReflectRef<'a> {
|
||||||
Struct(&'a dyn Struct),
|
Struct(&'a dyn Struct),
|
||||||
TupleStruct(&'a dyn TupleStruct),
|
TupleStruct(&'a dyn TupleStruct),
|
||||||
@ -12,6 +18,12 @@ pub enum ReflectRef<'a> {
|
|||||||
Value(&'a dyn Reflect),
|
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> {
|
pub enum ReflectMut<'a> {
|
||||||
Struct(&'a mut dyn Struct),
|
Struct(&'a mut dyn Struct),
|
||||||
TupleStruct(&'a mut dyn TupleStruct),
|
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)
|
/// value passed in. If this is not done, [`Reflect::downcast`](trait.Reflect.html#method.downcast)
|
||||||
/// will be UB (and also just logically broken).
|
/// will be UB (and also just logically broken).
|
||||||
pub unsafe trait Reflect: Any + Send + Sync {
|
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;
|
fn type_name(&self) -> &str;
|
||||||
|
|
||||||
|
/// Returns the value as a [`&dyn Any`][std::any::Any].
|
||||||
fn any(&self) -> &dyn 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;
|
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);
|
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>>;
|
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;
|
fn reflect_ref(&self) -> ReflectRef;
|
||||||
|
|
||||||
|
/// Returns a mutable enumeration of "kinds" of type.
|
||||||
|
///
|
||||||
|
/// See [`ReflectMut`].
|
||||||
fn reflect_mut(&mut self) -> 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>;
|
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>;
|
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>;
|
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>;
|
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 {
|
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>;
|
fn from_reflect(reflect: &dyn Reflect) -> Option<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,6 +157,9 @@ impl Debug for dyn Reflect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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>> {
|
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
|
// SAFE?: Same approach used by std::any::Box::downcast. ReflectValue is always Any and type
|
||||||
// has been checked.
|
// 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>> {
|
pub fn take<T: Reflect>(self: Box<dyn Reflect>) -> Result<T, Box<dyn Reflect>> {
|
||||||
self.downcast::<T>().map(|value| *value)
|
self.downcast::<T>().map(|value| *value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the underlying value is of type `T`, or `false`
|
||||||
|
/// otherwise.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is<T: Reflect>(&self) -> bool {
|
pub fn is<T: Reflect>(&self) -> bool {
|
||||||
self.any().is::<T>()
|
self.any().is::<T>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Downcasts the value to type `T` by reference.
|
||||||
|
///
|
||||||
|
/// If the underlying value is not of type `T`, returns `None`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn downcast_ref<T: Reflect>(&self) -> Option<&T> {
|
pub fn downcast_ref<T: Reflect>(&self) -> Option<&T> {
|
||||||
self.any().downcast_ref::<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]
|
#[inline]
|
||||||
pub fn downcast_mut<T: Reflect>(&mut self) -> Option<&mut T> {
|
pub fn downcast_mut<T: Reflect>(&mut self) -> Option<&mut T> {
|
||||||
self.any_mut().downcast_mut::<T>()
|
self.any_mut().downcast_mut::<T>()
|
||||||
|
|||||||
@ -154,12 +154,12 @@ pub struct DynamicStruct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DynamicStruct {
|
impl DynamicStruct {
|
||||||
/// Returns the name of the struct.
|
/// Returns the type name of the struct.
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the name of the struct.
|
/// Sets the type name of the struct.
|
||||||
pub fn set_name(&mut self, name: String) {
|
pub fn set_name(&mut self, name: String) {
|
||||||
self.name = name;
|
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]
|
#[inline]
|
||||||
pub fn struct_partial_eq<S: Struct>(a: &S, b: &dyn Reflect) -> Option<bool> {
|
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() {
|
let struct_value = if let ReflectRef::Struct(struct_value) = b.reflect_ref() {
|
||||||
|
|||||||
@ -128,14 +128,14 @@ pub struct DynamicTuple {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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.
|
/// The tuple's name is automatically generated from its element types.
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
&self.name
|
&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.
|
/// Note that the tuple name will be overwritten when elements are added.
|
||||||
pub fn set_name(&mut self, name: String) {
|
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]
|
#[inline]
|
||||||
pub fn tuple_apply<T: Tuple>(a: &mut T, b: &dyn Reflect) {
|
pub fn tuple_apply<T: Tuple>(a: &mut T, b: &dyn Reflect) {
|
||||||
if let ReflectRef::Tuple(tuple) = b.reflect_ref() {
|
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]
|
#[inline]
|
||||||
pub fn tuple_partial_eq<T: Tuple>(a: &T, b: &dyn Reflect) -> Option<bool> {
|
pub fn tuple_partial_eq<T: Tuple>(a: &T, b: &dyn Reflect) -> Option<bool> {
|
||||||
let b = if let ReflectRef::Tuple(tuple) = b.reflect_ref() {
|
let b = if let ReflectRef::Tuple(tuple) = b.reflect_ref() {
|
||||||
|
|||||||
@ -135,12 +135,12 @@ pub struct DynamicTupleStruct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DynamicTupleStruct {
|
impl DynamicTupleStruct {
|
||||||
/// Returns the name of the tuple struct.
|
/// Returns the type name of the tuple struct.
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
&self.name
|
&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) {
|
pub fn set_name(&mut self, name: String) {
|
||||||
self.name = name;
|
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]
|
#[inline]
|
||||||
pub fn tuple_struct_partial_eq<S: TupleStruct>(a: &S, b: &dyn Reflect) -> Option<bool> {
|
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() {
|
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 serde::Deserialize;
|
||||||
use std::{any::TypeId, fmt::Debug, sync::Arc};
|
use std::{any::TypeId, fmt::Debug, sync::Arc};
|
||||||
|
|
||||||
|
/// A registry of reflected types.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct TypeRegistry {
|
pub struct TypeRegistry {
|
||||||
registrations: HashMap<TypeId, TypeRegistration>,
|
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
|
// TODO: remove this wrapper once we migrate to Atelier Assets and the Scene AssetLoader doesn't
|
||||||
// need a TypeRegistry ref
|
// need a TypeRegistry ref
|
||||||
|
/// A synchronized wrapper around a [`TypeRegistry`].
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct TypeRegistryArc {
|
pub struct TypeRegistryArc {
|
||||||
pub internal: Arc<RwLock<TypeRegistry>>,
|
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 {
|
pub trait GetTypeRegistration {
|
||||||
fn get_type_registration() -> TypeRegistration;
|
fn get_type_registration() -> TypeRegistration;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeRegistry {
|
impl TypeRegistry {
|
||||||
|
/// Registers the type `T`.
|
||||||
pub fn register<T>(&mut self)
|
pub fn register<T>(&mut self)
|
||||||
where
|
where
|
||||||
T: GetTypeRegistration,
|
T: GetTypeRegistration,
|
||||||
@ -38,6 +44,7 @@ impl TypeRegistry {
|
|||||||
self.add_registration(T::get_type_registration());
|
self.add_registration(T::get_type_registration());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Registers the type described by `registration`.
|
||||||
pub fn add_registration(&mut self, registration: TypeRegistration) {
|
pub fn add_registration(&mut self, registration: TypeRegistration) {
|
||||||
let short_name = registration.short_name.to_string();
|
let short_name = registration.short_name.to_string();
|
||||||
if self.short_name_to_id.contains_key(&short_name)
|
if self.short_name_to_id.contains_key(&short_name)
|
||||||
@ -56,20 +63,40 @@ impl TypeRegistry {
|
|||||||
.insert(registration.type_id, registration);
|
.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> {
|
pub fn get(&self, type_id: TypeId) -> Option<&TypeRegistration> {
|
||||||
self.registrations.get(&type_id)
|
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> {
|
pub fn get_mut(&mut self, type_id: TypeId) -> Option<&mut TypeRegistration> {
|
||||||
self.registrations.get_mut(&type_id)
|
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> {
|
pub fn get_with_name(&self, type_name: &str) -> Option<&TypeRegistration> {
|
||||||
self.full_name_to_id
|
self.full_name_to_id
|
||||||
.get(type_name)
|
.get(type_name)
|
||||||
.and_then(|id| self.get(*id))
|
.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> {
|
pub fn get_with_name_mut(&mut self, type_name: &str) -> Option<&mut TypeRegistration> {
|
||||||
self.full_name_to_id
|
self.full_name_to_id
|
||||||
.get(type_name)
|
.get(type_name)
|
||||||
@ -77,32 +104,64 @@ impl TypeRegistry {
|
|||||||
.and_then(move |id| self.get_mut(id))
|
.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> {
|
pub fn get_with_short_name(&self, short_type_name: &str) -> Option<&TypeRegistration> {
|
||||||
self.short_name_to_id
|
self.short_name_to_id
|
||||||
.get(short_type_name)
|
.get(short_type_name)
|
||||||
.and_then(|id| self.registrations.get(id))
|
.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> {
|
pub fn get_type_data<T: TypeData>(&self, type_id: TypeId) -> Option<&T> {
|
||||||
self.get(type_id)
|
self.get(type_id)
|
||||||
.and_then(|registration| registration.data::<T>())
|
.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> {
|
pub fn iter(&self) -> impl Iterator<Item = &TypeRegistration> {
|
||||||
self.registrations.values()
|
self.registrations.values()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeRegistryArc {
|
impl TypeRegistryArc {
|
||||||
|
/// Takes a read lock on the underlying [`TypeRegistry`].
|
||||||
pub fn read(&self) -> RwLockReadGuard<'_, TypeRegistry> {
|
pub fn read(&self) -> RwLockReadGuard<'_, TypeRegistry> {
|
||||||
self.internal.read()
|
self.internal.read()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Takes a write lock on the underlying [`TypeRegistry`].
|
||||||
pub fn write(&self) -> RwLockWriteGuard<'_, TypeRegistry> {
|
pub fn write(&self) -> RwLockWriteGuard<'_, TypeRegistry> {
|
||||||
self.internal.write()
|
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 {
|
pub struct TypeRegistration {
|
||||||
type_id: TypeId,
|
type_id: TypeId,
|
||||||
short_name: String,
|
short_name: String,
|
||||||
@ -111,27 +170,42 @@ pub struct TypeRegistration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TypeRegistration {
|
impl TypeRegistration {
|
||||||
|
/// Returns the [`TypeId`] of the type.
|
||||||
|
///
|
||||||
|
/// [`TypeId`]: std::any::TypeId
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn type_id(&self) -> TypeId {
|
pub fn type_id(&self) -> TypeId {
|
||||||
self.type_id
|
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> {
|
pub fn data<T: TypeData>(&self) -> Option<&T> {
|
||||||
self.data
|
self.data
|
||||||
.get(&TypeId::of::<T>())
|
.get(&TypeId::of::<T>())
|
||||||
.and_then(|value| value.downcast_ref())
|
.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> {
|
pub fn data_mut<T: TypeData>(&mut self) -> Option<&mut T> {
|
||||||
self.data
|
self.data
|
||||||
.get_mut(&TypeId::of::<T>())
|
.get_mut(&TypeId::of::<T>())
|
||||||
.and_then(|value| value.downcast_mut())
|
.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) {
|
pub fn insert<T: TypeData>(&mut self, data: T) {
|
||||||
self.data.insert(TypeId::of::<T>(), Box::new(data));
|
self.data.insert(TypeId::of::<T>(), Box::new(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates type registration information for `T`.
|
||||||
pub fn of<T: Reflect>() -> Self {
|
pub fn of<T: Reflect>() -> Self {
|
||||||
let ty = TypeId::of::<T>();
|
let ty = TypeId::of::<T>();
|
||||||
let type_name = std::any::type_name::<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 {
|
pub fn short_name(&self) -> &str {
|
||||||
&self.short_name
|
&self.short_name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the name of the type.
|
||||||
pub fn name(&self) -> &'static str {
|
pub fn name(&self) -> &'static str {
|
||||||
self.name
|
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 {
|
pub fn get_short_name(full_name: &str) -> String {
|
||||||
let mut short_name = String::new();
|
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 {
|
pub trait TypeData: Downcast + Send + Sync {
|
||||||
fn clone_type_data(&self) -> Box<dyn TypeData>;
|
fn clone_type_data(&self) -> Box<dyn TypeData>;
|
||||||
}
|
}
|
||||||
@ -221,12 +308,16 @@ where
|
|||||||
|
|
||||||
/// Trait used to generate [`TypeData`] for trait reflection.
|
/// Trait used to generate [`TypeData`] for trait reflection.
|
||||||
///
|
///
|
||||||
/// This is used by the `#[derive(Reflect)]` macro to generate an implementation of [`TypeData`]
|
/// This is used by the `#[derive(Reflect)]` macro to generate an implementation
|
||||||
/// to pass to [`TypeRegistration::insert`].
|
/// of [`TypeData`] to pass to [`TypeRegistration::insert`].
|
||||||
pub trait FromType<T> {
|
pub trait FromType<T> {
|
||||||
fn from_type() -> Self;
|
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)]
|
#[derive(Clone)]
|
||||||
pub struct ReflectDeserialize {
|
pub struct ReflectDeserialize {
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
@ -236,6 +327,11 @@ pub struct ReflectDeserialize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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>
|
pub fn deserialize<'de, D>(&self, deserializer: D) -> Result<Box<dyn Reflect>, D::Error>
|
||||||
where
|
where
|
||||||
D: serde::Deserializer<'de>,
|
D: serde::Deserializer<'de>,
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
pub use bevy_reflect_derive::TypeUuid;
|
pub use bevy_reflect_derive::TypeUuid;
|
||||||
pub use bevy_utils::Uuid;
|
pub use bevy_utils::Uuid;
|
||||||
|
|
||||||
|
/// A trait for types with a statically associated UUID.
|
||||||
pub trait TypeUuid {
|
pub trait TypeUuid {
|
||||||
const TYPE_UUID: Uuid;
|
const TYPE_UUID: Uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A trait for types with an associated UUID.
|
||||||
pub trait TypeUuidDynamic {
|
pub trait TypeUuidDynamic {
|
||||||
fn type_uuid(&self) -> Uuid;
|
fn type_uuid(&self) -> Uuid;
|
||||||
fn type_name(&self) -> &'static str;
|
fn type_name(&self) -> &'static str;
|
||||||
@ -14,10 +16,14 @@ impl<T> TypeUuidDynamic for T
|
|||||||
where
|
where
|
||||||
T: TypeUuid,
|
T: TypeUuid,
|
||||||
{
|
{
|
||||||
|
/// Returns the UUID associated with this value's type.
|
||||||
fn type_uuid(&self) -> Uuid {
|
fn type_uuid(&self) -> Uuid {
|
||||||
Self::TYPE_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 {
|
fn type_name(&self) -> &'static str {
|
||||||
std::any::type_name::<Self>()
|
std::any::type_name::<Self>()
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user