1
1
use super :: { FetchResource , ResourceQuery } ;
2
2
use crate :: system:: SystemId ;
3
- use bevy_hecs:: { Archetype , Entity , Ref , RefMut , TypeInfo , TypeState } ;
3
+ use bevy_hecs:: { Archetype , AtomicBorrow , Entity , Ref , RefMut , TypeInfo , TypeState } ;
4
4
use bevy_utils:: HashMap ;
5
5
use core:: any:: TypeId ;
6
- use std:: ptr:: NonNull ;
6
+ use downcast_rs:: { impl_downcast, Downcast } ;
7
+ use std:: {
8
+ fmt:: Debug ,
9
+ ops:: { Deref , DerefMut } ,
10
+ ptr:: NonNull ,
11
+ thread:: ThreadId ,
12
+ } ;
7
13
8
14
/// A Resource type
9
15
pub trait Resource : Send + Sync + ' static { }
@@ -22,17 +28,103 @@ pub enum ResourceIndex {
22
28
System ( SystemId ) ,
23
29
}
24
30
31
+ // TODO: consider using this for normal resources (would require change tracking)
32
+ trait ResourceStorage : Downcast { }
33
+ impl_downcast ! ( ResourceStorage ) ;
34
+
35
+ struct StoredResource < T : ' static > {
36
+ value : T ,
37
+ atomic_borrow : AtomicBorrow ,
38
+ }
39
+
40
+ pub struct VecResourceStorage < T : ' static > {
41
+ stored : Vec < StoredResource < T > > ,
42
+ }
43
+
44
+ impl < T : ' static > VecResourceStorage < T > {
45
+ fn get ( & self , index : usize ) -> Option < ResourceRef < ' _ , T > > {
46
+ self . stored
47
+ . get ( index)
48
+ . map ( |stored| ResourceRef :: new ( & stored. value , & stored. atomic_borrow ) )
49
+ }
50
+
51
+ fn get_mut ( & self , index : usize ) -> Option < ResourceRefMut < ' _ , T > > {
52
+ self . stored . get ( index) . map ( |stored|
53
+ // SAFE: ResourceRefMut ensures that this borrow is unique
54
+ unsafe {
55
+ let value = & stored. value as * const T as * mut T ;
56
+ ResourceRefMut :: new ( & mut * value, & stored. atomic_borrow )
57
+ } )
58
+ }
59
+
60
+ fn push ( & mut self , resource : T ) {
61
+ self . stored . push ( StoredResource {
62
+ atomic_borrow : AtomicBorrow :: new ( ) ,
63
+ value : resource,
64
+ } )
65
+ }
66
+
67
+ fn set ( & mut self , index : usize , resource : T ) {
68
+ self . stored [ index] . value = resource;
69
+ }
70
+
71
+ fn is_empty ( & self ) -> bool {
72
+ self . stored . is_empty ( )
73
+ }
74
+ }
75
+
76
+ impl < T : ' static > Default for VecResourceStorage < T > {
77
+ fn default ( ) -> Self {
78
+ Self {
79
+ stored : Default :: default ( ) ,
80
+ }
81
+ }
82
+ }
83
+
84
+ impl < T : ' static > ResourceStorage for VecResourceStorage < T > { }
85
+
25
86
/// A collection of resource instances identified by their type.
26
- #[ derive( Debug , Default ) ]
27
87
pub struct Resources {
28
88
pub ( crate ) resource_data : HashMap < TypeId , ResourceData > ,
89
+ thread_local_data : HashMap < TypeId , Box < dyn ResourceStorage > > ,
90
+ main_thread_id : ThreadId ,
91
+ }
92
+
93
+ impl Default for Resources {
94
+ fn default ( ) -> Self {
95
+ Resources {
96
+ resource_data : Default :: default ( ) ,
97
+ thread_local_data : Default :: default ( ) ,
98
+ main_thread_id : std:: thread:: current ( ) . id ( ) ,
99
+ }
100
+ }
29
101
}
30
102
31
103
impl Resources {
32
104
pub fn insert < T : Resource > ( & mut self , resource : T ) {
33
105
self . insert_resource ( resource, ResourceIndex :: Global ) ;
34
106
}
35
107
108
+ pub fn insert_thread_local < T : ' static > ( & mut self , resource : T ) {
109
+ self . check_thread_local ( ) ;
110
+ let entry = self
111
+ . thread_local_data
112
+ . entry ( TypeId :: of :: < T > ( ) )
113
+ . or_insert_with ( || Box :: new ( VecResourceStorage :: < T > :: default ( ) ) ) ;
114
+ let resources = entry. downcast_mut :: < VecResourceStorage < T > > ( ) . unwrap ( ) ;
115
+ if resources. is_empty ( ) {
116
+ resources. push ( resource) ;
117
+ } else {
118
+ resources. set ( 0 , resource) ;
119
+ }
120
+ }
121
+
122
+ fn check_thread_local ( & self ) {
123
+ if std:: thread:: current ( ) . id ( ) != self . main_thread_id {
124
+ panic ! ( "Attempted to access a thread local resource off of the main thread." )
125
+ }
126
+ }
127
+
36
128
pub fn contains < T : Resource > ( & self ) -> bool {
37
129
self . get_resource :: < T > ( ResourceIndex :: Global ) . is_some ( )
38
130
}
@@ -45,6 +137,26 @@ impl Resources {
45
137
self . get_resource_mut ( ResourceIndex :: Global )
46
138
}
47
139
140
+ pub fn get_thread_local < T : ' static > ( & self ) -> Option < ResourceRef < ' _ , T > > {
141
+ self . check_thread_local ( ) ;
142
+ self . thread_local_data
143
+ . get ( & TypeId :: of :: < T > ( ) )
144
+ . and_then ( |storage| {
145
+ let resources = storage. downcast_ref :: < VecResourceStorage < T > > ( ) . unwrap ( ) ;
146
+ resources. get ( 0 )
147
+ } )
148
+ }
149
+
150
+ pub fn get_thread_local_mut < T : ' static > ( & self ) -> Option < ResourceRefMut < ' _ , T > > {
151
+ self . check_thread_local ( ) ;
152
+ self . thread_local_data
153
+ . get ( & TypeId :: of :: < T > ( ) )
154
+ . and_then ( |storage| {
155
+ let resources = storage. downcast_ref :: < VecResourceStorage < T > > ( ) . unwrap ( ) ;
156
+ resources. get_mut ( 0 )
157
+ } )
158
+ }
159
+
48
160
/// Returns a clone of the underlying resource, this is helpful when borrowing something
49
161
/// cloneable (like a task pool) without taking a borrow on the resource map
50
162
pub fn get_cloned < T : Resource + Clone > ( & self ) -> Option < T > {
@@ -281,6 +393,93 @@ where
281
393
}
282
394
}
283
395
396
+ /// Shared borrow of an entity's component
397
+ #[ derive( Clone ) ]
398
+ pub struct ResourceRef < ' a , T : ' static > {
399
+ borrow : & ' a AtomicBorrow ,
400
+ resource : & ' a T ,
401
+ }
402
+
403
+ impl < ' a , T : ' static > ResourceRef < ' a , T > {
404
+ /// Creates a new resource borrow
405
+ pub fn new ( resource : & ' a T , borrow : & ' a AtomicBorrow ) -> Self {
406
+ borrow. borrow ( ) ;
407
+ Self { resource, borrow }
408
+ }
409
+ }
410
+
411
+ unsafe impl < T : ' static > Send for ResourceRef < ' _ , T > { }
412
+ unsafe impl < T : ' static > Sync for ResourceRef < ' _ , T > { }
413
+
414
+ impl < ' a , T : ' static > Drop for ResourceRef < ' a , T > {
415
+ fn drop ( & mut self ) {
416
+ self . borrow . release ( )
417
+ }
418
+ }
419
+
420
+ impl < ' a , T : ' static > Deref for ResourceRef < ' a , T > {
421
+ type Target = T ;
422
+
423
+ fn deref ( & self ) -> & T {
424
+ self . resource
425
+ }
426
+ }
427
+
428
+ impl < ' a , T : ' static > Debug for ResourceRef < ' a , T >
429
+ where
430
+ T : Debug ,
431
+ {
432
+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
433
+ self . deref ( ) . fmt ( f)
434
+ }
435
+ }
436
+
437
+ /// Unique borrow of a resource
438
+ pub struct ResourceRefMut < ' a , T : ' static > {
439
+ borrow : & ' a AtomicBorrow ,
440
+ resource : & ' a mut T ,
441
+ }
442
+
443
+ impl < ' a , T : ' static > ResourceRefMut < ' a , T > {
444
+ /// Creates a new entity component mutable borrow
445
+ pub fn new ( resource : & ' a mut T , borrow : & ' a AtomicBorrow ) -> Self {
446
+ borrow. borrow_mut ( ) ;
447
+ Self { resource, borrow }
448
+ }
449
+ }
450
+
451
+ unsafe impl < T : ' static > Send for ResourceRefMut < ' _ , T > { }
452
+ unsafe impl < T : ' static > Sync for ResourceRefMut < ' _ , T > { }
453
+
454
+ impl < ' a , T : ' static > Drop for ResourceRefMut < ' a , T > {
455
+ fn drop ( & mut self ) {
456
+ self . borrow . release_mut ( ) ;
457
+ }
458
+ }
459
+
460
+ impl < ' a , T : ' static > Deref for ResourceRefMut < ' a , T > {
461
+ type Target = T ;
462
+
463
+ fn deref ( & self ) -> & T {
464
+ self . resource
465
+ }
466
+ }
467
+
468
+ impl < ' a , T : ' static > DerefMut for ResourceRefMut < ' a , T > {
469
+ fn deref_mut ( & mut self ) -> & mut T {
470
+ self . resource
471
+ }
472
+ }
473
+
474
+ impl < ' a , T : ' static > Debug for ResourceRefMut < ' a , T >
475
+ where
476
+ T : Debug ,
477
+ {
478
+ fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
479
+ self . deref ( ) . fmt ( f)
480
+ }
481
+ }
482
+
284
483
#[ cfg( test) ]
285
484
mod tests {
286
485
use super :: Resources ;
@@ -335,4 +534,44 @@ mod tests {
335
534
let _x = resources. get_mut :: < i32 > ( ) ;
336
535
let _y = resources. get_mut :: < i32 > ( ) ;
337
536
}
537
+
538
+ #[ test]
539
+ fn thread_local_resource ( ) {
540
+ let mut resources = Resources :: default ( ) ;
541
+ resources. insert_thread_local ( 123i32 ) ;
542
+ resources. insert_thread_local ( 456i64 ) ;
543
+ assert_eq ! ( * resources. get_thread_local:: <i32 >( ) . unwrap( ) , 123 ) ;
544
+ assert_eq ! ( * resources. get_thread_local_mut:: <i64 >( ) . unwrap( ) , 456 ) ;
545
+ }
546
+
547
+ #[ test]
548
+ fn thread_local_resource_ref_aliasing ( ) {
549
+ let mut resources = Resources :: default ( ) ;
550
+ resources. insert_thread_local ( 123i32 ) ;
551
+ let a = resources. get_thread_local :: < i32 > ( ) . unwrap ( ) ;
552
+ let b = resources. get_thread_local :: < i32 > ( ) . unwrap ( ) ;
553
+ assert_eq ! ( * a, 123 ) ;
554
+ assert_eq ! ( * b, 123 ) ;
555
+ }
556
+
557
+ #[ test]
558
+ #[ should_panic]
559
+ fn thread_local_resource_mut_ref_aliasing ( ) {
560
+ let mut resources = Resources :: default ( ) ;
561
+ resources. insert_thread_local ( 123i32 ) ;
562
+ let _a = resources. get_thread_local :: < i32 > ( ) . unwrap ( ) ;
563
+ let _b = resources. get_thread_local_mut :: < i32 > ( ) . unwrap ( ) ;
564
+ }
565
+
566
+ #[ test]
567
+ #[ should_panic]
568
+ fn thread_local_resource_panic ( ) {
569
+ let mut resources = Resources :: default ( ) ;
570
+ resources. insert_thread_local ( 0i32 ) ;
571
+ std:: thread:: spawn ( move || {
572
+ let _ = resources. get_thread_local_mut :: < i32 > ( ) ;
573
+ } )
574
+ . join ( )
575
+ . unwrap ( ) ;
576
+ }
338
577
}
0 commit comments