mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 15:14:50 +00:00
document Struct
, TupleStruct
and Tuple
(#3081)
# Objective These traits are undocumented on `main`. ## Solution Now they have docs! Included are examples for each trait and their corresponding `GetTypeField` trait. The docs also mention that `#[derive(Reflect)]` will automatically derive the correct subtrait on structs and tuple structs.
This commit is contained in:
parent
458cb7a9e9
commit
4b4dbb021f
4 changed files with 212 additions and 5 deletions
|
@ -21,11 +21,17 @@ pub enum ReflectMut<'a> {
|
|||
Value(&'a mut dyn Reflect),
|
||||
}
|
||||
|
||||
/// A reflected rust type.
|
||||
/// A reflected Rust type.
|
||||
///
|
||||
/// Methods for working with particular kinds of Rust type are available using the [`List`], [`Map`],
|
||||
/// [`Struct`], [`TupleStruct`], and [`Tuple`] subtraits.
|
||||
///
|
||||
/// When using `#[derive(Reflect)]` with a struct or tuple struct, the suitable subtrait for that
|
||||
/// type (`Struct` or `TupleStruct`) is derived automatically.
|
||||
///
|
||||
/// # Safety
|
||||
/// Implementors _must_ ensure that [`Reflect::any`] and [`Reflect::any_mut`] both return the `self`
|
||||
/// 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).
|
||||
pub unsafe trait Reflect: Any + Send + Sync {
|
||||
fn type_name(&self) -> &str;
|
||||
|
|
|
@ -2,19 +2,65 @@ use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef};
|
|||
use bevy_utils::HashMap;
|
||||
use std::{any::Any, borrow::Cow, collections::hash_map::Entry};
|
||||
|
||||
/// An ordered &str->ReflectValue mapping where &str is a "field".
|
||||
/// This corresponds to rust struct types.
|
||||
/// A reflected Rust regular struct type.
|
||||
///
|
||||
/// Implementors of this trait allow their fields to be addressed by name as
|
||||
/// well as by index.
|
||||
///
|
||||
/// This trait is automatically implemented for `struct` types with named fields
|
||||
/// when using `#[derive(Reflect)]`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use bevy_reflect::{Reflect, Struct};
|
||||
///
|
||||
/// #[derive(Reflect)]
|
||||
/// struct Foo {
|
||||
/// bar: String,
|
||||
/// }
|
||||
///
|
||||
/// # fn main() {
|
||||
/// let foo = Foo { bar: "Hello, world!".to_string() };
|
||||
///
|
||||
/// assert_eq!(foo.field_len(), 1);
|
||||
/// assert_eq!(foo.name_at(0), Some("bar"));
|
||||
///
|
||||
/// let bar = foo.field("bar").unwrap();
|
||||
/// assert_eq!(bar.downcast_ref::<String>(), Some(&"Hello, world!".to_string()));
|
||||
/// # }
|
||||
/// ```
|
||||
pub trait Struct: Reflect {
|
||||
/// Returns a reference to the value of the field named `name` as a `&dyn
|
||||
/// Reflect`.
|
||||
fn field(&self, name: &str) -> Option<&dyn Reflect>;
|
||||
|
||||
/// Returns a mutable reference to the value of the field named `name` as a
|
||||
/// `&mut dyn Reflect`.
|
||||
fn field_mut(&mut self, name: &str) -> Option<&mut dyn Reflect>;
|
||||
|
||||
/// Returns a reference to the value of the field with index `index` as a
|
||||
/// `&dyn Reflect`.
|
||||
fn field_at(&self, index: usize) -> Option<&dyn Reflect>;
|
||||
|
||||
/// Returns a mutable reference to the value of the field with index `index`
|
||||
/// as a `&mut dyn Reflect`.
|
||||
fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>;
|
||||
|
||||
/// Returns the name of the field with index `index`.
|
||||
fn name_at(&self, index: usize) -> Option<&str>;
|
||||
|
||||
/// Returns the number of fields in the struct.
|
||||
fn field_len(&self) -> usize;
|
||||
|
||||
/// Returns an iterator over the values of the struct's fields.
|
||||
fn iter_fields(&self) -> FieldIter;
|
||||
|
||||
/// Clones the struct into a [`DynamicStruct`].
|
||||
fn clone_dynamic(&self) -> DynamicStruct;
|
||||
}
|
||||
|
||||
/// An iterator over the field values of a struct.
|
||||
pub struct FieldIter<'a> {
|
||||
pub(crate) struct_val: &'a dyn Struct,
|
||||
pub(crate) index: usize,
|
||||
|
@ -46,8 +92,33 @@ impl<'a> Iterator for FieldIter<'a> {
|
|||
|
||||
impl<'a> ExactSizeIterator for FieldIter<'a> {}
|
||||
|
||||
/// A convenience trait which combines fetching and downcasting of struct
|
||||
/// fields.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use bevy_reflect::{GetField, Reflect};
|
||||
///
|
||||
/// #[derive(Reflect)]
|
||||
/// struct Foo {
|
||||
/// bar: String,
|
||||
/// }
|
||||
///
|
||||
/// # fn main() {
|
||||
/// let mut foo = Foo { bar: "Hello, world!".to_string() };
|
||||
///
|
||||
/// foo.get_field_mut::<String>("bar").unwrap().truncate(5);
|
||||
/// assert_eq!(foo.get_field::<String>("bar"), Some(&"Hello".to_string()));
|
||||
/// # }
|
||||
/// ```
|
||||
pub trait GetField {
|
||||
/// Returns a reference to the value of the field named `name`, downcast to
|
||||
/// `T`.
|
||||
fn get_field<T: Reflect>(&self, name: &str) -> Option<&T>;
|
||||
|
||||
/// Returns a mutable reference to the value of the field named `name`,
|
||||
/// downcast to `T`.
|
||||
fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T>;
|
||||
}
|
||||
|
||||
|
@ -73,6 +144,7 @@ impl GetField for dyn Struct {
|
|||
}
|
||||
}
|
||||
|
||||
/// A struct type which allows fields to be added at runtime.
|
||||
#[derive(Default)]
|
||||
pub struct DynamicStruct {
|
||||
name: String,
|
||||
|
@ -82,14 +154,19 @@ pub struct DynamicStruct {
|
|||
}
|
||||
|
||||
impl DynamicStruct {
|
||||
/// Returns the name of the struct.
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
/// Sets the name of the struct.
|
||||
pub fn set_name(&mut self, name: String) {
|
||||
self.name = name;
|
||||
}
|
||||
|
||||
/// Inserts a field named `name` with value `value` into the struct.
|
||||
///
|
||||
/// If the field already exists, it is overwritten.
|
||||
pub fn insert_boxed(&mut self, name: &str, value: Box<dyn Reflect>) {
|
||||
let name = Cow::Owned(name.to_string());
|
||||
match self.field_indices.entry(name) {
|
||||
|
@ -104,6 +181,9 @@ impl DynamicStruct {
|
|||
}
|
||||
}
|
||||
|
||||
/// Inserts a field named `name` with the typed value `value` into the struct.
|
||||
///
|
||||
/// If the field already exists, it is overwritten.
|
||||
pub fn insert<T: Reflect>(&mut self, name: &str, value: T) {
|
||||
if let Some(index) = self.field_indices.get(name) {
|
||||
self.fields[*index] = Box::new(value);
|
||||
|
|
|
@ -2,14 +2,44 @@ use std::any::Any;
|
|||
|
||||
use crate::{serde::Serializable, FromReflect, Reflect, ReflectMut, ReflectRef};
|
||||
|
||||
/// A reflected Rust tuple.
|
||||
///
|
||||
/// This trait is automatically implemented for arbitrary tuples of up to 12
|
||||
/// elements, provided that each element implements [`Reflect`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use bevy_reflect::Tuple;
|
||||
///
|
||||
/// # fn main() {
|
||||
/// let foo = ("blue".to_string(), 42_i32);
|
||||
/// assert_eq!(foo.field_len(), 2);
|
||||
///
|
||||
/// let first = foo.field(0).unwrap();
|
||||
/// assert_eq!(first.downcast_ref::<String>(), Some(&"blue".to_string()));
|
||||
/// # }
|
||||
/// ```
|
||||
pub trait Tuple: Reflect {
|
||||
/// Returns a reference to the value of the field with index `index` as a
|
||||
/// `&dyn Reflect`.
|
||||
fn field(&self, index: usize) -> Option<&dyn Reflect>;
|
||||
|
||||
/// Returns a mutable reference to the value of the field with index `index`
|
||||
/// as a `&mut dyn Reflect`.
|
||||
fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>;
|
||||
|
||||
/// Returns the number of fields in the tuple.
|
||||
fn field_len(&self) -> usize;
|
||||
|
||||
/// Returns an iterator over the values of the tuple's fields.
|
||||
fn iter_fields(&self) -> TupleFieldIter;
|
||||
|
||||
/// Clones the struct into a [`DynamicTuple`].
|
||||
fn clone_dynamic(&self) -> DynamicTuple;
|
||||
}
|
||||
|
||||
/// An iterator over the field values of a tuple.
|
||||
pub struct TupleFieldIter<'a> {
|
||||
pub(crate) tuple: &'a dyn Tuple,
|
||||
pub(crate) index: usize,
|
||||
|
@ -41,8 +71,28 @@ impl<'a> Iterator for TupleFieldIter<'a> {
|
|||
|
||||
impl<'a> ExactSizeIterator for TupleFieldIter<'a> {}
|
||||
|
||||
/// A convenience trait which combines fetching and downcasting of tuple
|
||||
/// fields.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use bevy_reflect::GetTupleField;
|
||||
///
|
||||
/// # fn main() {
|
||||
/// let foo = ("blue".to_string(), 42_i32);
|
||||
///
|
||||
/// assert_eq!(foo.get_field::<String>(0), Some(&"blue".to_string()));
|
||||
/// assert_eq!(foo.get_field::<i32>(1), Some(&42));
|
||||
/// # }
|
||||
/// ```
|
||||
pub trait GetTupleField {
|
||||
/// Returns a reference to the value of the field with index `index`,
|
||||
/// downcast to `T`.
|
||||
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T>;
|
||||
|
||||
/// Returns a mutable reference to the value of the field with index
|
||||
/// `index`, downcast to `T`.
|
||||
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T>;
|
||||
}
|
||||
|
||||
|
@ -70,6 +120,7 @@ impl GetTupleField for dyn Tuple {
|
|||
}
|
||||
}
|
||||
|
||||
/// A tuple which allows fields to be added at runtime.
|
||||
#[derive(Default)]
|
||||
pub struct DynamicTuple {
|
||||
name: String,
|
||||
|
@ -77,19 +128,27 @@ pub struct DynamicTuple {
|
|||
}
|
||||
|
||||
impl DynamicTuple {
|
||||
/// Returns the 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.
|
||||
///
|
||||
/// Note that the tuple name will be overwritten when elements are added.
|
||||
pub fn set_name(&mut self, name: String) {
|
||||
self.name = name;
|
||||
}
|
||||
|
||||
/// Appends an element with value `value` to the tuple.
|
||||
pub fn insert_boxed(&mut self, value: Box<dyn Reflect>) {
|
||||
self.fields.push(value);
|
||||
self.generate_name();
|
||||
}
|
||||
|
||||
/// Appends a typed element with value `value` to the tuple.
|
||||
pub fn insert<T: Reflect>(&mut self, value: T) {
|
||||
self.insert_boxed(Box::new(value));
|
||||
self.generate_name();
|
||||
|
|
|
@ -1,15 +1,49 @@
|
|||
use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef};
|
||||
use std::any::Any;
|
||||
|
||||
/// A rust "tuple struct" reflection
|
||||
/// A reflected Rust tuple struct.
|
||||
///
|
||||
/// Implementors of this trait allow their tuple fields to be addressed by
|
||||
/// index.
|
||||
///
|
||||
/// This trait is automatically implemented for tuple struct types when using
|
||||
/// `#[derive(Reflect)]`.
|
||||
///
|
||||
/// ```
|
||||
/// use bevy_reflect::{Reflect, TupleStruct};
|
||||
///
|
||||
/// #[derive(Reflect)]
|
||||
/// struct Foo(String);
|
||||
///
|
||||
/// # fn main() {
|
||||
/// let foo = Foo("Hello, world!".to_string());
|
||||
///
|
||||
/// assert_eq!(foo.field_len(), 1);
|
||||
///
|
||||
/// let first = foo.field(0).unwrap();
|
||||
/// assert_eq!(first.downcast_ref::<String>(), Some(&"Hello, world!".to_string()));
|
||||
/// # }
|
||||
/// ```
|
||||
pub trait TupleStruct: Reflect {
|
||||
/// Returns a reference to the value of the field with index `index` as a
|
||||
/// `&dyn Reflect`.
|
||||
fn field(&self, index: usize) -> Option<&dyn Reflect>;
|
||||
|
||||
/// Returns a mutable reference to the value of the field with index `index`
|
||||
/// as a `&mut dyn Reflect`.
|
||||
fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>;
|
||||
|
||||
/// Returns the number of fields in the tuple struct.
|
||||
fn field_len(&self) -> usize;
|
||||
|
||||
/// Returns an iterator over the values of the tuple struct's fields.
|
||||
fn iter_fields(&self) -> TupleStructFieldIter;
|
||||
|
||||
/// Clones the struct into a [`DynamicTupleStruct`].
|
||||
fn clone_dynamic(&self) -> DynamicTupleStruct;
|
||||
}
|
||||
|
||||
/// An iterator over the field values of a tuple struct.
|
||||
pub struct TupleStructFieldIter<'a> {
|
||||
pub(crate) tuple_struct: &'a dyn TupleStruct,
|
||||
pub(crate) index: usize,
|
||||
|
@ -41,8 +75,31 @@ impl<'a> Iterator for TupleStructFieldIter<'a> {
|
|||
|
||||
impl<'a> ExactSizeIterator for TupleStructFieldIter<'a> {}
|
||||
|
||||
/// A convenience trait which combines fetching and downcasting of tuple
|
||||
/// struct fields.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use bevy_reflect::{GetTupleStructField, Reflect};
|
||||
///
|
||||
/// #[derive(Reflect)]
|
||||
/// struct Foo(String);
|
||||
///
|
||||
/// # fn main() {
|
||||
/// let mut foo = Foo("Hello, world!".to_string());
|
||||
///
|
||||
/// foo.get_field_mut::<String>(0).unwrap().truncate(5);
|
||||
/// assert_eq!(foo.get_field::<String>(0), Some(&"Hello".to_string()));
|
||||
/// # }
|
||||
/// ```
|
||||
pub trait GetTupleStructField {
|
||||
/// Returns a reference to the value of the field with index `index`,
|
||||
/// downcast to `T`.
|
||||
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T>;
|
||||
|
||||
/// Returns a mutable reference to the value of the field with index
|
||||
/// `index`, downcast to `T`.
|
||||
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T>;
|
||||
}
|
||||
|
||||
|
@ -70,6 +127,7 @@ impl GetTupleStructField for dyn TupleStruct {
|
|||
}
|
||||
}
|
||||
|
||||
/// A tuple struct which allows fields to be added at runtime.
|
||||
#[derive(Default)]
|
||||
pub struct DynamicTupleStruct {
|
||||
name: String,
|
||||
|
@ -77,18 +135,22 @@ pub struct DynamicTupleStruct {
|
|||
}
|
||||
|
||||
impl DynamicTupleStruct {
|
||||
/// Returns the name of the tuple struct.
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
/// Sets the name of the tuple struct.
|
||||
pub fn set_name(&mut self, name: String) {
|
||||
self.name = name;
|
||||
}
|
||||
|
||||
/// Appends an element with value `value` to the tuple struct.
|
||||
pub fn insert_boxed(&mut self, value: Box<dyn Reflect>) {
|
||||
self.fields.push(value);
|
||||
}
|
||||
|
||||
/// Appends a typed element with value `value` to the tuple struct.
|
||||
pub fn insert<T: Reflect>(&mut self, value: T) {
|
||||
self.insert_boxed(Box::new(value));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue