1use crate::nativepointer::NativePointer;
8use crate::plumbing;
9use crate::plumbing::utils::this_wrap;
10use js_sys::Object;
11use wasm_bindgen::prelude::*;
12use wasm_bindgen::JsCast;
13
14pub use plumbing::interceptor::{InvocationArgs, InvocationReturnValue};
15
16#[derive(Debug)]
30pub struct InvocationContext {
31 pub return_address: NativePointer,
33 pub context: crate::cpu::CpuContext,
35 pub thread_id: u32,
37 pub depth: u32,
39 _js: plumbing::interceptor::InvocationContext,
40}
41
42impl InvocationContext {
43 pub fn get<T>(&self, prop: &str) -> T
45 where
46 T: for<'a> serde::Deserialize<'a>,
47 {
48 self._js.get(prop).into_serde().unwrap()
49 }
50
51 pub fn set<T>(&self, prop: &str, val: &T)
54 where
55 T: serde::Serialize + ?Sized,
56 {
57 self._js.set(prop, JsValue::from_serde(val).unwrap())
58 }
59}
60
61impl From<plumbing::interceptor::InvocationContext> for InvocationContext {
62 fn from(m: plumbing::interceptor::InvocationContext) -> Self {
63 InvocationContext {
64 return_address: m.return_address(),
65 context: crate::cpu::CpuContext::from(m.context()),
66 thread_id: m.thread_id(),
67 depth: m.depth(),
68 _js: m,
69 }
70 }
71}
72
73impl wasm_bindgen::describe::WasmDescribe for InvocationContext {
75 fn describe() {
76 plumbing::interceptor::InvocationContext::describe()
77 }
78}
79
80impl wasm_bindgen::convert::FromWasmAbi for InvocationContext {
82 type Abi = u32;
83
84 unsafe fn from_abi(js: u32) -> InvocationContext {
85 let i = plumbing::interceptor::InvocationContext::from_abi(js);
86 InvocationContext::from(i)
87 }
88}
89
90pub struct InvocationCallbacks {
91 pub on_enter: Option<Box<dyn FnMut(InvocationContext, InvocationArgs)>>,
92 pub on_leave: Option<Box<dyn FnMut(InvocationContext, InvocationReturnValue)>>,
93}
94
95pub fn attach(target: NativePointer, callbacks: InvocationCallbacks) {
112 let callbacks_object = Object::new();
113
114 if let Some(f) = callbacks.on_enter {
115 let on_enter = Closure::wrap(f);
116 let on_enter_wrapped = this_wrap(on_enter.as_ref().unchecked_ref());
117 js_sys::Reflect::set(
118 &callbacks_object,
119 &JsValue::from_str("onEnter"),
120 &on_enter_wrapped,
121 )
122 .unwrap();
123 on_enter.forget();
124 }
125
126 if let Some(f) = callbacks.on_leave {
127 let on_leave = Closure::wrap(f);
128 let on_leave_wrapped = this_wrap(on_leave.as_ref().unchecked_ref());
129 js_sys::Reflect::set(
130 &callbacks_object,
131 &JsValue::from_str("onLeave"),
132 &on_leave_wrapped,
133 )
134 .unwrap();
135 on_leave.forget();
136 }
137
138 plumbing::interceptor::attach(target, callbacks_object);
139}