1
1
use crate :: {
2
2
archetype:: { Archetype , ArchetypeId , Archetypes } ,
3
3
bundle:: { Bundle , BundleInfo } ,
4
- change_detection:: Ticks ,
4
+ change_detection:: { MutUntyped , Ticks } ,
5
5
component:: { Component , ComponentId , ComponentTicks , Components , StorageType } ,
6
6
entity:: { Entities , Entity , EntityLocation } ,
7
7
storage:: { SparseSet , Storages } ,
@@ -103,14 +103,31 @@ impl<'w> EntityRef<'w> {
103
103
. map ( |( value, ticks) | Mut {
104
104
value : value. assert_unique ( ) . deref_mut :: < T > ( ) ,
105
105
ticks : Ticks {
106
- component_ticks : & mut * ticks. get ( ) ,
106
+ component_ticks : ticks. deref_mut ( ) ,
107
107
last_change_tick,
108
108
change_tick,
109
109
} ,
110
110
} )
111
111
}
112
112
}
113
113
114
+ impl < ' w > EntityRef < ' w > {
115
+ /// Gets the component of the given [`ComponentId`] from the entity.
116
+ ///
117
+ /// **You should prefer to use the typed API where possible and only
118
+ /// use this in cases where the actual component types are not known at
119
+ /// compile time.**
120
+ ///
121
+ /// Unlike [`EntityRef::get`], this returns a raw pointer to the component,
122
+ /// which is only valid while the `'w` borrow of the lifetime is active.
123
+ #[ inline]
124
+ pub fn get_by_id ( & self , component_id : ComponentId ) -> Option < Ptr < ' w > > {
125
+ self . world . components ( ) . get_info ( component_id) ?;
126
+ // SAFE: entity_location is valid, component_id is valid as checked by the line above
127
+ unsafe { get_component ( self . world , component_id, self . entity , self . location ) }
128
+ }
129
+ }
130
+
114
131
/// A mutable reference to a particular [`Entity`] and all of its components
115
132
pub struct EntityMut < ' w > {
116
133
world : & ' w mut World ,
@@ -207,7 +224,7 @@ impl<'w> EntityMut<'w> {
207
224
. map ( |( value, ticks) | Mut {
208
225
value : value. assert_unique ( ) . deref_mut :: < T > ( ) ,
209
226
ticks : Ticks {
210
- component_ticks : & mut * ticks. get ( ) ,
227
+ component_ticks : ticks. deref_mut ( ) ,
211
228
last_change_tick : self . world . last_change_tick ( ) ,
212
229
change_tick : self . world . read_change_tick ( ) ,
213
230
} ,
@@ -488,14 +505,47 @@ impl<'w> EntityMut<'w> {
488
505
}
489
506
}
490
507
508
+ impl < ' w > EntityMut < ' w > {
509
+ /// Gets the component of the given [`ComponentId`] from the entity.
510
+ ///
511
+ /// **You should prefer to use the typed API [`EntityMut::get`] where possible and only
512
+ /// use this in cases where the actual component types are not known at
513
+ /// compile time.**
514
+ ///
515
+ /// Unlike [`EntityMut::get`], this returns a raw pointer to the component,
516
+ /// which is only valid while the [`EntityMut`] is alive.
517
+ #[ inline]
518
+ pub fn get_by_id ( & self , component_id : ComponentId ) -> Option < Ptr < ' _ > > {
519
+ self . world . components ( ) . get_info ( component_id) ?;
520
+ // SAFE: entity_location is valid, component_id is valid as checked by the line above
521
+ unsafe { get_component ( self . world , component_id, self . entity , self . location ) }
522
+ }
523
+
524
+ /// Gets a [`MutUntyped`] of the component of the given [`ComponentId`] from the entity.
525
+ ///
526
+ /// **You should prefer to use the typed API [`EntityMut::get_mut`] where possible and only
527
+ /// use this in cases where the actual component types are not known at
528
+ /// compile time.**
529
+ ///
530
+ /// Unlike [`EntityMut::get_mut`], this returns a raw pointer to the component,
531
+ /// which is only valid while the [`EntityMut`] is alive.
532
+ #[ inline]
533
+ pub fn get_mut_by_id ( & mut self , component_id : ComponentId ) -> Option < MutUntyped < ' _ > > {
534
+ self . world . components ( ) . get_info ( component_id) ?;
535
+ // SAFE: entity_location is valid, component_id is valid as checked by the line above
536
+ unsafe { get_mut_by_id ( self . world , self . entity , self . location , component_id) }
537
+ }
538
+ }
539
+
491
540
// TODO: move to Storages?
492
541
/// Get a raw pointer to a particular [`Component`] on a particular [`Entity`] in the provided [`World`].
493
542
///
494
543
/// # Safety
495
- /// `entity_location` must be within bounds of the given archetype and `entity` must exist inside
544
+ /// - `entity_location` must be within bounds of the given archetype and `entity` must exist inside
496
545
/// the archetype
546
+ /// - `component_id` must be valid
497
547
#[ inline]
498
- unsafe fn get_component (
548
+ pub ( crate ) unsafe fn get_component (
499
549
world : & World ,
500
550
component_id : ComponentId ,
501
551
entity : Entity ,
@@ -808,16 +858,41 @@ pub(crate) unsafe fn get_mut<T: Component>(
808
858
|( value, ticks) | Mut {
809
859
value : value. assert_unique ( ) . deref_mut :: < T > ( ) ,
810
860
ticks : Ticks {
811
- component_ticks : & mut * ticks. get ( ) ,
861
+ component_ticks : ticks. deref_mut ( ) ,
812
862
last_change_tick,
813
863
change_tick,
814
864
} ,
815
865
} ,
816
866
)
817
867
}
818
868
869
+ // SAFETY: EntityLocation must be valid, component_id must be valid
870
+ #[ inline]
871
+ pub ( crate ) unsafe fn get_mut_by_id (
872
+ world : & mut World ,
873
+ entity : Entity ,
874
+ location : EntityLocation ,
875
+ component_id : ComponentId ,
876
+ ) -> Option < MutUntyped > {
877
+ // SAFE: world access is unique, entity location and component_id required to be valid
878
+ get_component_and_ticks ( world, component_id, entity, location) . map ( |( value, ticks) | {
879
+ MutUntyped {
880
+ value : value. assert_unique ( ) ,
881
+ ticks : Ticks {
882
+ component_ticks : ticks. deref_mut ( ) ,
883
+ last_change_tick : world. last_change_tick ( ) ,
884
+ change_tick : world. read_change_tick ( ) ,
885
+ } ,
886
+ }
887
+ } )
888
+ }
889
+
819
890
#[ cfg( test) ]
820
891
mod tests {
892
+ use crate as bevy_ecs;
893
+ use crate :: component:: ComponentId ;
894
+ use crate :: prelude:: * ; // for the `#[derive(Component)]`
895
+
821
896
#[ test]
822
897
fn sorted_remove ( ) {
823
898
let mut a = vec ! [ 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ;
@@ -838,4 +913,70 @@ mod tests {
838
913
839
914
assert_eq ! ( a, vec![ 1 ] ) ;
840
915
}
916
+
917
+ #[ derive( Component ) ]
918
+ struct TestComponent ( u32 ) ;
919
+
920
+ #[ test]
921
+ fn entity_ref_get_by_id ( ) {
922
+ let mut world = World :: new ( ) ;
923
+ let entity = world. spawn ( ) . insert ( TestComponent ( 42 ) ) . id ( ) ;
924
+ let component_id = world
925
+ . components ( )
926
+ . get_id ( std:: any:: TypeId :: of :: < TestComponent > ( ) )
927
+ . unwrap ( ) ;
928
+
929
+ let entity = world. entity ( entity) ;
930
+ let test_component = entity. get_by_id ( component_id) . unwrap ( ) ;
931
+ // SAFE: points to a valid `TestComponent`
932
+ let test_component = unsafe { test_component. deref :: < TestComponent > ( ) } ;
933
+
934
+ assert_eq ! ( test_component. 0 , 42 ) ;
935
+ }
936
+
937
+ #[ test]
938
+ fn entity_mut_get_by_id ( ) {
939
+ let mut world = World :: new ( ) ;
940
+ let entity = world. spawn ( ) . insert ( TestComponent ( 42 ) ) . id ( ) ;
941
+ let component_id = world
942
+ . components ( )
943
+ . get_id ( std:: any:: TypeId :: of :: < TestComponent > ( ) )
944
+ . unwrap ( ) ;
945
+
946
+ let mut entity_mut = world. entity_mut ( entity) ;
947
+ let mut test_component = entity_mut. get_mut_by_id ( component_id) . unwrap ( ) ;
948
+ {
949
+ test_component. set_changed ( ) ;
950
+ // SAFE: `test_component` has unique access of the `EntityMut` and is not used afterwards
951
+ let test_component =
952
+ unsafe { test_component. into_inner ( ) . deref_mut :: < TestComponent > ( ) } ;
953
+ test_component. 0 = 43 ;
954
+ }
955
+
956
+ let entity = world. entity ( entity) ;
957
+ let test_component = entity. get_by_id ( component_id) . unwrap ( ) ;
958
+ let test_component = unsafe { test_component. deref :: < TestComponent > ( ) } ;
959
+
960
+ assert_eq ! ( test_component. 0 , 43 ) ;
961
+ }
962
+
963
+ #[ test]
964
+ fn entity_ref_get_by_id_invalid_component_id ( ) {
965
+ let invalid_component_id = ComponentId :: new ( usize:: MAX ) ;
966
+
967
+ let mut world = World :: new ( ) ;
968
+ let entity = world. spawn ( ) . id ( ) ;
969
+ let entity = world. entity ( entity) ;
970
+ assert ! ( entity. get_by_id( invalid_component_id) . is_none( ) ) ;
971
+ }
972
+
973
+ #[ test]
974
+ fn entity_mut_get_by_id_invalid_component_id ( ) {
975
+ let invalid_component_id = ComponentId :: new ( usize:: MAX ) ;
976
+
977
+ let mut world = World :: new ( ) ;
978
+ let mut entity = world. spawn ( ) ;
979
+ assert ! ( entity. get_by_id( invalid_component_id) . is_none( ) ) ;
980
+ assert ! ( entity. get_mut_by_id( invalid_component_id) . is_none( ) ) ;
981
+ }
841
982
}
0 commit comments