11//! Defines a set of traits which destruture [`bevy::reflect::TypeInfo`] and implement a light weight wrapper around it, to allow types
22//! which normally can't implement [`bevy::reflect::Typed`] to be used in a reflection context.
33
4- use std:: { any :: TypeId , ffi:: OsString , path:: PathBuf } ;
4+ use std:: { ffi:: OsString , path:: PathBuf } ;
55
66use bevy:: reflect:: { TypeInfo , Typed } ;
77
@@ -16,7 +16,7 @@ use crate::{
1616 script_value:: ScriptValue ,
1717 ReflectReference ,
1818 } ,
19- error:: InteropError ,
19+ error:: InteropError , reflection_extensions :: TypeInfoExtensions ,
2020} ;
2121
2222/// All Through types follow one rule:
@@ -34,8 +34,6 @@ pub enum ThroughTypeInfo {
3434 UntypedWrapper {
3535 /// The type information of the inner type.
3636 through_type : & ' static TypeInfo ,
37- /// The type id of the wrapper type.
38- wrapper_type_id : TypeId ,
3937 /// The name of the wrapper type.
4038 wrapper_kind : UntypedWrapperKind ,
4139 } ,
@@ -75,6 +73,66 @@ pub enum TypedWrapperKind {
7573 Tuple ( Vec < ThroughTypeInfo > ) ,
7674}
7775
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+
78136/// A trait for types that can be converted to a [`ThroughTypeInfo`].
79137pub trait TypedThrough {
80138 /// Get the [`ThroughTypeInfo`] for the type.
@@ -94,7 +152,6 @@ impl<T: Typed> TypedThrough for Ref<'_, T> {
94152 fn through_type_info ( ) -> ThroughTypeInfo {
95153 ThroughTypeInfo :: UntypedWrapper {
96154 through_type : T :: type_info ( ) ,
97- wrapper_type_id : TypeId :: of :: < Ref < T > > ( ) ,
98155 wrapper_kind : UntypedWrapperKind :: Ref ,
99156 }
100157 }
@@ -104,7 +161,6 @@ impl<T: Typed> TypedThrough for Mut<'_, T> {
104161 fn through_type_info ( ) -> ThroughTypeInfo {
105162 ThroughTypeInfo :: UntypedWrapper {
106163 through_type : T :: type_info ( ) ,
107- wrapper_type_id : TypeId :: of :: < Mut < T > > ( ) ,
108164 wrapper_kind : UntypedWrapperKind :: Mut ,
109165 }
110166 }
@@ -114,7 +170,6 @@ impl<T: Typed> TypedThrough for Val<T> {
114170 fn through_type_info ( ) -> ThroughTypeInfo {
115171 ThroughTypeInfo :: UntypedWrapper {
116172 through_type : T :: type_info ( ) ,
117- wrapper_type_id : TypeId :: of :: < Val < T > > ( ) ,
118173 wrapper_kind : UntypedWrapperKind :: Val ,
119174 }
120175 }
@@ -207,6 +262,7 @@ macro_rules! impl_through_typed_tuple {
207262
208263bevy:: utils:: all_tuples!( impl_through_typed_tuple, 0 , 13 , T ) ;
209264
265+
210266#[ cfg( test) ]
211267mod test {
212268 use super :: * ;
@@ -224,29 +280,64 @@ mod test {
224280 }
225281 }
226282
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+
227297 #[ test]
228298 fn test_typed_through_primitives ( ) {
229299 assert_type_info_is_through :: < bool > ( ) ;
300+ assert_dynamic_through_type_is_val_info :: < bool > ( ) ;
230301 assert_type_info_is_through :: < i8 > ( ) ;
302+ assert_dynamic_through_type_is_val_info :: < i8 > ( ) ;
231303 assert_type_info_is_through :: < i16 > ( ) ;
304+ assert_dynamic_through_type_is_val_info :: < i16 > ( ) ;
232305 assert_type_info_is_through :: < i32 > ( ) ;
306+ assert_dynamic_through_type_is_val_info :: < i32 > ( ) ;
233307 assert_type_info_is_through :: < i64 > ( ) ;
308+ assert_dynamic_through_type_is_val_info :: < i64 > ( ) ;
234309 assert_type_info_is_through :: < i128 > ( ) ;
310+ assert_dynamic_through_type_is_val_info :: < i128 > ( ) ;
235311 assert_type_info_is_through :: < u8 > ( ) ;
312+ assert_dynamic_through_type_is_val_info :: < u8 > ( ) ;
236313 assert_type_info_is_through :: < u16 > ( ) ;
314+ assert_dynamic_through_type_is_val_info :: < u16 > ( ) ;
237315 assert_type_info_is_through :: < u32 > ( ) ;
316+ assert_dynamic_through_type_is_val_info :: < u32 > ( ) ;
238317 assert_type_info_is_through :: < u64 > ( ) ;
318+ assert_dynamic_through_type_is_val_info :: < u64 > ( ) ;
239319 assert_type_info_is_through :: < u128 > ( ) ;
320+ assert_dynamic_through_type_is_val_info :: < u128 > ( ) ;
240321 assert_type_info_is_through :: < f32 > ( ) ;
322+ assert_dynamic_through_type_is_val_info :: < f32 > ( ) ;
241323 assert_type_info_is_through :: < f64 > ( ) ;
324+ assert_dynamic_through_type_is_val_info :: < f64 > ( ) ;
242325 assert_type_info_is_through :: < usize > ( ) ;
326+ assert_dynamic_through_type_is_val_info :: < usize > ( ) ;
243327 assert_type_info_is_through :: < isize > ( ) ;
328+ assert_dynamic_through_type_is_val_info :: < isize > ( ) ;
244329 assert_type_info_is_through :: < String > ( ) ;
330+ assert_dynamic_through_type_is_val_info :: < String > ( ) ;
245331 assert_type_info_is_through :: < PathBuf > ( ) ;
332+ assert_dynamic_through_type_is_val_info :: < PathBuf > ( ) ;
246333 assert_type_info_is_through :: < OsString > ( ) ;
334+ assert_dynamic_through_type_is_val_info :: < OsString > ( ) ;
247335 assert_type_info_is_through :: < char > ( ) ;
336+ assert_dynamic_through_type_is_val_info :: < char > ( ) ;
248337 assert_type_info_is_through :: < ReflectReference > ( ) ;
338+ assert_dynamic_through_type_is_val_info :: < ReflectReference > ( ) ;
249339 assert_type_info_is_through :: < & ' static str > ( ) ;
340+ assert_dynamic_through_type_is_val_info :: < & ' static str > ( ) ;
250341 }
251342
252343 #[ test]
@@ -281,4 +372,37 @@ mod test {
281372 ThroughTypeInfo :: TypedWrapper ( TypedWrapperKind :: Tuple ( ..) )
282373 ) ) ;
283374 }
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+ }
284408}
0 commit comments