15
15
*
16
16
*/
17
17
18
- use bevy:: prelude :: { Entity , Commands } ;
18
+ use bevy:: utils :: all_tuples ;
19
19
20
20
use smallvec:: SmallVec ;
21
21
@@ -29,174 +29,82 @@ pub trait Unzippable: Sized {
29
29
type Unzipped ;
30
30
fn unzip_output ( output : Output < Self > , builder : & mut Builder ) -> Self :: Unzipped ;
31
31
32
- fn make_targets ( commands : & mut Commands ) -> SmallVec < [ Entity ; 8 ] > ;
33
-
34
32
fn distribute_values ( request : OperationRequest ) -> OperationResult ;
35
33
36
34
type Prepended < T > ;
37
35
fn prepend < T > ( self , value : T ) -> Self :: Prepended < T > ;
38
36
}
39
37
40
- impl < A : ' static + Send + Sync > Unzippable for ( A , ) {
41
- type Unzipped = Output < A > ;
42
- fn unzip_output ( output : Output < Self > , builder : & mut Builder ) -> Self :: Unzipped {
43
- assert_eq ! ( output. scope( ) , builder. scope( ) ) ;
44
- let targets = Self :: make_targets ( builder. commands ) ;
45
-
46
- let result = Output :: new ( builder. scope , targets[ 0 ] ) ;
47
-
48
- builder. commands . add ( AddOperation :: new (
49
- Some ( output. scope ( ) ) ,
50
- output. id ( ) ,
51
- ForkUnzip :: < Self > :: new ( ForkTargetStorage ( targets) ) ,
52
- ) ) ;
53
- result
54
- }
55
-
56
- fn make_targets ( commands : & mut Commands ) -> SmallVec < [ Entity ; 8 ] > {
57
- SmallVec :: from_iter ( [ commands. spawn ( UnusedTarget ) . id ( ) ] )
58
- }
59
-
60
- fn distribute_values (
61
- OperationRequest { source, world, roster } : OperationRequest
62
- ) -> OperationResult {
63
- let Input { session, data : inputs } = world
64
- . get_entity_mut ( source) . or_broken ( ) ?
65
- . take_input :: < Self > ( ) ?;
66
-
67
- let targets = world. get :: < ForkTargetStorage > ( source) . or_broken ( ) ?;
68
- let target = ( targets. 0 ) [ 0 ] ;
69
- if let Some ( mut t_mut) = world. get_entity_mut ( target) {
70
- t_mut. give_input ( session, inputs. 0 , roster) ?;
71
- }
72
- Ok ( ( ) )
73
- }
74
-
75
- type Prepended < T > = ( T , A ) ;
76
- fn prepend < T > ( self , value : T ) -> Self :: Prepended < T > {
77
- ( value, self . 0 )
78
- }
79
- }
80
-
81
- impl < A : ' static + Send + Sync , B : ' static + Send + Sync > Unzippable for ( A , B ) {
82
- type Unzipped = ( Output < A > , Output < B > ) ;
83
- fn unzip_output ( output : Output < Self > , builder : & mut Builder ) -> Self :: Unzipped {
84
- assert_eq ! ( output. scope( ) , builder. scope( ) ) ;
85
- let targets = Self :: make_targets ( builder. commands ) ;
86
-
87
- let result = (
88
- Output :: new ( builder. scope , targets[ 0 ] ) ,
89
- Output :: new ( builder. scope , targets[ 1 ] ) ,
90
- ) ;
91
-
92
- builder. commands . add ( AddOperation :: new (
93
- Some ( output. scope ( ) ) ,
94
- output. id ( ) ,
95
- ForkUnzip :: < Self > :: new ( ForkTargetStorage ( targets) ) ,
96
- ) ) ;
97
- result
98
- }
99
-
100
- fn make_targets ( commands : & mut Commands ) -> SmallVec < [ Entity ; 8 ] > {
101
- SmallVec :: from_iter ( [
102
- commands. spawn ( UnusedTarget ) . id ( ) ,
103
- commands. spawn ( UnusedTarget ) . id ( ) ,
104
- ] )
105
- }
106
-
107
- fn distribute_values (
108
- OperationRequest { source, world, roster } : OperationRequest ,
109
- ) -> OperationResult {
110
- let Input { session, data : inputs } = world
111
- . get_entity_mut ( source) . or_broken ( ) ?
112
- . take_input :: < Self > ( ) ?;
113
-
114
- let targets = world. get :: < ForkTargetStorage > ( source) . or_broken ( ) ?;
115
- let target_0 = * targets. 0 . get ( 0 ) . or_broken ( ) ?;
116
- let target_1 = * targets. 0 . get ( 1 ) . or_broken ( ) ?;
117
-
118
- if let Some ( mut t_mut) = world. get_entity_mut ( target_0) {
119
- t_mut. give_input ( session, inputs. 0 , roster) ?;
120
- }
121
-
122
- if let Some ( mut t_mut) = world. get_entity_mut ( target_1) {
123
- t_mut. give_input ( session, inputs. 1 , roster) ?;
38
+ macro_rules! impl_unzippable_for_tuple {
39
+ ( $( $T: ident) ,* ) => {
40
+ #[ allow( non_snake_case) ]
41
+ impl <$( $T: ' static + Send + Sync ) ,* > Unzippable for ( $( $T, ) * )
42
+ {
43
+ type Unzipped = ( $( Output <$T>, ) * ) ;
44
+ fn unzip_output( output: Output <Self >, builder: & mut Builder ) -> Self :: Unzipped {
45
+ assert_eq!( output. scope( ) , builder. scope( ) ) ;
46
+ let mut targets = SmallVec :: new( ) ;
47
+ let result =
48
+ (
49
+ $(
50
+ {
51
+ // Variable is only used to make sure this cycle is repeated once
52
+ // for each instance of the $T type, but the type itself is not
53
+ // used.
54
+ #[ allow( unused) ]
55
+ let $T = std:: marker:: PhantomData :: <$T>;
56
+ let target = builder. commands. spawn( UnusedTarget ) . id( ) ;
57
+ targets. push( target) ;
58
+ Output :: new( builder. scope, target)
59
+ } ,
60
+ ) *
61
+ ) ;
62
+
63
+ builder. commands. add( AddOperation :: new(
64
+ Some ( output. scope( ) ) ,
65
+ output. id( ) ,
66
+ ForkUnzip :: <Self >:: new( ForkTargetStorage ( targets) ) ,
67
+ ) ) ;
68
+ result
69
+ }
70
+
71
+ fn distribute_values(
72
+ OperationRequest { source, world, roster } : OperationRequest ,
73
+ ) -> OperationResult {
74
+ let Input { session, data: inputs } = world
75
+ . get_entity_mut( source) . or_broken( ) ?
76
+ . take_input:: <Self >( ) ?;
77
+
78
+ // Targets is cloned to avoid borrow checker issues when
79
+ // doing a mutable borrow of the world later
80
+ let targets = world. get:: <ForkTargetStorage >( source) . or_broken( ) ?. clone( ) ;
81
+ // The compiler throws a warning when implementing this for
82
+ // tuple sizes that wouldn't use the result of the first _idx = _idx + 1
83
+ // so we add a leading underscore to suppress the warning
84
+ let mut _idx = 0 ;
85
+ let ( $( $T, ) * ) = inputs;
86
+ $(
87
+ let target = * targets. 0 . get( _idx) . or_broken( ) ?;
88
+ if let Some ( mut t_mut) = world. get_entity_mut( target) {
89
+ t_mut. give_input( session, $T, roster) ?;
90
+ }
91
+ _idx = _idx + 1 ;
92
+ ) *
93
+ Ok ( ( ) )
94
+ }
95
+
96
+ type Prepended <T > = ( T , $( $T, ) * ) ;
97
+ fn prepend<T >( self , value: T ) -> Self :: Prepended <T > {
98
+ let ( $( $T, ) * ) = self ;
99
+ ( value, $( $T, ) * )
100
+ }
124
101
}
125
-
126
- Ok ( ( ) )
127
- }
128
-
129
- type Prepended < T > = ( T , A , B ) ;
130
- fn prepend < T > ( self , value : T ) -> Self :: Prepended < T > {
131
- ( value, self . 0 , self . 1 )
132
102
}
133
103
}
134
104
135
- impl < A , B , C > Unzippable for ( A , B , C )
136
- where
137
- A : ' static + Send + Sync ,
138
- B : ' static + Send + Sync ,
139
- C : ' static + Send + Sync ,
140
- {
141
- type Unzipped = ( Output < A > , Output < B > , Output < C > ) ;
142
- fn unzip_output ( output : Output < Self > , builder : & mut Builder ) -> Self :: Unzipped {
143
- assert_eq ! ( output. scope( ) , builder. scope( ) ) ;
144
- let targets = Self :: make_targets ( builder. commands ) ;
145
-
146
- let result = (
147
- Output :: new ( builder. scope , targets[ 0 ] ) ,
148
- Output :: new ( builder. scope , targets[ 1 ] ) ,
149
- Output :: new ( builder. scope , targets[ 2 ] ) ,
150
- ) ;
151
-
152
- builder. commands . add ( AddOperation :: new (
153
- Some ( output. scope ( ) ) ,
154
- output. id ( ) ,
155
- ForkUnzip :: < Self > :: new ( ForkTargetStorage ( targets) ) ,
156
- ) ) ;
157
- result
158
- }
159
-
160
- fn make_targets ( commands : & mut Commands ) -> SmallVec < [ Entity ; 8 ] > {
161
- SmallVec :: from_iter ( [
162
- commands. spawn ( UnusedTarget ) . id ( ) ,
163
- commands. spawn ( UnusedTarget ) . id ( ) ,
164
- commands. spawn ( UnusedTarget ) . id ( ) ,
165
- ] )
166
- }
167
-
168
- fn distribute_values (
169
- OperationRequest { source, world, roster } : OperationRequest ,
170
- ) -> OperationResult {
171
- let Input { session, data : inputs } = world
172
- . get_entity_mut ( source) . or_broken ( ) ?
173
- . take_input :: < Self > ( ) ?;
174
-
175
- let targets = world. get :: < ForkTargetStorage > ( source) . or_broken ( ) ?;
176
- let target_0 = * targets. 0 . get ( 0 ) . or_broken ( ) ?;
177
- let target_1 = * targets. 0 . get ( 1 ) . or_broken ( ) ?;
178
- let target_2 = * targets. 0 . get ( 2 ) . or_broken ( ) ?;
179
-
180
- if let Some ( mut t_mut) = world. get_entity_mut ( target_0) {
181
- t_mut. give_input ( session, inputs. 0 , roster) ?;
182
- }
183
-
184
- if let Some ( mut t_mut) = world. get_entity_mut ( target_1) {
185
- t_mut. give_input ( session, inputs. 1 , roster) ?;
186
- }
187
-
188
- if let Some ( mut t_mut) = world. get_entity_mut ( target_2) {
189
- t_mut. give_input ( session, inputs. 2 , roster) ?;
190
- }
191
-
192
- Ok ( ( ) )
193
- }
194
-
195
- type Prepended < T > = ( T , A , B , C ) ;
196
- fn prepend < T > ( self , value : T ) -> Self :: Prepended < T > {
197
- ( value, self . 0 , self . 1 , self . 2 )
198
- }
199
- }
105
+ // Implements the `Unzippable` trait for all tuples between size 1 and 15
106
+ // (inclusive) made of 'static lifetime types that are `Send` and `Sync`
107
+ all_tuples ! ( impl_unzippable_for_tuple, 1 , 15 , T ) ;
200
108
201
109
/// A trait for constructs that are able to perform a forking unzip of an
202
110
/// unzippable chain. An unzippable chain is one whose response type contains a
@@ -206,37 +114,25 @@ pub trait UnzipBuilder<Z> {
206
114
fn unzip_build ( self , output : Output < Z > , builder : & mut Builder ) -> Self :: ReturnType ;
207
115
}
208
116
209
- impl < A , Fa , Ua , B , Fb , Ub > UnzipBuilder < ( A , B ) > for ( Fa , Fb )
210
- where
211
- A : ' static + Send + Sync ,
212
- B : ' static + Send + Sync ,
213
- Fa : FnOnce ( Chain < A > ) -> Ua ,
214
- Fb : FnOnce ( Chain < B > ) -> Ub ,
215
- {
216
- type ReturnType = ( Ua , Ub ) ;
217
- fn unzip_build ( self , output : Output < ( A , B ) > , builder : & mut Builder ) -> Self :: ReturnType {
218
- let outputs = <( A , B ) >:: unzip_output ( output, builder) ;
219
- let u_a = ( self . 0 ) ( outputs. 0 . chain ( builder) ) ;
220
- let u_b = ( self . 1 ) ( outputs. 1 . chain ( builder) ) ;
221
- ( u_a, u_b)
117
+ macro_rules! impl_unzipbuilder_for_tuple {
118
+ ( $( ( $A: ident, $F: ident, $U: ident) ) ,* ) => {
119
+ #[ allow( non_snake_case) ]
120
+ impl <$( $A: ' static + Send + Sync ) ,* , $( $F: FnOnce ( Chain <$A>) -> $U) ,* , $( $U) ,* > UnzipBuilder <( $( $A, ) * ) > for ( $( $F, ) * )
121
+ {
122
+ type ReturnType = ( $( $U) ,* ) ;
123
+ fn unzip_build( self , output: Output <( $( $A, ) * ) >, builder: & mut Builder ) -> Self :: ReturnType {
124
+ let outputs = <( $( $A) ,* ) >:: unzip_output( output, builder) ;
125
+ let ( $( $A, ) * ) = outputs;
126
+ let ( $( $F, ) * ) = self ;
127
+ (
128
+ $(
129
+ ( $F) ( $A. chain( builder) ) ,
130
+ ) *
131
+ )
132
+ }
133
+ }
222
134
}
223
135
}
224
136
225
- impl < A , Fa , Ua , B , Fb , Ub , C , Fc , Uc > UnzipBuilder < ( A , B , C ) > for ( Fa , Fb , Fc )
226
- where
227
- A : ' static + Send + Sync ,
228
- B : ' static + Send + Sync ,
229
- C : ' static + Send + Sync ,
230
- Fa : FnOnce ( Chain < A > ) -> Ua ,
231
- Fb : FnOnce ( Chain < B > ) -> Ub ,
232
- Fc : FnOnce ( Chain < C > ) -> Uc ,
233
- {
234
- type ReturnType = ( Ua , Ub , Uc ) ;
235
- fn unzip_build ( self , output : Output < ( A , B , C ) > , builder : & mut Builder ) -> Self :: ReturnType {
236
- let outputs = <( A , B , C ) >:: unzip_output ( output, builder) ;
237
- let u_a = ( self . 0 ) ( outputs. 0 . chain ( builder) ) ;
238
- let u_b = ( self . 1 ) ( outputs. 1 . chain ( builder) ) ;
239
- let u_c = ( self . 2 ) ( outputs. 2 . chain ( builder) ) ;
240
- ( u_a, u_b, u_c)
241
- }
242
- }
137
+ // Implements the `UnzipBuilder` trait for all tuples between size 1 and 15
138
+ all_tuples ! ( impl_unzipbuilder_for_tuple, 2 , 15 , A , F , U ) ;
0 commit comments