Path: blob/main/crates/bevy_reflect/src/serde/ser/mod.rs
9416 views
pub use processor::*;1pub use serializable::*;2pub use serialize_with_registry::*;3pub use serializer::*;45mod arrays;6mod custom_serialization;7mod enums;8mod error_utils;9mod lists;10mod maps;11mod processor;12mod serializable;13mod serialize_with_registry;14mod serializer;15mod sets;16mod structs;17mod tuple_structs;18mod tuples;1920#[cfg(test)]21mod tests {22use crate::{23serde::{ReflectSerializer, ReflectSerializerProcessor},24structs::Struct,25PartialReflect, Reflect, ReflectSerialize, TypeRegistry,26};27#[cfg(feature = "functions")]28use alloc::boxed::Box;29use alloc::{30string::{String, ToString},31vec,32vec::Vec,33};34use bevy_platform::collections::{HashMap, HashSet};35use core::{any::TypeId, f32::consts::PI, ops::RangeInclusive};36use ron::{extensions::Extensions, ser::PrettyConfig};37use serde::{Serialize, Serializer};3839#[derive(Reflect, Debug, PartialEq)]40struct MyStruct {41primitive_value: i8,42option_value: Option<String>,43option_value_complex: Option<SomeStruct>,44tuple_value: (f32, usize),45list_value: Vec<i32>,46array_value: [i32; 5],47map_value: HashMap<u8, usize>,48set_value: HashSet<u8>,49struct_value: SomeStruct,50tuple_struct_value: SomeTupleStruct,51unit_struct: SomeUnitStruct,52unit_enum: SomeEnum,53newtype_enum: SomeEnum,54tuple_enum: SomeEnum,55struct_enum: SomeEnum,56ignored_struct: SomeIgnoredStruct,57ignored_tuple_struct: SomeIgnoredTupleStruct,58ignored_struct_variant: SomeIgnoredEnum,59ignored_tuple_variant: SomeIgnoredEnum,60custom_serialize: CustomSerialize,61}6263#[derive(Reflect, Debug, PartialEq)]64struct SomeStruct {65foo: i64,66}6768#[derive(Reflect, Debug, PartialEq)]69struct SomeTupleStruct(String);7071#[derive(Reflect, Debug, PartialEq)]72struct SomeUnitStruct;7374#[derive(Reflect, Debug, PartialEq)]75struct SomeIgnoredStruct {76#[reflect(ignore)]77ignored: i32,78}7980#[derive(Reflect, Debug, PartialEq)]81struct SomeIgnoredTupleStruct(#[reflect(ignore)] i32);8283#[derive(Reflect, Debug, PartialEq)]84enum SomeEnum {85Unit,86NewType(usize),87Tuple(f32, f32),88Struct { foo: String },89}9091#[derive(Reflect, Debug, PartialEq)]92enum SomeIgnoredEnum {93Tuple(#[reflect(ignore)] f32, #[reflect(ignore)] f32),94Struct {95#[reflect(ignore)]96foo: String,97},98}99100#[derive(Reflect, Debug, PartialEq, Serialize)]101struct SomeSerializableStruct {102foo: i64,103}104105/// Implements a custom serialize using `#[reflect(Serialize)]`.106///107/// For testing purposes, this just uses the generated one from deriving Serialize.108#[derive(Reflect, Debug, PartialEq, Serialize)]109#[reflect(Serialize)]110struct CustomSerialize {111value: usize,112#[serde(rename = "renamed")]113inner_struct: SomeSerializableStruct,114}115116fn get_registry() -> TypeRegistry {117let mut registry = TypeRegistry::default();118registry.register::<MyStruct>();119registry.register::<SomeStruct>();120registry.register::<SomeTupleStruct>();121registry.register::<SomeUnitStruct>();122registry.register::<SomeIgnoredStruct>();123registry.register::<SomeIgnoredTupleStruct>();124registry.register::<SomeIgnoredEnum>();125registry.register::<CustomSerialize>();126registry.register::<SomeEnum>();127registry.register::<SomeSerializableStruct>();128registry.register_type_data::<SomeSerializableStruct, ReflectSerialize>();129registry.register::<String>();130registry.register::<Option<String>>();131registry.register_type_data::<Option<String>, ReflectSerialize>();132registry133}134135fn get_my_struct() -> MyStruct {136let mut map = <HashMap<_, _>>::default();137map.insert(64, 32);138139let mut set = <HashSet<_>>::default();140set.insert(64);141142MyStruct {143primitive_value: 123,144option_value: Some(String::from("Hello world!")),145option_value_complex: Some(SomeStruct { foo: 123 }),146tuple_value: (PI, 1337),147list_value: vec![-2, -1, 0, 1, 2],148array_value: [-2, -1, 0, 1, 2],149map_value: map,150set_value: set,151struct_value: SomeStruct { foo: 999999999 },152tuple_struct_value: SomeTupleStruct(String::from("Tuple Struct")),153unit_struct: SomeUnitStruct,154unit_enum: SomeEnum::Unit,155newtype_enum: SomeEnum::NewType(123),156tuple_enum: SomeEnum::Tuple(1.23, 3.21),157struct_enum: SomeEnum::Struct {158foo: String::from("Struct variant value"),159},160ignored_struct: SomeIgnoredStruct { ignored: 123 },161ignored_tuple_struct: SomeIgnoredTupleStruct(123),162ignored_struct_variant: SomeIgnoredEnum::Struct {163foo: String::from("Struct Variant"),164},165ignored_tuple_variant: SomeIgnoredEnum::Tuple(1.23, 3.45),166custom_serialize: CustomSerialize {167value: 100,168inner_struct: SomeSerializableStruct { foo: 101 },169},170}171}172173#[test]174fn should_serialize() {175let input = get_my_struct();176let registry = get_registry();177178let serializer = ReflectSerializer::new(&input, ®istry);179180let config = PrettyConfig::default()181.new_line(String::from("\n"))182.indentor(String::from(" "));183184let output = ron::ser::to_string_pretty(&serializer, config).unwrap();185let expected = r#"{186"bevy_reflect::serde::ser::tests::MyStruct": (187primitive_value: 123,188option_value: Some("Hello world!"),189option_value_complex: Some((190foo: 123,191)),192tuple_value: (3.1415927, 1337),193list_value: [194-2,195-1,1960,1971,1982,199],200array_value: (-2, -1, 0, 1, 2),201map_value: {20264: 32,203},204set_value: [20564,206],207struct_value: (208foo: 999999999,209),210tuple_struct_value: ("Tuple Struct"),211unit_struct: (),212unit_enum: Unit,213newtype_enum: NewType(123),214tuple_enum: Tuple(1.23, 3.21),215struct_enum: Struct(216foo: "Struct variant value",217),218ignored_struct: (),219ignored_tuple_struct: (),220ignored_struct_variant: Struct(),221ignored_tuple_variant: Tuple(),222custom_serialize: (223value: 100,224renamed: (225foo: 101,226),227),228),229}"#;230assert_eq!(expected, output);231}232233#[test]234fn should_serialize_option() {235#[derive(Reflect, Debug, PartialEq)]236struct OptionTest {237none: Option<()>,238simple: Option<String>,239complex: Option<SomeStruct>,240}241242let value = OptionTest {243none: None,244simple: Some(String::from("Hello world!")),245complex: Some(SomeStruct { foo: 123 }),246};247248let registry = get_registry();249let serializer = ReflectSerializer::new(&value, ®istry);250251// === Normal === //252let config = PrettyConfig::default()253.new_line(String::from("\n"))254.indentor(String::from(" "));255256let output = ron::ser::to_string_pretty(&serializer, config).unwrap();257let expected = r#"{258"bevy_reflect::serde::ser::tests::OptionTest": (259none: None,260simple: Some("Hello world!"),261complex: Some((262foo: 123,263)),264),265}"#;266267assert_eq!(expected, output);268269// === Implicit Some === //270let config = PrettyConfig::default()271.new_line(String::from("\n"))272.extensions(Extensions::IMPLICIT_SOME)273.indentor(String::from(" "));274275let output = ron::ser::to_string_pretty(&serializer, config).unwrap();276let expected = r#"#![enable(implicit_some)]277{278"bevy_reflect::serde::ser::tests::OptionTest": (279none: None,280simple: "Hello world!",281complex: (282foo: 123,283),284),285}"#;286287assert_eq!(expected, output);288}289290#[test]291fn enum_should_serialize() {292#[derive(Reflect)]293enum MyEnum {294Unit,295NewType(usize),296Tuple(f32, f32),297Struct { value: String },298}299300let mut registry = get_registry();301registry.register::<MyEnum>();302303let config = PrettyConfig::default().new_line(String::from("\n"));304305// === Unit Variant === //306let value = MyEnum::Unit;307let serializer = ReflectSerializer::new(&value, ®istry);308let output = ron::ser::to_string_pretty(&serializer, config.clone()).unwrap();309let expected = r#"{310"bevy_reflect::serde::ser::tests::MyEnum": Unit,311}"#;312assert_eq!(expected, output);313314// === NewType Variant === //315let value = MyEnum::NewType(123);316let serializer = ReflectSerializer::new(&value, ®istry);317let output = ron::ser::to_string_pretty(&serializer, config.clone()).unwrap();318let expected = r#"{319"bevy_reflect::serde::ser::tests::MyEnum": NewType(123),320}"#;321assert_eq!(expected, output);322323// === Tuple Variant === //324let value = MyEnum::Tuple(1.23, 3.21);325let serializer = ReflectSerializer::new(&value, ®istry);326let output = ron::ser::to_string_pretty(&serializer, config.clone()).unwrap();327let expected = r#"{328"bevy_reflect::serde::ser::tests::MyEnum": Tuple(1.23, 3.21),329}"#;330assert_eq!(expected, output);331332// === Struct Variant === //333let value = MyEnum::Struct {334value: String::from("I <3 Enums"),335};336let serializer = ReflectSerializer::new(&value, ®istry);337let output = ron::ser::to_string_pretty(&serializer, config).unwrap();338let expected = r#"{339"bevy_reflect::serde::ser::tests::MyEnum": Struct(340value: "I <3 Enums",341),342}"#;343assert_eq!(expected, output);344}345346#[test]347fn should_serialize_non_self_describing_binary() {348let input = get_my_struct();349let registry = get_registry();350351let serializer = ReflectSerializer::new(&input, ®istry);352353let mut postcard = postcard::Serializer {354output: postcard::ser_flavors::AllocVec::default(),355};356serializer.serialize(&mut postcard).unwrap();357let bytes = postcard::ser_flavors::Flavor::finalize(postcard.output).unwrap();358359let expected: Vec<u8> = vec![3601, 41, 98, 101, 118, 121, 95, 114, 101, 102, 108, 101, 99, 116, 58, 58, 115, 101, 114,361100, 101, 58, 58, 115, 101, 114, 58, 58, 116, 101, 115, 116, 115, 58, 58, 77, 121, 83,362116, 114, 117, 99, 116, 123, 1, 12, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108,363100, 33, 1, 246, 1, 219, 15, 73, 64, 185, 10, 5, 3, 1, 0, 2, 4, 3, 1, 0, 2, 4, 1, 64,36432, 1, 64, 254, 167, 214, 185, 7, 12, 84, 117, 112, 108, 101, 32, 83, 116, 114, 117,36599, 116, 0, 1, 123, 2, 164, 112, 157, 63, 164, 112, 77, 64, 3, 20, 83, 116, 114, 117,36699, 116, 32, 118, 97, 114, 105, 97, 110, 116, 32, 118, 97, 108, 117, 101, 1, 0, 100,367202, 1,368];369370assert_eq!(expected, bytes);371}372373#[test]374fn should_serialize_self_describing_binary() {375let input = get_my_struct();376let registry = get_registry();377378let serializer = ReflectSerializer::new(&input, ®istry);379let bytes: Vec<u8> = rmp_serde::to_vec(&serializer).unwrap();380381let expected: Vec<u8> = vec![382129, 217, 41, 98, 101, 118, 121, 95, 114, 101, 102, 108, 101, 99, 116, 58, 58, 115,383101, 114, 100, 101, 58, 58, 115, 101, 114, 58, 58, 116, 101, 115, 116, 115, 58, 58, 77,384121, 83, 116, 114, 117, 99, 116, 220, 0, 20, 123, 172, 72, 101, 108, 108, 111, 32, 119,385111, 114, 108, 100, 33, 145, 123, 146, 202, 64, 73, 15, 219, 205, 5, 57, 149, 254, 255,3860, 1, 2, 149, 254, 255, 0, 1, 2, 129, 64, 32, 145, 64, 145, 206, 59, 154, 201, 255,387172, 84, 117, 112, 108, 101, 32, 83, 116, 114, 117, 99, 116, 144, 164, 85, 110, 105,388116, 129, 167, 78, 101, 119, 84, 121, 112, 101, 123, 129, 165, 84, 117, 112, 108, 101,389146, 202, 63, 157, 112, 164, 202, 64, 77, 112, 164, 129, 166, 83, 116, 114, 117, 99,390116, 145, 180, 83, 116, 114, 117, 99, 116, 32, 118, 97, 114, 105, 97, 110, 116, 32,391118, 97, 108, 117, 101, 144, 144, 129, 166, 83, 116, 114, 117, 99, 116, 144, 129, 165,39284, 117, 112, 108, 101, 144, 146, 100, 145, 101,393];394395assert_eq!(expected, bytes);396}397398#[test]399fn should_serialize_dynamic_option() {400#[derive(Default, Reflect)]401struct OtherStruct {402some: Option<SomeStruct>,403none: Option<SomeStruct>,404}405406let value = OtherStruct {407some: Some(SomeStruct { foo: 999999999 }),408none: None,409};410let dynamic = value.to_dynamic_struct();411let reflect = dynamic.as_partial_reflect();412413let registry = get_registry();414415let serializer = ReflectSerializer::new(reflect, ®istry);416417let mut buf = Vec::new();418419let format = serde_json::ser::PrettyFormatter::with_indent(b" ");420let mut ser = serde_json::Serializer::with_formatter(&mut buf, format);421422serializer.serialize(&mut ser).unwrap();423424let output = core::str::from_utf8(&buf).unwrap();425let expected = r#"{426"bevy_reflect::serde::ser::tests::OtherStruct": {427"some": {428"foo": 999999999429},430"none": null431}432}"#;433434assert_eq!(expected, output);435}436437#[test]438fn should_return_error_if_missing_registration() {439let value = RangeInclusive::<f32>::new(0.0, 1.0);440let registry = TypeRegistry::new();441442let serializer = ReflectSerializer::new(&value, ®istry);443let error = ron::ser::to_string(&serializer).unwrap_err();444#[cfg(feature = "debug_stack")]445assert_eq!(446error,447ron::Error::Message(448"type `core::ops::RangeInclusive<f32>` is not registered in the type registry (stack: `core::ops::RangeInclusive<f32>`)"449.to_string(),450)451);452#[cfg(not(feature = "debug_stack"))]453assert_eq!(454error,455ron::Error::Message(456"type `core::ops::RangeInclusive<f32>` is not registered in the type registry"457.to_string(),458)459);460}461462#[test]463fn should_return_error_if_missing_type_data() {464let value = RangeInclusive::<f32>::new(0.0, 1.0);465let mut registry = TypeRegistry::new();466registry.register::<RangeInclusive<f32>>();467468let serializer = ReflectSerializer::new(&value, ®istry);469let error = ron::ser::to_string(&serializer).unwrap_err();470#[cfg(feature = "debug_stack")]471assert_eq!(472error,473ron::Error::Message(474"type `core::ops::RangeInclusive<f32>` did not register the `ReflectSerialize` or `ReflectSerializeWithRegistry` type data. For certain types, this may need to be registered manually using `register_type_data` (stack: `core::ops::RangeInclusive<f32>`)".to_string()475)476);477#[cfg(not(feature = "debug_stack"))]478assert_eq!(479error,480ron::Error::Message(481"type `core::ops::RangeInclusive<f32>` did not register the `ReflectSerialize` type data. For certain types, this may need to be registered manually using `register_type_data`".to_string()482)483);484}485486#[test]487fn should_use_processor_for_custom_serialization() {488#[derive(Reflect, Debug, PartialEq)]489struct Foo {490bar: i32,491qux: i64,492}493494struct FooProcessor;495496impl ReflectSerializerProcessor for FooProcessor {497fn try_serialize<S>(498&self,499value: &dyn PartialReflect,500_: &TypeRegistry,501serializer: S,502) -> Result<Result<S::Ok, S>, S::Error>503where504S: Serializer,505{506let Some(value) = value.try_as_reflect() else {507return Ok(Err(serializer));508};509510let type_id = value.reflect_type_info().type_id();511if type_id == TypeId::of::<i64>() {512Ok(Ok(serializer.serialize_str("custom!")?))513} else {514Ok(Err(serializer))515}516}517}518519let value = Foo { bar: 123, qux: 456 };520521let mut registry = TypeRegistry::new();522registry.register::<Foo>();523524let processor = FooProcessor;525let serializer = ReflectSerializer::with_processor(&value, ®istry, &processor);526527let config = PrettyConfig::default().new_line(String::from("\n"));528let output = ron::ser::to_string_pretty(&serializer, config).unwrap();529530let expected = r#"{531"bevy_reflect::serde::ser::tests::Foo": (532bar: 123,533qux: "custom!",534),535}"#;536537assert_eq!(expected, output);538}539540#[test]541fn should_use_processor_for_multiple_registrations() {542#[derive(Reflect, Debug, PartialEq)]543struct Foo {544bar: i32,545sub: SubFoo,546}547548#[derive(Reflect, Debug, PartialEq)]549struct SubFoo {550val: i32,551}552553struct FooProcessor;554555impl ReflectSerializerProcessor for FooProcessor {556fn try_serialize<S>(557&self,558value: &dyn PartialReflect,559_: &TypeRegistry,560serializer: S,561) -> Result<Result<S::Ok, S>, S::Error>562where563S: Serializer,564{565let Some(value) = value.try_as_reflect() else {566return Ok(Err(serializer));567};568569let type_id = value.reflect_type_info().type_id();570if type_id == TypeId::of::<i32>() {571Ok(Ok(serializer.serialize_str("an i32")?))572} else if type_id == TypeId::of::<SubFoo>() {573Ok(Ok(serializer.serialize_str("a SubFoo")?))574} else {575Ok(Err(serializer))576}577}578}579580let value = Foo {581bar: 123,582sub: SubFoo { val: 456 },583};584585let mut registry = TypeRegistry::new();586registry.register::<Foo>();587registry.register::<SubFoo>();588589let processor = FooProcessor;590let serializer = ReflectSerializer::with_processor(&value, ®istry, &processor);591592let config = PrettyConfig::default().new_line(String::from("\n"));593let output = ron::ser::to_string_pretty(&serializer, config).unwrap();594595let expected = r#"{596"bevy_reflect::serde::ser::tests::Foo": (597bar: "an i32",598sub: "a SubFoo",599),600}"#;601602assert_eq!(expected, output);603}604605#[test]606fn should_propagate_processor_serialize_error() {607struct ErroringProcessor;608609impl ReflectSerializerProcessor for ErroringProcessor {610fn try_serialize<S>(611&self,612value: &dyn PartialReflect,613_: &TypeRegistry,614serializer: S,615) -> Result<Result<S::Ok, S>, S::Error>616where617S: Serializer,618{619let Some(value) = value.try_as_reflect() else {620return Ok(Err(serializer));621};622623let type_id = value.reflect_type_info().type_id();624if type_id == TypeId::of::<i32>() {625Err(serde::ser::Error::custom("my custom serialize error"))626} else {627Ok(Err(serializer))628}629}630}631632let value = 123_i32;633634let registry = TypeRegistry::new();635636let processor = ErroringProcessor;637let serializer = ReflectSerializer::with_processor(&value, ®istry, &processor);638let error = ron::ser::to_string_pretty(&serializer, PrettyConfig::default()).unwrap_err();639640#[cfg(feature = "debug_stack")]641assert_eq!(642error,643ron::Error::Message("my custom serialize error (stack: `i32`)".to_string())644);645#[cfg(not(feature = "debug_stack"))]646assert_eq!(647error,648ron::Error::Message("my custom serialize error".to_string())649);650}651652#[cfg(feature = "functions")]653mod functions {654use super::*;655use crate::func::{DynamicFunction, IntoFunction};656use alloc::string::ToString;657658#[test]659fn should_not_serialize_function() {660#[derive(Reflect)]661#[reflect(from_reflect = false)]662struct MyStruct {663func: DynamicFunction<'static>,664}665666let value: Box<dyn Reflect> = Box::new(MyStruct {667func: String::new.into_function(),668});669670let registry = TypeRegistry::new();671let serializer = ReflectSerializer::new(value.as_partial_reflect(), ®istry);672673let error = ron::ser::to_string(&serializer).unwrap_err();674675#[cfg(feature = "debug_stack")]676assert_eq!(677error,678ron::Error::Message("functions cannot be serialized (stack: `bevy_reflect::serde::ser::tests::functions::MyStruct`)".to_string())679);680681#[cfg(not(feature = "debug_stack"))]682assert_eq!(683error,684ron::Error::Message("functions cannot be serialized".to_string())685);686}687}688689#[cfg(feature = "debug_stack")]690mod debug_stack {691use super::*;692693#[test]694fn should_report_context_in_errors() {695#[derive(Reflect)]696struct Foo {697bar: Bar,698}699700#[derive(Reflect)]701struct Bar {702some_other_field: Option<u32>,703baz: Baz,704}705706#[derive(Reflect)]707struct Baz {708value: Vec<RangeInclusive<f32>>,709}710711let value = Foo {712bar: Bar {713some_other_field: Some(123),714baz: Baz {715value: vec![0.0..=1.0],716},717},718};719720let registry = TypeRegistry::new();721let serializer = ReflectSerializer::new(&value, ®istry);722723let error = ron::ser::to_string(&serializer).unwrap_err();724assert_eq!(725error,726ron::Error::Message(727"type `core::ops::RangeInclusive<f32>` is not registered in the type registry (stack: `bevy_reflect::serde::ser::tests::debug_stack::Foo` -> `bevy_reflect::serde::ser::tests::debug_stack::Bar` -> `bevy_reflect::serde::ser::tests::debug_stack::Baz` -> `alloc::vec::Vec<core::ops::RangeInclusive<f32>>` -> `core::ops::RangeInclusive<f32>`)".to_string()728)729);730}731}732}733734735