use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::{Index, IndexMut};
pub trait Idx: Copy + Eq + Debug {
fn new(raw: u32) -> Self;
fn index(self) -> u32;
}
#[derive(Clone)]
pub struct IndexVec<I: Idx, T> {
raw: Vec<T>,
_marker: PhantomData<fn(&I)>,
}
impl<I: Idx, T: Debug> Debug for IndexVec<I, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("IndexVec")
.field("len", &self.raw.len())
.field("data", &self.raw)
.finish()
}
}
impl<I: Idx, T> Default for IndexVec<I, T> {
fn default() -> Self {
Self::new()
}
}
impl<I: Idx, T> IndexVec<I, T> {
#[inline]
pub const fn new() -> Self {
Self {
raw: Vec::new(),
_marker: PhantomData,
}
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self {
raw: Vec::with_capacity(capacity),
_marker: PhantomData,
}
}
#[inline]
pub fn push(&mut self, val: T) -> I {
let idx = self.raw.len() as u32;
self.raw.push(val);
I::new(idx)
}
#[inline]
pub fn get(&self, idx: I) -> Option<&T> {
self.raw.get(idx.index() as usize)
}
#[inline]
pub fn get_mut(&mut self, idx: I) -> Option<&mut T> {
self.raw.get_mut(idx.index() as usize)
}
#[inline]
pub fn len(&self) -> usize {
self.raw.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.raw.is_empty()
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.raw.iter()
}
#[inline]
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
self.raw.iter_mut()
}
#[inline]
pub fn iter_enumerated(&self) -> impl Iterator<Item = (I, &T)> {
self.raw
.iter()
.enumerate()
.map(|(i, v)| (I::new(i as u32), v))
}
#[inline]
pub fn indices(&self) -> impl Iterator<Item = I> {
(0..self.raw.len() as u32).map(I::new)
}
#[inline]
pub fn raw(&self) -> &Vec<T> {
&self.raw
}
#[inline]
pub fn into_raw(self) -> Vec<T> {
self.raw
}
}
impl<I: Idx, T> Index<I> for IndexVec<I, T> {
type Output = T;
#[inline]
fn index(&self, idx: I) -> &Self::Output {
&self.raw[idx.index() as usize]
}
}
impl<I: Idx, T> IndexMut<I> for IndexVec<I, T> {
#[inline]
fn index_mut(&mut self, idx: I) -> &mut Self::Output {
&mut self.raw[idx.index() as usize]
}
}
impl<I: Idx, T> FromIterator<T> for IndexVec<I, T> {
fn from_iter<It: IntoIterator<Item = T>>(iter: It) -> Self {
Self {
raw: iter.into_iter().collect(),
_marker: PhantomData,
}
}
}
#[macro_export]
macro_rules! define_index {
($(#[$attr:meta])* $vis:vis struct $name:ident;) => {
$(#[$attr])*
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, serde::Serialize, serde::Deserialize)]
#[repr(transparent)]
$vis struct $name(u32);
impl $crate::query::index_vec::Idx for $name {
#[inline]
fn new(raw: u32) -> Self {
Self(raw)
}
#[inline]
fn index(self) -> u32 {
self.0
}
}
impl $name {
#[inline]
pub const fn from_raw(raw: u32) -> Self {
Self(raw)
}
#[inline]
pub const fn as_u32(self) -> u32 {
self.0
}
#[inline]
pub const fn as_usize(self) -> usize {
self.0 as usize
}
}
};
}
#[cfg(test)]
mod tests {
use super::*;
define_index! {
struct TestId;
}
#[test]
fn test_push_and_get() {
let mut vec: IndexVec<TestId, &str> = IndexVec::new();
let a = vec.push("hello");
let b = vec.push("world");
assert_eq!(vec[a], "hello");
assert_eq!(vec[b], "world");
assert_eq!(vec.len(), 2);
}
#[test]
fn test_iter_enumerated() {
let mut vec: IndexVec<TestId, i32> = IndexVec::new();
vec.push(10);
vec.push(20);
vec.push(30);
let pairs: Vec<_> = vec.iter_enumerated().collect();
assert_eq!(pairs.len(), 3);
assert_eq!(pairs[0].0.as_u32(), 0);
assert_eq!(*pairs[0].1, 10);
assert_eq!(pairs[2].0.as_u32(), 2);
assert_eq!(*pairs[2].1, 30);
}
#[test]
fn test_indices() {
let mut vec: IndexVec<TestId, ()> = IndexVec::new();
vec.push(());
vec.push(());
vec.push(());
let indices: Vec<_> = vec.indices().collect();
assert_eq!(indices.len(), 3);
assert_eq!(indices[0].as_u32(), 0);
assert_eq!(indices[1].as_u32(), 1);
assert_eq!(indices[2].as_u32(), 2);
assert_eq!(indices[0].as_usize(), 0);
assert_eq!(TestId::from_raw(5).as_u32(), 5);
}
}