use grid::GridPoint3;
use super::{Globe, ChunkOrigin};
use super::chunk::{Chunk, Cell};
use globe::globe::GlobeGuts;
#[derive(Clone)]
pub struct Cursor<'a> {
globe: &'a Globe,
pos: GridPoint3,
current_chunk: Option<&'a Chunk>,
current_chunk_might_be_dirty: bool,
}
pub struct CursorMut<'a> {
globe: &'a mut Globe,
pos: GridPoint3,
current_chunk_origin: Option<ChunkOrigin>,
current_chunk_might_be_dirty: bool,
}
macro_rules! cursor {
($name:ident, $globe:ty, $cell:ty, $chunks_fn:ident, $chunks_get_fn:ident, $cell_fn:ident) => {
impl<'a> $name<'a> {
pub fn new_in_chunk(globe: $globe, chunk_origin: ChunkOrigin) -> $name<'a> {
let mut cursor = $name::new_without_chunk_hint(globe, chunk_origin.into());
cursor.update_current_chunk_origin();
cursor
}
pub fn pos(&self) -> GridPoint3 {
self.pos
}
pub fn set_pos(&mut self, new_pos: GridPoint3) {
self.pos = new_pos;
self.current_chunk_might_be_dirty = true;
}
pub fn globe(&self) -> &Globe {
self.globe
}
pub fn cell(&mut self) -> Option<$cell> {
let pos = self.pos;
self.update_current_chunk_origin();
self.current_chunk().map(|chunk| chunk.$cell_fn(pos))
}
fn update_current_chunk_origin(&mut self) {
if !self.current_chunk_might_be_dirty {
return;
}
let pos = self.pos;
let current_chunk_contains_pos = self.current_chunk()
.map(|chunk| chunk.contains_pos(pos))
.unwrap_or(false);
if current_chunk_contains_pos {
self.current_chunk_might_be_dirty = false;
return;
}
let chunk_origin = self.globe.origin_of_chunk_in_same_root_containing(self.pos);
self.set_current_chunk(chunk_origin);
}
}
}
}
cursor!{Cursor, &'a Globe, &'a Cell, chunks, get, cell}
cursor!{CursorMut, &'a mut Globe, &mut Cell, chunks_mut, get_mut, cell_mut}
impl<'a> Cursor<'a> {
fn new_without_chunk_hint(globe: &'a Globe, pos: GridPoint3) -> Cursor<'a> {
Cursor {
globe: globe,
pos: pos,
current_chunk: None,
current_chunk_might_be_dirty: true,
}
}
fn current_chunk(&self) -> Option<&'a Chunk> {
self.current_chunk
}
fn set_current_chunk(&mut self, new_chunk_origin: ChunkOrigin) {
self.current_chunk = self.globe.chunks().get(&new_chunk_origin);
self.current_chunk_might_be_dirty = false;
}
}
impl<'a> CursorMut<'a> {
pub fn ensure_chunk_present(&mut self) {
let chunk_origin: ChunkOrigin =
self.globe.origin_of_chunk_in_same_root_containing(self.pos);
self.globe.ensure_chunk_present(chunk_origin);
}
fn new_without_chunk_hint(globe: &'a mut Globe, pos: GridPoint3) -> CursorMut<'a> {
CursorMut {
globe: globe,
pos: pos,
current_chunk_origin: None,
current_chunk_might_be_dirty: true,
}
}
fn current_chunk(&mut self) -> Option<&mut Chunk> {
self.current_chunk_origin.and_then(move |chunk_origin| {
self.globe.chunks_mut().get_mut(&chunk_origin)
})
}
fn set_current_chunk(&mut self, new_chunk_origin: ChunkOrigin) {
self.current_chunk_origin = Some(new_chunk_origin);
self.current_chunk_might_be_dirty = false;
}
}