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. pub trait Struct: Reflect { fn field(&self, name: &str) -> Option<&dyn Reflect>; fn field_mut(&mut self, name: &str) -> Option<&mut dyn Reflect>; fn field_at(&self, index: usize) -> Option<&dyn Reflect>; fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>; fn name_at(&self, index: usize) -> Option<&str>; fn field_len(&self) -> usize; fn iter_fields(&self) -> FieldIter; fn clone_dynamic(&self) -> DynamicStruct; } pub struct FieldIter<'a> { pub(crate) struct_val: &'a dyn Struct, pub(crate) index: usize, } impl<'a> FieldIter<'a> { pub fn new(value: &'a dyn Struct) -> Self { FieldIter { struct_val: value, index: 0, } } } impl<'a> Iterator for FieldIter<'a> { type Item = &'a dyn Reflect; fn next(&mut self) -> Option { let value = self.struct_val.field_at(self.index); self.index += 1; value } } pub trait GetField { fn get_field(&self, name: &str) -> Option<&T>; fn get_field_mut(&mut self, name: &str) -> Option<&mut T>; } impl GetField for S { fn get_field(&self, name: &str) -> Option<&T> { self.field(name).and_then(|value| value.downcast_ref::()) } fn get_field_mut(&mut self, name: &str) -> Option<&mut T> { self.field_mut(name) .and_then(|value| value.downcast_mut::()) } } impl GetField for dyn Struct { fn get_field(&self, name: &str) -> Option<&T> { self.field(name).and_then(|value| value.downcast_ref::()) } fn get_field_mut(&mut self, name: &str) -> Option<&mut T> { self.field_mut(name) .and_then(|value| value.downcast_mut::()) } } #[derive(Default)] pub struct DynamicStruct { name: String, fields: Vec>, field_names: Vec>, field_indices: HashMap, usize>, } impl DynamicStruct { pub fn name(&self) -> &str { &self.name } pub fn set_name(&mut self, name: String) { self.name = name; } pub fn insert_boxed(&mut self, name: &str, value: Box) { let name = Cow::Owned(name.to_string()); match self.field_indices.entry(name) { Entry::Occupied(entry) => { self.fields[*entry.get()] = value; } Entry::Vacant(entry) => { self.fields.push(value); self.field_names.push(entry.key().clone()); entry.insert(self.fields.len() - 1); } } } pub fn insert(&mut self, name: &str, value: T) { if let Some(index) = self.field_indices.get(name) { self.fields[*index] = Box::new(value); } else { self.insert_boxed(name, Box::new(value)); } } } impl Struct for DynamicStruct { #[inline] fn field(&self, name: &str) -> Option<&dyn Reflect> { if let Some(index) = self.field_indices.get(name) { Some(&*self.fields[*index]) } else { None } } #[inline] fn field_mut(&mut self, name: &str) -> Option<&mut dyn Reflect> { if let Some(index) = self.field_indices.get(name) { Some(&mut *self.fields[*index]) } else { None } } #[inline] fn field_at(&self, index: usize) -> Option<&dyn Reflect> { self.fields.get(index).map(|value| &**value) } #[inline] fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> { self.fields.get_mut(index).map(|value| &mut **value) } #[inline] fn name_at(&self, index: usize) -> Option<&str> { self.field_names.get(index).map(|name| name.as_ref()) } #[inline] fn field_len(&self) -> usize { self.fields.len() } #[inline] fn iter_fields(&self) -> FieldIter { FieldIter { struct_val: self, index: 0, } } fn clone_dynamic(&self) -> DynamicStruct { DynamicStruct { name: self.name.clone(), field_names: self.field_names.clone(), field_indices: self.field_indices.clone(), fields: self .fields .iter() .map(|value| value.clone_value()) .collect(), } } } impl Reflect for DynamicStruct { #[inline] fn type_name(&self) -> &str { &self.name } #[inline] fn any(&self) -> &dyn Any { self } #[inline] fn any_mut(&mut self) -> &mut dyn Any { self } #[inline] fn clone_value(&self) -> Box { Box::new(self.clone_dynamic()) } #[inline] fn reflect_ref(&self) -> ReflectRef { ReflectRef::Struct(self) } #[inline] fn reflect_mut(&mut self) -> ReflectMut { ReflectMut::Struct(self) } fn apply(&mut self, value: &dyn Reflect) { if let ReflectRef::Struct(struct_value) = value.reflect_ref() { for (i, value) in struct_value.iter_fields().enumerate() { let name = struct_value.name_at(i).unwrap(); if let Some(v) = self.field_mut(name) { v.apply(value) } } } else { panic!("attempted to apply non-struct type to struct type"); } } fn set(&mut self, value: Box) -> Result<(), Box> { *self = value.take()?; Ok(()) } fn hash(&self) -> Option { None } fn partial_eq(&self, value: &dyn Reflect) -> Option { struct_partial_eq(self, value) } fn serializable(&self) -> Option { None } } #[inline] pub fn struct_partial_eq(a: &S, b: &dyn Reflect) -> Option { let struct_value = if let ReflectRef::Struct(struct_value) = b.reflect_ref() { struct_value } else { return Some(false); }; if a.field_len() != struct_value.field_len() { return Some(false); } for (i, value) in struct_value.iter_fields().enumerate() { let name = struct_value.name_at(i).unwrap(); if let Some(field_value) = a.field(name) { if let Some(false) | None = field_value.partial_eq(value) { return Some(false); } } else { return Some(false); } } Some(true) }