use crate::error::Error;
use std::{
collections::HashMap,
fmt::Debug,
marker::PhantomData,
ops::{Index, IndexMut},
};
#[cfg(feature = "bevy_reflect")]
pub use bevy::RawIndex;
#[cfg(feature = "bevy_reflect")]
mod bevy {
use std::fmt::Debug;
use bevy_reflect::prelude::*;
#[derive(Reflect, Clone, Copy, PartialEq, Eq, Hash, Default, PartialOrd, Ord)]
#[reflect(Default)]
pub struct RawIndex(usize);
impl RawIndex {
pub fn as_index(&self) -> usize {
self.0
}
pub unsafe fn from_index(index: usize) -> Self {
Self(index)
}
}
impl Debug for RawIndex {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_index())
}
}
}
#[cfg(not(feature = "bevy_reflect"))]
pub use common_raw_index::RawIndex;
#[cfg(not(feature = "bevy_reflect"))]
mod common_raw_index {
use std::fmt::Debug;
use std::num::NonZero;
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct RawIndex(NonZero<usize>);
impl RawIndex {
pub fn as_index(&self) -> usize {
self.0.get() - 1
}
pub unsafe fn from_index(index: usize) -> Self {
Self(unsafe { NonZero::new_unchecked(index + 1) })
}
}
impl Debug for RawIndex {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_index())
}
}
}
#[macro_export]
macro_rules! new_index {
($name:ident) => {
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::prelude::ReflectDefault; #[cfg_attr(
feature = "bevy_reflect",
derive(::bevy_reflect::Reflect, ::core::default::Default)
)]
#[derive(
::core::fmt::Debug,
::core::clone::Clone,
::core::marker::Copy,
::core::cmp::PartialEq,
::core::cmp::Eq,
::core::hash::Hash,
::core::cmp::PartialOrd,
::core::cmp::Ord,
)]
#[cfg_attr(feature = "bevy_reflect", reflect(Default))]
pub struct $name($crate::custom_index::RawIndex);
unsafe impl $crate::custom_index::AsIndex for $name {
fn as_index(&self) -> ::core::primitive::usize {
self.0.as_index()
}
unsafe fn from_index(index: ::core::primitive::usize) -> Self {
Self(unsafe { $crate::custom_index::RawIndex::from_index(index) })
}
}
impl ::core::fmt::Display for $name {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
::core::fmt::Debug::fmt(self, f)
}
}
};
($($name:ident),*) => {
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::prelude::ReflectDefault; $(
#[cfg_attr(
feature = "bevy_reflect",
derive(::bevy_reflect::Reflect, ::core::default::Default)
)]
#[derive(
::core::fmt::Debug,
::core::clone::Clone,
::core::marker::Copy,
::core::cmp::PartialEq,
::core::cmp::Eq,
::core::hash::Hash,
::core::cmp::PartialOrd,
::core::cmp::Ord,
)]
#[cfg_attr(feature = "bevy_reflect", reflect(Default))]
pub struct $name($crate::custom_index::RawIndex);
unsafe impl $crate::custom_index::AsIndex for $name {
fn as_index(&self) -> ::core::primitive::usize {
self.0.as_index()
}
unsafe fn from_index(index: ::core::primitive::usize) -> Self {
Self(unsafe { $crate::custom_index::RawIndex::from_index(index) })
}
}
impl ::core::fmt::Display for $name {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
::core::fmt::Debug::fmt(self, f)
}
}
)*
};
}
pub unsafe trait AsIndex {
fn as_index(&self) -> usize;
unsafe fn from_index(index: usize) -> Self;
}
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
#[derive(Debug, Clone)]
pub struct NameMap<IndexType, Data>
where
IndexType: Copy + AsIndex + std::fmt::Debug,
{
map: HashMap<String, IndexType>,
data: Vec<Data>,
names: Vec<String>,
}
impl<IndexType, Data> Default for NameMap<IndexType, Data>
where
IndexType: Copy + AsIndex + std::fmt::Debug,
{
fn default() -> Self {
Self::new()
}
}
impl<IndexType, Data> NameMap<IndexType, Data>
where
IndexType: Copy + AsIndex + std::fmt::Debug,
{
pub fn new() -> Self {
Self {
map: HashMap::new(),
data: Vec::new(),
names: Vec::new(),
}
}
pub fn get_index(&self, name: &str) -> Option<IndexType> {
self.map.get(name).copied()
}
pub fn exist(&self, name: &str) -> bool {
self.map.contains_key(name)
}
pub fn insert(&mut self, name: String, data: Data) -> IndexType {
if let Some(&idx) = self.map.get(&name) {
return idx;
}
let idx = unsafe { IndexType::from_index(self.data.len()) };
self.data.push(data);
self.names.push(name.clone());
self.map.insert(name, idx);
idx
}
pub fn get_name(&self, index: IndexType) -> Result<&str, Error> {
let idx: usize = index.as_index();
if idx >= self.names.len() {
return Err(Error::InvalidIndex(format!("{:?}", index)));
}
Ok(&self.names[idx])
}
pub fn get_name_with_number(&self, index: usize) -> Option<&str> {
self.names.get(index).map(|s| s.as_str())
}
pub fn get_data(&self, index: IndexType) -> Result<&Data, Error> {
let idx: usize = index.as_index();
match self.data.get(idx) {
None => Err(Error::InvalidIndex(format!("{:?}", index))),
Some(v) => Ok(v),
}
}
pub fn get_data_mut(&mut self, index: IndexType) -> Result<&mut Data, Error> {
let idx: usize = index.as_index();
match self.data.get_mut(idx) {
None => Err(Error::InvalidIndex(format!("{:?}", index))),
Some(v) => Ok(v),
}
}
pub fn map_to_vec<Data1>(
&self,
mut data_mapper: impl FnMut(&str, &Data) -> Data1,
) -> TypedIndexVec<IndexType, Data1> {
let vec = self
.iter()
.map(|(_, name, data)| data_mapper(name, data))
.collect();
TypedIndexVec {
data: vec,
phantom: PhantomData,
}
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn keys(&self) -> impl Iterator<Item = &str> {
self.names.iter().map(|s| s.as_str())
}
pub fn indexs(&self) -> impl Iterator<Item = IndexType> + '_ {
self.data
.iter()
.enumerate()
.map(|(i, _)| unsafe { IndexType::from_index(i) })
}
pub fn iter(&self) -> impl Iterator<Item = (IndexType, &str, &Data)> {
self.names.iter().enumerate().map(move |(i, name)| {
(
unsafe { IndexType::from_index(i) },
name.as_str(),
&self.data[i],
)
})
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = (IndexType, &str, &mut Data)> {
let names = &self.names;
self.data
.iter_mut()
.enumerate()
.map(move |(i, data)| (unsafe { IndexType::from_index(i) }, names[i].as_str(), data))
}
}
impl<IndexType, Data> Index<IndexType> for NameMap<IndexType, Data>
where
IndexType: Copy + AsIndex + std::fmt::Debug,
{
type Output = Data;
fn index(&self, index: IndexType) -> &Self::Output {
self.get_data(index).expect("Invalid index in NameMap")
}
}
impl<IndexType, Data> IndexMut<IndexType> for NameMap<IndexType, Data>
where
IndexType: Copy + AsIndex + std::fmt::Debug,
{
fn index_mut(&mut self, index: IndexType) -> &mut Self::Output {
self.get_data_mut(index).expect("Invalid index in NameMap")
}
}
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TypedIndexVec<IndexType, Data>
where
IndexType: Copy + AsIndex + std::fmt::Debug,
{
data: Vec<Data>,
#[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
phantom: PhantomData<IndexType>,
}
impl<IndexType, Data> TypedIndexVec<IndexType, Data>
where
IndexType: Copy + AsIndex + std::fmt::Debug,
{
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn get_data(&self, index: IndexType) -> Result<&Data, Error> {
if !self.valid() {
return Err(Error::InvalidIndex("TypedIndexVec is invalid".to_string()));
}
let idx: usize = index.as_index();
match self.data.get(idx) {
None => Err(Error::InvalidIndex(format!("{:?}", index))),
Some(v) => Ok(v),
}
}
pub fn get_data_mut(&mut self, index: IndexType) -> Result<&mut Data, Error> {
if !self.valid() {
return Err(Error::InvalidIndex("TypedIndexVec is invalid".to_string()));
}
let idx: usize = index.as_index();
match self.data.get_mut(idx) {
None => Err(Error::InvalidIndex(format!("{:?}", index))),
Some(v) => Ok(v),
}
}
pub fn map_to_vec<Data1>(
&self,
data_mapper: impl FnMut(&Data) -> Data1,
) -> TypedIndexVec<IndexType, Data1> {
let vec = self.data.iter().map(data_mapper).collect();
TypedIndexVec {
data: vec,
phantom: PhantomData,
}
}
pub fn indexs(&self) -> impl Iterator<Item = IndexType> + '_ {
self.data
.iter()
.enumerate()
.map(|(i, _)| unsafe { IndexType::from_index(i) })
}
pub fn iter(&self) -> impl Iterator<Item = (IndexType, &Data)> {
self.data
.iter()
.enumerate()
.map(move |(i, data)| (unsafe { IndexType::from_index(i) }, data))
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = (IndexType, &mut Data)> {
self.data
.iter_mut()
.enumerate()
.map(move |(i, data)| (unsafe { IndexType::from_index(i) }, data))
}
pub fn new_invalid() -> Self {
Self {
data: Vec::new(),
phantom: PhantomData,
}
}
pub fn invalidate(&mut self) {
self.data.clear();
}
pub fn valid(&self) -> bool {
!self.data.is_empty()
}
pub fn reconstruct_from_map<Data0>(
&mut self,
map: &NameMap<IndexType, Data0>,
mut data_mapper: impl FnMut(&str, &Data0) -> Data,
) {
self.data.clear();
for data in map.iter() {
let (_, name, d0) = data;
let d1 = data_mapper(name, d0);
self.data.push(d1);
}
}
pub fn reconstruct_from_vec<Data0>(
&mut self,
vec: &TypedIndexVec<IndexType, Data0>,
mut data_mapper: impl FnMut(&Data0) -> Data,
) {
self.data.clear();
for (_, d0) in vec.iter() {
let d1 = data_mapper(d0);
self.data.push(d1);
}
}
}
impl<IndexType, Data> Index<IndexType> for TypedIndexVec<IndexType, Data>
where
IndexType: Copy + AsIndex + std::fmt::Debug,
{
type Output = Data;
fn index(&self, index: IndexType) -> &Self::Output {
self.get_data(index)
.expect("Invalid index in TypedIndexVec")
}
}
impl<IndexType, Data> IndexMut<IndexType> for TypedIndexVec<IndexType, Data>
where
IndexType: Copy + AsIndex + std::fmt::Debug,
{
fn index_mut(&mut self, index: IndexType) -> &mut Self::Output {
self.get_data_mut(index)
.expect("Invalid index in TypedIndexVec")
}
}
#[test]
fn t() {
new_index!(DebugIdx);
let mut a = NameMap::<DebugIdx, u32>::new();
let idx = a.insert("dd".to_owned(), 32);
let idx1 = a.insert("d2".to_owned(), 14);
assert!(idx.as_index() == 0);
assert_ne!(idx, idx1);
assert!(idx1.as_index() == 1);
let b = a.map_to_vec(|_name, e| *e);
b.iter()
.for_each(|(idx, data)| println!("{} {}", idx, data));
let c = b.map_to_vec(|e| e + 2);
c.iter()
.for_each(|(idx, data)| println!("{} {}", idx, data));
assert_eq!(idx1, unsafe { DebugIdx::from_index(idx1.as_index()) });
assert_eq!(idx, unsafe { DebugIdx::from_index(idx.as_index()) });
}