@@ -31,7 +31,7 @@ use bevy_ecs::{
31
31
32
32
use serde:: { de:: DeserializeOwned , Serialize } ;
33
33
34
- use serde_json:: Value as JsonMessage ;
34
+ pub use serde_json:: Value as JsonMessage ;
35
35
36
36
use smallvec:: SmallVec ;
37
37
@@ -427,6 +427,19 @@ impl<'a> JsonMut<'a> {
427
427
* self . modified = true ;
428
428
self . interface . insert ( message)
429
429
}
430
+
431
+ /// Modify the data of the underlying message. This is equivalent to calling
432
+ /// [`Self::serialize`], modifying the value, and then calling [`Self::insert`].
433
+ /// The benefit of this function is that you do not need to remember to
434
+ /// insert after you have finished your modifications.
435
+ pub fn modify (
436
+ & mut self ,
437
+ f : impl FnOnce ( & mut JsonMessage ) ,
438
+ ) -> Result < ( ) , serde_json:: Error > {
439
+ let mut message = self . serialize ( ) ?;
440
+ f ( & mut message) ;
441
+ self . insert ( message)
442
+ }
430
443
}
431
444
432
445
/// The return type for functions that give a JSON view of a message in a buffer.
@@ -794,3 +807,257 @@ impl Accessed for JsonBuffer {
794
807
key. is_in_use ( )
795
808
}
796
809
}
810
+
811
+ #[ cfg( test) ]
812
+ mod tests {
813
+ use bevy_ecs:: prelude:: World ;
814
+ use crate :: { prelude:: * , testing:: * } ;
815
+ use serde:: { Serialize , Deserialize } ;
816
+
817
+ #[ derive( Serialize , Deserialize , Clone ) ]
818
+ struct TestMessage {
819
+ v_i32 : i32 ,
820
+ v_u32 : u32 ,
821
+ v_string : String ,
822
+ }
823
+
824
+ impl TestMessage {
825
+ fn new ( ) -> Self {
826
+ Self {
827
+ v_i32 : 1 ,
828
+ v_u32 : 2 ,
829
+ v_string : "hello" . to_string ( ) ,
830
+ }
831
+ }
832
+ }
833
+
834
+ #[ test]
835
+ fn test_json_count ( ) {
836
+ let mut context = TestingContext :: minimal_plugins ( ) ;
837
+
838
+ let workflow = context. spawn_io_workflow ( |scope, builder| {
839
+ let buffer = builder. create_buffer ( BufferSettings :: keep_all ( ) ) ;
840
+ let push_multiple_times = builder. commands ( ) . spawn_service (
841
+ push_multiple_times_into_buffer. into_blocking_service ( )
842
+ ) ;
843
+ let count = builder. commands ( ) . spawn_service (
844
+ get_buffer_count. into_blocking_service ( )
845
+ ) ;
846
+
847
+ scope
848
+ . input
849
+ . chain ( builder)
850
+ . with_access ( buffer)
851
+ . then ( push_multiple_times)
852
+ . then ( count)
853
+ . connect ( scope. terminate ) ;
854
+ } ) ;
855
+
856
+ let msg = TestMessage :: new ( ) ;
857
+ let mut promise = context. command (
858
+ |commands| commands. request ( msg, workflow) . take_response ( )
859
+ ) ;
860
+
861
+ context. run_with_conditions ( & mut promise, Duration :: from_secs ( 2 ) ) ;
862
+ let count = promise. take ( ) . available ( ) . unwrap ( ) ;
863
+ assert_eq ! ( count, 5 ) ;
864
+ assert ! ( context. no_unhandled_errors( ) ) ;
865
+ }
866
+
867
+ fn push_multiple_times_into_buffer (
868
+ In ( ( value, key) ) : In < ( TestMessage , BufferKey < TestMessage > ) > ,
869
+ mut access : BufferAccessMut < TestMessage > ,
870
+ ) -> JsonBufferKey {
871
+ let mut buffer = access. get_mut ( & key) . unwrap ( ) ;
872
+ for _ in 0 ..5 {
873
+ buffer. push ( value. clone ( ) ) ;
874
+ }
875
+
876
+ key. into ( )
877
+ }
878
+
879
+ fn get_buffer_count (
880
+ In ( key) : In < JsonBufferKey > ,
881
+ world : & mut World ,
882
+ ) -> usize {
883
+ world. json_buffer_mut ( & key, |access| {
884
+ access. len ( )
885
+ } ) . unwrap ( )
886
+ }
887
+
888
+ #[ test]
889
+ fn test_modify_json_message ( ) {
890
+ let mut context = TestingContext :: minimal_plugins ( ) ;
891
+
892
+ let workflow = context. spawn_io_workflow ( |scope, builder| {
893
+ let buffer = builder. create_buffer ( BufferSettings :: keep_all ( ) ) ;
894
+ let push_multiple_times = builder. commands ( ) . spawn_service (
895
+ push_multiple_times_into_buffer. into_blocking_service ( )
896
+ ) ;
897
+ let modify_content = builder. commands ( ) . spawn_service (
898
+ modify_buffer_content. into_blocking_service ( )
899
+ ) ;
900
+ let drain_content = builder. commands ( ) . spawn_service (
901
+ pull_each_buffer_item. into_blocking_service ( )
902
+ ) ;
903
+
904
+ scope
905
+ . input
906
+ . chain ( builder)
907
+ . with_access ( buffer)
908
+ . then ( push_multiple_times)
909
+ . then ( modify_content)
910
+ . then ( drain_content)
911
+ . connect ( scope. terminate ) ;
912
+ } ) ;
913
+
914
+ let msg = TestMessage :: new ( ) ;
915
+ let mut promise = context. command (
916
+ |commands| commands. request ( msg, workflow) . take_response ( )
917
+ ) ;
918
+
919
+ context. run_with_conditions ( & mut promise, Duration :: from_secs ( 2 ) ) ;
920
+ let values = promise. take ( ) . available ( ) . unwrap ( ) ;
921
+ assert_eq ! ( values. len( ) , 5 ) ;
922
+ for i in 0 ..values. len ( ) {
923
+ let v_i32 = values[ i] . get ( "v_i32" ) . unwrap ( ) . as_i64 ( ) . unwrap ( ) ;
924
+ assert_eq ! ( v_i32, i as i64 ) ;
925
+ }
926
+ assert ! ( context. no_unhandled_errors( ) ) ;
927
+ }
928
+
929
+ fn modify_buffer_content (
930
+ In ( key) : In < JsonBufferKey > ,
931
+ world : & mut World ,
932
+ ) -> JsonBufferKey {
933
+ world. json_buffer_mut ( & key, |mut access| {
934
+ for i in 0 ..access. len ( ) {
935
+ access. get_mut ( i) . unwrap ( ) . modify ( |value| {
936
+ let v_i32 = value. get_mut ( "v_i32" ) . unwrap ( ) ;
937
+ let modified_v_i32 = i as i64 * v_i32. as_i64 ( ) . unwrap ( ) ;
938
+ * v_i32 = modified_v_i32. into ( ) ;
939
+ } ) . unwrap ( ) ;
940
+ }
941
+ } ) . unwrap ( ) ;
942
+
943
+ key
944
+ }
945
+
946
+ fn pull_each_buffer_item (
947
+ In ( key) : In < JsonBufferKey > ,
948
+ world : & mut World ,
949
+ ) -> Vec < JsonMessage > {
950
+ world. json_buffer_mut ( & key, |mut access| {
951
+ let mut values = Vec :: new ( ) ;
952
+ while let Ok ( Some ( value) ) = access. pull ( ) {
953
+ values. push ( value) ;
954
+ }
955
+ values
956
+ } ) . unwrap ( )
957
+ }
958
+
959
+ #[ test]
960
+ fn test_drain_json_message ( ) {
961
+ let mut context = TestingContext :: minimal_plugins ( ) ;
962
+
963
+ let workflow = context. spawn_io_workflow ( |scope, builder| {
964
+ let buffer = builder. create_buffer ( BufferSettings :: keep_all ( ) ) ;
965
+ let push_multiple_times = builder. commands ( ) . spawn_service (
966
+ push_multiple_times_into_buffer. into_blocking_service ( )
967
+ ) ;
968
+ let modify_content = builder. commands ( ) . spawn_service (
969
+ modify_buffer_content. into_blocking_service ( )
970
+ ) ;
971
+ let drain_content = builder. commands ( ) . spawn_service (
972
+ drain_buffer_contents. into_blocking_service ( )
973
+ ) ;
974
+
975
+ scope
976
+ . input
977
+ . chain ( builder)
978
+ . with_access ( buffer)
979
+ . then ( push_multiple_times)
980
+ . then ( modify_content)
981
+ . then ( drain_content)
982
+ . connect ( scope. terminate ) ;
983
+ } ) ;
984
+
985
+ let msg = TestMessage :: new ( ) ;
986
+ let mut promise = context. command (
987
+ |commands| commands. request ( msg, workflow) . take_response ( )
988
+ ) ;
989
+
990
+ context. run_with_conditions ( & mut promise, Duration :: from_secs ( 2 ) ) ;
991
+ let values = promise. take ( ) . available ( ) . unwrap ( ) ;
992
+ assert_eq ! ( values. len( ) , 5 ) ;
993
+ for i in 0 ..values. len ( ) {
994
+ let v_i32 = values[ i] . get ( "v_i32" ) . unwrap ( ) . as_i64 ( ) . unwrap ( ) ;
995
+ assert_eq ! ( v_i32, i as i64 ) ;
996
+ }
997
+ assert ! ( context. no_unhandled_errors( ) ) ;
998
+ }
999
+
1000
+ fn drain_buffer_contents (
1001
+ In ( key) : In < JsonBufferKey > ,
1002
+ world : & mut World ,
1003
+ ) -> Vec < JsonMessage > {
1004
+ world. json_buffer_mut ( & key, |mut access| {
1005
+ access
1006
+ . drain ( ..)
1007
+ . collect :: < Result < Vec < _ > , _ > > ( )
1008
+ } )
1009
+ . unwrap ( )
1010
+ . unwrap ( )
1011
+ }
1012
+
1013
+ #[ test]
1014
+ fn double_json_messages ( ) {
1015
+ let mut context = TestingContext :: minimal_plugins ( ) ;
1016
+
1017
+ let workflow = context. spawn_io_workflow ( |scope, builder| {
1018
+ let buffer_double_u32: JsonBuffer = builder. create_buffer :: < TestMessage > ( BufferSettings :: default ( ) ) . into ( ) ;
1019
+ let buffer_double_i32: JsonBuffer = builder. create_buffer :: < TestMessage > ( BufferSettings :: default ( ) ) . into ( ) ;
1020
+ let buffer_double_string: JsonBuffer = builder. create_buffer :: < TestMessage > ( BufferSettings :: default ( ) ) . into ( ) ;
1021
+
1022
+ scope
1023
+ . input
1024
+ . chain ( builder)
1025
+ . fork_clone ( (
1026
+ |chain : Chain < _ > | chain
1027
+ . map_block ( |mut msg : TestMessage | {
1028
+ msg. v_u32 *= 2 ;
1029
+ msg
1030
+ } )
1031
+ . connect ( buffer_double_u32. downcast :: < TestMessage > ( ) . unwrap ( ) . input_slot ( ) ) ,
1032
+ |chain : Chain < _ > | chain
1033
+ . map_block ( |mut msg : TestMessage | {
1034
+ msg. v_i32 *= 2 ;
1035
+ msg
1036
+ } )
1037
+ . connect ( buffer_double_i32. downcast :: < TestMessage > ( ) . unwrap ( ) . input_slot ( ) ) ,
1038
+ |chain : Chain < _ > | chain
1039
+ . map_block ( |mut msg : TestMessage | {
1040
+ msg. v_string = msg. v_string . clone ( ) + & msg. v_string ;
1041
+ msg
1042
+ } )
1043
+ . connect ( buffer_double_string. downcast :: < TestMessage > ( ) . unwrap ( ) . input_slot ( ) ) ,
1044
+ ) ) ;
1045
+
1046
+ ( buffer_double_u32, buffer_double_i32, buffer_double_string)
1047
+ . join ( builder)
1048
+ . connect ( scope. terminate ) ;
1049
+ } ) ;
1050
+
1051
+ let msg = TestMessage :: new ( ) ;
1052
+ let mut promise = context. command (
1053
+ |commands| commands. request ( msg, workflow) . take_response ( )
1054
+ ) ;
1055
+
1056
+ context. run_with_conditions ( & mut promise, Duration :: from_secs ( 2 ) ) ;
1057
+ let ( double_u32, double_i32, double_string) = promise. take ( ) . available ( ) . unwrap ( ) ;
1058
+ assert_eq ! ( 4 , double_u32. get( "v_u32" ) . unwrap( ) . as_i64( ) . unwrap( ) ) ;
1059
+ assert_eq ! ( 2 , double_i32. get( "v_i32" ) . unwrap( ) . as_i64( ) . unwrap( ) ) ;
1060
+ assert_eq ! ( "hellohello" , double_string. get( "v_string" ) . unwrap( ) . as_str( ) . unwrap( ) ) ;
1061
+ assert ! ( context. no_unhandled_errors( ) ) ;
1062
+ }
1063
+ }
0 commit comments