1
1
//! Defines a set of traits which destruture [`bevy::reflect::TypeInfo`] and implement a light weight wrapper around it, to allow types
2
2
//! which normally can't implement [`bevy::reflect::Typed`] to be used in a reflection context.
3
3
4
- use std:: { any :: TypeId , ffi:: OsString , path:: PathBuf } ;
4
+ use std:: { ffi:: OsString , path:: PathBuf } ;
5
5
6
6
use bevy:: reflect:: { TypeInfo , Typed } ;
7
7
@@ -16,7 +16,7 @@ use crate::{
16
16
script_value:: ScriptValue ,
17
17
ReflectReference ,
18
18
} ,
19
- error:: InteropError ,
19
+ error:: InteropError , reflection_extensions :: TypeInfoExtensions ,
20
20
} ;
21
21
22
22
/// All Through types follow one rule:
@@ -34,8 +34,6 @@ pub enum ThroughTypeInfo {
34
34
UntypedWrapper {
35
35
/// The type information of the inner type.
36
36
through_type : & ' static TypeInfo ,
37
- /// The type id of the wrapper type.
38
- wrapper_type_id : TypeId ,
39
37
/// The name of the wrapper type.
40
38
wrapper_kind : UntypedWrapperKind ,
41
39
} ,
@@ -75,6 +73,66 @@ pub enum TypedWrapperKind {
75
73
Tuple ( Vec < ThroughTypeInfo > ) ,
76
74
}
77
75
76
+ /// A dynamic version of [`TypedThrough`], which can be used to convert a [`TypeInfo`] into a [`ThroughTypeInfo`].
77
+ pub fn into_through_type_info ( type_info : & ' static TypeInfo ) -> ThroughTypeInfo {
78
+
79
+ let option = ( ||{
80
+ if let Ok ( array) = type_info. as_array ( ) {
81
+ let len = array. capacity ( ) ;
82
+ let inner = array. item_info ( ) ?;
83
+ return Some ( ThroughTypeInfo :: TypedWrapper ( TypedWrapperKind :: Array (
84
+ Box :: new ( into_through_type_info ( inner) ) ,
85
+ len,
86
+ ) ) ) ;
87
+ } else if let Ok ( hash_map) = type_info. as_map ( ) {
88
+ let key_type = hash_map. key_info ( ) ?;
89
+ let value_type = hash_map. value_info ( ) ?;
90
+
91
+ return Some ( ThroughTypeInfo :: TypedWrapper ( TypedWrapperKind :: HashMap (
92
+ Box :: new ( into_through_type_info ( key_type) ) ,
93
+ Box :: new ( into_through_type_info ( value_type) ) ,
94
+ ) ) ) ;
95
+ } else if let Ok ( list) = type_info. as_list ( ) {
96
+ let inner = list. item_info ( ) ?;
97
+ return Some ( ThroughTypeInfo :: TypedWrapper ( TypedWrapperKind :: Vec (
98
+ Box :: new ( into_through_type_info ( inner) ) ,
99
+ ) ) ) ;
100
+ } else if type_info. is_option ( ) {
101
+ let enum_ = type_info. as_enum ( ) . ok ( ) ?;
102
+ let inner = enum_. variant ( "Some" ) ?;
103
+ let inner = inner. as_tuple_variant ( ) . ok ( ) ?;
104
+ let inner = inner. field_at ( 0 ) ?;
105
+ let inner = inner. type_info ( ) ?;
106
+ return Some ( ThroughTypeInfo :: TypedWrapper ( TypedWrapperKind :: Option (
107
+ Box :: new ( into_through_type_info ( inner) ) ,
108
+ ) ) ) ;
109
+ } else if type_info. is_result ( ) {
110
+ let enum_ = type_info. as_enum ( ) . ok ( ) ?;
111
+ // let error_variant = enum_.variant("Err")?;
112
+ // TODO verify error variant is InteropError
113
+
114
+ let inner = enum_. variant ( "Ok" ) ?;
115
+ let inner = inner. as_tuple_variant ( ) . ok ( ) ?;
116
+ let inner = inner. field_at ( 0 ) ?;
117
+ let inner = inner. type_info ( ) ?;
118
+ return Some ( ThroughTypeInfo :: TypedWrapper ( TypedWrapperKind :: InteropResult (
119
+ Box :: new ( into_through_type_info ( inner) ) ,
120
+ ) ) ) ;
121
+ } else if let Ok ( tuple) = type_info. as_tuple ( ) {
122
+ let mut tuple_types = Vec :: new ( ) ;
123
+ for i in 0 ..tuple. field_len ( ) {
124
+ let field = tuple. field_at ( i) ?;
125
+ let field_type = field. type_info ( ) ?;
126
+ tuple_types. push ( into_through_type_info ( field_type) ) ;
127
+ }
128
+ return Some ( ThroughTypeInfo :: TypedWrapper ( TypedWrapperKind :: Tuple ( tuple_types) ) ) ;
129
+ }
130
+ None
131
+ } ) ( ) ;
132
+
133
+ option. unwrap_or ( ThroughTypeInfo :: UntypedWrapper { through_type : type_info, wrapper_kind : UntypedWrapperKind :: Val } )
134
+ }
135
+
78
136
/// A trait for types that can be converted to a [`ThroughTypeInfo`].
79
137
pub trait TypedThrough {
80
138
/// Get the [`ThroughTypeInfo`] for the type.
@@ -94,7 +152,6 @@ impl<T: Typed> TypedThrough for Ref<'_, T> {
94
152
fn through_type_info ( ) -> ThroughTypeInfo {
95
153
ThroughTypeInfo :: UntypedWrapper {
96
154
through_type : T :: type_info ( ) ,
97
- wrapper_type_id : TypeId :: of :: < Ref < T > > ( ) ,
98
155
wrapper_kind : UntypedWrapperKind :: Ref ,
99
156
}
100
157
}
@@ -104,7 +161,6 @@ impl<T: Typed> TypedThrough for Mut<'_, T> {
104
161
fn through_type_info ( ) -> ThroughTypeInfo {
105
162
ThroughTypeInfo :: UntypedWrapper {
106
163
through_type : T :: type_info ( ) ,
107
- wrapper_type_id : TypeId :: of :: < Mut < T > > ( ) ,
108
164
wrapper_kind : UntypedWrapperKind :: Mut ,
109
165
}
110
166
}
@@ -114,7 +170,6 @@ impl<T: Typed> TypedThrough for Val<T> {
114
170
fn through_type_info ( ) -> ThroughTypeInfo {
115
171
ThroughTypeInfo :: UntypedWrapper {
116
172
through_type : T :: type_info ( ) ,
117
- wrapper_type_id : TypeId :: of :: < Val < T > > ( ) ,
118
173
wrapper_kind : UntypedWrapperKind :: Val ,
119
174
}
120
175
}
@@ -207,6 +262,7 @@ macro_rules! impl_through_typed_tuple {
207
262
208
263
bevy:: utils:: all_tuples!( impl_through_typed_tuple, 0 , 13 , T ) ;
209
264
265
+
210
266
#[ cfg( test) ]
211
267
mod test {
212
268
use super :: * ;
@@ -224,29 +280,64 @@ mod test {
224
280
}
225
281
}
226
282
283
+ fn assert_dynamic_through_type_is_val_info < T : Typed + TypedThrough > ( ) {
284
+ let type_info = T :: type_info ( ) ;
285
+ let through_type_info = into_through_type_info ( type_info) ;
286
+
287
+ match through_type_info {
288
+ ThroughTypeInfo :: UntypedWrapper { through_type, wrapper_kind} => {
289
+ assert_eq ! ( wrapper_kind, UntypedWrapperKind :: Val ) ;
290
+ assert_eq ! ( through_type. type_id( ) , type_info. type_id( ) ) ;
291
+ assert_eq ! ( through_type. type_path( ) , type_info. type_path( ) ) ;
292
+ }
293
+ _ => panic ! ( "Expected ThroughTypeInfo::TypeInfo" ) ,
294
+ }
295
+ }
296
+
227
297
#[ test]
228
298
fn test_typed_through_primitives ( ) {
229
299
assert_type_info_is_through :: < bool > ( ) ;
300
+ assert_dynamic_through_type_is_val_info :: < bool > ( ) ;
230
301
assert_type_info_is_through :: < i8 > ( ) ;
302
+ assert_dynamic_through_type_is_val_info :: < i8 > ( ) ;
231
303
assert_type_info_is_through :: < i16 > ( ) ;
304
+ assert_dynamic_through_type_is_val_info :: < i16 > ( ) ;
232
305
assert_type_info_is_through :: < i32 > ( ) ;
306
+ assert_dynamic_through_type_is_val_info :: < i32 > ( ) ;
233
307
assert_type_info_is_through :: < i64 > ( ) ;
308
+ assert_dynamic_through_type_is_val_info :: < i64 > ( ) ;
234
309
assert_type_info_is_through :: < i128 > ( ) ;
310
+ assert_dynamic_through_type_is_val_info :: < i128 > ( ) ;
235
311
assert_type_info_is_through :: < u8 > ( ) ;
312
+ assert_dynamic_through_type_is_val_info :: < u8 > ( ) ;
236
313
assert_type_info_is_through :: < u16 > ( ) ;
314
+ assert_dynamic_through_type_is_val_info :: < u16 > ( ) ;
237
315
assert_type_info_is_through :: < u32 > ( ) ;
316
+ assert_dynamic_through_type_is_val_info :: < u32 > ( ) ;
238
317
assert_type_info_is_through :: < u64 > ( ) ;
318
+ assert_dynamic_through_type_is_val_info :: < u64 > ( ) ;
239
319
assert_type_info_is_through :: < u128 > ( ) ;
320
+ assert_dynamic_through_type_is_val_info :: < u128 > ( ) ;
240
321
assert_type_info_is_through :: < f32 > ( ) ;
322
+ assert_dynamic_through_type_is_val_info :: < f32 > ( ) ;
241
323
assert_type_info_is_through :: < f64 > ( ) ;
324
+ assert_dynamic_through_type_is_val_info :: < f64 > ( ) ;
242
325
assert_type_info_is_through :: < usize > ( ) ;
326
+ assert_dynamic_through_type_is_val_info :: < usize > ( ) ;
243
327
assert_type_info_is_through :: < isize > ( ) ;
328
+ assert_dynamic_through_type_is_val_info :: < isize > ( ) ;
244
329
assert_type_info_is_through :: < String > ( ) ;
330
+ assert_dynamic_through_type_is_val_info :: < String > ( ) ;
245
331
assert_type_info_is_through :: < PathBuf > ( ) ;
332
+ assert_dynamic_through_type_is_val_info :: < PathBuf > ( ) ;
246
333
assert_type_info_is_through :: < OsString > ( ) ;
334
+ assert_dynamic_through_type_is_val_info :: < OsString > ( ) ;
247
335
assert_type_info_is_through :: < char > ( ) ;
336
+ assert_dynamic_through_type_is_val_info :: < char > ( ) ;
248
337
assert_type_info_is_through :: < ReflectReference > ( ) ;
338
+ assert_dynamic_through_type_is_val_info :: < ReflectReference > ( ) ;
249
339
assert_type_info_is_through :: < & ' static str > ( ) ;
340
+ assert_dynamic_through_type_is_val_info :: < & ' static str > ( ) ;
250
341
}
251
342
252
343
#[ test]
@@ -281,4 +372,37 @@ mod test {
281
372
ThroughTypeInfo :: TypedWrapper ( TypedWrapperKind :: Tuple ( ..) )
282
373
) ) ;
283
374
}
375
+
376
+ #[ test]
377
+ fn test_dynamic_typed_wrapper_outer_variant_matches ( ) {
378
+ assert ! ( matches!(
379
+ into_through_type_info( Vec :: <i32 >:: type_info( ) ) ,
380
+ ThroughTypeInfo :: TypedWrapper ( TypedWrapperKind :: Vec ( ..) )
381
+ ) ) ;
382
+
383
+ assert ! ( matches!(
384
+ into_through_type_info( std:: collections:: HashMap :: <i32 , f32 >:: type_info( ) ) ,
385
+ ThroughTypeInfo :: TypedWrapper ( TypedWrapperKind :: HashMap ( ..) )
386
+ ) ) ;
387
+
388
+ assert ! ( matches!(
389
+ into_through_type_info( Result :: <i32 , InteropError >:: type_info( ) ) ,
390
+ ThroughTypeInfo :: TypedWrapper ( TypedWrapperKind :: InteropResult ( ..) )
391
+ ) ) ;
392
+
393
+ assert ! ( matches!(
394
+ into_through_type_info( <[ i32 ; 3 ] >:: type_info( ) ) ,
395
+ ThroughTypeInfo :: TypedWrapper ( TypedWrapperKind :: Array ( ..) )
396
+ ) ) ;
397
+
398
+ assert ! ( matches!(
399
+ into_through_type_info( Option :: <i32 >:: type_info( ) ) ,
400
+ ThroughTypeInfo :: TypedWrapper ( TypedWrapperKind :: Option ( ..) )
401
+ ) ) ;
402
+
403
+ assert ! ( matches!(
404
+ into_through_type_info( <( i32 , f32 ) >:: type_info( ) ) ,
405
+ ThroughTypeInfo :: TypedWrapper ( TypedWrapperKind :: Tuple ( ..) )
406
+ ) ) ;
407
+ }
284
408
}
0 commit comments