use crate::Error;
use crate::Reader;
use crate::engine::block::{VolumeShape, VoxelBlock};
use crate::mode::Voxel;
#[doc(hidden)]
pub trait Stepper {
fn next(&mut self, volume_shape: VolumeShape) -> Option<([usize; 3], [usize; 3])>;
}
#[derive(Debug, Clone, Copy, Default)]
pub struct SliceStepper {
z: usize,
}
impl Stepper for SliceStepper {
fn next(&mut self, volume_shape: VolumeShape) -> Option<([usize; 3], [usize; 3])> {
if self.z >= volume_shape.nz {
return None;
}
let z = self.z;
self.z += 1;
Some(([0, 0, z], [volume_shape.nx, volume_shape.ny, 1]))
}
}
#[derive(Debug, Clone, Copy)]
pub struct SlabStepper {
z: usize,
k: usize,
}
impl SlabStepper {
pub fn new(k: usize) -> Self {
Self { z: 0, k: k.max(1) }
}
}
impl Stepper for SlabStepper {
fn next(&mut self, volume_shape: VolumeShape) -> Option<([usize; 3], [usize; 3])> {
if self.z >= volume_shape.nz {
return None;
}
let z = self.z;
let sz = self.k.min(volume_shape.nz - z);
self.z += sz;
Some(([0, 0, z], [volume_shape.nx, volume_shape.ny, sz]))
}
}
#[derive(Debug, Clone, Copy)]
pub struct TileStepper {
position: [usize; 3],
tile_shape: [usize; 3],
}
impl TileStepper {
pub fn new(tile_shape: [usize; 3]) -> Result<Self, crate::Error> {
if tile_shape[0] == 0 || tile_shape[1] == 0 || tile_shape[2] == 0 {
return Err(crate::Error::bounds_err());
}
Ok(Self {
position: [0, 0, 0],
tile_shape,
})
}
}
impl Stepper for TileStepper {
fn next(&mut self, volume_shape: VolumeShape) -> Option<([usize; 3], [usize; 3])> {
let [nx, ny, nz] = [volume_shape.nx, volume_shape.ny, volume_shape.nz];
let [cx, cy, cz] = self.tile_shape;
let [px, py, pz] = self.position;
if pz >= nz {
return None;
}
let sx = cx.min(nx - px);
let sy = cy.min(ny - py);
let sz = cz.min(nz - pz);
self.position[0] += cx;
if self.position[0] >= nx {
self.position[0] = 0;
self.position[1] += cy;
if self.position[1] >= ny {
self.position[1] = 0;
self.position[2] += cz;
}
}
Some(([px, py, pz], [sx, sy, sz]))
}
}
#[derive(Debug)]
pub struct RegionIter<'a, T, S> {
reader: &'a Reader,
volume_shape: VolumeShape,
stepper: S,
_phantom: core::marker::PhantomData<T>,
}
impl<'a, T, S> RegionIter<'a, T, S> {
pub fn with_stepper(reader: &'a Reader, volume_shape: VolumeShape, stepper: S) -> Self {
Self {
reader,
volume_shape,
stepper,
_phantom: core::marker::PhantomData,
}
}
}
impl<'a, T, S> Iterator for RegionIter<'a, T, S>
where
S: Stepper,
T: Voxel,
{
type Item = Result<VoxelBlock<T>, Error>;
fn next(&mut self) -> Option<Self::Item> {
let (offset, shape) = self.stepper.next(self.volume_shape)?;
let bytes = match self.reader.read_block_bytes_cow(offset, shape) {
Ok(b) => b,
Err(e) => return Some(Err(e)),
};
let data = match self.reader.decode_block::<T>(&bytes) {
Ok(d) => d,
Err(e) => return Some(Err(e)),
};
Some(Ok(VoxelBlock {
offset,
shape,
data,
}))
}
}
impl<'a, T, S> core::iter::FusedIterator for RegionIter<'a, T, S>
where
S: Stepper,
T: Voxel,
{
}