use crate::block_entity::BlockEntity;
use rustc_hash::FxHashMap;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::sync::Arc;
#[derive(Debug, Clone, Default)]
pub struct BlockEntityStore {
palette: Vec<Arc<BlockEntity>>,
by_pos: FxHashMap<(i32, i32, i32), u32>,
}
impl BlockEntityStore {
pub fn new() -> Self {
Self::default()
}
#[inline]
pub fn insert(&mut self, pos: (i32, i32, i32), be: BlockEntity) -> Option<BlockEntity> {
let idx = self.palette.len() as u32;
self.palette.push(Arc::new(be));
let prev = self.by_pos.insert(pos, idx);
prev.map(|old_idx| (*self.palette[old_idx as usize]).clone())
}
pub fn insert_template(&mut self, positions: &[(i32, i32, i32)], template: Arc<BlockEntity>) {
if positions.is_empty() {
return;
}
let idx = self.palette.len() as u32;
self.palette.push(template);
self.by_pos.reserve(positions.len());
for &pos in positions {
self.by_pos.insert(pos, idx);
}
}
#[inline]
pub fn get(&self, pos: &(i32, i32, i32)) -> Option<&BlockEntity> {
self.by_pos
.get(pos)
.map(|&idx| self.palette[idx as usize].as_ref())
}
#[inline]
pub fn contains_key(&self, pos: &(i32, i32, i32)) -> bool {
self.by_pos.contains_key(pos)
}
#[inline]
pub fn len(&self) -> usize {
self.by_pos.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.by_pos.is_empty()
}
pub fn remove(&mut self, pos: &(i32, i32, i32)) -> Option<BlockEntity> {
self.by_pos
.remove(pos)
.map(|idx| (*self.palette[idx as usize]).clone())
}
pub fn clear(&mut self) {
self.palette.clear();
self.by_pos.clear();
}
pub fn reserve(&mut self, n: usize) {
self.by_pos.reserve(n);
}
pub fn iter(&self) -> impl Iterator<Item = ((i32, i32, i32), &BlockEntity)> + '_ {
self.by_pos
.iter()
.map(|(&pos, &idx)| (pos, self.palette[idx as usize].as_ref()))
}
pub fn values(&self) -> impl Iterator<Item = &BlockEntity> + '_ {
self.by_pos
.values()
.map(|&idx| self.palette[idx as usize].as_ref())
}
pub fn keys(&self) -> impl Iterator<Item = &(i32, i32, i32)> + '_ {
self.by_pos.keys()
}
pub fn remap_positions<F>(&mut self, f: F)
where
F: Fn((i32, i32, i32)) -> (i32, i32, i32),
{
let old = std::mem::take(&mut self.by_pos);
self.by_pos.reserve(old.len());
for (pos, idx) in old {
let new_pos = f(pos);
self.by_pos.insert(new_pos, idx);
}
}
pub fn drain(&mut self) -> Vec<((i32, i32, i32), BlockEntity)> {
let palette = std::mem::take(&mut self.palette);
let by_pos = std::mem::take(&mut self.by_pos);
by_pos
.into_iter()
.map(|(pos, idx)| {
let mut be = (*palette[idx as usize]).clone();
be.position = pos;
(pos, be)
})
.collect()
}
pub fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = ((i32, i32, i32), BlockEntity)>,
{
let iter = iter.into_iter();
let (lo, _) = iter.size_hint();
self.by_pos.reserve(lo);
self.palette.reserve(lo);
for (pos, be) in iter {
self.insert(pos, be);
}
}
}
impl Serialize for BlockEntityStore {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let owned: Vec<BlockEntity> = self
.iter()
.map(|(pos, be)| {
let mut cloned = be.clone();
cloned.position = pos;
cloned
})
.collect();
owned.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for BlockEntityStore {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let entries: Vec<BlockEntity> = Vec::deserialize(deserializer)?;
let mut store = BlockEntityStore::new();
store.palette.reserve(entries.len());
store.by_pos.reserve(entries.len());
for be in entries {
let pos = be.position;
let idx = store.palette.len() as u32;
store.palette.push(Arc::new(be));
store.by_pos.insert(pos, idx);
}
Ok(store)
}
}