diff --git a/src/bin/minedmap/region_processor.rs b/src/bin/minedmap/region_processor.rs index a95f6ea..f2720c7 100644 --- a/src/bin/minedmap/region_processor.rs +++ b/src/bin/minedmap/region_processor.rs @@ -57,8 +57,8 @@ impl<'a> RegionProcessor<'a> { image::GrayAlphaImage::from_fn(N, N, |x, z| { let v: f32 = block_light[LayerBlockCoords { - x: BlockX(x as u8), - z: BlockZ(z as u8), + x: BlockX::new(x), + z: BlockZ::new(z), }] .into(); image::LumaA([0, (192.0 * (1.0 - v / 15.0)) as u8]) diff --git a/src/bin/minedmap/tile_renderer.rs b/src/bin/minedmap/tile_renderer.rs index 955c964..70b55de 100644 --- a/src/bin/minedmap/tile_renderer.rs +++ b/src/bin/minedmap/tile_renderer.rs @@ -28,8 +28,8 @@ impl<'a> TileRenderer<'a> { let chunk_image = image::RgbaImage::from_fn(N, N, |x, z| { let coords = LayerBlockCoords { - x: BlockX(x as u8), - z: BlockZ(z as u8), + x: BlockX::new(x), + z: BlockZ::new(z), }; image::Rgba( match ( diff --git a/src/types.rs b/src/types.rs index 18045bb..465dd2a 100644 --- a/src/types.rs +++ b/src/types.rs @@ -7,38 +7,57 @@ use std::{ use itertools::iproduct; use serde::{Deserialize, Serialize}; -macro_rules! coord_impl { +pub mod axis { + pub const X: u8 = 0; + pub const Y: u8 = 1; + pub const Z: u8 = 2; +} + +macro_rules! coord_type { ($t:ident, $max:expr) => { - impl $t { + #[derive(Debug, Clone, Copy, PartialEq, Eq)] + pub struct $t(pub u8); + + impl $t { + const MAX: usize = $max; + + /// Constructs a new value + /// + /// Will panic if the value is not in the valid range + pub fn new>(value: T) -> Self { + Self( + value + .try_into() + .ok() + .filter(|&v| (v as usize) < Self::MAX) + .expect("coordinate should be in the valid range"), + ) + } + /// Returns an iterator over all possible values of the type - pub fn iter() -> impl Iterator + pub fn iter() -> impl Iterator> + DoubleEndedIterator + ExactSizeIterator + FusedIterator + Clone + Debug { - (0..$max as u8).map($t) + (0..Self::MAX as u8).map($t) } } }; } pub const BLOCKS_PER_CHUNK: usize = 16; +coord_type!(BlockCoord, BLOCKS_PER_CHUNK); /// A block X coordinate relative to a chunk -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct BlockX(pub u8); -coord_impl!(BlockX, BLOCKS_PER_CHUNK); +pub type BlockX = BlockCoord<{ axis::X }>; /// A block Y coordinate relative to a chunk section -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct BlockY(pub u8); -coord_impl!(BlockY, BLOCKS_PER_CHUNK); +pub type BlockY = BlockCoord<{ axis::Y }>; /// A block Z coordinate relative to a chunk -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct BlockZ(pub u8); -coord_impl!(BlockZ, BLOCKS_PER_CHUNK); +pub type BlockZ = BlockCoord<{ axis::Z }>; /// X and Z coordinates of a block in a chunk #[derive(Clone, Copy, PartialEq, Eq)] @@ -118,16 +137,13 @@ impl Debug for SectionBlockCoords { pub struct SectionY(pub i32); pub const CHUNKS_PER_REGION: usize = 32; +coord_type!(ChunkCoord, CHUNKS_PER_REGION); /// A chunk X coordinate relative to a region -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct ChunkX(pub u8); -coord_impl!(ChunkX, CHUNKS_PER_REGION); +pub type ChunkX = ChunkCoord<{ axis::X }>; /// A chunk Z coordinate relative to a region -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct ChunkZ(pub u8); -coord_impl!(ChunkZ, CHUNKS_PER_REGION); +pub type ChunkZ = ChunkCoord<{ axis::Z }>; /// A pair of chunk coordinates relative to a region #[derive(Clone, Copy, PartialEq, Eq)]