use std::sync::Arc;
use rayon::iter::{IndexedParallelIterator, ParallelIterator};
use rayon::iter::plumbing::{bridge, Consumer, Producer, ProducerCallback, UnindexedConsumer};
use crate::{Archetype, Chunk};
use crate::chunk_set::ChunkSet;
use crate::world::ChunkGuard;
use crate::world::transaction::Transaction;
pub struct ChunkSetGuard<'a> {
transaction: &'a Transaction,
archetype: Arc<Archetype>,
chunk_set: &'a ChunkSet,
}
impl<'a> ChunkSetGuard<'a> {
pub(crate) fn new(
transaction: &'a Transaction,
archetype: Arc<Archetype>,
chunk_set: &'a ChunkSet,
) -> ChunkSetGuard<'a> {
ChunkSetGuard {
transaction,
archetype,
chunk_set,
}
}
pub fn archetype(&self) -> &Arc<Archetype> {
&self.archetype
}
pub fn len(&self) -> usize {
self.chunk_set.len()
}
pub fn chunk_mut(&mut self, idx: usize) -> Option<ChunkGuard<'_>> {
self.chunk_set.get(idx).map(|chunk| {
ChunkGuard::new(self.transaction, chunk)
})
}
pub fn iter_chunks_mut(&mut self) -> ChunkIter<'a> {
ChunkIter::new(self.transaction, self.chunk_set.chunks())
}
pub fn par_iter_chunks_mut(&mut self) -> ChunkParIter<'a> {
ChunkParIter::new(self.transaction, self.chunk_set.chunks())
}
}
pub struct ChunkIter<'a> {
transaction: &'a Transaction,
slice: &'a [Arc<Chunk>],
offset: usize,
}
impl<'a> ChunkIter<'a> {
pub(crate) fn new(transaction: &'a Transaction, slice: &'a [Arc<Chunk>]) -> ChunkIter<'a> {
ChunkIter {
transaction,
slice,
offset: 0,
}
}
}
impl<'a> Iterator for ChunkIter<'a> {
type Item = ChunkGuard<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.slice.get(self.offset).map(|chunk| {
self.offset += 1;
ChunkGuard::new(self.transaction, chunk)
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.slice.len() - self.offset;
(len, Some(len))
}
}
impl<'a> DoubleEndedIterator for ChunkIter<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.offset == 0 {
return None;
}
self.offset -= 1;
self.slice.get(self.offset).map(|chunk| {
ChunkGuard::new(self.transaction, chunk)
})
}
}
impl<'a> ExactSizeIterator for ChunkIter<'a> {}
pub struct ChunkParIter<'a> {
transaction: &'a Transaction,
slice: &'a [Arc<Chunk>],
}
impl<'a> ChunkParIter<'a> {
pub(crate) fn new(transaction: &'a Transaction, slice: &'a [Arc<Chunk>]) -> ChunkParIter<'a> {
ChunkParIter {
transaction,
slice,
}
}
}
impl<'a> ParallelIterator for ChunkParIter<'a> {
type Item = ChunkGuard<'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 ChunkParIter<'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(ChunkProducer::new(self.transaction, self.slice))
}
}
pub(crate) struct ChunkProducer<'a> {
transaction: &'a Transaction,
slice: &'a [Arc<Chunk>],
}
impl<'a> ChunkProducer<'a> {
pub fn new(transaction: &'a Transaction, slice: &'a [Arc<Chunk>]) -> ChunkProducer<'a> {
ChunkProducer {
transaction,
slice,
}
}
}
impl<'a> Producer for ChunkProducer<'a> {
type Item = ChunkGuard<'a>;
type IntoIter = ChunkIter<'a>;
fn into_iter(self) -> Self::IntoIter {
ChunkIter::new(self.transaction, self.slice)
}
fn split_at(self, index: usize) -> (Self, Self) {
let (left, right) = self.slice.split_at(index);
let left = ChunkProducer::new(self.transaction, left);
let right = ChunkProducer::new(self.transaction, right);
(left, right)
}
}