use std::sync::Arc;
use rayon::iter::{IndexedParallelIterator, ParallelIterator};
use rayon::iter::plumbing::{bridge, Consumer, Producer, ProducerCallback, UnindexedConsumer};
use crate::{Archetype, Snapshot};
use crate::archetype::ComponentSetExt;
use crate::world::{ChunkGuard, ChunkSetGuard, Lock};
pub(crate) fn locks_include_archetype(a: &Arc<Archetype>, locks: &[Lock]) -> bool {
assert!(locks.len() <= 32, "only 32 locks supported currently");
let component_types = a.component_types();
for lock in locks.iter() {
match lock {
Lock::Read(type_id) => {
if !component_types.includes(type_id) {
return false;
}
}
Lock::Write(type_id) => {
if !component_types.includes(type_id) {
return false;
}
}
Lock::Exclude(type_id) => {
if component_types.includes(type_id) {
return false;
}
}
}
}
true
}
pub(crate) struct Transaction {
snapshot: Arc<Snapshot>,
archetypes: Vec<Arc<Archetype>>,
locks: Vec<Lock>,
}
impl Transaction {
pub fn new(
snapshot: Arc<Snapshot>,
archetypes: Vec<Arc<Archetype>>,
locks: Vec<Lock>,
) -> Transaction {
Transaction {
snapshot,
archetypes,
locks,
}
}
pub fn locks(&self) -> &[Lock] {
&self.locks
}
}
pub struct TransactionGuard<'a> {
transaction: &'a Transaction,
}
impl<'a> TransactionGuard<'a> {
pub(crate) fn new(transaction: &'a Transaction) -> TransactionGuard<'a> {
TransactionGuard {
transaction,
}
}
}
impl<'a> TransactionGuard<'a> {
pub fn archetypes(&self) -> &[Arc<Archetype>] {
&self.transaction.archetypes
}
pub fn chunk_set_mut(&mut self, archetype: &Arc<Archetype>) -> Option<ChunkSetGuard<'_>> {
match self.transaction.archetypes
.binary_search_by_key(&archetype.id(), |a| a.id()) {
Ok(_) => {
let chunk_set = self.transaction.snapshot.chunk_set(archetype).unwrap();
Some(ChunkSetGuard::new(self.transaction, archetype.clone(), chunk_set))
}
Err(_) => None
}
}
pub fn iter_chunk_sets_mut(&mut self) -> ChunkSetIter<'a> {
ChunkSetIter::new(self.transaction, &self.transaction.archetypes)
}
pub fn par_iter_chunk_sets_mut(&mut self) -> ChunkSetParIter<'a> {
ChunkSetParIter::new(self.transaction, &self.transaction.archetypes)
}
pub fn iter_chunks_mut(&mut self) -> impl Iterator<Item=ChunkGuard<'a>> {
self.iter_chunk_sets_mut()
.flat_map(|mut chunk_set| chunk_set.iter_chunks_mut())
}
pub fn par_iter_chunks_mut(&mut self) -> impl ParallelIterator<Item=ChunkGuard<'a>> {
self.par_iter_chunk_sets_mut()
.flat_map(|mut chunk_set| chunk_set.par_iter_chunks_mut())
}
}
pub struct ChunkSetIter<'a> {
transaction: &'a Transaction,
slice: &'a [Arc<Archetype>],
offset: usize,
}
impl<'a> ChunkSetIter<'a> {
pub(crate) fn new(transaction: &'a Transaction, slice: &'a [Arc<Archetype>]) -> ChunkSetIter<'a> {
ChunkSetIter {
transaction,
slice,
offset: 0,
}
}
}
impl<'a> Iterator for ChunkSetIter<'a> {
type Item = ChunkSetGuard<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.slice.get(self.offset).map(|archetype| {
self.offset += 1;
let chunk_set = self.transaction.snapshot.chunk_set(archetype).unwrap();
let archetype = archetype.clone();
ChunkSetGuard::new(self.transaction, archetype, chunk_set)
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.slice.len() - self.offset;
(len, Some(len))
}
}
impl<'a> DoubleEndedIterator for ChunkSetIter<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.offset == 0 {
return None;
}
self.offset -= 1;
self.slice.get(self.offset).map(|archetype| {
let chunk_set = self.transaction.snapshot.chunk_set(archetype).unwrap();
let archetype = archetype.clone();
ChunkSetGuard::new(self.transaction, archetype, chunk_set)
})
}
}
impl<'a> ExactSizeIterator for ChunkSetIter<'a> {}
pub struct ChunkSetParIter<'a> {
transaction: &'a Transaction,
slice: &'a [Arc<Archetype>],
}
impl<'a> ChunkSetParIter<'a> {
pub(crate) fn new(transaction: &'a Transaction, slice: &'a [Arc<Archetype>]) -> ChunkSetParIter<'a> {
ChunkSetParIter {
transaction,
slice,
}
}
}
impl<'a> ParallelIterator for ChunkSetParIter<'a> {
type Item = ChunkSetGuard<'a>;
fn drive_unindexed<C>(self, consumer: C) -> <C as Consumer<Self::Item>>::Result where
C: UnindexedConsumer<Self::Item> {
bridge(self, consumer)
}
}
impl<'a> IndexedParallelIterator for ChunkSetParIter<'a> {
fn len(&self) -> usize {
self.slice.len()
}
fn drive<C: Consumer<Self::Item>>(self, consumer: C) -> <C as Consumer<Self::Item>>::Result {
bridge(self, consumer)
}
fn with_producer<CB: ProducerCallback<Self::Item>>(self, callback: CB) -> <CB as ProducerCallback<Self::Item>>::Output {
callback.callback(ChunkSetProducer::new(self.transaction, self.slice))
}
}
pub(crate) struct ChunkSetProducer<'a> {
transaction: &'a Transaction,
slice: &'a [Arc<Archetype>],
}
impl<'a> ChunkSetProducer<'a> {
pub fn new(transaction: &'a Transaction, slice: &'a [Arc<Archetype>]) -> ChunkSetProducer<'a> {
ChunkSetProducer {
transaction,
slice,
}
}
}
impl<'a> Producer for ChunkSetProducer<'a> {
type Item = ChunkSetGuard<'a>;
type IntoIter = ChunkSetIter<'a>;
fn into_iter(self) -> Self::IntoIter {
ChunkSetIter::new(self.transaction, self.slice)
}
fn split_at(self, index: usize) -> (Self, Self) {
let (left, right) = self.slice.split_at(index);
let left = ChunkSetProducer::new(self.transaction, left);
let right = ChunkSetProducer::new(self.transaction, right);
(left, right)
}
}