// Standard use std::marker::PhantomData; // Library use vek::*; // Local use crate::vol::{ Vox, BaseVol, SizedVol, ReadVol, WriteVol, VolSize, }; #[derive(Debug)] pub enum ChunkErr { OutOfBounds, } /// A volume with dimensions known at compile-time. // V = Voxel // S = Size (replace when const generics are a thing) // M = Metadata pub struct Chunk { vox: Vec, meta: M, phantom: PhantomData, } impl Chunk { /// Used to transform a voxel position in the volume into its corresponding index in the voxel // array. #[inline(always)] fn idx_for(pos: Vec3) -> Option { if pos.map(|e| e >= 0).reduce_and() && pos.map2(S::SIZE, |e, lim| e < lim as i32).reduce_and() { Some(( pos.x * S::SIZE.y as i32 * S::SIZE.z as i32 + pos.y * S::SIZE.z as i32 + pos.z ) as usize) } else { None } } } impl BaseVol for Chunk { type Vox = V; type Err = ChunkErr; } impl SizedVol for Chunk { #[inline(always)] fn get_size(&self) -> Vec3 { S::SIZE } } impl ReadVol for Chunk { #[inline(always)] fn get(&self, pos: Vec3) -> Result<&V, ChunkErr> { Self::idx_for(pos) .and_then(|idx| self.vox.get(idx)) .ok_or(ChunkErr::OutOfBounds) } } impl WriteVol for Chunk { #[inline(always)] fn set(&mut self, pos: Vec3, vox: Self::Vox) -> Result<(), ChunkErr> { Self::idx_for(pos) .and_then(|idx| self.vox.get_mut(idx)) .map(|old_vox| *old_vox = vox) .ok_or(ChunkErr::OutOfBounds) } } impl Chunk { /// Create a new `Chunk` with the provided dimensions and all voxels filled with duplicates of /// the provided voxel. pub fn filled(vox: V, meta: M) -> Self { Self { vox: vec![vox; S::SIZE.product() as usize], meta, phantom: PhantomData, } } /// Get a reference to the internal metadata. pub fn metadata(&self) -> &M { &self.meta } /// Get a mutable reference to the internal metadata. pub fn metadata_mut(&mut self) -> &mut M { &mut self.meta } }