bevy/crates/bevy_reflect/src/tuple_struct.rs

297 lines
7.8 KiB
Rust
Raw Normal View History

2020-11-28 00:39:59 +00:00
use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef};
use std::any::Any;
/// 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()));
/// # }
/// ```
2020-11-28 00:39:59 +00:00
pub trait TupleStruct: Reflect {
/// Returns a reference to the value of the field with index `index` as a
/// `&dyn Reflect`.
2020-11-28 00:39:59 +00:00
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`.
2020-11-28 00:39:59 +00:00
fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>;
/// Returns the number of fields in the tuple struct.
2020-11-28 00:39:59 +00:00
fn field_len(&self) -> usize;
/// Returns an iterator over the values of the tuple struct's fields.
2020-11-28 00:39:59 +00:00
fn iter_fields(&self) -> TupleStructFieldIter;
/// Clones the struct into a [`DynamicTupleStruct`].
2020-11-28 00:39:59 +00:00
fn clone_dynamic(&self) -> DynamicTupleStruct;
}
/// An iterator over the field values of a tuple struct.
2020-11-28 00:39:59 +00:00
pub struct TupleStructFieldIter<'a> {
pub(crate) tuple_struct: &'a dyn TupleStruct,
pub(crate) index: usize,
}
impl<'a> TupleStructFieldIter<'a> {
pub fn new(value: &'a dyn TupleStruct) -> Self {
TupleStructFieldIter {
tuple_struct: value,
index: 0,
}
}
}
impl<'a> Iterator for TupleStructFieldIter<'a> {
type Item = &'a dyn Reflect;
fn next(&mut self) -> Option<Self::Item> {
let value = self.tuple_struct.field(self.index);
self.index += 1;
value
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.tuple_struct.field_len();
(size, Some(size))
}
2020-11-28 00:39:59 +00:00
}
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()));
/// # }
/// ```
2020-11-28 00:39:59 +00:00
pub trait GetTupleStructField {
/// Returns a reference to the value of the field with index `index`,
/// downcast to `T`.
2020-11-28 00:39:59 +00:00
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`.
2020-11-28 00:39:59 +00:00
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T>;
}
impl<S: TupleStruct> GetTupleStructField for S {
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T> {
self.field(index)
.and_then(|value| value.downcast_ref::<T>())
}
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T> {
self.field_mut(index)
.and_then(|value| value.downcast_mut::<T>())
}
}
impl GetTupleStructField for dyn TupleStruct {
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T> {
self.field(index)
.and_then(|value| value.downcast_ref::<T>())
}
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T> {
self.field_mut(index)
.and_then(|value| value.downcast_mut::<T>())
}
}
/// A tuple struct which allows fields to be added at runtime.
2020-11-28 00:39:59 +00:00
#[derive(Default)]
pub struct DynamicTupleStruct {
name: String,
fields: Vec<Box<dyn Reflect>>,
}
impl DynamicTupleStruct {
/// Returns the type name of the tuple struct.
2020-11-28 00:39:59 +00:00
pub fn name(&self) -> &str {
&self.name
}
/// Sets the type name of the tuple struct.
2020-11-28 00:39:59 +00:00
pub fn set_name(&mut self, name: String) {
self.name = name;
}
/// Appends an element with value `value` to the tuple struct.
2020-11-28 00:39:59 +00:00
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.
2020-11-28 00:39:59 +00:00
pub fn insert<T: Reflect>(&mut self, value: T) {
self.insert_boxed(Box::new(value));
}
}
impl TupleStruct for DynamicTupleStruct {
#[inline]
fn field(&self, index: usize) -> Option<&dyn Reflect> {
self.fields.get(index).map(|field| &**field)
}
#[inline]
fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {
self.fields.get_mut(index).map(|field| &mut **field)
}
#[inline]
fn field_len(&self) -> usize {
self.fields.len()
}
#[inline]
fn iter_fields(&self) -> TupleStructFieldIter {
TupleStructFieldIter {
tuple_struct: self,
index: 0,
}
}
fn clone_dynamic(&self) -> DynamicTupleStruct {
DynamicTupleStruct {
name: self.name.clone(),
fields: self
.fields
.iter()
.map(|value| value.clone_value())
.collect(),
}
}
}
// SAFE: any and any_mut both return self
unsafe impl Reflect for DynamicTupleStruct {
2020-11-28 00:39:59 +00:00
#[inline]
fn type_name(&self) -> &str {
self.name.as_str()
2020-11-28 00:39:59 +00:00
}
#[inline]
fn any(&self) -> &dyn Any {
self
}
#[inline]
fn any_mut(&mut self) -> &mut dyn Any {
self
}
bevy_reflect: Add `as_reflect` and `as_reflect_mut` (#4350) # Objective Trait objects that have `Reflect` as a supertrait cannot be upcast to a `dyn Reflect`. Attempting something like: ```rust trait MyTrait: Reflect { // ... } fn foo(value: &dyn MyTrait) { let reflected = value as &dyn Reflect; // Error! // ... } ``` Results in `error[E0658]: trait upcasting coercion is experimental`. The reason this is important is that a lot of `bevy_reflect` methods require a `&dyn Reflect`. This is trivial with concrete types, but if we don't know the concrete type (we only have the trait object), we can't use these methods. For example, we couldn't create a `ReflectSerializer` for the type since it expects a `&dyn Reflect` value— even though we should be able to. ## Solution Add `as_reflect` and `as_reflect_mut` to `Reflect` to allow upcasting to a `dyn Reflect`: ```rust trait MyTrait: Reflect { // ... } fn foo(value: &dyn MyTrait) { let reflected = value.as_reflect(); // ... } ``` ## Alternatives We could defer this type of logic to the crate/user. They can add these methods to their trait in the same exact way we do here. The main benefit of doing it ourselves is it makes things convenient for them (especially when using the derive macro). We could also create an `AsReflect` trait with a blanket impl over all reflected types, however, I could not get that to work for trait objects since they aren't sized. --- ## Changelog - Added trait method `Reflect::as_reflect(&self)` - Added trait method `Reflect::as_reflect_mut(&mut self)` ## Migration Guide - Manual implementors of `Reflect` will need to add implementations for the methods above (this should be pretty easy as most cases just need to return `self`)
2022-04-25 13:54:48 +00:00
#[inline]
fn as_reflect(&self) -> &dyn Reflect {
self
}
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn Reflect {
self
}
2020-11-28 00:39:59 +00:00
#[inline]
fn clone_value(&self) -> Box<dyn Reflect> {
Box::new(self.clone_dynamic())
}
#[inline]
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::TupleStruct(self)
}
#[inline]
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::TupleStruct(self)
}
fn apply(&mut self, value: &dyn Reflect) {
if let ReflectRef::TupleStruct(tuple_struct) = value.reflect_ref() {
for (i, value) in tuple_struct.iter_fields().enumerate() {
if let Some(v) = self.field_mut(i) {
v.apply(value);
2020-11-28 00:39:59 +00:00
}
}
} else {
panic!("Attempted to apply non-TupleStruct type to TupleStruct type.");
2020-11-28 00:39:59 +00:00
}
}
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
fn reflect_hash(&self) -> Option<u64> {
2020-11-28 00:39:59 +00:00
None
}
fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
2020-11-28 00:39:59 +00:00
tuple_struct_partial_eq(self, value)
}
fn serializable(&self) -> Option<Serializable> {
None
}
}
/// 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`.
2020-11-28 00:39:59 +00:00
#[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() {
tuple_struct
} else {
return Some(false);
};
if a.field_len() != tuple_struct.field_len() {
return Some(false);
}
for (i, value) in tuple_struct.iter_fields().enumerate() {
if let Some(field_value) = a.field(i) {
if let Some(false) | None = field_value.reflect_partial_eq(value) {
2020-11-28 00:39:59 +00:00
return Some(false);
}
} else {
return Some(false);
}
}
Some(true)
}