Implement Reflect for tuples up to length 12 (#1218)

Add Reflect impls for tuples up to length 12
This commit is contained in:
TehPers 2021-01-07 19:50:09 -08:00 committed by GitHub
parent 9bce8712b5
commit 5e7456115a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 435 additions and 6 deletions

View File

@ -3,6 +3,7 @@ mod map;
mod path;
mod reflect;
mod struct_trait;
mod tuple;
mod tuple_struct;
mod type_registry;
mod type_uuid;
@ -46,6 +47,7 @@ pub use map::*;
pub use path::*;
pub use reflect::*;
pub use struct_trait::*;
pub use tuple::*;
pub use tuple_struct::*;
pub use type_registry::*;
pub use type_uuid::*;
@ -208,6 +210,7 @@ mod tests {
c: Vec<isize>,
d: HashMap<usize, i8>,
e: Bar,
f: (i32, Vec<isize>, Bar),
}
#[derive(Reflect, Eq, PartialEq, Debug)]
@ -224,6 +227,7 @@ mod tests {
c: vec![1, 2],
d: hash_map,
e: Bar { x: 1 },
f: (1, vec![1, 2], Bar { x: 1 }),
};
let mut foo_patch = DynamicStruct::default();
@ -234,7 +238,7 @@ mod tests {
list.push(3isize);
list.push(4isize);
list.push(5isize);
foo_patch.insert("c", list);
foo_patch.insert("c", list.clone_dynamic());
let mut map = DynamicMap::default();
map.insert(2usize, 3i8);
@ -242,7 +246,13 @@ mod tests {
let mut bar_patch = DynamicStruct::default();
bar_patch.insert("x", 2u32);
foo_patch.insert("e", bar_patch);
foo_patch.insert("e", bar_patch.clone_dynamic());
let mut tuple = DynamicTuple::default();
tuple.insert(2i32);
tuple.insert(list);
tuple.insert(bar_patch);
foo_patch.insert("f", tuple);
foo.apply(&foo_patch);
@ -255,6 +265,7 @@ mod tests {
c: vec![3, 4, 5],
d: hash_map,
e: Bar { x: 2 },
f: (2, vec![3, 4, 5], Bar { x: 2 }),
};
assert_eq!(foo, expected_foo);
@ -271,6 +282,7 @@ mod tests {
d: HashMap<usize, i8>,
e: Bar,
f: String,
g: (i32, Vec<isize>, Bar),
}
#[derive(Reflect)]
@ -288,6 +300,7 @@ mod tests {
d: hash_map,
e: Bar { x: 1 },
f: "hi".to_string(),
g: (1, vec![1, 2], Bar { x: 1 }),
};
let mut registry = TypeRegistry::default();
@ -297,6 +310,7 @@ mod tests {
registry.register::<Bar>();
registry.register::<String>();
registry.register::<i8>();
registry.register::<i32>();
let serializer = ReflectSerializer::new(&foo, &registry);
let serialized = to_string_pretty(&serializer, PrettyConfig::default()).unwrap();

View File

@ -1,4 +1,4 @@
use crate::{serde::Serializable, List, Map, Struct, TupleStruct};
use crate::{serde::Serializable, List, Map, Struct, Tuple, TupleStruct};
use std::{any::Any, fmt::Debug};
pub use bevy_utils::AHasher as ReflectHasher;
@ -6,6 +6,7 @@ pub use bevy_utils::AHasher as ReflectHasher;
pub enum ReflectRef<'a> {
Struct(&'a dyn Struct),
TupleStruct(&'a dyn TupleStruct),
Tuple(&'a dyn Tuple),
List(&'a dyn List),
Map(&'a dyn Map),
Value(&'a dyn Reflect),
@ -14,6 +15,7 @@ pub enum ReflectRef<'a> {
pub enum ReflectMut<'a> {
Struct(&'a mut dyn Struct),
TupleStruct(&'a mut dyn TupleStruct),
Tuple(&'a dyn Tuple),
List(&'a mut dyn List),
Map(&'a mut dyn Map),
Value(&'a mut dyn Reflect),

View File

@ -1,6 +1,6 @@
use crate::{
serde::type_fields, DynamicList, DynamicMap, DynamicStruct, DynamicTupleStruct, Reflect,
ReflectDeserialize, TypeRegistry,
serde::type_fields, DynamicList, DynamicMap, DynamicStruct, DynamicTuple, DynamicTupleStruct,
Reflect, ReflectDeserialize, TypeRegistry,
};
use erased_serde::Deserializer;
use serde::de::{self, DeserializeSeed, MapAccess, SeqAccess, Visitor};
@ -176,6 +176,15 @@ impl<'a, 'de> Visitor<'de> for ReflectVisitor<'a> {
tuple_struct.set_name(type_name);
return Ok(Box::new(tuple_struct));
}
type_fields::TUPLE => {
let _type_name = type_name
.take()
.ok_or_else(|| de::Error::missing_field(type_fields::TYPE))?;
let tuple = map.next_value_seed(TupleDeserializer {
registry: self.registry,
})?;
return Ok(Box::new(tuple));
}
type_fields::LIST => {
let _type_name = type_name
.take()
@ -401,3 +410,45 @@ impl<'a, 'de> Visitor<'de> for TupleStructVisitor<'a> {
Ok(tuple_struct)
}
}
struct TupleDeserializer<'a> {
registry: &'a TypeRegistry,
}
impl<'a, 'de> DeserializeSeed<'de> for TupleDeserializer<'a> {
type Value = DynamicTuple;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_seq(TupleVisitor {
registry: self.registry,
})
}
}
struct TupleVisitor<'a> {
registry: &'a TypeRegistry,
}
impl<'a, 'de> Visitor<'de> for TupleVisitor<'a> {
type Value = DynamicTuple;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("tuple value")
}
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
let mut tuple = DynamicTuple::default();
while let Some(value) = seq.next_element_seed(ReflectDeserializer {
registry: self.registry,
})? {
tuple.insert_boxed(value);
}
Ok(tuple)
}
}

View File

@ -9,6 +9,7 @@ pub(crate) mod type_fields {
pub const MAP: &str = "map";
pub const STRUCT: &str = "struct";
pub const TUPLE_STRUCT: &str = "tuple_struct";
pub const TUPLE: &str = "tuple";
pub const LIST: &str = "list";
pub const VALUE: &str = "value";
}

View File

@ -1,5 +1,5 @@
use crate::{
serde::type_fields, List, Map, Reflect, ReflectRef, Struct, TupleStruct, TypeRegistry,
serde::type_fields, List, Map, Reflect, ReflectRef, Struct, Tuple, TupleStruct, TypeRegistry,
};
use serde::{
ser::{SerializeMap, SerializeSeq},
@ -57,6 +57,11 @@ impl<'a> Serialize for ReflectSerializer<'a> {
registry: self.registry,
}
.serialize(serializer),
ReflectRef::Tuple(value) => TupleSerializer {
tuple: value,
registry: self.registry,
}
.serialize(serializer),
ReflectRef::List(value) => ListSerializer {
list: value,
registry: self.registry,
@ -181,6 +186,48 @@ impl<'a> Serialize for TupleStructValueSerializer<'a> {
}
}
pub struct TupleSerializer<'a> {
pub tuple: &'a dyn Tuple,
pub registry: &'a TypeRegistry,
}
impl<'a> Serialize for TupleSerializer<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_map(Some(2))?;
state.serialize_entry(type_fields::TYPE, self.tuple.type_name())?;
state.serialize_entry(
type_fields::TUPLE,
&TupleValueSerializer {
tuple: self.tuple,
registry: self.registry,
},
)?;
state.end()
}
}
pub struct TupleValueSerializer<'a> {
pub tuple: &'a dyn Tuple,
pub registry: &'a TypeRegistry,
}
impl<'a> Serialize for TupleValueSerializer<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_seq(Some(self.tuple.field_len()))?;
for value in self.tuple.iter_fields() {
state.serialize_element(&ReflectSerializer::new(value, self.registry))?;
}
state.end()
}
}
pub struct MapSerializer<'a> {
pub map: &'a dyn Map,
pub registry: &'a TypeRegistry,

View File

@ -0,0 +1,310 @@
use std::any::Any;
use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef};
pub trait Tuple: Reflect {
fn field(&self, index: usize) -> Option<&dyn Reflect>;
fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>;
fn field_len(&self) -> usize;
fn iter_fields(&self) -> TupleFieldIter;
fn clone_dynamic(&self) -> DynamicTuple;
}
pub struct TupleFieldIter<'a> {
pub(crate) tuple: &'a dyn Tuple,
pub(crate) index: usize,
}
impl<'a> TupleFieldIter<'a> {
pub fn new(value: &'a dyn Tuple) -> Self {
TupleFieldIter {
tuple: value,
index: 0,
}
}
}
impl<'a> Iterator for TupleFieldIter<'a> {
type Item = &'a dyn Reflect;
fn next(&mut self) -> Option<Self::Item> {
let value = self.tuple.field(self.index);
self.index += 1;
value
}
}
pub trait GetTupleField {
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T>;
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T>;
}
impl<S: Tuple> GetTupleField 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 GetTupleField for dyn Tuple {
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>())
}
}
#[derive(Default)]
pub struct DynamicTuple {
pub(crate) fields: Vec<Box<dyn Reflect>>,
}
impl DynamicTuple {
pub fn insert_boxed(&mut self, value: Box<dyn Reflect>) {
self.fields.push(value);
}
pub fn insert<T: Reflect>(&mut self, value: T) {
self.insert_boxed(Box::new(value));
}
}
impl Tuple for DynamicTuple {
#[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) -> TupleFieldIter {
TupleFieldIter {
tuple: self,
index: 0,
}
}
#[inline]
fn clone_dynamic(&self) -> DynamicTuple {
DynamicTuple {
fields: self
.fields
.iter()
.map(|value| value.clone_value())
.collect(),
}
}
}
impl Reflect for DynamicTuple {
#[inline]
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[inline]
fn any(&self) -> &dyn Any {
self
}
#[inline]
fn any_mut(&mut self) -> &mut dyn Any {
self
}
#[inline]
fn clone_value(&self) -> Box<dyn Reflect> {
Box::new(self.clone_dynamic())
}
#[inline]
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Tuple(self)
}
#[inline]
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Tuple(self)
}
fn apply(&mut self, value: &dyn Reflect) {
tuple_apply(self, value);
}
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
fn reflect_hash(&self) -> Option<u64> {
None
}
fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
tuple_partial_eq(self, value)
}
fn serializable(&self) -> Option<Serializable> {
None
}
}
#[inline]
pub fn tuple_apply<T: Tuple>(a: &mut T, b: &dyn Reflect) {
if let ReflectRef::Tuple(tuple) = b.reflect_ref() {
for (i, value) in tuple.iter_fields().enumerate() {
if let Some(v) = a.field_mut(i) {
v.apply(value)
}
}
} else {
panic!("Attempted to apply non-Tuple type to Tuple type.");
}
}
#[inline]
pub fn tuple_partial_eq<T: Tuple>(a: &T, b: &dyn Reflect) -> Option<bool> {
let b = if let ReflectRef::Tuple(tuple) = b.reflect_ref() {
tuple
} else {
return Some(false);
};
if a.field_len() != b.field_len() {
return Some(false);
}
for (a_field, b_field) in a.iter_fields().zip(b.iter_fields()) {
match a_field.reflect_partial_eq(b_field) {
Some(false) | None => return Some(false),
Some(true) => {}
}
}
Some(true)
}
macro_rules! impl_reflect_tuple {
{$($index:tt : $name:tt),*} => {
impl<$($name: Reflect),*> Tuple for ($($name,)*) {
#[inline]
fn field(&self, index: usize) -> Option<&dyn Reflect> {
match index {
$($index => Some(&self.$index as &dyn Reflect),)*
_ => None,
}
}
#[inline]
fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {
match index {
$($index => Some(&mut self.$index as &mut dyn Reflect),)*
_ => None,
}
}
#[inline]
fn field_len(&self) -> usize {
let indices: &[usize] = &[$($index as usize),*];
indices.len()
}
#[inline]
fn iter_fields(&self) -> TupleFieldIter {
TupleFieldIter {
tuple: self,
index: 0,
}
}
#[inline]
fn clone_dynamic(&self) -> DynamicTuple {
DynamicTuple {
fields: self
.iter_fields()
.map(|value| value.clone_value())
.collect(),
}
}
}
impl<$($name: Reflect),*> Reflect for ($($name,)*) {
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
fn any(&self) -> &dyn Any {
self
}
fn any_mut(&mut self) -> &mut dyn Any {
self
}
fn apply(&mut self, value: &dyn Reflect) {
crate::tuple_apply(self, value);
}
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
*self = value.take()?;
Ok(())
}
fn reflect_ref(&self) -> ReflectRef {
ReflectRef::Tuple(self)
}
fn reflect_mut(&mut self) -> ReflectMut {
ReflectMut::Tuple(self)
}
fn clone_value(&self) -> Box<dyn Reflect> {
Box::new(self.clone_dynamic())
}
fn reflect_hash(&self) -> Option<u64> {
None
}
fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
crate::tuple_partial_eq(self, value)
}
fn serializable(&self) -> Option<Serializable> {
None
}
}
}
}
impl_reflect_tuple! {}
impl_reflect_tuple! {0: A}
impl_reflect_tuple! {0: A, 1: B}
impl_reflect_tuple! {0: A, 1: B, 2: C}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K}
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K, 11: L}

View File

@ -71,6 +71,10 @@ fn setup() {
// `TupleStruct` is a trait automatically implemented for tuple structs that derive Reflect. This trait allows you
// to interact with fields via their indices
ReflectRef::TupleStruct(_) => {}
// `Tuple` is a special trait that can be manually implemented (instead of deriving Reflect). This exposes "tuple"
// operations on your type, allowing you to interact with fields via their indices. Tuple is automatically
// implemented for tuples of arity 12 or less.
ReflectRef::Tuple(_) => {}
// `List` is a special trait that can be manually implemented (instead of deriving Reflect). This exposes "list"
// operations on your type, such as indexing and insertion. List is automatically implemented for relevant core
// types like Vec<T>