use std::fmt::Debug;
use std::hash::Hash;
use crate::base64;
mod fast_map;
mod vec_map;
pub use fast_map::{FastEntityMap, FastEntityMapIntoIterator, FastEntityMapIterator};
pub use vec_map::VecEntityMap;
pub trait Entity: Copy + Default + Debug + Eq + Ord + Hash {
fn display(&self) -> String;
fn decrement(self) -> Self;
fn increment(self) -> Self;
fn max_value() -> Self;
}
impl Entity for u32 {
fn display(&self) -> String {
let bytes = self.to_le_bytes();
base64::encode(&bytes)
}
fn decrement(self) -> Self {
self.wrapping_sub(1)
}
fn increment(self) -> Self {
self.wrapping_add(1)
}
fn max_value() -> Self {
Self::MAX
}
}
impl Entity for u64 {
fn display(&self) -> String {
let bytes = self.to_le_bytes();
base64::encode(&bytes)
}
fn decrement(self) -> Self {
self.wrapping_sub(1)
}
fn increment(self) -> Self {
self.wrapping_add(1)
}
fn max_value() -> Self {
Self::MAX
}
}
impl Entity for u128 {
fn display(&self) -> String {
let bytes = self.to_le_bytes();
base64::encode(&bytes)
}
fn decrement(self) -> Self {
self.wrapping_sub(1)
}
fn increment(self) -> Self {
self.wrapping_add(1)
}
fn max_value() -> Self {
Self::MAX
}
}
pub trait EntityMap<E: Entity>: Debug + IntoIterator<Item = E> + FromIterator<E> {
type Iter<'a>: Iterator<Item = E> + 'a
where
Self: 'a;
fn is_empty(&self) -> bool;
fn len(&self) -> usize;
fn get(&self, offset: usize) -> E;
fn offset_of(&self, entity: E) -> usize;
fn exact_offset_of(&self, entity: E) -> Option<usize>;
fn lower_bound(&self, entity: E) -> Option<E>;
fn iter(&self) -> Self::Iter<'_>;
}
#[cfg(test)]
mod tests {
use super::*;
pub fn check_entity_map<E: Entity, EM: EntityMap<E>>(entities: Vec<E>, map: EM) {
assert_eq!(entities.is_empty(), map.is_empty());
assert_eq!(entities.len(), map.len());
for (idx, (lhs, rhs)) in std::iter::zip(map.iter(), entities.iter()).enumerate() {
assert_eq!(lhs, *rhs);
assert_eq!(lhs, map.get(idx));
assert_eq!(idx, map.offset_of(lhs));
assert_eq!(Some(lhs), map.lower_bound(lhs));
if idx > 0 && entities[idx - 1].increment() != entities[idx] {
assert_eq!(idx, map.offset_of(lhs.decrement()));
assert_eq!(Some(lhs), map.lower_bound(lhs.decrement()));
}
}
for (expected, returned) in std::iter::zip(entities.iter(), map.into_iter()) {
assert_eq!(*expected, returned);
}
}
}