Skip to content

Commit

Permalink
Implement Reflect for tuples up to length 12 (bevyengine#1218)
Browse files Browse the repository at this point in the history
Add Reflect impls for tuples up to length 12
  • Loading branch information
TehPers authored and rparrett committed Jan 27, 2021
1 parent 07e627f commit 58054da
Show file tree
Hide file tree
Showing 7 changed files with 435 additions and 6 deletions.
18 changes: 16 additions & 2 deletions crates/bevy_reflect/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod map;
mod path;
mod reflect;
mod struct_trait;
mod tuple;
mod tuple_struct;
mod type_registry;
mod type_uuid;
Expand Down Expand Up @@ -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::*;
Expand Down Expand Up @@ -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)]
Expand All @@ -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();
Expand All @@ -234,15 +238,21 @@ 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);
foo_patch.insert("d", map);

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);

Expand All @@ -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);
Expand All @@ -271,6 +282,7 @@ mod tests {
d: HashMap<usize, i8>,
e: Bar,
f: String,
g: (i32, Vec<isize>, Bar),
}

#[derive(Reflect)]
Expand All @@ -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();
Expand All @@ -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();
Expand Down
4 changes: 3 additions & 1 deletion crates/bevy_reflect/src/reflect.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
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;

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),
Expand All @@ -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),
Expand Down
55 changes: 53 additions & 2 deletions crates/bevy_reflect/src/serde/de.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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)
}
}
1 change: 1 addition & 0 deletions crates/bevy_reflect/src/serde/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
49 changes: 48 additions & 1 deletion crates/bevy_reflect/src/serde/ser.rs
Original file line number Diff line number Diff line change
@@ -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},
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
Loading

0 comments on commit 58054da

Please sign in to comment.