use std::fmt;
use std::hash::Hash;
use std::hash::Hasher;
use crate::prelude::*;
use crate::util::fmt::typename;
#[repr(transparent)]
pub struct GMRef<T> {
pub(crate) index: u32,
_marker: std::marker::PhantomData<T>,
}
impl<T> Copy for GMRef<T> {}
impl<T> Clone for GMRef<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> PartialEq for GMRef<T> {
fn eq(&self, other: &Self) -> bool {
self.index == other.index
}
}
impl<T> Eq for GMRef<T> {}
impl<T> Hash for GMRef<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.index.hash(state);
}
}
impl<T> From<u32> for GMRef<T> {
fn from(index: u32) -> Self {
Self::new(index)
}
}
impl<T> From<usize> for GMRef<T> {
fn from(index: usize) -> Self {
Self::new(index as u32)
}
}
impl<T> From<GMRef<T>> for u32 {
fn from(gm_ref: GMRef<T>) -> Self {
gm_ref.index
}
}
impl<T> From<GMRef<T>> for usize {
fn from(gm_ref: GMRef<T>) -> Self {
gm_ref.index as Self
}
}
impl<T> fmt::Debug for GMRef<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "GMRef<{}#{}>", typename::<T>(), self.index)
}
}
impl<T> GMRef<T> {
#[must_use]
pub const fn new(index: u32) -> Self {
Self { index, _marker: std::marker::PhantomData }
}
pub fn resolve(self, elements_by_index: &[T]) -> Result<&T> {
let element = elements_by_index.get(self.index as usize).ok_or_else(|| {
format!(
"Could not resolve {} reference with index {} in list with length {}",
typename::<T>(),
self.index,
elements_by_index.len(),
)
})?;
Ok(element)
}
pub fn resolve_mut(self, elements_by_index: &mut [T]) -> Result<&mut T> {
let length = elements_by_index.len();
let element = elements_by_index
.get_mut(self.index as usize)
.ok_or_else(|| {
format!(
"Could not resolve {} reference with index {} in list with length {}",
typename::<T>(),
self.index,
length,
)
})?;
Ok(element)
}
}