@@ -759,3 +759,117 @@ impl<Trait: ?Sized + TraitQuery> QueryFilter for OneChanged<Trait> {
759
759
<Self as WorldQuery >:: fetch ( fetch, entity, table_row)
760
760
}
761
761
}
762
+
763
+ /// [`WorldQuery`] filter for entities with exactly [one](crate::One) component
764
+ /// implementing a trait.
765
+ pub struct WithOne < Trait : ?Sized + TraitQuery > ( PhantomData < & ' static Trait > ) ;
766
+
767
+ // this takes inspiration from `With` in bevy's main repo
768
+ unsafe impl < Trait : ?Sized + TraitQuery > WorldQuery for WithOne < Trait > {
769
+ type Item < ' w > = ( ) ;
770
+ type Fetch < ' w > = ( ) ;
771
+ type State = TraitQueryState < Trait > ;
772
+
773
+ #[ inline]
774
+ fn shrink < ' wlong : ' wshort , ' wshort > ( item : QueryItem < ' wlong , Self > ) -> QueryItem < ' wshort , Self > {
775
+ item
776
+ }
777
+
778
+ #[ inline]
779
+ unsafe fn init_fetch < ' w > (
780
+ _world : UnsafeWorldCell < ' w > ,
781
+ _state : & Self :: State ,
782
+ _last_run : Tick ,
783
+ _this_run : Tick ,
784
+ ) {
785
+ }
786
+
787
+ const IS_DENSE : bool = false ;
788
+ // const IS_ARCHETYPAL: bool = false;
789
+
790
+ #[ inline]
791
+ unsafe fn set_archetype < ' w > (
792
+ _fetch : & mut ( ) ,
793
+ _state : & Self :: State ,
794
+ _archetype : & ' w bevy_ecs:: archetype:: Archetype ,
795
+ _table : & ' w bevy_ecs:: storage:: Table ,
796
+ ) {
797
+ }
798
+
799
+ #[ inline]
800
+ unsafe fn set_table < ' w > (
801
+ _fetch : & mut ( ) ,
802
+ _state : & Self :: State ,
803
+ _table : & ' w bevy_ecs:: storage:: Table ,
804
+ ) {
805
+ }
806
+
807
+ #[ inline]
808
+ unsafe fn fetch < ' w > (
809
+ _fetch : & mut Self :: Fetch < ' w > ,
810
+ _entity : Entity ,
811
+ _table_row : TableRow ,
812
+ ) -> Self :: Item < ' w > {
813
+ }
814
+
815
+ #[ inline]
816
+ fn update_component_access (
817
+ state : & Self :: State ,
818
+ access : & mut bevy_ecs:: query:: FilteredAccess < ComponentId > ,
819
+ ) {
820
+ let mut new_access = access. clone ( ) ;
821
+ let mut not_first = false ;
822
+ for & component in & * state. components {
823
+ assert ! (
824
+ !access. access( ) . has_write( component) ,
825
+ "&{} conflicts with a previous access in this query. Shared access cannot coincide with exclusive access." ,
826
+ std:: any:: type_name:: <Trait >( ) ,
827
+ ) ;
828
+ if not_first {
829
+ let mut intermediate = access. clone ( ) ;
830
+ intermediate. add_read ( component) ;
831
+ new_access. append_or ( & intermediate) ;
832
+ new_access. extend_access ( & intermediate) ;
833
+ } else {
834
+ new_access. and_with ( component) ;
835
+ new_access. access_mut ( ) . add_read ( component) ;
836
+ not_first = true ;
837
+ }
838
+ }
839
+ * access = new_access;
840
+ }
841
+
842
+ #[ inline]
843
+ fn init_state ( world : & mut World ) -> Self :: State {
844
+ TraitQueryState :: init ( world)
845
+ }
846
+
847
+ #[ inline]
848
+ fn get_state ( world : & World ) -> Option < Self :: State > {
849
+ TraitQueryState :: get ( world)
850
+ }
851
+
852
+ #[ inline]
853
+ fn matches_component_set (
854
+ state : & Self :: State ,
855
+ set_contains_id : & impl Fn ( ComponentId ) -> bool ,
856
+ ) -> bool {
857
+ state. matches_component_set_one ( set_contains_id)
858
+ }
859
+ }
860
+
861
+ /// SAFETY: read-only access
862
+ unsafe impl < Trait : ?Sized + TraitQuery > QueryData for WithOne < Trait > {
863
+ type ReadOnly = Self ;
864
+ }
865
+ unsafe impl < Trait : ?Sized + TraitQuery > ReadOnlyQueryData for WithOne < Trait > { }
866
+ impl < Trait : ?Sized + TraitQuery > QueryFilter for WithOne < Trait > {
867
+ const IS_ARCHETYPAL : bool = false ;
868
+ unsafe fn filter_fetch (
869
+ _fetch : & mut Self :: Fetch < ' _ > ,
870
+ _entity : Entity ,
871
+ _table_row : TableRow ,
872
+ ) -> bool {
873
+ true
874
+ }
875
+ }
0 commit comments