Path: blob/main/crates/bevy_reflect/src/serde/ser/mod.rs
6600 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},24PartialReflect, Reflect, ReflectSerialize, Struct, TypeRegistry,25};26#[cfg(feature = "functions")]27use alloc::boxed::Box;28use alloc::{29string::{String, ToString},30vec,31vec::Vec,32};33use bevy_platform::collections::{HashMap, HashSet};34use core::{any::TypeId, f32::consts::PI, ops::RangeInclusive};35use ron::{extensions::Extensions, ser::PrettyConfig};36use serde::{Serialize, Serializer};3738#[derive(Reflect, Debug, PartialEq)]39struct MyStruct {40primitive_value: i8,41option_value: Option<String>,42option_value_complex: Option<SomeStruct>,43tuple_value: (f32, usize),44list_value: Vec<i32>,45array_value: [i32; 5],46map_value: HashMap<u8, usize>,47set_value: HashSet<u8>,48struct_value: SomeStruct,49tuple_struct_value: SomeTupleStruct,50unit_struct: SomeUnitStruct,51unit_enum: SomeEnum,52newtype_enum: SomeEnum,53tuple_enum: SomeEnum,54struct_enum: SomeEnum,55ignored_struct: SomeIgnoredStruct,56ignored_tuple_struct: SomeIgnoredTupleStruct,57ignored_struct_variant: SomeIgnoredEnum,58ignored_tuple_variant: SomeIgnoredEnum,59custom_serialize: CustomSerialize,60}6162#[derive(Reflect, Debug, PartialEq)]63struct SomeStruct {64foo: i64,65}6667#[derive(Reflect, Debug, PartialEq)]68struct SomeTupleStruct(String);6970#[derive(Reflect, Debug, PartialEq)]71struct SomeUnitStruct;7273#[derive(Reflect, Debug, PartialEq)]74struct SomeIgnoredStruct {75#[reflect(ignore)]76ignored: i32,77}7879#[derive(Reflect, Debug, PartialEq)]80struct SomeIgnoredTupleStruct(#[reflect(ignore)] i32);8182#[derive(Reflect, Debug, PartialEq)]83enum SomeEnum {84Unit,85NewType(usize),86Tuple(f32, f32),87Struct { foo: String },88}8990#[derive(Reflect, Debug, PartialEq)]91enum SomeIgnoredEnum {92Tuple(#[reflect(ignore)] f32, #[reflect(ignore)] f32),93Struct {94#[reflect(ignore)]95foo: String,96},97}9899#[derive(Reflect, Debug, PartialEq, Serialize)]100struct SomeSerializableStruct {101foo: i64,102}103104/// Implements a custom serialize using `#[reflect(Serialize)]`.105///106/// For testing purposes, this just uses the generated one from deriving Serialize.107#[derive(Reflect, Debug, PartialEq, Serialize)]108#[reflect(Serialize)]109struct CustomSerialize {110value: usize,111#[serde(rename = "renamed")]112inner_struct: SomeSerializableStruct,113}114115fn get_registry() -> TypeRegistry {116let mut registry = TypeRegistry::default();117registry.register::<MyStruct>();118registry.register::<SomeStruct>();119registry.register::<SomeTupleStruct>();120registry.register::<SomeUnitStruct>();121registry.register::<SomeIgnoredStruct>();122registry.register::<SomeIgnoredTupleStruct>();123registry.register::<SomeIgnoredEnum>();124registry.register::<CustomSerialize>();125registry.register::<SomeEnum>();126registry.register::<SomeSerializableStruct>();127registry.register_type_data::<SomeSerializableStruct, ReflectSerialize>();128registry.register::<String>();129registry.register::<Option<String>>();130registry.register_type_data::<Option<String>, ReflectSerialize>();131registry132}133134fn get_my_struct() -> MyStruct {135let mut map = <HashMap<_, _>>::default();136map.insert(64, 32);137138let mut set = <HashSet<_>>::default();139set.insert(64);140141MyStruct {142primitive_value: 123,143option_value: Some(String::from("Hello world!")),144option_value_complex: Some(SomeStruct { foo: 123 }),145tuple_value: (PI, 1337),146list_value: vec![-2, -1, 0, 1, 2],147array_value: [-2, -1, 0, 1, 2],148map_value: map,149set_value: set,150struct_value: SomeStruct { foo: 999999999 },151tuple_struct_value: SomeTupleStruct(String::from("Tuple Struct")),152unit_struct: SomeUnitStruct,153unit_enum: SomeEnum::Unit,154newtype_enum: SomeEnum::NewType(123),155tuple_enum: SomeEnum::Tuple(1.23, 3.21),156struct_enum: SomeEnum::Struct {157foo: String::from("Struct variant value"),158},159ignored_struct: SomeIgnoredStruct { ignored: 123 },160ignored_tuple_struct: SomeIgnoredTupleStruct(123),161ignored_struct_variant: SomeIgnoredEnum::Struct {162foo: String::from("Struct Variant"),163},164ignored_tuple_variant: SomeIgnoredEnum::Tuple(1.23, 3.45),165custom_serialize: CustomSerialize {166value: 100,167inner_struct: SomeSerializableStruct { foo: 101 },168},169}170}171172#[test]173fn should_serialize() {174let input = get_my_struct();175let registry = get_registry();176177let serializer = ReflectSerializer::new(&input, ®istry);178179let config = PrettyConfig::default()180.new_line(String::from("\n"))181.indentor(String::from(" "));182183let output = ron::ser::to_string_pretty(&serializer, config).unwrap();184let expected = r#"{185"bevy_reflect::serde::ser::tests::MyStruct": (186primitive_value: 123,187option_value: Some("Hello world!"),188option_value_complex: Some((189foo: 123,190)),191tuple_value: (3.1415927, 1337),192list_value: [193-2,194-1,1950,1961,1972,198],199array_value: (-2, -1, 0, 1, 2),200map_value: {20164: 32,202},203set_value: [20464,205],206struct_value: (207foo: 999999999,208),209tuple_struct_value: ("Tuple Struct"),210unit_struct: (),211unit_enum: Unit,212newtype_enum: NewType(123),213tuple_enum: Tuple(1.23, 3.21),214struct_enum: Struct(215foo: "Struct variant value",216),217ignored_struct: (),218ignored_tuple_struct: (),219ignored_struct_variant: Struct(),220ignored_tuple_variant: Tuple(),221custom_serialize: (222value: 100,223renamed: (224foo: 101,225),226),227),228}"#;229assert_eq!(expected, output);230}231232#[test]233fn should_serialize_option() {234#[derive(Reflect, Debug, PartialEq)]235struct OptionTest {236none: Option<()>,237simple: Option<String>,238complex: Option<SomeStruct>,239}240241let value = OptionTest {242none: None,243simple: Some(String::from("Hello world!")),244complex: Some(SomeStruct { foo: 123 }),245};246247let registry = get_registry();248let serializer = ReflectSerializer::new(&value, ®istry);249250// === Normal === //251let config = PrettyConfig::default()252.new_line(String::from("\n"))253.indentor(String::from(" "));254255let output = ron::ser::to_string_pretty(&serializer, config).unwrap();256let expected = r#"{257"bevy_reflect::serde::ser::tests::OptionTest": (258none: None,259simple: Some("Hello world!"),260complex: Some((261foo: 123,262)),263),264}"#;265266assert_eq!(expected, output);267268// === Implicit Some === //269let config = PrettyConfig::default()270.new_line(String::from("\n"))271.extensions(Extensions::IMPLICIT_SOME)272.indentor(String::from(" "));273274let output = ron::ser::to_string_pretty(&serializer, config).unwrap();275let expected = r#"#![enable(implicit_some)]276{277"bevy_reflect::serde::ser::tests::OptionTest": (278none: None,279simple: "Hello world!",280complex: (281foo: 123,282),283),284}"#;285286assert_eq!(expected, output);287}288289#[test]290fn enum_should_serialize() {291#[derive(Reflect)]292enum MyEnum {293Unit,294NewType(usize),295Tuple(f32, f32),296Struct { value: String },297}298299let mut registry = get_registry();300registry.register::<MyEnum>();301302let config = PrettyConfig::default().new_line(String::from("\n"));303304// === Unit Variant === //305let value = MyEnum::Unit;306let serializer = ReflectSerializer::new(&value, ®istry);307let output = ron::ser::to_string_pretty(&serializer, config.clone()).unwrap();308let expected = r#"{309"bevy_reflect::serde::ser::tests::MyEnum": Unit,310}"#;311assert_eq!(expected, output);312313// === NewType Variant === //314let value = MyEnum::NewType(123);315let serializer = ReflectSerializer::new(&value, ®istry);316let output = ron::ser::to_string_pretty(&serializer, config.clone()).unwrap();317let expected = r#"{318"bevy_reflect::serde::ser::tests::MyEnum": NewType(123),319}"#;320assert_eq!(expected, output);321322// === Tuple Variant === //323let value = MyEnum::Tuple(1.23, 3.21);324let serializer = ReflectSerializer::new(&value, ®istry);325let output = ron::ser::to_string_pretty(&serializer, config.clone()).unwrap();326let expected = r#"{327"bevy_reflect::serde::ser::tests::MyEnum": Tuple(1.23, 3.21),328}"#;329assert_eq!(expected, output);330331// === Struct Variant === //332let value = MyEnum::Struct {333value: String::from("I <3 Enums"),334};335let serializer = ReflectSerializer::new(&value, ®istry);336let output = ron::ser::to_string_pretty(&serializer, config).unwrap();337let expected = r#"{338"bevy_reflect::serde::ser::tests::MyEnum": Struct(339value: "I <3 Enums",340),341}"#;342assert_eq!(expected, output);343}344345#[test]346fn should_serialize_non_self_describing_binary() {347let input = get_my_struct();348let registry = get_registry();349350let serializer = ReflectSerializer::new(&input, ®istry);351let config = bincode::config::standard().with_fixed_int_encoding();352let bytes = bincode::serde::encode_to_vec(&serializer, config).unwrap();353354let expected: Vec<u8> = vec![3551, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 98, 101, 118, 121, 95, 114, 101, 102,356108, 101, 99, 116, 58, 58, 115, 101, 114, 100, 101, 58, 58, 115, 101, 114, 58, 58, 116,357101, 115, 116, 115, 58, 58, 77, 121, 83, 116, 114, 117, 99, 116, 123, 1, 12, 0, 0, 0,3580, 0, 0, 0, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 1, 123, 0, 0, 0,3590, 0, 0, 0, 219, 15, 73, 64, 57, 5, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 254, 255,360255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 254, 255, 255, 255,361255, 255, 255, 255, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 64, 32,3620, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 64, 255, 201, 154, 59, 0, 0, 0, 0, 12, 0,3630, 0, 0, 0, 0, 0, 84, 117, 112, 108, 101, 32, 83, 116, 114, 117, 99, 116, 0, 0, 0, 0,3641, 0, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 164, 112, 157, 63, 164, 112, 77, 64,3653, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 83, 116, 114, 117, 99, 116, 32, 118, 97, 114, 105,36697, 110, 116, 32, 118, 97, 108, 117, 101, 1, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0,3670, 0, 101, 0, 0, 0, 0, 0, 0, 0,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