@@ -21,7 +21,7 @@ use std::{
21
21
any:: { Any , TypeId } ,
22
22
collections:: { hash_map:: Entry , HashMap } ,
23
23
ops:: RangeBounds ,
24
- sync:: { Arc , Mutex , OnceLock } ,
24
+ sync:: { Mutex , OnceLock } ,
25
25
} ;
26
26
27
27
use bevy_ecs:: {
@@ -34,10 +34,10 @@ use thiserror::Error as ThisError;
34
34
use smallvec:: SmallVec ;
35
35
36
36
use crate :: {
37
- add_listener_to_source, Accessed , Buffer , BufferAccessLifecycle , BufferAccessMut ,
38
- BufferAccessors , BufferError , BufferKey , BufferKeyTag , BufferLocation , BufferStorage ,
39
- Bufferable , Buffered , Builder , DrainBuffer , Gate , GateState , InspectBuffer , Joined ,
40
- ManageBuffer , NotifyBufferUpdate , OperationError , OperationResult , OperationRoster , OrBroken ,
37
+ add_listener_to_source, Accessed , Buffer , BufferAccessMut , BufferAccessors , BufferError ,
38
+ BufferKey , BufferKeyTag , BufferLocation , BufferStorage , Bufferable , Buffered , Builder ,
39
+ DrainBuffer , Gate , GateState , InspectBuffer , Joined , ManageBuffer , NotifyBufferUpdate ,
40
+ OperationError , OperationResult , OperationRoster , OrBroken ,
41
41
} ;
42
42
43
43
/// A [`Buffer`] whose message type has been anonymized. Joining with this buffer
@@ -143,18 +143,29 @@ pub struct AnyBufferKey {
143
143
}
144
144
145
145
impl AnyBufferKey {
146
- /// Downcast this into a concrete [`BufferKey`] type.
147
- pub fn downcast < T : ' static > ( & self ) -> Option < BufferKey < T > > {
148
- if TypeId :: of :: < T > ( ) == self . interface . message_type_id ( ) {
146
+ /// Downcast this into a concrete [`BufferKey`] for the specified message type.
147
+ ///
148
+ /// To downcast to a specialized kind of key, use [`Self::downcast_buffer_key`] instead.
149
+ pub fn downcast_for_message < Message : ' static > ( self ) -> Option < BufferKey < Message > > {
150
+ if TypeId :: of :: < Message > ( ) == self . interface . message_type_id ( ) {
149
151
Some ( BufferKey {
150
- tag : self . tag . clone ( ) ,
152
+ tag : self . tag ,
151
153
_ignore : Default :: default ( ) ,
152
154
} )
153
155
} else {
154
156
None
155
157
}
156
158
}
157
159
160
+ /// Downcast this into a different special buffer key representation, such
161
+ /// as a `JsonBufferKey`.
162
+ pub fn downcast_buffer_key < KeyType : ' static > ( self ) -> Option < KeyType > {
163
+ self . interface . key_downcast ( TypeId :: of :: < KeyType > ( ) ) ?( self . tag )
164
+ . downcast :: < KeyType > ( )
165
+ . ok ( )
166
+ . map ( |x| * x)
167
+ }
168
+
158
169
/// The buffer ID of this key.
159
170
pub fn id ( & self ) -> Entity {
160
171
self . tag . buffer
@@ -780,6 +791,10 @@ pub trait AnyBufferAccessInterface {
780
791
781
792
fn buffer_downcast ( & self , buffer_type : TypeId ) -> Option < BufferDowncastRef > ;
782
793
794
+ fn register_key_downcast ( & self , key_type : TypeId , f : KeyDowncastBox ) ;
795
+
796
+ fn key_downcast ( & self , key_type : TypeId ) -> Option < KeyDowncastRef > ;
797
+
783
798
fn pull (
784
799
& self ,
785
800
entity_mut : & mut EntityWorldMut ,
@@ -800,16 +815,23 @@ pub trait AnyBufferAccessInterface {
800
815
801
816
pub type BufferDowncastBox = Box < dyn Fn ( BufferLocation ) -> Box < dyn Any > + Send + Sync > ;
802
817
pub type BufferDowncastRef = & ' static ( dyn Fn ( BufferLocation ) -> Box < dyn Any > + Send + Sync ) ;
818
+ pub type KeyDowncastBox = Box < dyn Fn ( BufferKeyTag ) -> Box < dyn Any > + Send + Sync > ;
819
+ pub type KeyDowncastRef = & ' static ( dyn Fn ( BufferKeyTag ) -> Box < dyn Any > + Send + Sync ) ;
803
820
804
821
struct AnyBufferAccessImpl < T > {
805
822
buffer_downcasts : Mutex < HashMap < TypeId , BufferDowncastRef > > ,
823
+ key_downcasts : Mutex < HashMap < TypeId , KeyDowncastRef > > ,
806
824
_ignore : std:: marker:: PhantomData < fn ( T ) > ,
807
825
}
808
826
809
827
impl < T : ' static + Send + Sync > AnyBufferAccessImpl < T > {
810
828
fn new ( ) -> Self {
811
829
let mut buffer_downcasts: HashMap < _ , BufferDowncastRef > = HashMap :: new ( ) ;
812
830
831
+ // SAFETY: These leaks are okay because we will only ever instantiate
832
+ // AnyBufferAccessImpl once per generic argument T, which puts a firm
833
+ // ceiling on how many of these callbacks will get leaked.
834
+
813
835
// Automatically register a downcast into AnyBuffer
814
836
buffer_downcasts. insert (
815
837
TypeId :: of :: < AnyBuffer > ( ) ,
@@ -821,8 +843,22 @@ impl<T: 'static + Send + Sync> AnyBufferAccessImpl<T> {
821
843
} ) ) ,
822
844
) ;
823
845
846
+ let mut key_downcasts: HashMap < _ , KeyDowncastRef > = HashMap :: new ( ) ;
847
+
848
+ // Automatically register a downcast to AnyBufferKey
849
+ key_downcasts. insert (
850
+ TypeId :: of :: < AnyBufferKey > ( ) ,
851
+ Box :: leak ( Box :: new ( |tag| -> Box < dyn Any > {
852
+ Box :: new ( AnyBufferKey {
853
+ tag,
854
+ interface : AnyBuffer :: interface_for :: < T > ( ) ,
855
+ } )
856
+ } ) ) ,
857
+ ) ;
858
+
824
859
Self {
825
860
buffer_downcasts : Mutex :: new ( buffer_downcasts) ,
861
+ key_downcasts : Mutex :: new ( key_downcasts) ,
826
862
_ignore : Default :: default ( ) ,
827
863
}
828
864
}
@@ -862,6 +898,19 @@ impl<T: 'static + Send + Sync + Any> AnyBufferAccessInterface for AnyBufferAcces
862
898
. copied ( )
863
899
}
864
900
901
+ fn register_key_downcast ( & self , key_type : TypeId , f : KeyDowncastBox ) {
902
+ let mut downcasts = self . key_downcasts . lock ( ) . unwrap ( ) ;
903
+
904
+ if let Entry :: Vacant ( entry) = downcasts. entry ( key_type) {
905
+ // We should only leak this in to the register once per type
906
+ entry. insert ( Box :: leak ( f) ) ;
907
+ }
908
+ }
909
+
910
+ fn key_downcast ( & self , key_type : TypeId ) -> Option < KeyDowncastRef > {
911
+ self . key_downcasts . lock ( ) . unwrap ( ) . get ( & key_type) . copied ( )
912
+ }
913
+
865
914
fn pull (
866
915
& self ,
867
916
entity_mut : & mut EntityWorldMut ,
0 commit comments