rust/hwphysics/src/data.rs
branchhedgeroid
changeset 15510 7030706266df
parent 15426 a027e60d7820
child 15829 d5e6c8c92d87
equal deleted inserted replaced
7861:bc7b6aa5d67a 15510:7030706266df
       
     1 use super::common::GearId;
       
     2 use std::{
       
     3     any::TypeId,
       
     4     fmt::{Debug, Error, Formatter},
       
     5     marker::PhantomData,
       
     6     mem::{align_of, size_of, MaybeUninit},
       
     7     num::NonZeroU16,
       
     8     ptr::{copy_nonoverlapping, null_mut, NonNull},
       
     9     slice,
       
    10 };
       
    11 
       
    12 pub trait TypeTuple: Sized {
       
    13     fn get_types(types: &mut Vec<TypeId>);
       
    14 }
       
    15 
       
    16 impl TypeTuple for () {
       
    17     fn get_types(_types: &mut Vec<TypeId>) {}
       
    18 }
       
    19 
       
    20 impl<T: 'static> TypeTuple for &T {
       
    21     fn get_types(types: &mut Vec<TypeId>) {
       
    22         types.push(TypeId::of::<T>());
       
    23     }
       
    24 }
       
    25 
       
    26 pub trait TypeIter: TypeTuple {
       
    27     unsafe fn iter<F: FnMut(GearId, Self)>(slices: &[*mut u8], count: usize, f: F);
       
    28 }
       
    29 
       
    30 macro_rules! type_tuple_impl {
       
    31     ($($n: literal: $t: ident),+) => {
       
    32         impl<$($t: 'static),+> TypeTuple for ($(&$t),+,) {
       
    33             fn get_types(types: &mut Vec<TypeId>) {
       
    34                 $(types.push(TypeId::of::<$t>()));+
       
    35             }
       
    36         }
       
    37 
       
    38         impl<$($t: 'static),+> TypeIter for ($(&$t),+,) {
       
    39             unsafe fn iter<F: FnMut(GearId, Self)>(slices: &[*mut u8], count: usize, mut f: F) {
       
    40                 for i in 0..count {
       
    41                     f(*(*slices.get_unchecked(0) as *const GearId).add(i),
       
    42                       ($(&*(*slices.get_unchecked($n + 1) as *mut $t).add(i)),+,));
       
    43                 }
       
    44             }
       
    45         }
       
    46 
       
    47         impl<$($t: 'static),+> TypeTuple for ($(&mut $t),+,) {
       
    48             fn get_types(types: &mut Vec<TypeId>) {
       
    49                 $(types.push(TypeId::of::<$t>()));+
       
    50             }
       
    51         }
       
    52 
       
    53         impl<$($t: 'static),+> TypeIter for ($(&mut $t),+,) {
       
    54             unsafe fn iter<F: FnMut(GearId, Self)>(slices: &[*mut u8], count: usize, mut f: F) {
       
    55                 for i in 0..count {
       
    56                     f(*(*slices.get_unchecked(0) as *const GearId).add(i),
       
    57                       ($(&mut *(*slices.get_unchecked($n + 1) as *mut $t).add(i)),+,));
       
    58                 }
       
    59             }
       
    60         }
       
    61     }
       
    62 }
       
    63 
       
    64 type_tuple_impl!(0: A);
       
    65 type_tuple_impl!(0: A, 1: B);
       
    66 type_tuple_impl!(0: A, 1: B, 2: C);
       
    67 type_tuple_impl!(0: A, 1: B, 2: C, 3: D);
       
    68 type_tuple_impl!(0: A, 1: B, 2: C, 3: D, 4: E);
       
    69 
       
    70 const BLOCK_SIZE: usize = 32768;
       
    71 
       
    72 struct DataBlock {
       
    73     max_elements: u16,
       
    74     elements_count: u16,
       
    75     data: Box<[u8; BLOCK_SIZE]>,
       
    76     component_blocks: [Option<NonNull<u8>>; 64],
       
    77     element_sizes: Box<[u16]>,
       
    78 }
       
    79 
       
    80 impl Unpin for DataBlock {}
       
    81 
       
    82 impl Debug for DataBlock {
       
    83     fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
       
    84         write!(
       
    85             f,
       
    86             "Block ({}/{}) {{\n",
       
    87             self.elements_count, self.max_elements
       
    88         )?;
       
    89         write!(f, "\tIDs: [")?;
       
    90         let id_slice = unsafe {
       
    91             slice::from_raw_parts(
       
    92                 self.data.as_ptr() as *const GearId,
       
    93                 self.elements_count as usize,
       
    94             )
       
    95         };
       
    96         for gear_id in id_slice {
       
    97             write!(f, "{}, ", gear_id)?;
       
    98         }
       
    99         write!(f, "]\n")?;
       
   100         for type_index in 0..self.element_sizes.len() {
       
   101             if let Some(ptr) = self.component_blocks[type_index] {
       
   102                 write!(f, "\tC{}: [", type_index)?;
       
   103                 let slice = unsafe {
       
   104                     slice::from_raw_parts(
       
   105                         ptr.as_ptr(),
       
   106                         (self.elements_count * self.element_sizes[type_index]) as usize,
       
   107                     )
       
   108                 };
       
   109                 for byte in slice {
       
   110                     write!(f, "{}, ", byte)?;
       
   111                 }
       
   112                 write!(f, "]\n")?;
       
   113             }
       
   114         }
       
   115         write!(f, "}}\n")
       
   116     }
       
   117 }
       
   118 
       
   119 impl DataBlock {
       
   120     fn new(mask: u64, element_sizes: &[u16], element_alignments: &[u8]) -> Self {
       
   121         let total_padding: usize = element_alignments.iter().map(|x| *x as usize).sum();
       
   122         let total_size: u16 = element_sizes
       
   123             .iter()
       
   124             .enumerate()
       
   125             .filter(|(i, _)| mask & (1 << *i as u64) != 0)
       
   126             .map(|(_, size)| *size)
       
   127             .sum();
       
   128         let max_elements =
       
   129             ((BLOCK_SIZE - total_padding) / (total_size as usize + size_of::<GearId>())) as u16;
       
   130 
       
   131         //ensure the block memory is aligned to GearId
       
   132         let tmp_data: Box<[GearId; BLOCK_SIZE / size_of::<GearId>()]> =
       
   133             Box::new(unsafe { MaybeUninit::uninit().assume_init() });
       
   134         let mut data: Box<[u8; BLOCK_SIZE]> =
       
   135             unsafe { Box::from_raw(Box::into_raw(tmp_data) as *mut [u8; BLOCK_SIZE]) };
       
   136 
       
   137         let mut blocks = [None; 64];
       
   138         let mut address = unsafe {
       
   139             data.as_mut_ptr()
       
   140                 .add(size_of::<GearId>() * max_elements as usize)
       
   141         };
       
   142 
       
   143         for i in 0..element_sizes.len() {
       
   144             if mask & (1 << i as u64) != 0 {
       
   145                 unsafe {
       
   146                     address = address.add(address.align_offset(element_alignments[i] as usize));
       
   147                     blocks[i] = Some(NonNull::new_unchecked(address));
       
   148                     address = address.add(element_sizes[i] as usize * max_elements as usize)
       
   149                 };
       
   150             }
       
   151         }
       
   152 
       
   153         Self {
       
   154             elements_count: 0,
       
   155             max_elements,
       
   156             data,
       
   157             component_blocks: blocks,
       
   158             element_sizes: Box::from(element_sizes),
       
   159         }
       
   160     }
       
   161 
       
   162     fn gear_ids(&self) -> &[GearId] {
       
   163         unsafe {
       
   164             slice::from_raw_parts(
       
   165                 self.data.as_ptr() as *const GearId,
       
   166                 self.max_elements as usize,
       
   167             )
       
   168         }
       
   169     }
       
   170 
       
   171     fn gear_ids_mut(&mut self) -> &mut [GearId] {
       
   172         unsafe {
       
   173             slice::from_raw_parts_mut(
       
   174                 self.data.as_mut_ptr() as *mut GearId,
       
   175                 self.max_elements as usize,
       
   176             )
       
   177         }
       
   178     }
       
   179 
       
   180     fn is_full(&self) -> bool {
       
   181         self.elements_count == self.max_elements
       
   182     }
       
   183 }
       
   184 
       
   185 #[derive(Clone, Copy, Debug, Default)]
       
   186 struct LookupEntry {
       
   187     index: Option<NonZeroU16>,
       
   188     block_index: u16,
       
   189 }
       
   190 
       
   191 impl LookupEntry {
       
   192     fn new(block_index: u16, index: u16) -> Self {
       
   193         Self {
       
   194             index: unsafe { Some(NonZeroU16::new_unchecked(index + 1)) },
       
   195             block_index,
       
   196         }
       
   197     }
       
   198 }
       
   199 
       
   200 #[derive(Copy, Clone, Eq, PartialEq, Debug)]
       
   201 struct BlockMask {
       
   202     type_mask: u64,
       
   203     tag_mask: u64,
       
   204 }
       
   205 
       
   206 impl BlockMask {
       
   207     #[inline]
       
   208     fn new(type_mask: u64, tag_mask: u64) -> Self {
       
   209         Self {
       
   210             type_mask,
       
   211             tag_mask,
       
   212         }
       
   213     }
       
   214 
       
   215     #[inline]
       
   216     fn with_type(&self, type_bit: u64) -> Self {
       
   217         Self::new(self.type_mask | type_bit, self.tag_mask)
       
   218     }
       
   219 
       
   220     #[inline]
       
   221     fn with_tag(&self, tag_bit: u64) -> Self {
       
   222         Self::new(self.type_mask, self.tag_mask | tag_bit)
       
   223     }
       
   224 }
       
   225 
       
   226 pub struct GearDataManager {
       
   227     types: Vec<TypeId>,
       
   228     tags: Vec<TypeId>,
       
   229     blocks: Vec<DataBlock>,
       
   230     block_masks: Vec<BlockMask>,
       
   231     element_sizes: Box<[u16; 64]>,
       
   232     element_alignments: Box<[u8; 64]>,
       
   233     lookup: Box<[LookupEntry]>,
       
   234 }
       
   235 
       
   236 impl GearDataManager {
       
   237     pub fn new() -> Self {
       
   238         Self {
       
   239             types: Vec::with_capacity(64),
       
   240             tags: Vec::with_capacity(64),
       
   241             blocks: vec![],
       
   242             block_masks: vec![],
       
   243             element_sizes: Box::new([0; 64]),
       
   244             element_alignments: Box::new([0; 64]),
       
   245             lookup: vec![LookupEntry::default(); u16::max_value() as usize].into_boxed_slice(),
       
   246         }
       
   247     }
       
   248 
       
   249     #[inline]
       
   250     fn get_type_index<T: 'static>(&self) -> Option<usize> {
       
   251         let type_id = TypeId::of::<T>();
       
   252         self.types.iter().position(|id| *id == type_id)
       
   253     }
       
   254 
       
   255     #[inline]
       
   256     fn get_tag_index<T: 'static>(&self) -> Option<usize> {
       
   257         let type_id = TypeId::of::<T>();
       
   258         self.tags.iter().position(|id| *id == type_id)
       
   259     }
       
   260 
       
   261     fn move_between_blocks(
       
   262         &mut self,
       
   263         src_block_index: u16,
       
   264         src_index: u16,
       
   265         dest_block_index: u16,
       
   266     ) -> u16 {
       
   267         debug_assert!(src_block_index != dest_block_index);
       
   268         let src_mask = self.block_masks[src_block_index as usize];
       
   269         let dest_mask = self.block_masks[dest_block_index as usize];
       
   270         debug_assert!(src_mask.type_mask & dest_mask.type_mask == src_mask.type_mask);
       
   271 
       
   272         let src_block = &self.blocks[src_block_index as usize];
       
   273         let dest_block = &self.blocks[dest_block_index as usize];
       
   274         debug_assert!(src_index < src_block.elements_count);
       
   275         debug_assert!(!dest_block.is_full());
       
   276 
       
   277         let dest_index = dest_block.elements_count;
       
   278         for i in 0..self.types.len() {
       
   279             if src_mask.type_mask & (1 << i as u64) != 0 {
       
   280                 let size = self.element_sizes[i];
       
   281                 let src_ptr = src_block.component_blocks[i].unwrap().as_ptr();
       
   282                 let dest_ptr = dest_block.component_blocks[i].unwrap().as_ptr();
       
   283                 unsafe {
       
   284                     copy_nonoverlapping(
       
   285                         src_ptr.add((src_index * size) as usize),
       
   286                         dest_ptr.add((dest_index * size) as usize),
       
   287                         size as usize,
       
   288                     );
       
   289                     if src_index < src_block.elements_count - 1 {
       
   290                         copy_nonoverlapping(
       
   291                             src_ptr.add((size * (src_block.elements_count - 1)) as usize),
       
   292                             src_ptr.add((size * src_index) as usize),
       
   293                             size as usize,
       
   294                         );
       
   295                     }
       
   296                 }
       
   297             }
       
   298         }
       
   299 
       
   300         let src_block = &mut self.blocks[src_block_index as usize];
       
   301         let gear_id = src_block.gear_ids()[src_index as usize];
       
   302 
       
   303         if src_index < src_block.elements_count - 1 {
       
   304             let relocated_index = src_block.elements_count as usize - 1;
       
   305             let gear_ids = src_block.gear_ids_mut();
       
   306             let relocated_id = gear_ids[relocated_index];
       
   307 
       
   308             gear_ids[src_index as usize] = relocated_id;
       
   309             self.lookup[relocated_id.get() as usize - 1] =
       
   310                 LookupEntry::new(src_block_index, src_index);
       
   311         }
       
   312         src_block.elements_count -= 1;
       
   313 
       
   314         let dest_block = &mut self.blocks[dest_block_index as usize];
       
   315         let dest_index = dest_block.elements_count;
       
   316 
       
   317         dest_block.gear_ids_mut()[dest_index as usize] = gear_id;
       
   318         self.lookup[gear_id.get() as usize - 1] = LookupEntry::new(dest_block_index, dest_index);
       
   319         dest_block.elements_count += 1;
       
   320         dest_block.elements_count - 1
       
   321     }
       
   322 
       
   323     fn add_to_block<T: Clone>(&mut self, gear_id: GearId, block_index: u16, value: &T) {
       
   324         debug_assert!(
       
   325             self.block_masks[block_index as usize]
       
   326                 .type_mask
       
   327                 .count_ones()
       
   328                 == 1
       
   329         );
       
   330 
       
   331         let block = &mut self.blocks[block_index as usize];
       
   332         debug_assert!(block.elements_count < block.max_elements);
       
   333 
       
   334         unsafe {
       
   335             *(block.component_blocks[0].unwrap().as_ptr() as *mut T)
       
   336                 .add(block.elements_count as usize) = value.clone();
       
   337         };
       
   338 
       
   339         let index = block.elements_count;
       
   340         self.lookup[gear_id.get() as usize - 1] = LookupEntry::new(block_index, index);
       
   341         block.gear_ids_mut()[index as usize] = gear_id;
       
   342         block.elements_count += 1;
       
   343     }
       
   344 
       
   345     fn remove_from_block(&mut self, block_index: u16, index: u16) {
       
   346         let block = &mut self.blocks[block_index as usize];
       
   347         debug_assert!(index < block.elements_count);
       
   348 
       
   349         for (i, size) in self.element_sizes.iter().cloned().enumerate() {
       
   350             if index < block.elements_count - 1 {
       
   351                 if let Some(ptr) = block.component_blocks[i] {
       
   352                     unsafe {
       
   353                         copy_nonoverlapping(
       
   354                             ptr.as_ptr()
       
   355                                 .add((size * (block.elements_count - 1)) as usize),
       
   356                             ptr.as_ptr().add((size * index) as usize),
       
   357                             size as usize,
       
   358                         );
       
   359                     }
       
   360                 }
       
   361             }
       
   362         }
       
   363 
       
   364         self.lookup[block.gear_ids()[index as usize].get() as usize - 1] = LookupEntry::default();
       
   365         if index < block.elements_count - 1 {
       
   366             let relocated_index = block.elements_count as usize - 1;
       
   367             let gear_ids = block.gear_ids_mut();
       
   368 
       
   369             gear_ids[index as usize] = gear_ids[relocated_index];
       
   370             self.lookup[gear_ids[relocated_index].get() as usize - 1] =
       
   371                 LookupEntry::new(block_index, index);
       
   372         }
       
   373         block.elements_count -= 1;
       
   374     }
       
   375 
       
   376     fn write_component<T: Clone>(
       
   377         &mut self,
       
   378         block_index: u16,
       
   379         index: u16,
       
   380         type_index: usize,
       
   381         value: &T,
       
   382     ) {
       
   383         debug_assert!(type_index < self.types.len());
       
   384         let block = &mut self.blocks[block_index as usize];
       
   385         debug_assert!(index < block.elements_count);
       
   386 
       
   387         unsafe {
       
   388             *(block.component_blocks[type_index].unwrap().as_ptr() as *mut T).add(index as usize) =
       
   389                 value.clone();
       
   390         };
       
   391     }
       
   392 
       
   393     #[inline]
       
   394     fn ensure_block(&mut self, mask: BlockMask) -> u16 {
       
   395         if let Some(index) = self
       
   396             .block_masks
       
   397             .iter()
       
   398             .enumerate()
       
   399             .position(|(i, m)| *m == mask && !self.blocks[i].is_full())
       
   400         {
       
   401             index as u16
       
   402         } else {
       
   403             self.blocks.push(DataBlock::new(
       
   404                 mask.type_mask,
       
   405                 &self.element_sizes[0..self.types.len()],
       
   406                 &self.element_alignments[0..self.types.len()],
       
   407             ));
       
   408             self.block_masks.push(mask);
       
   409             (self.blocks.len() - 1) as u16
       
   410         }
       
   411     }
       
   412 
       
   413     pub fn add<T: Clone + 'static>(&mut self, gear_id: GearId, value: &T) {
       
   414         if let Some(type_index) = self.get_type_index::<T>() {
       
   415             let type_bit = 1 << type_index as u64;
       
   416             let entry = self.lookup[gear_id.get() as usize - 1];
       
   417 
       
   418             if let Some(index) = entry.index {
       
   419                 let mask = self.block_masks[entry.block_index as usize];
       
   420                 let new_mask = mask.with_type(type_bit);
       
   421 
       
   422                 if new_mask != mask {
       
   423                     let dest_block_index = self.ensure_block(new_mask);
       
   424                     let dest_index = self.move_between_blocks(
       
   425                         entry.block_index,
       
   426                         index.get() - 1,
       
   427                         dest_block_index,
       
   428                     );
       
   429                     self.write_component(dest_block_index, dest_index, type_index, value);
       
   430                 }
       
   431             } else {
       
   432                 let dest_block_index = self.ensure_block(BlockMask::new(type_bit, 0));
       
   433                 self.add_to_block(gear_id, dest_block_index, value);
       
   434             }
       
   435         } else {
       
   436             panic!("Unregistered type")
       
   437         }
       
   438     }
       
   439 
       
   440     pub fn add_tag<T: 'static>(&mut self, gear_id: GearId) {
       
   441         if let Some(tag_index) = self.get_tag_index::<T>() {
       
   442             let tag_bit = 1 << tag_index as u64;
       
   443             let entry = self.lookup[gear_id.get() as usize - 1];
       
   444 
       
   445             if let Some(index) = entry.index {
       
   446                 let mask = self.block_masks[entry.block_index as usize];
       
   447                 let new_mask = mask.with_tag(tag_bit);
       
   448 
       
   449                 if new_mask != mask {
       
   450                     let dest_block_index = self.ensure_block(new_mask);
       
   451                     self.move_between_blocks(entry.block_index, index.get() - 1, dest_block_index);
       
   452                 }
       
   453             } else {
       
   454                 panic!("Cannot tag a gear with no data")
       
   455             }
       
   456         } else {
       
   457             panic!("Unregistered tag")
       
   458         }
       
   459     }
       
   460 
       
   461     pub fn remove<T: 'static>(&mut self, gear_id: GearId) {
       
   462         if let Some(type_index) = self.get_type_index::<T>() {
       
   463             let entry = self.lookup[gear_id.get() as usize - 1];
       
   464             if let Some(index) = entry.index {
       
   465                 let mut dest_mask = self.block_masks[entry.block_index as usize];
       
   466                 dest_mask.type_mask &= !(1 << type_index as u64);
       
   467 
       
   468                 if dest_mask.type_mask == 0 {
       
   469                     self.remove_from_block(entry.block_index, index.get() - 1);
       
   470                 } else {
       
   471                     let dest_block_index = self.ensure_block(dest_mask);
       
   472                     self.move_between_blocks(entry.block_index, index.get() - 1, dest_block_index);
       
   473                 }
       
   474             }
       
   475         } else {
       
   476             panic!("Unregistered type")
       
   477         }
       
   478     }
       
   479 
       
   480     pub fn remove_all(&mut self, gear_id: GearId) {
       
   481         let entry = self.lookup[gear_id.get() as usize - 1];
       
   482         if let Some(index) = entry.index {
       
   483             self.remove_from_block(entry.block_index, index.get() - 1);
       
   484         }
       
   485     }
       
   486 
       
   487     pub fn register<T: 'static>(&mut self) {
       
   488         debug_assert!(!std::mem::needs_drop::<T>());
       
   489         debug_assert!(size_of::<T>() <= u16::max_value() as usize);
       
   490 
       
   491         let id = TypeId::of::<T>();
       
   492         if size_of::<T>() == 0 {
       
   493             if !self.tags.contains(&id) {
       
   494                 debug_assert!(self.tags.len() <= 64);
       
   495                 self.tags.push(id)
       
   496             }
       
   497         } else {
       
   498             if !self.types.contains(&id) {
       
   499                 debug_assert!(self.types.len() <= 64);
       
   500                 self.element_sizes[self.types.len()] = size_of::<T>() as u16;
       
   501                 self.element_alignments[self.types.len()] = align_of::<T>() as u8;
       
   502                 self.types.push(id);
       
   503             }
       
   504         }
       
   505     }
       
   506 
       
   507     fn run_impl<T: TypeIter + 'static, F: FnMut(GearId, T)>(
       
   508         &mut self,
       
   509         type_selector: u64,
       
   510         included_tags: u64,
       
   511         type_indices: &[i8],
       
   512         mut f: F,
       
   513     ) {
       
   514         let mut slices = vec![null_mut(); type_indices.len() + 1];
       
   515 
       
   516         for (block_index, mask) in self.block_masks.iter().enumerate() {
       
   517             if mask.type_mask & type_selector == type_selector
       
   518                 && mask.tag_mask & included_tags == included_tags
       
   519             {
       
   520                 let block = &mut self.blocks[block_index];
       
   521                 slices[0] = block.data.as_mut_ptr();
       
   522 
       
   523                 for (arg_index, type_index) in type_indices.iter().cloned().enumerate() {
       
   524                     slices[arg_index as usize + 1] = block.component_blocks[type_index as usize]
       
   525                         .unwrap()
       
   526                         .as_ptr()
       
   527                 }
       
   528 
       
   529                 unsafe {
       
   530                     T::iter(&slices[..], block.elements_count as usize, |id, x| f(id, x));
       
   531                 }
       
   532             }
       
   533         }
       
   534     }
       
   535 
       
   536     pub fn iter<T: TypeIter + 'static>(&mut self) -> DataIterator<T> {
       
   537         let mut arg_types = Vec::with_capacity(64);
       
   538         T::get_types(&mut arg_types);
       
   539         let mut type_indices = vec![-1i8; arg_types.len()];
       
   540         let mut selector = 0u64;
       
   541 
       
   542         for (arg_index, type_id) in arg_types.iter().enumerate() {
       
   543             match self.types.iter().position(|t| t == type_id) {
       
   544                 Some(i) if selector & (1 << i as u64) != 0 => panic!("Duplicate type"),
       
   545                 Some(i) => {
       
   546                     type_indices[arg_index] = i as i8;
       
   547                     selector |= 1 << i as u64;
       
   548                 }
       
   549                 None => panic!("Unregistered type"),
       
   550             }
       
   551         }
       
   552         DataIterator::new(self, selector, type_indices)
       
   553     }
       
   554 }
       
   555 
       
   556 pub struct DataIterator<'a, T> {
       
   557     data: &'a mut GearDataManager,
       
   558     types: u64,
       
   559     type_indices: Vec<i8>,
       
   560     tags: u64,
       
   561     phantom_types: PhantomData<T>,
       
   562 }
       
   563 
       
   564 impl<'a, T: TypeIter + 'static> DataIterator<'a, T> {
       
   565     fn new(
       
   566         data: &'a mut GearDataManager,
       
   567         types: u64,
       
   568         type_indices: Vec<i8>,
       
   569     ) -> DataIterator<'a, T> {
       
   570         Self {
       
   571             data,
       
   572             types,
       
   573             type_indices,
       
   574             tags: 0,
       
   575             phantom_types: PhantomData,
       
   576         }
       
   577     }
       
   578 
       
   579     pub fn with_tags<U: TypeTuple + 'static>(self) -> Self {
       
   580         let mut tag_types = Vec::with_capacity(64);
       
   581         U::get_types(&mut tag_types);
       
   582         let mut tags = 0;
       
   583 
       
   584         for (i, tag) in self.data.tags.iter().enumerate() {
       
   585             if tag_types.contains(tag) {
       
   586                 tags |= 1 << i as u64;
       
   587             }
       
   588         }
       
   589         Self { tags, ..self }
       
   590     }
       
   591 
       
   592     #[inline]
       
   593     pub fn run<F: FnMut(T)>(&mut self, mut f: F) {
       
   594         self.run_id(|_, x| f(x))
       
   595     }
       
   596 
       
   597     #[inline]
       
   598     pub fn run_id<F: FnMut(GearId, T)>(&mut self, f: F) {
       
   599         self.data
       
   600             .run_impl(self.types, self.tags, &self.type_indices, f);
       
   601     }
       
   602 }
       
   603 
       
   604 #[cfg(test)]
       
   605 mod test {
       
   606     use super::{super::common::GearId, GearDataManager};
       
   607 
       
   608     #[derive(Clone)]
       
   609     struct Datum {
       
   610         value: u32,
       
   611     }
       
   612 
       
   613     #[derive(Clone)]
       
   614     struct Tag;
       
   615 
       
   616     #[test]
       
   617     fn single_component_iteration() {
       
   618         let mut manager = GearDataManager::new();
       
   619         manager.register::<Datum>();
       
   620         for i in 1..=5 {
       
   621             manager.add(GearId::new(i as u16).unwrap(), &Datum { value: i });
       
   622         }
       
   623 
       
   624         let mut sum = 0;
       
   625         manager.iter().run(|(d,): (&Datum,)| sum += d.value);
       
   626         assert_eq!(sum, 15);
       
   627 
       
   628         manager.iter().run(|(d,): (&mut Datum,)| d.value += 1);
       
   629         manager.iter().run(|(d,): (&Datum,)| sum += d.value);
       
   630         assert_eq!(sum, 35);
       
   631     }
       
   632 
       
   633     #[test]
       
   634     fn tagged_component_iteration() {
       
   635         let mut manager = GearDataManager::new();
       
   636         manager.register::<Datum>();
       
   637         manager.register::<Tag>();
       
   638         for i in 1..=10 {
       
   639             let gear_id = GearId::new(i as u16).unwrap();
       
   640             manager.add(gear_id, &Datum { value: i });
       
   641         }
       
   642 
       
   643         for i in 1..=10 {
       
   644             let gear_id = GearId::new(i as u16).unwrap();
       
   645             if i & 1 == 0 {
       
   646                 manager.add_tag::<Tag>(gear_id);
       
   647             }
       
   648         }
       
   649 
       
   650         let mut sum = 0;
       
   651         manager.iter().run(|(d,): (&Datum,)| sum += d.value);
       
   652         assert_eq!(sum, 55);
       
   653 
       
   654         let mut tag_sum = 0;
       
   655         manager
       
   656             .iter()
       
   657             .with_tags::<&Tag>()
       
   658             .run(|(d,): (&Datum,)| tag_sum += d.value);
       
   659         assert_eq!(tag_sum, 30);
       
   660     }
       
   661 }