1
1
//! Module with JSON Schema type for Bevy Registry Types.
2
2
//! It tries to follow this standard: <https://json-schema.org/specification>
3
- use bevy_ecs :: reflect :: { ReflectComponent , ReflectResource } ;
3
+ use alloc :: borrow :: Cow ;
4
4
use bevy_platform:: collections:: HashMap ;
5
5
use bevy_reflect:: {
6
- prelude :: ReflectDefault , NamedField , OpaqueInfo , ReflectDeserialize , ReflectSerialize ,
7
- TypeInfo , TypeRegistration , VariantInfo ,
6
+ GetTypeRegistration , NamedField , OpaqueInfo , TypeInfo , TypeRegistration , TypeRegistry ,
7
+ VariantInfo ,
8
8
} ;
9
9
use core:: any:: TypeId ;
10
10
use serde:: { Deserialize , Serialize } ;
11
11
use serde_json:: { json, Map , Value } ;
12
12
13
- /// Exports schema info for a given type
14
- pub fn export_type ( reg : & TypeRegistration ) -> ( String , JsonSchemaBevyType ) {
15
- ( reg. type_info ( ) . type_path ( ) . to_owned ( ) , reg. into ( ) )
13
+ use crate :: schemas:: SchemaTypesMetadata ;
14
+
15
+ /// Helper trait for converting `TypeRegistration` to `JsonSchemaBevyType`
16
+ pub trait TypeRegistrySchemaReader {
17
+ /// Export type JSON Schema.
18
+ fn export_type_json_schema < T : GetTypeRegistration + ' static > (
19
+ & self ,
20
+ extra_info : & SchemaTypesMetadata ,
21
+ ) -> Option < JsonSchemaBevyType > {
22
+ self . export_type_json_schema_for_id ( extra_info, TypeId :: of :: < T > ( ) )
23
+ }
24
+ /// Export type JSON Schema.
25
+ fn export_type_json_schema_for_id (
26
+ & self ,
27
+ extra_info : & SchemaTypesMetadata ,
28
+ type_id : TypeId ,
29
+ ) -> Option < JsonSchemaBevyType > ;
16
30
}
17
31
18
- fn get_registered_reflect_types ( reg : & TypeRegistration ) -> Vec < String > {
19
- // Vec could be moved to allow registering more types by game maker.
20
- let registered_reflect_types: [ ( TypeId , & str ) ; 5 ] = [
21
- { ( TypeId :: of :: < ReflectComponent > ( ) , "Component" ) } ,
22
- { ( TypeId :: of :: < ReflectResource > ( ) , "Resource" ) } ,
23
- { ( TypeId :: of :: < ReflectDefault > ( ) , "Default" ) } ,
24
- { ( TypeId :: of :: < ReflectSerialize > ( ) , "Serialize" ) } ,
25
- { ( TypeId :: of :: < ReflectDeserialize > ( ) , "Deserialize" ) } ,
26
- ] ;
27
- let mut result = Vec :: new ( ) ;
28
- for ( id, name) in registered_reflect_types {
29
- if reg. data_by_id ( id) . is_some ( ) {
30
- result. push ( name. to_owned ( ) ) ;
31
- }
32
+ impl TypeRegistrySchemaReader for TypeRegistry {
33
+ fn export_type_json_schema_for_id (
34
+ & self ,
35
+ extra_info : & SchemaTypesMetadata ,
36
+ type_id : TypeId ,
37
+ ) -> Option < JsonSchemaBevyType > {
38
+ let type_reg = self . get ( type_id) ?;
39
+ Some ( ( type_reg, extra_info) . into ( ) )
32
40
}
33
- result
34
41
}
35
42
36
- impl From < & TypeRegistration > for JsonSchemaBevyType {
37
- fn from ( reg : & TypeRegistration ) -> Self {
43
+ /// Exports schema info for a given type
44
+ pub fn export_type (
45
+ reg : & TypeRegistration ,
46
+ metadata : & SchemaTypesMetadata ,
47
+ ) -> ( Cow < ' static , str > , JsonSchemaBevyType ) {
48
+ ( reg. type_info ( ) . type_path ( ) . into ( ) , ( reg, metadata) . into ( ) )
49
+ }
50
+
51
+ impl From < ( & TypeRegistration , & SchemaTypesMetadata ) > for JsonSchemaBevyType {
52
+ fn from ( value : ( & TypeRegistration , & SchemaTypesMetadata ) ) -> Self {
53
+ let ( reg, metadata) = value;
38
54
let t = reg. type_info ( ) ;
39
55
let binding = t. type_path_table ( ) ;
40
56
41
57
let short_path = binding. short_path ( ) ;
42
58
let type_path = binding. path ( ) ;
43
59
let mut typed_schema = JsonSchemaBevyType {
44
- reflect_types : get_registered_reflect_types ( reg) ,
60
+ reflect_types : metadata . get_registered_reflect_types ( reg) ,
45
61
short_path : short_path. to_owned ( ) ,
46
62
type_path : type_path. to_owned ( ) ,
47
63
crate_name : binding. crate_name ( ) . map ( str:: to_owned) ,
@@ -351,8 +367,12 @@ impl SchemaJsonReference for &NamedField {
351
367
#[ cfg( test) ]
352
368
mod tests {
353
369
use super :: * ;
370
+ use bevy_ecs:: prelude:: ReflectComponent ;
371
+ use bevy_ecs:: prelude:: ReflectResource ;
372
+
354
373
use bevy_ecs:: { component:: Component , reflect:: AppTypeRegistry , resource:: Resource } ;
355
- use bevy_reflect:: Reflect ;
374
+ use bevy_reflect:: prelude:: ReflectDefault ;
375
+ use bevy_reflect:: { Reflect , ReflectDeserialize , ReflectSerialize } ;
356
376
357
377
#[ test]
358
378
fn reflect_export_struct ( ) {
@@ -373,7 +393,7 @@ mod tests {
373
393
. get ( TypeId :: of :: < Foo > ( ) )
374
394
. expect ( "SHOULD BE REGISTERED" )
375
395
. clone ( ) ;
376
- let ( _, schema) = export_type ( & foo_registration) ;
396
+ let ( _, schema) = export_type ( & foo_registration, & SchemaTypesMetadata :: default ( ) ) ;
377
397
378
398
assert ! (
379
399
!schema. reflect_types. contains( & "Component" . to_owned( ) ) ,
@@ -418,7 +438,7 @@ mod tests {
418
438
. get ( TypeId :: of :: < EnumComponent > ( ) )
419
439
. expect ( "SHOULD BE REGISTERED" )
420
440
. clone ( ) ;
421
- let ( _, schema) = export_type ( & foo_registration) ;
441
+ let ( _, schema) = export_type ( & foo_registration, & SchemaTypesMetadata :: default ( ) ) ;
422
442
assert ! (
423
443
schema. reflect_types. contains( & "Component" . to_owned( ) ) ,
424
444
"Should be a component"
@@ -453,7 +473,7 @@ mod tests {
453
473
. get ( TypeId :: of :: < EnumComponent > ( ) )
454
474
. expect ( "SHOULD BE REGISTERED" )
455
475
. clone ( ) ;
456
- let ( _, schema) = export_type ( & foo_registration) ;
476
+ let ( _, schema) = export_type ( & foo_registration, & SchemaTypesMetadata :: default ( ) ) ;
457
477
assert ! (
458
478
!schema. reflect_types. contains( & "Component" . to_owned( ) ) ,
459
479
"Should not be a component"
@@ -466,6 +486,62 @@ mod tests {
466
486
assert ! ( schema. one_of. len( ) == 3 , "Should have 3 possible schemas" ) ;
467
487
}
468
488
489
+ #[ test]
490
+ fn reflect_struct_with_custom_type_data ( ) {
491
+ #[ derive( Reflect , Default , Deserialize , Serialize ) ]
492
+ #[ reflect( Default ) ]
493
+ enum EnumComponent {
494
+ ValueOne ( i32 ) ,
495
+ ValueTwo {
496
+ test : i32 ,
497
+ } ,
498
+ #[ default]
499
+ NoValue ,
500
+ }
501
+
502
+ #[ derive( Clone ) ]
503
+ pub struct ReflectCustomData ;
504
+
505
+ impl < T : Reflect > bevy_reflect:: FromType < T > for ReflectCustomData {
506
+ fn from_type ( ) -> Self {
507
+ ReflectCustomData
508
+ }
509
+ }
510
+
511
+ let atr = AppTypeRegistry :: default ( ) ;
512
+ {
513
+ let mut register = atr. write ( ) ;
514
+ register. register :: < EnumComponent > ( ) ;
515
+ register. register_type_data :: < EnumComponent , ReflectCustomData > ( ) ;
516
+ }
517
+ let mut metadata = SchemaTypesMetadata :: default ( ) ;
518
+ metadata. map_type_data :: < ReflectCustomData > ( "CustomData" ) ;
519
+ let type_registry = atr. read ( ) ;
520
+ let foo_registration = type_registry
521
+ . get ( TypeId :: of :: < EnumComponent > ( ) )
522
+ . expect ( "SHOULD BE REGISTERED" )
523
+ . clone ( ) ;
524
+ let ( _, schema) = export_type ( & foo_registration, & metadata) ;
525
+ assert ! (
526
+ !metadata. has_type_data:: <ReflectComponent >( & schema. reflect_types) ,
527
+ "Should not be a component"
528
+ ) ;
529
+ assert ! (
530
+ !metadata. has_type_data:: <ReflectResource >( & schema. reflect_types) ,
531
+ "Should not be a resource"
532
+ ) ;
533
+ assert ! (
534
+ metadata. has_type_data:: <ReflectDefault >( & schema. reflect_types) ,
535
+ "Should have default"
536
+ ) ;
537
+ assert ! (
538
+ metadata. has_type_data:: <ReflectCustomData >( & schema. reflect_types) ,
539
+ "Should have CustomData"
540
+ ) ;
541
+ assert ! ( schema. properties. is_empty( ) , "Should not have any field" ) ;
542
+ assert ! ( schema. one_of. len( ) == 3 , "Should have 3 possible schemas" ) ;
543
+ }
544
+
469
545
#[ test]
470
546
fn reflect_export_tuple_struct ( ) {
471
547
#[ derive( Reflect , Component , Default , Deserialize , Serialize ) ]
@@ -482,7 +558,7 @@ mod tests {
482
558
. get ( TypeId :: of :: < TupleStructType > ( ) )
483
559
. expect ( "SHOULD BE REGISTERED" )
484
560
. clone ( ) ;
485
- let ( _, schema) = export_type ( & foo_registration) ;
561
+ let ( _, schema) = export_type ( & foo_registration, & SchemaTypesMetadata :: default ( ) ) ;
486
562
assert ! (
487
563
schema. reflect_types. contains( & "Component" . to_owned( ) ) ,
488
564
"Should be a component"
@@ -513,7 +589,7 @@ mod tests {
513
589
. get ( TypeId :: of :: < Foo > ( ) )
514
590
. expect ( "SHOULD BE REGISTERED" )
515
591
. clone ( ) ;
516
- let ( _, schema) = export_type ( & foo_registration) ;
592
+ let ( _, schema) = export_type ( & foo_registration, & SchemaTypesMetadata :: default ( ) ) ;
517
593
let schema_as_value = serde_json:: to_value ( & schema) . expect ( "Should serialize" ) ;
518
594
let value = json ! ( {
519
595
"shortPath" : "Foo" ,
@@ -538,6 +614,31 @@ mod tests {
538
614
"a"
539
615
]
540
616
} ) ;
541
- assert_eq ! ( schema_as_value, value) ;
617
+ assert_normalized_values ( schema_as_value, value) ;
618
+ }
619
+
620
+ /// This function exist to avoid false failures due to ordering differences between `serde_json` values.
621
+ fn assert_normalized_values ( mut one : Value , mut two : Value ) {
622
+ normalize_json ( & mut one) ;
623
+ normalize_json ( & mut two) ;
624
+ assert_eq ! ( one, two) ;
625
+
626
+ /// Recursively sorts arrays in a `serde_json::Value`
627
+ fn normalize_json ( value : & mut Value ) {
628
+ match value {
629
+ Value :: Array ( arr) => {
630
+ for v in arr. iter_mut ( ) {
631
+ normalize_json ( v) ;
632
+ }
633
+ arr. sort_by_key ( ToString :: to_string) ; // Sort by stringified version
634
+ }
635
+ Value :: Object ( map) => {
636
+ for ( _k, v) in map. iter_mut ( ) {
637
+ normalize_json ( v) ;
638
+ }
639
+ }
640
+ _ => { }
641
+ }
642
+ }
542
643
}
543
644
}
0 commit comments