@@ -268,6 +268,22 @@ impl<'a, 'de> Visitor<'de> for SceneEntityVisitor<'a> {
268
268
formatter. write_str ( "entities" )
269
269
}
270
270
271
+ fn visit_seq < A > ( self , mut seq : A ) -> std:: result:: Result < Self :: Value , A :: Error >
272
+ where
273
+ A : SeqAccess < ' de > ,
274
+ {
275
+ let entity = seq
276
+ . next_element :: < u32 > ( ) ?
277
+ . ok_or_else ( || Error :: missing_field ( ENTITY_FIELD_ENTITY ) ) ?;
278
+ let components = seq
279
+ . next_element_seed ( ComponentDeserializer {
280
+ registry : self . registry ,
281
+ } ) ?
282
+ . ok_or_else ( || Error :: missing_field ( ENTITY_FIELD_COMPONENTS ) ) ?;
283
+
284
+ Ok ( DynamicEntity { entity, components } )
285
+ }
286
+
271
287
fn visit_map < A > ( self , mut map : A ) -> Result < Self :: Value , A :: Error >
272
288
where
273
289
A : MapAccess < ' de > ,
@@ -376,12 +392,13 @@ impl<'a, 'de> Visitor<'de> for ComponentVisitor<'a> {
376
392
377
393
#[ cfg( test) ]
378
394
mod tests {
379
- use crate :: serde:: SceneDeserializer ;
380
- use crate :: DynamicSceneBuilder ;
395
+ use crate :: serde:: { SceneDeserializer , SceneSerializer } ;
396
+ use crate :: { DynamicScene , DynamicSceneBuilder } ;
381
397
use bevy_app:: AppTypeRegistry ;
382
398
use bevy_ecs:: entity:: EntityMap ;
383
399
use bevy_ecs:: prelude:: { Component , ReflectComponent , World } ;
384
- use bevy_reflect:: Reflect ;
400
+ use bevy_reflect:: { FromReflect , Reflect , ReflectSerialize } ;
401
+ use bincode:: Options ;
385
402
use serde:: de:: DeserializeSeed ;
386
403
387
404
#[ derive( Component , Reflect , Default ) ]
@@ -394,6 +411,24 @@ mod tests {
394
411
#[ reflect( Component ) ]
395
412
struct Baz ( i32 ) ;
396
413
414
+ #[ derive( Component , Reflect , Default ) ]
415
+ #[ reflect( Component ) ]
416
+ struct MyComponent {
417
+ foo : [ usize ; 3 ] ,
418
+ bar : ( f32 , f32 ) ,
419
+ baz : MyEnum ,
420
+ }
421
+
422
+ #[ derive( Reflect , FromReflect , Default ) ]
423
+ enum MyEnum {
424
+ #[ default]
425
+ Unit ,
426
+ Tuple ( String ) ,
427
+ Struct {
428
+ value : u32 ,
429
+ } ,
430
+ }
431
+
397
432
fn create_world ( ) -> World {
398
433
let mut world = World :: new ( ) ;
399
434
let registry = AppTypeRegistry :: default ( ) ;
@@ -402,6 +437,12 @@ mod tests {
402
437
registry. register :: < Foo > ( ) ;
403
438
registry. register :: < Bar > ( ) ;
404
439
registry. register :: < Baz > ( ) ;
440
+ registry. register :: < MyComponent > ( ) ;
441
+ registry. register :: < MyEnum > ( ) ;
442
+ registry. register :: < String > ( ) ;
443
+ registry. register_type_data :: < String , ReflectSerialize > ( ) ;
444
+ registry. register :: < [ usize ; 3 ] > ( ) ;
445
+ registry. register :: < ( f32 , f32 ) > ( ) ;
405
446
}
406
447
world. insert_resource ( registry) ;
407
448
world
@@ -499,4 +540,198 @@ mod tests {
499
540
assert_eq ! ( 2 , dst_world. query:: <& Bar >( ) . iter( & dst_world) . count( ) ) ;
500
541
assert_eq ! ( 1 , dst_world. query:: <& Baz >( ) . iter( & dst_world) . count( ) ) ;
501
542
}
543
+
544
+ #[ test]
545
+ fn should_roundtrip_postcard ( ) {
546
+ let mut world = create_world ( ) ;
547
+
548
+ world. spawn ( MyComponent {
549
+ foo : [ 1 , 2 , 3 ] ,
550
+ bar : ( 1.3 , 3.7 ) ,
551
+ baz : MyEnum :: Tuple ( "Hello World!" . to_string ( ) ) ,
552
+ } ) ;
553
+
554
+ let registry = world. resource :: < AppTypeRegistry > ( ) ;
555
+
556
+ let scene = DynamicScene :: from_world ( & world, registry) ;
557
+
558
+ let scene_serializer = SceneSerializer :: new ( & scene, & registry. 0 ) ;
559
+ let serialized_scene = postcard:: to_allocvec ( & scene_serializer) . unwrap ( ) ;
560
+
561
+ assert_eq ! (
562
+ vec![
563
+ 1 , 0 , 1 , 37 , 98 , 101 , 118 , 121 , 95 , 115 , 99 , 101 , 110 , 101 , 58 , 58 , 115 , 101 , 114 ,
564
+ 100 , 101 , 58 , 58 , 116 , 101 , 115 , 116 , 115 , 58 , 58 , 77 , 121 , 67 , 111 , 109 , 112 , 111 ,
565
+ 110 , 101 , 110 , 116 , 1 , 2 , 3 , 102 , 102 , 166 , 63 , 205 , 204 , 108 , 64 , 1 , 12 , 72 , 101 ,
566
+ 108 , 108 , 111 , 32 , 87 , 111 , 114 , 108 , 100 , 33
567
+ ] ,
568
+ serialized_scene
569
+ ) ;
570
+
571
+ let scene_deserializer = SceneDeserializer {
572
+ type_registry : & registry. 0 . read ( ) ,
573
+ } ;
574
+ let deserialized_scene = scene_deserializer
575
+ . deserialize ( & mut postcard:: Deserializer :: from_bytes ( & serialized_scene) )
576
+ . unwrap ( ) ;
577
+
578
+ assert_eq ! ( 1 , deserialized_scene. entities. len( ) ) ;
579
+ assert_scene_eq ( & scene, & deserialized_scene) ;
580
+ }
581
+
582
+ #[ test]
583
+ fn should_roundtrip_bincode ( ) {
584
+ let mut world = create_world ( ) ;
585
+
586
+ world. spawn ( MyComponent {
587
+ foo : [ 1 , 2 , 3 ] ,
588
+ bar : ( 1.3 , 3.7 ) ,
589
+ baz : MyEnum :: Tuple ( "Hello World!" . to_string ( ) ) ,
590
+ } ) ;
591
+
592
+ let registry = world. resource :: < AppTypeRegistry > ( ) ;
593
+
594
+ let scene = DynamicScene :: from_world ( & world, registry) ;
595
+
596
+ let scene_serializer = SceneSerializer :: new ( & scene, & registry. 0 ) ;
597
+ let serialized_scene = bincode:: serialize ( & scene_serializer) . unwrap ( ) ;
598
+
599
+ assert_eq ! (
600
+ vec![
601
+ 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 37 , 0 , 0 , 0 , 0 , 0 , 0 ,
602
+ 0 , 98 , 101 , 118 , 121 , 95 , 115 , 99 , 101 , 110 , 101 , 58 , 58 , 115 , 101 , 114 , 100 , 101 ,
603
+ 58 , 58 , 116 , 101 , 115 , 116 , 115 , 58 , 58 , 77 , 121 , 67 , 111 , 109 , 112 , 111 , 110 , 101 ,
604
+ 110 , 116 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
605
+ 102 , 102 , 166 , 63 , 205 , 204 , 108 , 64 , 1 , 0 , 0 , 0 , 12 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 72 , 101 ,
606
+ 108 , 108 , 111 , 32 , 87 , 111 , 114 , 108 , 100 , 33
607
+ ] ,
608
+ serialized_scene
609
+ ) ;
610
+
611
+ let scene_deserializer = SceneDeserializer {
612
+ type_registry : & registry. 0 . read ( ) ,
613
+ } ;
614
+
615
+ let deserialized_scene = bincode:: DefaultOptions :: new ( )
616
+ . with_fixint_encoding ( )
617
+ . deserialize_seed ( scene_deserializer, & serialized_scene)
618
+ . unwrap ( ) ;
619
+
620
+ assert_eq ! ( 1 , deserialized_scene. entities. len( ) ) ;
621
+ assert_scene_eq ( & scene, & deserialized_scene) ;
622
+ }
623
+
624
+ /// A crude equality checker for [`DynamicScene`], used solely for testing purposes.
625
+ fn assert_scene_eq ( expected : & DynamicScene , received : & DynamicScene ) {
626
+ assert_eq ! (
627
+ expected. entities. len( ) ,
628
+ received. entities. len( ) ,
629
+ "entity count did not match" ,
630
+ ) ;
631
+
632
+ for expected in & expected. entities {
633
+ let received = received
634
+ . entities
635
+ . iter ( )
636
+ . find ( |dynamic_entity| dynamic_entity. entity == expected. entity )
637
+ . unwrap_or_else ( || panic ! ( "missing entity (expected: `{}`)" , expected. entity) ) ;
638
+
639
+ assert_eq ! ( expected. entity, received. entity, "entities did not match" , ) ;
640
+
641
+ for expected in & expected. components {
642
+ let received = received
643
+ . components
644
+ . iter ( )
645
+ . find ( |component| component. type_name ( ) == expected. type_name ( ) )
646
+ . unwrap_or_else ( || {
647
+ panic ! ( "missing component (expected: `{}`)" , expected. type_name( ) )
648
+ } ) ;
649
+
650
+ assert ! (
651
+ expected
652
+ . reflect_partial_eq( received. as_ref( ) )
653
+ . unwrap_or_default( ) ,
654
+ "components did not match: (expected: `{:?}`, received: `{:?}`)" ,
655
+ expected,
656
+ received
657
+ ) ;
658
+ }
659
+ }
660
+ }
661
+
662
+ /// These tests just verify that that the [`assert_scene_eq`] function is working properly for our tests.
663
+ mod assert_scene_eq_tests {
664
+ use super :: * ;
665
+
666
+ #[ test]
667
+ #[ should_panic( expected = "entity count did not match" ) ]
668
+ fn should_panic_when_entity_count_not_eq ( ) {
669
+ let mut world = create_world ( ) ;
670
+ let registry = world. resource :: < AppTypeRegistry > ( ) ;
671
+ let scene_a = DynamicScene :: from_world ( & world, registry) ;
672
+
673
+ world. spawn ( MyComponent {
674
+ foo : [ 1 , 2 , 3 ] ,
675
+ bar : ( 1.3 , 3.7 ) ,
676
+ baz : MyEnum :: Unit ,
677
+ } ) ;
678
+
679
+ let registry = world. resource :: < AppTypeRegistry > ( ) ;
680
+ let scene_b = DynamicScene :: from_world ( & world, registry) ;
681
+
682
+ assert_scene_eq ( & scene_a, & scene_b) ;
683
+ }
684
+
685
+ #[ test]
686
+ #[ should_panic( expected = "components did not match" ) ]
687
+ fn should_panic_when_components_not_eq ( ) {
688
+ let mut world = create_world ( ) ;
689
+
690
+ let entity = world
691
+ . spawn ( MyComponent {
692
+ foo : [ 1 , 2 , 3 ] ,
693
+ bar : ( 1.3 , 3.7 ) ,
694
+ baz : MyEnum :: Unit ,
695
+ } )
696
+ . id ( ) ;
697
+
698
+ let registry = world. resource :: < AppTypeRegistry > ( ) ;
699
+ let scene_a = DynamicScene :: from_world ( & world, registry) ;
700
+
701
+ world. entity_mut ( entity) . insert ( MyComponent {
702
+ foo : [ 3 , 2 , 1 ] ,
703
+ bar : ( 1.3 , 3.7 ) ,
704
+ baz : MyEnum :: Unit ,
705
+ } ) ;
706
+
707
+ let registry = world. resource :: < AppTypeRegistry > ( ) ;
708
+ let scene_b = DynamicScene :: from_world ( & world, registry) ;
709
+
710
+ assert_scene_eq ( & scene_a, & scene_b) ;
711
+ }
712
+
713
+ #[ test]
714
+ #[ should_panic( expected = "missing component" ) ]
715
+ fn should_panic_when_missing_component ( ) {
716
+ let mut world = create_world ( ) ;
717
+
718
+ let entity = world
719
+ . spawn ( MyComponent {
720
+ foo : [ 1 , 2 , 3 ] ,
721
+ bar : ( 1.3 , 3.7 ) ,
722
+ baz : MyEnum :: Unit ,
723
+ } )
724
+ . id ( ) ;
725
+
726
+ let registry = world. resource :: < AppTypeRegistry > ( ) ;
727
+ let scene_a = DynamicScene :: from_world ( & world, registry) ;
728
+
729
+ world. entity_mut ( entity) . remove :: < MyComponent > ( ) ;
730
+
731
+ let registry = world. resource :: < AppTypeRegistry > ( ) ;
732
+ let scene_b = DynamicScene :: from_world ( & world, registry) ;
733
+
734
+ assert_scene_eq ( & scene_a, & scene_b) ;
735
+ }
736
+ }
502
737
}
0 commit comments