use alloc::boxed::Box;
use core::ops::{Deref, DerefMut};
use wry_bindgen_runtime::wire::Runtime as RuntimeState;
use wry_bindgen_runtime::wire::{DecodedData, EncodedData, JsRef, ObjectHandle};
use crate::BatchableResult;
struct CheckedOutObject<T: 'static> {
handle: ObjectHandle,
value: Option<T>,
}
impl<T: 'static> CheckedOutObject<T> {
fn checkout(rt: &mut Runtime, handle: ObjectHandle) -> Self {
let value = rt.take_object::<T>(handle).expect("invalid handle");
Self {
handle,
value: Some(value),
}
}
fn get(&self) -> &T {
self.value.as_ref().expect("checked-out object missing")
}
fn get_mut(&mut self) -> &mut T {
self.value.as_mut().expect("checked-out object missing")
}
}
impl<T> Deref for CheckedOutObject<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.get()
}
}
impl<T> DerefMut for CheckedOutObject<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.get_mut()
}
}
impl<T: 'static> Drop for CheckedOutObject<T> {
fn drop(&mut self) {
if let Some(value) = self.value.take() {
with_runtime(|rt| rt.reinsert_object(self.handle, value));
}
}
}
pub struct Runtime<'a> {
backend: &'a mut RuntimeState,
}
impl Runtime<'_> {
pub fn insert_object<T: 'static>(&mut self, obj: T) -> ObjectHandle {
self.backend.insert_object_box(Box::new(obj))
}
fn take_object<T: 'static>(&mut self, handle: ObjectHandle) -> Option<T> {
self.backend
.take_object_box(handle)
.map(|obj| *obj.downcast::<T>().expect("object type mismatch"))
}
pub fn object<T: 'static>(
&mut self,
handle: ObjectHandle,
) -> impl DerefMut<Target = T> + use<T> {
CheckedOutObject::checkout(self, handle)
}
pub fn remove_object<T: 'static>(&mut self, handle: ObjectHandle) -> Option<T> {
self.backend
.remove_object_untyped(handle)
.map(|obj| *obj.downcast::<T>().expect("object type mismatch"))
}
fn reinsert_object<T: 'static>(&mut self, handle: ObjectHandle, obj: T) {
self.backend.reinsert_object_box(handle, Box::new(obj));
}
pub(crate) fn next_placeholder_ref(&mut self) -> JsRef {
self.backend.next_placeholder_ref()
}
}
pub fn with_runtime<R>(f: impl FnOnce(&mut Runtime) -> R) -> R {
wry_bindgen_runtime::wire::with_runtime(|backend| f(&mut Runtime { backend }))
}
pub(crate) fn with_backend<R>(f: impl FnOnce(&mut RuntimeState) -> R) -> R {
wry_bindgen_runtime::wire::with_runtime(f)
}
pub(crate) fn run_js_sync<R: BatchableResult + 'static>(
fn_id: u32,
add_args: impl FnOnce(&mut EncodedData),
) -> R {
wry_bindgen_runtime::wire::run_js_sync(
fn_id,
add_args,
|backend| R::try_placeholder(&mut Runtime { backend }),
|mut data: DecodedData<'_>| R::decode(&mut data).expect("Failed to decode return value"),
)
}