use std::{any::type_name, cmp::Ordering, fmt, hash::Hash, ops::Deref};
use super::{blocks::Index, store::StoreInner};
pub struct Handle<T> {
pub(super) store: StoreInner<T>,
pub(super) index: Index,
pub(super) ptr: *const Option<T>,
}
impl<T> Handle<T> {
pub fn id(&self) -> ObjectId {
ObjectId::from_ptr(self.ptr)
}
pub fn clone_object(&self) -> T
where
T: Clone,
{
self.deref().clone()
}
}
impl<T> Deref for Handle<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
let slot = unsafe { &*self.ptr };
slot.as_ref()
.expect("Handle references non-existing object")
}
}
impl<T> Clone for Handle<T> {
fn clone(&self) -> Self {
Self {
store: self.store.clone(),
index: self.index,
ptr: self.ptr,
}
}
}
impl<T> Eq for Handle<T> where T: Eq {}
impl<T> PartialEq for Handle<T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.deref().eq(other.deref())
}
}
impl<T> Hash for Handle<T>
where
T: Hash,
{
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.deref().hash(state);
}
}
impl<T> Ord for Handle<T>
where
T: Ord,
{
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.deref().cmp(other.deref())
}
}
impl<T> PartialOrd for Handle<T>
where
T: PartialOrd,
{
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.deref().partial_cmp(other.deref())
}
}
impl<T> fmt::Debug for Handle<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let name = {
let type_name = type_name::<T>();
match type_name.rsplit_once("::") {
Some((_, name)) => name,
None => type_name,
}
};
let id = self.id().0;
let object = self.deref();
if f.alternate() {
write!(f, "{name} @ {id:#x} => {object:#?}")?;
} else {
write!(f, "{name} @ {id:#x}")?;
}
Ok(())
}
}
impl<T> From<HandleWrapper<T>> for Handle<T> {
fn from(wrapper: HandleWrapper<T>) -> Self {
wrapper.0
}
}
unsafe impl<T> Send for Handle<T> {}
unsafe impl<T> Sync for Handle<T> {}
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct ObjectId(pub(crate) u64);
impl ObjectId {
pub(crate) fn from_ptr<T>(ptr: *const T) -> ObjectId {
Self(ptr as u64)
}
}
impl fmt::Debug for ObjectId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let id = self.0;
write!(f, "object id {id:#x}")
}
}
pub struct HandleWrapper<T>(pub Handle<T>);
impl<T> Deref for HandleWrapper<T> {
type Target = Handle<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> Clone for HandleWrapper<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T> Eq for HandleWrapper<T> {}
impl<T> PartialEq for HandleWrapper<T> {
fn eq(&self, other: &Self) -> bool {
if cfg!(test) {
return true;
}
self.0.id().eq(&other.0.id())
}
}
impl<T> Hash for HandleWrapper<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
if cfg!(test) {
return;
}
self.0.id().hash(state);
}
}
impl<T> Ord for HandleWrapper<T> {
fn cmp(&self, other: &Self) -> Ordering {
if cfg!(test) {
return Ordering::Equal;
}
self.0.id().cmp(&other.0.id())
}
}
impl<T> PartialOrd for HandleWrapper<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
if cfg!(test) {
return Some(Ordering::Equal);
}
self.0.id().partial_cmp(&other.0.id())
}
}
impl<T> fmt::Debug for HandleWrapper<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl<T> From<Handle<T>> for HandleWrapper<T> {
fn from(handle: Handle<T>) -> Self {
Self(handle)
}
}
unsafe impl<T> Send for HandleWrapper<T> {}
unsafe impl<T> Sync for HandleWrapper<T> {}