use crate::nativepointer::NativePointer;
use crate::plumbing;
use crate::plumbing::utils::this_wrap;
use js_sys::Object;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
pub use plumbing::interceptor::{InvocationArgs, InvocationReturnValue};
#[derive(Debug)]
pub struct InvocationContext {
pub return_address: NativePointer,
pub context: crate::cpu::CpuContext,
pub thread_id: u32,
pub depth: u32,
_js: plumbing::interceptor::InvocationContext,
}
impl InvocationContext {
pub fn get<T>(&self, prop: &str) -> T
where
T: for<'a> serde::Deserialize<'a>,
{
self._js.get(prop).into_serde().unwrap()
}
pub fn set<T>(&self, prop: &str, val: &T)
where
T: serde::Serialize + ?Sized,
{
self._js.set(prop, JsValue::from_serde(val).unwrap())
}
}
impl From<plumbing::interceptor::InvocationContext> for InvocationContext {
fn from(m: plumbing::interceptor::InvocationContext) -> Self {
InvocationContext {
return_address: m.return_address(),
context: crate::cpu::CpuContext::from(m.context()),
thread_id: m.thread_id(),
depth: m.depth(),
_js: m,
}
}
}
impl wasm_bindgen::describe::WasmDescribe for InvocationContext {
fn describe() {
plumbing::interceptor::InvocationContext::describe()
}
}
impl wasm_bindgen::convert::FromWasmAbi for InvocationContext {
type Abi = u32;
unsafe fn from_abi(js: u32) -> InvocationContext {
let i = plumbing::interceptor::InvocationContext::from_abi(js);
InvocationContext::from(i)
}
}
pub struct InvocationCallbacks {
pub on_enter: Option<Box<dyn FnMut(InvocationContext, InvocationArgs)>>,
pub on_leave: Option<Box<dyn FnMut(InvocationContext, InvocationReturnValue)>>,
}
pub fn attach(target: NativePointer, callbacks: InvocationCallbacks) {
let callbacks_object = Object::new();
if let Some(f) = callbacks.on_enter {
let on_enter = Closure::wrap(f);
let on_enter_wrapped = this_wrap(on_enter.as_ref().unchecked_ref());
js_sys::Reflect::set(
&callbacks_object,
&JsValue::from_str("onEnter"),
&on_enter_wrapped,
)
.unwrap();
on_enter.forget();
}
if let Some(f) = callbacks.on_leave {
let on_leave = Closure::wrap(f);
let on_leave_wrapped = this_wrap(on_leave.as_ref().unchecked_ref());
js_sys::Reflect::set(
&callbacks_object,
&JsValue::from_str("onLeave"),
&on_leave_wrapped,
)
.unwrap();
on_leave.forget();
}
plumbing::interceptor::attach(target, callbacks_object);
}