Path: blob/main/crates/bevy_reflect/src/tuple_struct.rs
9353 views
//! Traits and types used to power [tuple-struct-like] operations via reflection.1//!2//! [tuple-struct-like]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html#using-tuple-structs-without-named-fields-to-create-different-types3use bevy_reflect_derive::impl_type_path;45use crate::generics::impl_generic_info_methods;6use crate::{7attributes::{impl_custom_attribute_methods, CustomAttributes},8tuple::{DynamicTuple, Tuple},9type_info::impl_type_methods,10ApplyError, Generics, PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned,11ReflectRef, Type, TypeInfo, TypePath, UnnamedField,12};13use alloc::{boxed::Box, vec::Vec};14use bevy_platform::sync::Arc;15use core::{16fmt::{Debug, Formatter},17slice::Iter,18};1920/// A trait used to power [tuple struct-like] operations via [reflection].21///22/// This trait uses the [`Reflect`] trait to allow implementors to have their fields23/// be dynamically addressed by index.24///25/// When using [`#[derive(Reflect)]`](derive@crate::Reflect) on a tuple struct,26/// this trait will be automatically implemented.27///28/// # Example29///30/// ```31/// use bevy_reflect::{PartialReflect, Reflect, tuple_struct::TupleStruct};32///33/// #[derive(Reflect)]34/// struct Foo(u32);35///36/// let foo = Foo(123);37///38/// assert_eq!(foo.field_len(), 1);39///40/// let field: &dyn PartialReflect = foo.field(0).unwrap();41/// assert_eq!(field.try_downcast_ref::<u32>(), Some(&123));42/// ```43///44/// [tuple struct-like]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html#using-tuple-structs-without-named-fields-to-create-different-types45/// [reflection]: crate46pub trait TupleStruct: PartialReflect {47/// Returns a reference to the value of the field with index `index` as a48/// `&dyn Reflect`.49fn field(&self, index: usize) -> Option<&dyn PartialReflect>;5051/// Returns a mutable reference to the value of the field with index `index`52/// as a `&mut dyn Reflect`.53fn field_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;5455/// Returns the number of fields in the tuple struct.56fn field_len(&self) -> usize;5758/// Returns an iterator over the values of the tuple struct's fields.59fn iter_fields(&self) -> TupleStructFieldIter<'_>;6061/// Creates a new [`DynamicTupleStruct`] from this tuple struct.62fn to_dynamic_tuple_struct(&self) -> DynamicTupleStruct {63DynamicTupleStruct {64represented_type: self.get_represented_type_info(),65fields: self.iter_fields().map(PartialReflect::to_dynamic).collect(),66}67}6869/// Will return `None` if [`TypeInfo`] is not available.70fn get_represented_tuple_struct_info(&self) -> Option<&'static TupleStructInfo> {71self.get_represented_type_info()?.as_tuple_struct().ok()72}73}7475/// A container for compile-time tuple struct info.76#[derive(Clone, Debug)]77pub struct TupleStructInfo {78ty: Type,79generics: Generics,80fields: Box<[UnnamedField]>,81custom_attributes: Arc<CustomAttributes>,82#[cfg(feature = "reflect_documentation")]83docs: Option<&'static str>,84}8586impl TupleStructInfo {87/// Create a new [`TupleStructInfo`].88///89/// # Arguments90///91/// * `fields`: The fields of this struct in the order they are defined92pub fn new<T: Reflect + TypePath>(fields: &[UnnamedField]) -> Self {93Self {94ty: Type::of::<T>(),95generics: Generics::new(),96fields: fields.to_vec().into_boxed_slice(),97custom_attributes: Arc::new(CustomAttributes::default()),98#[cfg(feature = "reflect_documentation")]99docs: None,100}101}102103/// Sets the docstring for this struct.104#[cfg(feature = "reflect_documentation")]105pub fn with_docs(self, docs: Option<&'static str>) -> Self {106Self { docs, ..self }107}108109/// Sets the custom attributes for this struct.110pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {111Self {112custom_attributes: Arc::new(custom_attributes),113..self114}115}116117/// Get the field at the given index.118pub fn field_at(&self, index: usize) -> Option<&UnnamedField> {119self.fields.get(index)120}121122/// Iterate over the fields of this struct.123pub fn iter(&self) -> Iter<'_, UnnamedField> {124self.fields.iter()125}126127/// The total number of fields in this struct.128pub fn field_len(&self) -> usize {129self.fields.len()130}131132impl_type_methods!(ty);133134/// The docstring of this struct, if any.135#[cfg(feature = "reflect_documentation")]136pub fn docs(&self) -> Option<&'static str> {137self.docs138}139140impl_custom_attribute_methods!(self.custom_attributes, "struct");141142impl_generic_info_methods!(generics);143}144145/// An iterator over the field values of a tuple struct.146pub struct TupleStructFieldIter<'a> {147pub(crate) tuple_struct: &'a dyn TupleStruct,148pub(crate) index: usize,149}150151impl<'a> TupleStructFieldIter<'a> {152/// Creates a new [`TupleStructFieldIter`].153pub fn new(value: &'a dyn TupleStruct) -> Self {154TupleStructFieldIter {155tuple_struct: value,156index: 0,157}158}159}160161impl<'a> Iterator for TupleStructFieldIter<'a> {162type Item = &'a dyn PartialReflect;163164fn next(&mut self) -> Option<Self::Item> {165let value = self.tuple_struct.field(self.index);166self.index += value.is_some() as usize;167value168}169170fn size_hint(&self) -> (usize, Option<usize>) {171let size = self.tuple_struct.field_len();172(size, Some(size))173}174}175176impl<'a> ExactSizeIterator for TupleStructFieldIter<'a> {}177178/// A convenience trait which combines fetching and downcasting of tuple179/// struct fields.180///181/// # Example182///183/// ```184/// use bevy_reflect::{tuple_struct::GetTupleStructField, Reflect};185///186/// #[derive(Reflect)]187/// struct Foo(String);188///189/// # fn main() {190/// let mut foo = Foo("Hello, world!".to_string());191///192/// foo.get_field_mut::<String>(0).unwrap().truncate(5);193/// assert_eq!(foo.get_field::<String>(0), Some(&"Hello".to_string()));194/// # }195/// ```196pub trait GetTupleStructField {197/// Returns a reference to the value of the field with index `index`,198/// downcast to `T`.199fn get_field<T: Reflect>(&self, index: usize) -> Option<&T>;200201/// Returns a mutable reference to the value of the field with index202/// `index`, downcast to `T`.203fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T>;204}205206impl<S: TupleStruct> GetTupleStructField for S {207fn get_field<T: Reflect>(&self, index: usize) -> Option<&T> {208self.field(index)209.and_then(|value| value.try_downcast_ref::<T>())210}211212fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T> {213self.field_mut(index)214.and_then(|value| value.try_downcast_mut::<T>())215}216}217218impl GetTupleStructField for dyn TupleStruct {219fn get_field<T: Reflect>(&self, index: usize) -> Option<&T> {220self.field(index)221.and_then(|value| value.try_downcast_ref::<T>())222}223224fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T> {225self.field_mut(index)226.and_then(|value| value.try_downcast_mut::<T>())227}228}229230/// A tuple struct which allows fields to be added at runtime.231#[derive(Default)]232pub struct DynamicTupleStruct {233represented_type: Option<&'static TypeInfo>,234fields: Vec<Box<dyn PartialReflect>>,235}236237impl DynamicTupleStruct {238/// Sets the [type] to be represented by this `DynamicTupleStruct`.239///240/// # Panics241///242/// Panics if the given [type] is not a [`TypeInfo::TupleStruct`].243///244/// [type]: TypeInfo245pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {246if let Some(represented_type) = represented_type {247assert!(248matches!(represented_type, TypeInfo::TupleStruct(_)),249"expected TypeInfo::TupleStruct but received: {represented_type:?}"250);251}252253self.represented_type = represented_type;254}255256/// Appends an element with value `value` to the tuple struct.257pub fn insert_boxed(&mut self, value: Box<dyn PartialReflect>) {258self.fields.push(value);259}260261/// Appends a typed element with value `value` to the tuple struct.262pub fn insert<T: PartialReflect>(&mut self, value: T) {263self.insert_boxed(Box::new(value));264}265}266267impl TupleStruct for DynamicTupleStruct {268#[inline]269fn field(&self, index: usize) -> Option<&dyn PartialReflect> {270self.fields.get(index).map(|field| &**field)271}272273#[inline]274fn field_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {275self.fields.get_mut(index).map(|field| &mut **field)276}277278#[inline]279fn field_len(&self) -> usize {280self.fields.len()281}282283#[inline]284fn iter_fields(&self) -> TupleStructFieldIter<'_> {285TupleStructFieldIter {286tuple_struct: self,287index: 0,288}289}290}291292impl PartialReflect for DynamicTupleStruct {293#[inline]294fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {295self.represented_type296}297298#[inline]299fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {300self301}302303#[inline]304fn as_partial_reflect(&self) -> &dyn PartialReflect {305self306}307308#[inline]309fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {310self311}312313fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {314Err(self)315}316317fn try_as_reflect(&self) -> Option<&dyn Reflect> {318None319}320321fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {322None323}324325fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {326let tuple_struct = value.reflect_ref().as_tuple_struct()?;327328for (i, value) in tuple_struct.iter_fields().enumerate() {329if let Some(v) = self.field_mut(i) {330v.try_apply(value)?;331}332}333334Ok(())335}336337#[inline]338fn reflect_kind(&self) -> ReflectKind {339ReflectKind::TupleStruct340}341342#[inline]343fn reflect_ref(&self) -> ReflectRef<'_> {344ReflectRef::TupleStruct(self)345}346347#[inline]348fn reflect_mut(&mut self) -> ReflectMut<'_> {349ReflectMut::TupleStruct(self)350}351352#[inline]353fn reflect_owned(self: Box<Self>) -> ReflectOwned {354ReflectOwned::TupleStruct(self)355}356357#[inline]358fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {359tuple_struct_partial_eq(self, value)360}361362fn reflect_partial_cmp(&self, value: &dyn PartialReflect) -> Option<::core::cmp::Ordering> {363tuple_struct_partial_cmp(self, value)364}365366fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {367write!(f, "DynamicTupleStruct(")?;368tuple_struct_debug(self, f)?;369write!(f, ")")370}371372#[inline]373fn is_dynamic(&self) -> bool {374true375}376}377378impl_type_path!((in bevy_reflect) DynamicTupleStruct);379380impl Debug for DynamicTupleStruct {381fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {382self.debug(f)383}384}385386impl From<DynamicTuple> for DynamicTupleStruct {387fn from(value: DynamicTuple) -> Self {388Self {389represented_type: None,390fields: Box::new(value).drain(),391}392}393}394395impl FromIterator<Box<dyn PartialReflect>> for DynamicTupleStruct {396fn from_iter<I: IntoIterator<Item = Box<dyn PartialReflect>>>(fields: I) -> Self {397Self {398represented_type: None,399fields: fields.into_iter().collect(),400}401}402}403404impl IntoIterator for DynamicTupleStruct {405type Item = Box<dyn PartialReflect>;406type IntoIter = alloc::vec::IntoIter<Self::Item>;407408fn into_iter(self) -> Self::IntoIter {409self.fields.into_iter()410}411}412413impl<'a> IntoIterator for &'a DynamicTupleStruct {414type Item = &'a dyn PartialReflect;415type IntoIter = TupleStructFieldIter<'a>;416417fn into_iter(self) -> Self::IntoIter {418self.iter_fields()419}420}421422/// Compares a [`TupleStruct`] with a [`PartialReflect`] value.423///424/// Returns true if and only if all of the following are true:425/// - `b` is a tuple struct;426/// - `b` has the same number of fields as `a`;427/// - [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for pairwise fields of `a` and `b`.428///429/// Returns [`None`] if the comparison couldn't even be performed.430#[inline(never)]431pub fn tuple_struct_partial_eq(a: &dyn TupleStruct, b: &dyn PartialReflect) -> Option<bool> {432let ReflectRef::TupleStruct(tuple_struct) = b.reflect_ref() else {433return Some(false);434};435436if a.field_len() != tuple_struct.field_len() {437return Some(false);438}439440for (i, value) in tuple_struct.iter_fields().enumerate() {441if let Some(field_value) = a.field(i) {442let eq_result = field_value.reflect_partial_eq(value);443if let failed @ (Some(false) | None) = eq_result {444return failed;445}446} else {447return Some(false);448}449}450451Some(true)452}453/// Lexicographically compares two [`TupleStruct`] values and returns their ordering.454///455/// Returns [`None`] if the comparison couldn't be performed (e.g., kinds mismatch456/// or an element comparison returns `None`).457#[inline(never)]458pub fn tuple_struct_partial_cmp(459a: &dyn TupleStruct,460b: &dyn PartialReflect,461) -> Option<::core::cmp::Ordering> {462let ReflectRef::TupleStruct(tuple_struct) = b.reflect_ref() else {463return None;464};465466if a.field_len() != tuple_struct.field_len() {467return None;468}469470for (i, value) in tuple_struct.iter_fields().enumerate() {471if let Some(field_value) = a.field(i) {472match field_value.reflect_partial_cmp(value) {473None => return None,474Some(core::cmp::Ordering::Equal) => continue,475Some(ord) => return Some(ord),476}477}478return None;479}480481Some(core::cmp::Ordering::Equal)482}483484/// The default debug formatter for [`TupleStruct`] types.485///486/// # Example487/// ```488/// use bevy_reflect::Reflect;489/// #[derive(Reflect)]490/// struct MyTupleStruct(usize);491///492/// let my_tuple_struct: &dyn Reflect = &MyTupleStruct(123);493/// println!("{:#?}", my_tuple_struct);494///495/// // Output:496///497/// // MyTupleStruct (498/// // 123,499/// // )500/// ```501#[inline]502pub fn tuple_struct_debug(503dyn_tuple_struct: &dyn TupleStruct,504f: &mut Formatter<'_>,505) -> core::fmt::Result {506let mut debug = f.debug_tuple(507dyn_tuple_struct508.get_represented_type_info()509.map(TypeInfo::type_path)510.unwrap_or("_"),511);512for field in dyn_tuple_struct.iter_fields() {513debug.field(&field as &dyn Debug);514}515debug.finish()516}517518#[cfg(test)]519mod tests {520use super::TupleStruct;521use crate::Reflect;522#[derive(Reflect)]523struct Ts(u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8);524#[test]525fn next_index_increment() {526let mut iter = Ts(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11).iter_fields();527let size = iter.len();528iter.index = size - 1;529let prev_index = iter.index;530assert!(iter.next().is_some());531assert_eq!(prev_index, iter.index - 1);532533// When None we should no longer increase index534assert!(iter.next().is_none());535assert_eq!(size, iter.index);536assert!(iter.next().is_none());537assert_eq!(size, iter.index);538}539}540541542