use std::{
fmt,
marker::PhantomData,
sync::{Arc, Weak},
};
use wasm_runtime_layer::backend::{
AsContext, AsContextMut, WasmStore, WasmStoreContext, WasmStoreContextMut,
};
use wobbly::sync::Wobbly;
use crate::{func::PyHostFuncFn, Engine};
pub struct Store<T: 'static> {
inner: Arc<StoreProof>,
_marker: PhantomData<T>,
}
struct StoreInner<T: 'static> {
engine: Engine,
data: T,
host_funcs: Vec<Wobbly<PyHostFuncFn>>,
}
impl<T: 'static> WasmStore<T, Engine> for Store<T> {
fn new(engine: &Engine, data: T) -> Self {
#[cfg(feature = "tracing")]
tracing::debug!("Store::new");
Self {
inner: Arc::new(StoreProof::from_ptr(Box::into_raw(Box::new(StoreInner {
engine: engine.clone(),
data,
host_funcs: Vec::new(),
})))),
_marker: PhantomData::<T>,
}
}
fn engine(&self) -> &Engine {
&self.as_inner().engine
}
fn data(&self) -> &T {
&self.as_inner().data
}
fn data_mut(&mut self) -> &mut T {
&mut self.as_inner_mut().data
}
fn into_data(self) -> T {
let this = std::mem::ManuallyDrop::new(self);
let inner = Arc::into_inner(unsafe { std::ptr::read(&raw const this.inner) })
.expect("Store owns the only strong reference to StoreInner");
let inner = unsafe { Box::from_raw(inner.as_ptr()) };
inner.data
}
}
impl<T: 'static> AsContext<Engine> for Store<T> {
type UserState = T;
fn as_context(&self) -> StoreContext<'_, T> {
StoreContext {
store: self.as_inner(),
proof: &self.inner,
}
}
}
impl<T: 'static> AsContextMut<Engine> for Store<T> {
fn as_context_mut(&mut self) -> StoreContextMut<'_, T> {
let store = unsafe { &mut *self.inner.as_ptr() };
StoreContextMut {
store,
proof: &mut self.inner,
}
}
}
impl<T: 'static + fmt::Debug> fmt::Debug for Store<T> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let store = self.as_inner();
fmt.debug_struct("Store")
.field("engine", &store.engine)
.field("data", &store.data)
.finish_non_exhaustive()
}
}
impl<T: 'static + Default> Default for Store<T> {
fn default() -> Self {
Self::new(&Engine::default(), T::default())
}
}
impl<T: 'static + Clone> Clone for Store<T> {
fn clone(&self) -> Self {
Self::new(self.engine(), self.data().clone())
}
}
impl<T: 'static> Drop for Store<T> {
fn drop(&mut self) {
std::mem::drop(unsafe { Box::from_raw(self.inner.as_ptr::<T>()) });
#[cfg(feature = "tracing")]
tracing::debug!("Store::drop");
}
}
impl<T> Store<T> {
fn as_inner(&self) -> &StoreInner<T> {
unsafe { &*self.inner.as_ptr() }
}
fn as_inner_mut(&mut self) -> &mut StoreInner<T> {
unsafe { &mut *self.inner.as_ptr() }
}
}
#[allow(clippy::module_name_repetitions)]
pub struct StoreContext<'a, T: 'static> {
store: &'a StoreInner<T>,
proof: &'a Arc<StoreProof>,
}
#[allow(clippy::module_name_repetitions)]
pub struct StoreContextMut<'a, T: 'static> {
store: &'a mut StoreInner<T>,
proof: &'a mut Arc<StoreProof>,
}
impl<'a, T: 'static> StoreContextMut<'a, T> {
#[allow(clippy::needless_pass_by_ref_mut)]
pub(crate) fn as_weak_proof(&mut self) -> Weak<StoreProof> {
Arc::downgrade(self.proof)
}
pub(crate) unsafe fn from_proof_unchecked(proof: &'a mut Arc<StoreProof>) -> Self {
Self {
store: unsafe { &mut *(proof.as_ptr()) },
proof,
}
}
pub(crate) fn register_host_func(&mut self, func: Arc<PyHostFuncFn>) -> Wobbly<PyHostFuncFn> {
let func = Wobbly::new(func);
self.store.host_funcs.push(func.clone());
func
}
}
impl<'a, T: 'static> WasmStoreContext<'a, T, Engine> for StoreContext<'a, T> {
fn engine(&self) -> &Engine {
&self.store.engine
}
fn data(&self) -> &T {
&self.store.data
}
}
impl<'a, T: 'a> AsContext<Engine> for StoreContext<'a, T> {
type UserState = T;
fn as_context(&self) -> StoreContext<'_, T> {
StoreContext {
store: self.store,
proof: self.proof,
}
}
}
impl<'a, T: 'static> WasmStoreContext<'a, T, Engine> for StoreContextMut<'a, T> {
fn engine(&self) -> &Engine {
&self.store.engine
}
fn data(&self) -> &T {
&self.store.data
}
}
impl<'a, T: 'static> WasmStoreContextMut<'a, T, Engine> for StoreContextMut<'a, T> {
fn data_mut(&mut self) -> &mut T {
&mut self.store.data
}
}
impl<'a, T: 'a> AsContext<Engine> for StoreContextMut<'a, T> {
type UserState = T;
fn as_context(&self) -> StoreContext<'_, T> {
StoreContext {
store: self.store,
proof: self.proof,
}
}
}
impl<'a, T: 'a> AsContextMut<Engine> for StoreContextMut<'a, T> {
fn as_context_mut(&mut self) -> StoreContextMut<'_, T> {
StoreContextMut {
store: self.store,
proof: self.proof,
}
}
}
#[allow(clippy::module_name_repetitions)]
pub struct StoreProof(*mut ());
unsafe impl Send for StoreProof {}
unsafe impl Sync for StoreProof {}
impl StoreProof {
const fn from_ptr<T>(ptr: *mut StoreInner<T>) -> Self {
Self(ptr.cast())
}
const fn as_ptr<T>(&self) -> *mut StoreInner<T> {
self.0.cast()
}
}