pyodide_webassembly_runtime_layer/
externref.rsuse std::{any::Any, sync::Arc};
use pyo3::prelude::*;
use wasm_runtime_layer::backend::{AsContextMut, WasmExternRef};
use crate::{
conversion::{py_to_js_proxy, ToPy},
store::StoreContext,
Engine,
};
#[derive(Debug)]
pub struct ExternRef {
host: Option<Arc<AnyExternRef>>,
guest: Py<PyAny>,
}
impl Clone for ExternRef {
fn clone(&self) -> Self {
Python::with_gil(|py| Self {
host: self.host.clone(),
guest: self.guest.clone_ref(py),
})
}
}
impl WasmExternRef<Engine> for ExternRef {
fn new<T: 'static + Send + Sync>(_ctx: impl AsContextMut<Engine>, object: T) -> Self {
Python::with_gil(|py| -> Result<Self, PyErr> {
let object: Arc<AnyExternRef> = Arc::new(object);
let guest = Bound::new(
py,
PyExternRef {
object: Arc::clone(&object),
},
)?;
let guest = py_to_js_proxy(guest)?;
Ok(Self {
host: Some(object),
guest: guest.unbind(),
})
})
.expect("ExternRef::new should not fail")
}
fn downcast<'a, 's: 'a, T: 'static, S: 's>(
&'a self,
_ctx: StoreContext<'s, S>,
) -> anyhow::Result<&'a T> {
let Some(object) = self.host.as_ref() else {
anyhow::bail!("extern ref is from a different source");
};
let Some(object) = object.downcast_ref() else {
anyhow::bail!("incorrect extern ref type");
};
Ok(object)
}
}
impl ToPy for ExternRef {
fn to_py(&self, py: Python) -> Py<PyAny> {
self.guest.clone_ref(py)
}
}
impl ExternRef {
pub(crate) fn from_exported_externref(object: Bound<PyAny>) -> Self {
let Ok(host): Result<Bound<PyExternRef>, _> = object.extract() else {
return Self {
host: None,
guest: object.unbind(),
};
};
let host = Arc::clone(&host.get().object);
Self {
host: Some(host),
guest: object.unbind(),
}
}
}
type AnyExternRef = dyn 'static + Any + Send + Sync;
#[pyclass(frozen)]
struct PyExternRef {
object: Arc<AnyExternRef>,
}