use std::{marker::PhantomData, num::NonZeroUsize};
use wasmer_types::StoreId;
use super::{StoreObjects, obj::StoreObject};
pub struct StoreHandle<T> {
id: StoreId,
internal: InternalStoreHandle<T>,
}
impl<T> core::cmp::PartialEq for StoreHandle<T> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl<T> std::hash::Hash for StoreHandle<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.id.hash(state);
self.internal.idx.hash(state);
}
}
impl<T> Clone for StoreHandle<T> {
fn clone(&self) -> Self {
Self {
id: self.id,
internal: self.internal,
}
}
}
impl<T: StoreObject> std::fmt::Debug for StoreHandle<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("StoreHandle")
.field("id", &self.id)
.field("internal", &self.internal.index())
.finish()
}
}
impl<T: StoreObject> StoreHandle<T> {
pub fn new(store: &mut StoreObjects, val: T) -> Self {
Self {
id: store.id(),
internal: InternalStoreHandle::new(store, val),
}
}
pub fn get<'a>(&self, store: &'a StoreObjects) -> &'a T {
assert_eq!(self.id, store.id(), "object used with the wrong context");
self.internal.get(store)
}
pub fn get_mut<'a>(&self, store: &'a mut StoreObjects) -> &'a mut T {
assert_eq!(self.id, store.id(), "object used with the wrong context");
self.internal.get_mut(store)
}
pub fn internal_handle(&self) -> InternalStoreHandle<T> {
self.internal
}
#[allow(unused)]
pub fn store_id(&self) -> StoreId {
self.id
}
#[allow(unused)]
pub fn set_store_id(&mut self, id: StoreId) {
self.id = id;
}
pub unsafe fn from_internal(id: StoreId, internal: InternalStoreHandle<T>) -> Self {
Self { id, internal }
}
}
#[repr(transparent)]
pub struct InternalStoreHandle<T> {
idx: NonZeroUsize,
marker: PhantomData<fn() -> T>,
}
impl<T> Clone for InternalStoreHandle<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for InternalStoreHandle<T> {}
impl<T> std::fmt::Debug for InternalStoreHandle<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("InternalStoreHandle")
.field("idx", &self.idx)
.finish()
}
}
impl<T> PartialEq for InternalStoreHandle<T> {
fn eq(&self, other: &Self) -> bool {
self.idx == other.idx
}
}
impl<T> Eq for InternalStoreHandle<T> {}
impl<T: StoreObject> InternalStoreHandle<T> {
pub fn new(store: &mut StoreObjects, val: T) -> Self {
let list = T::list_mut(store);
let idx = NonZeroUsize::new(list.len() + 1).unwrap();
list.push(val);
Self {
idx,
marker: PhantomData,
}
}
pub fn get<'a>(&self, store: &'a StoreObjects) -> &'a T {
&T::list(store)[self.idx.get() - 1]
}
pub fn get_mut<'a>(&self, store: &'a mut StoreObjects) -> &'a mut T {
&mut T::list_mut(store)[self.idx.get() - 1]
}
pub(crate) fn index(&self) -> usize {
self.idx.get()
}
pub(crate) fn from_index(idx: usize) -> Option<Self> {
NonZeroUsize::new(idx).map(|idx| Self {
idx,
marker: PhantomData,
})
}
}