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