use crate::{CustomDecompression, McaError, REGION_SIZE, RegionReader};
#[derive(Debug, Clone)]
pub struct RegionIter<'a, D: CustomDecompression> {
region: &'a RegionReader<'a, D>,
current: usize,
chunks: Vec<(u8, u8)>,
}
pub type AvailableChunk = ((u8, u8), Vec<u8>);
impl<'a, D: CustomDecompression> RegionIter<'a, D> {
pub fn new(region: &'a RegionReader<'a, D>) -> Result<Self, McaError> {
let generated_chunks = region.generated_chunks()?;
Ok(Self {
region,
current: 0,
chunks: generated_chunks,
})
}
pub fn next_available_chunk(&mut self) -> Result<Option<AvailableChunk>, McaError> {
if self.current == self.chunks.len() {
return Ok(None);
}
let (x, z) = self.chunks[self.current];
let data = self
.region
.chunk_data(x, z)?
.ok_or(McaError::InvalidRegionIterChunk(self.chunks.clone(), x, z))?;
let mut buf = Vec::new();
RegionReader::decompress_data_ref(
data.data,
data.compression,
&mut buf,
&self.region.custom_decompression,
)?;
self.current += 1;
Ok(Some(((x, z), buf)))
}
pub fn region(&self) -> &'a RegionReader<'a, D> {
self.region
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ChunkIter(u16);
impl ChunkIter {
const MAX: usize = REGION_SIZE * REGION_SIZE;
pub fn new() -> Self {
ChunkIter(0)
}
}
impl Default for ChunkIter {
fn default() -> Self {
Self::new()
}
}
impl Iterator for ChunkIter {
type Item = (u8, u8);
fn next(&mut self) -> Option<Self::Item> {
if self.0 == Self::MAX as u16 {
None
} else {
let coordinate = (
(self.0 / REGION_SIZE as u16) as u8,
(self.0 % REGION_SIZE as u16) as u8,
);
self.0 += 1;
Some(coordinate)
}
}
}
#[cfg(test)]
mod test {
use crate::{
McaError, REGION_SIZE, RegionReader,
iter::ChunkIter,
regions::{FULL, HALF},
};
#[test]
fn iter_all_generated() -> Result<(), McaError> {
let region = RegionReader::new(FULL)?;
let generated = region.chunk_count()?;
let mut iterations = 0;
let mut iter = region.iter()?;
while let Some(_) = iter.next_available_chunk()? {
iterations += 1;
}
assert_eq!(generated, iterations);
Ok(())
}
#[test]
fn iter_half() -> Result<(), McaError> {
let region = RegionReader::new(HALF)?;
let mut iterations = 0;
let mut iter = region.iter()?;
while let Some(_) = iter.next_available_chunk()? {
iterations += 1;
}
assert_ne!(iterations, REGION_SIZE * REGION_SIZE);
Ok(())
}
#[test]
fn chunk_iter() -> Result<(), McaError> {
let mut region = RegionReader::new(FULL)?;
let mut iterations = 0;
for (x, z) in ChunkIter::new() {
let chunk = region.chunk(x, z)?;
std::hint::black_box(chunk);
iterations += 1;
}
assert_eq!(iterations, region.chunk_count()?);
Ok(())
}
}