1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
use super::{AbstractMut, CurrentId, IntoAbstract, IntoIterator, Shiperator};
use crate::EntityId;
use core::ptr;

macro_rules! impl_iterators {
    (
        $number: literal
        $update: ident
        $(($type: ident, $index: tt))+
    ) => {
        #[doc = "Update iterator over"]
        #[doc = $number]
        #[doc = "components."]
        pub struct $update<$($type: IntoAbstract),+> {
            pub(crate) data: ($($type::AbsView,)+),
            pub(crate) indices: *const EntityId,
            pub(crate) current: usize,
            pub(crate) end: usize,
            pub(crate) array: usize,
            pub(crate) current_id: EntityId,
        }

        impl<$($type: IntoAbstract),+> Shiperator for $update<$($type),+> {
            type Item = ($(<$type::AbsView as AbstractMut>::Out,)+);

            fn first_pass(&mut self) -> Option<Self::Item> {
                while self.current < self.end {
                    let current = self.current;
                    // SAFE at this point there are no mutable reference to sparse or dense
                    // and self.indices can't access out of bounds
                    let current_id = unsafe {ptr::read(self.indices.add(current))};
                    self.current += 1;
                    let data_indices = ($(
                        if $index == self.array {
                            current
                        } else {
                            if let Some(index) = self.data.$index.index_of(current_id) {
                                index
                            } else {
                                continue
                            }
                        },
                    )+);
                    self.current_id = current_id;
                    return Some(unsafe {($(self.data.$index.get_update_data(data_indices.$index),)+)})
                }
                None
            }
            fn post_process(&mut self) {
                unsafe {
                    $(
                        // SAFE current_id has the components
                        self.data.$index.flag(self.current_id);
                    )+
                }
            }
            fn size_hint(&self) -> (usize, Option<usize>) {
                (0, Some(self.end - self.current))
            }
        }

        impl<$($type: IntoAbstract),+> CurrentId for $update<$($type),+> {
            type Id = EntityId;

            unsafe fn current_id(&self) -> Self::Id {
                self.current_id
            }
        }

        impl<$($type: IntoAbstract),+> core::iter::IntoIterator for $update<$($type),+> {
            type IntoIter = IntoIterator<Self>;
            type Item = <Self as Shiperator>::Item;
            fn into_iter(self) -> Self::IntoIter {
                IntoIterator(self)
            }
        }
    }
}

macro_rules! iterators {
    (
        $($number: literal)*; $number1: literal $($queue_number: literal)+;
        $($update: ident)*; $update1: ident $($queue_update: ident)+;
        $(($type: ident, $index: tt))*;($type1: ident, $index1: tt) $(($queue_type: ident, $queue_index: tt))*
    ) => {
        impl_iterators![$number1 $update1 $(($type, $index))*];
        iterators![
            $($number)* $number1; $($queue_number)+;
            $($update)* $update1; $($queue_update)+;
            $(($type, $index))* ($type1, $index1); $(($queue_type, $queue_index))*
        ];
    };
    (
        $($number: literal)*; $number1: literal;
        $($update: ident)*; $update1: ident;
        $(($type: ident, $index: tt))*;
    ) => {
        impl_iterators![$number1 $update1 $(($type, $index))*];
    }
}

iterators![
    ;"2" "3" "4" "5" "6" "7" "8" "9" "10";
    ;Update2 Update3 Update4 Update5 Update6 Update7 Update8 Update9 Update10;
    (A, 0) (B, 1); (C, 2) (D, 3) (E, 4) (F, 5) (G, 6) (H, 7) (I, 8) (J, 9)
];