use bevy::prelude::*;
use serde::{Deserialize, Serialize};
use std::{
fmt::{Debug, Display},
hash::Hash,
marker::PhantomData,
};
#[derive(Component, Reflect, Serialize, Deserialize)]
pub struct Id<T> {
value: u64,
#[reflect(ignore)]
#[serde(skip)]
_phantom: PhantomData<T>,
}
const HASH_P: u64 = 53;
const HASH_M: u64 = 1_000_000_009;
impl<T> Id<T> {
#[must_use]
pub const fn from_name(name: &str) -> Self {
let mut value = 0;
let mut p_pow = 1;
let byte_slice = name.as_bytes();
let mut end_of_bytes = byte_slice.is_empty();
let mut byte_index = 0;
while !end_of_bytes {
let byte = byte_slice[byte_index];
value = (value + (byte as u64 + 1) * p_pow) % HASH_M;
p_pow = (p_pow * HASH_P) % HASH_M;
byte_index += 1;
end_of_bytes = byte_index == byte_slice.len();
}
Id {
value,
_phantom: PhantomData,
}
}
#[must_use]
pub const fn raw(&self) -> u64 {
self.value
}
#[must_use]
pub const fn from_raw(value: u64) -> Self {
Id {
value,
_phantom: PhantomData,
}
}
}
impl<T> Debug for Id<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Id").field("value", &self.value).finish()
}
}
impl<T> Display for Id<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.value)
}
}
impl<T> PartialEq for Id<T> {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
impl<T> Eq for Id<T> {}
impl<T> PartialOrd for Id<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<T> Ord for Id<T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.value.cmp(&other.value)
}
}
impl<T> Hash for Id<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.value.hash(state);
}
}
impl<T> Clone for Id<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for Id<T> {}