1mod not;
2mod or;
3mod tracking;
4
5use crate::component::Component;
6use crate::entity_id::EntityId;
7#[cfg(feature = "parallel")]
8use crate::iter::ParShiperator;
9use crate::iter::{captain::ShiperatorCaptain, mixed::Mixed, Shiperator};
10use crate::optional::Optional;
11use crate::sparse_set::{FullRawWindow, FullRawWindowMut, RawEntityIdAccess};
12use crate::storage::StorageId;
13use crate::tracking::Tracking;
14use crate::views::{View, ViewMut};
15use crate::ShipHashSet;
16use alloc::vec::Vec;
17use core::ptr::NonNull;
18
19pub trait IntoIter: IntoShiperator {
24 fn iter(self) -> Shiperator<Self::Shiperator>;
46 #[cfg(feature = "parallel")]
69 #[cfg_attr(docsrs, doc(cfg(feature = "parallel")))]
70 fn par_iter(self) -> ParShiperator<Self::Shiperator>;
71}
72
73impl<T: IntoShiperator> IntoIter for T
74where
75 <T as IntoShiperator>::Shiperator: ShiperatorCaptain,
76{
77 #[inline]
78 fn iter(self) -> Shiperator<Self::Shiperator> {
79 let mut storage_ids = ShipHashSet::new();
80 let (shiperator, len, entities) = self.into_shiperator(&mut storage_ids);
81 let is_infallible = shiperator.is_exact_sized();
82
83 Shiperator {
84 shiperator,
85 is_exact_sized: is_infallible,
86 entities,
87 start: 0,
88 end: len,
89 }
90 }
91
92 #[cfg(feature = "parallel")]
93 #[inline]
94 fn par_iter(self) -> ParShiperator<Self::Shiperator> {
95 ParShiperator(self.iter())
96 }
97}
98
99pub trait IntoShiperator {
101 #[allow(missing_docs)]
102 type Shiperator;
103
104 fn into_shiperator(
106 self,
107 storage_ids: &mut ShipHashSet<StorageId>,
108 ) -> (Self::Shiperator, usize, RawEntityIdAccess);
109 fn can_captain() -> bool;
111 fn can_sailor() -> bool;
113}
114
115impl<'tmp, 'v: 'tmp, T: Component, Track: Tracking> IntoShiperator for &'tmp View<'v, T, Track> {
116 type Shiperator = FullRawWindow<'tmp, T>;
117
118 #[inline]
119 fn into_shiperator(
120 self,
121 _storage_ids: &mut ShipHashSet<StorageId>,
122 ) -> (Self::Shiperator, usize, RawEntityIdAccess) {
123 let window = FullRawWindow::from_view(self);
124 let len = window.len();
125 let iter = window.entity_iter();
126
127 (window, len, iter)
128 }
129
130 #[inline]
131 fn can_captain() -> bool {
132 true
133 }
134
135 #[inline]
136 fn can_sailor() -> bool {
137 true
138 }
139}
140
141impl<'tmp, 'v: 'tmp, T: Component, Track: Tracking> IntoShiperator for &'tmp ViewMut<'v, T, Track> {
142 type Shiperator = FullRawWindow<'tmp, T>;
143
144 #[inline]
145 fn into_shiperator(
146 self,
147 _storage_ids: &mut ShipHashSet<StorageId>,
148 ) -> (Self::Shiperator, usize, RawEntityIdAccess) {
149 let window = FullRawWindow::from_view_mut(self);
150 let len = window.len();
151 let iter = window.entity_iter();
152
153 (window, len, iter)
154 }
155
156 #[inline]
157 fn can_captain() -> bool {
158 true
159 }
160
161 #[inline]
162 fn can_sailor() -> bool {
163 true
164 }
165}
166
167impl<'tmp, 'v: 'tmp, T: Component, Track> IntoShiperator for &'tmp mut ViewMut<'v, T, Track> {
168 type Shiperator = FullRawWindowMut<'tmp, T, Track>;
169
170 #[inline]
171 fn into_shiperator(
172 self,
173 _storage_ids: &mut ShipHashSet<StorageId>,
174 ) -> (Self::Shiperator, usize, RawEntityIdAccess) {
175 let window = FullRawWindowMut::new(self);
176 let len = window.len();
177 let iter = window.entity_iter();
178
179 (window, len, iter)
180 }
181
182 #[inline]
183 fn can_captain() -> bool {
184 true
185 }
186
187 #[inline]
188 fn can_sailor() -> bool {
189 true
190 }
191}
192
193impl<'tmp> IntoShiperator for &'tmp [EntityId] {
194 type Shiperator = &'tmp [EntityId];
195
196 #[inline]
197 fn into_shiperator(
198 self,
199 _storage_ids: &mut ShipHashSet<StorageId>,
200 ) -> (Self::Shiperator, usize, RawEntityIdAccess) {
201 let len = self.len();
202 let iter =
203 RawEntityIdAccess::new(NonNull::new(self.as_ptr().cast_mut()).unwrap(), Vec::new());
204
205 (self, len, iter)
206 }
207
208 #[inline]
209 fn can_captain() -> bool {
210 true
211 }
212
213 #[inline]
214 fn can_sailor() -> bool {
215 false
216 }
217}
218
219impl<'tmp, 'v: 'tmp, T: Component> IntoShiperator for Optional<&'tmp View<'v, T>> {
220 type Shiperator = Optional<FullRawWindow<'tmp, T>>;
221
222 fn into_shiperator(
223 self,
224 storage_ids: &mut ShipHashSet<StorageId>,
225 ) -> (Self::Shiperator, usize, RawEntityIdAccess) {
226 let (shiperator, len, entities) = self.0.into_shiperator(storage_ids);
227
228 (Optional(shiperator), len, entities)
229 }
230
231 fn can_captain() -> bool {
232 false
233 }
234
235 fn can_sailor() -> bool {
236 true
237 }
238}
239
240impl<'tmp, 'v: 'tmp, T: Component, Track: Tracking> IntoShiperator
241 for Optional<&'tmp ViewMut<'v, T, Track>>
242{
243 type Shiperator = Optional<FullRawWindow<'tmp, T>>;
244
245 fn into_shiperator(
246 self,
247 storage_ids: &mut ShipHashSet<StorageId>,
248 ) -> (Self::Shiperator, usize, RawEntityIdAccess) {
249 let (shiperator, len, entities) = self.0.into_shiperator(storage_ids);
250
251 (Optional(shiperator), len, entities)
252 }
253
254 fn can_captain() -> bool {
255 false
256 }
257
258 fn can_sailor() -> bool {
259 true
260 }
261}
262
263impl<'tmp, 'v: 'tmp, T: Component, Track: Tracking> IntoShiperator
264 for Optional<&'tmp mut ViewMut<'v, T, Track>>
265{
266 type Shiperator = Optional<FullRawWindowMut<'tmp, T, Track>>;
267
268 fn into_shiperator(
269 self,
270 storage_ids: &mut ShipHashSet<StorageId>,
271 ) -> (Self::Shiperator, usize, RawEntityIdAccess) {
272 let (shiperator, len, entities) = self.0.into_shiperator(storage_ids);
273
274 (Optional(shiperator), len, entities)
275 }
276
277 fn can_captain() -> bool {
278 false
279 }
280
281 fn can_sailor() -> bool {
282 true
283 }
284}
285
286impl<T: IntoShiperator> IntoShiperator for (T,) {
287 type Shiperator = T::Shiperator;
288
289 fn into_shiperator(
290 self,
291 storage_ids: &mut ShipHashSet<StorageId>,
292 ) -> (Self::Shiperator, usize, RawEntityIdAccess) {
293 self.0.into_shiperator(storage_ids)
294 }
295
296 fn can_captain() -> bool {
297 T::can_captain()
298 }
299
300 fn can_sailor() -> bool {
301 T::can_sailor()
302 }
303}
304
305macro_rules! strip_plus {
308 (+ $($rest: tt)*) => {
309 $($rest)*
310 }
311}
312
313pub(crate) use strip_plus;
315
316macro_rules! impl_into_shiperator_tuple {
317 ($(($type: ident, $index: tt))+) => {
318 impl<$($type: IntoShiperator),+> IntoShiperator for ($($type,)+) where $(<$type as IntoShiperator>::Shiperator: ShiperatorCaptain),+ {
319 type Shiperator = Mixed<($($type::Shiperator,)+)>;
320
321 #[inline]
322 #[track_caller]
323 fn into_shiperator(
324 self,
325 storage_ids: &mut ShipHashSet<StorageId>,
326 ) -> (Self::Shiperator, usize, RawEntityIdAccess) {
327 let mut shiperators = ($(self.$index.into_shiperator(storage_ids),)+);
328
329 let can_captains = ($(
330 $type::can_captain(),
331 )+);
332
333 let can_any_captain = $(
334 can_captains.$index
335 )||+;
336
337 if !can_any_captain {
338 panic!("Unable to build a Shiperator: None of the views could be a Captain.")
339 }
340
341 let can_sailors = ($(
342 $type::can_sailor(),
343 )+);
344
345 $(
346 if !can_captains.$index && !can_sailors.$index {
347 panic!("Unable to build a Shiperator: View at index {} could neither be a Captain nor a Sailor.", $index)
348 }
349 )+
350
351 let unable_sailor = strip_plus!($(
352 + (!can_sailors.$index as usize)
353 )+);
354
355 if unable_sailor > 1 {
356 panic!("Unable to build a Shiperator: Multiple views were unable to be Sailors.")
357 }
358
359 let sail_times = ($(
360 shiperators.$index.0.sail_time(),
361 )+);
362
363 if unable_sailor == 1 {
364 let mut mask = 0;
365 let mut len = 0;
366 let mut entity_iter = RawEntityIdAccess::dangling();
367
368 for (index, (can_sailor, shiperator_len, shiperator_entity_iter)) in
369 [$((can_sailors.$index, shiperators.$index.1, shiperators.$index.2)),+]
370 .into_iter()
371 .enumerate()
372 {
373 if !can_sailor {
374 mask = 1 << index;
375 len = shiperator_len;
376 entity_iter = shiperator_entity_iter;
377
378 break;
379 }
380 }
381
382 $(
383 if mask & (1 << $index) == 0 {
384 shiperators.$index.0.unpick();
385 } else {
386 if !shiperators.$index.0.is_exact_sized() {
387 mask = 0;
388 }
389 }
390 )+
391
392 return (
393 Mixed {
394 shiperator: ($(shiperators.$index.0,)+),
395 mask
396 },
397 len,
398 entity_iter,
399 );
400 }
401
402 let mut mask = 0;
403 let mut len = 0;
404 let mut entity_iter = RawEntityIdAccess::dangling();
405 let mut min_sail_time = usize::MAX;
406
407 $(
408 if can_captains.$index && sail_times.$index < min_sail_time {
409 mask = 1 << $index;
410 len = shiperators.$index.1;
411 entity_iter = shiperators.$index.2;
412 min_sail_time = sail_times.$index;
413 }
414 )+
415
416 let _ = min_sail_time;
417
418 $(
419 if mask & (1 << $index) == 0 {
420 shiperators.$index.0.unpick();
421 } else {
422 if !shiperators.$index.0.is_exact_sized() {
423 mask = 0;
424 }
425 }
426 )+
427
428 (
429 Mixed {
430 shiperator: ($(shiperators.$index.0,)+),
431 mask,
432 },
433 len,
434 entity_iter,
435 )
436 }
437
438 #[inline]
439 fn can_captain() -> bool {
440 $(
441 $type::can_captain()
442 )||+
443 }
444
445 #[inline]
446 fn can_sailor() -> bool {
447 $(
448 $type::can_sailor()
449 )&&+
450 }
451 }
452 };
453}
454
455macro_rules! into_shiperator_tuple {
456 ($(($type: ident, $index: tt))+; ($type1: ident, $index1: tt) $(($queue_type: ident, $queue_index: tt))*) => {
457 impl_into_shiperator_tuple![$(($type, $index))*];
458 into_shiperator_tuple![$(($type, $index))* ($type1, $index1); $(($queue_type, $queue_index))*];
459 };
460 ($(($type: ident, $index: tt))+;) => {
461 impl_into_shiperator_tuple![$(($type, $index))*];
462 }
463}
464
465#[cfg(not(feature = "extended_tuple"))]
466into_shiperator_tuple![(A, 0) (B, 1); (C, 2) (D, 3) (E, 4) (F, 5) (G, 6) (H, 7) (I, 8) (J, 9)];
467#[cfg(feature = "extended_tuple")]
468into_shiperator_tuple![
469 (A, 0) (B, 1); (C, 2) (D, 3) (E, 4) (F, 5) (G, 6) (H, 7) (I, 8) (J, 9)
470 (K, 10) (L, 11) (M, 12) (N, 13) (O, 14) (P, 15) (Q, 16) (R, 17) (S, 18) (T, 19)
471 (U, 20) (V, 21) (W, 22) (X, 23) (Y, 24) (Z, 25) (AA, 26) (BB, 27) (CC, 28) (DD, 29)
472 (EE, 30) (FF, 31)
473];