1use alloc::boxed::Box;
4
5use crate::JsValue;
6use crate::encode::{BinaryEncode, CallbackKey, EncodeTypeDef};
7use crate::function::RustCallback;
8use crate::ipc::{DecodeError, DecodedData, EncodedData};
9use crate::object_store::insert_object;
10
11pub struct ScopedClosure<'a, T: ?Sized> {
13 pub(crate) _phantom: core::marker::PhantomData<(&'a (), crate::alloc::boxed::Box<T>)>,
16 pub(crate) callback: CallbackOwnership,
17 pub(crate) value: crate::JsValue,
18}
19
20#[derive(Clone, Copy)]
25pub(crate) enum CallbackOwnership {
26 None,
28 Owned,
30 Detached,
33}
34
35impl CallbackOwnership {
36 pub(crate) fn needs_flush(&self) -> bool {
39 !matches!(self, Self::None)
40 }
41
42 pub(crate) fn detach(&mut self) {
44 if matches!(self, Self::Owned) {
45 *self = Self::Detached;
46 }
47 }
48}
49
50pub type Closure<T> = ScopedClosure<'static, T>;
52
53use crate::__rt::WasmWord;
54
55#[unsafe(no_mangle)]
62pub unsafe extern "C" fn __wbindgen_destroy_closure(a: WasmWord, b: WasmWord) {
63 let _ = (a, b);
64}
65
66impl<T: ?Sized> ScopedClosure<'static, T> {
67 pub(crate) fn wrap_encode_decode<FnPtr>(
69 encode_decode: impl Fn(&mut DecodedData, &mut EncodedData) -> Result<(), DecodeError> + 'static,
70 ) -> Self
71 where
72 CallbackKey<FnPtr>: BinaryEncode + EncodeTypeDef,
73 {
74 let key = insert_object(RustCallback::new_fn(encode_decode));
75 let value =
76 crate::__rt::wbg_cast::<CallbackKey<FnPtr>, crate::JsValue>(CallbackKey::new(key));
77 Self {
78 _phantom: core::marker::PhantomData,
79 callback: crate::closure::CallbackOwnership::Owned,
80 value,
81 }
82 }
83
84 pub(crate) fn wrap_encode_decode_mut<FnPtr>(
86 encode_decode: impl FnMut(&mut DecodedData, &mut EncodedData) -> Result<(), DecodeError>
87 + 'static,
88 ) -> Self
89 where
90 CallbackKey<FnPtr>: BinaryEncode + EncodeTypeDef,
91 {
92 let key = insert_object(RustCallback::new_fn_mut(encode_decode));
93 let value =
94 crate::__rt::wbg_cast::<CallbackKey<FnPtr>, crate::JsValue>(CallbackKey::new(key));
95 Self {
96 _phantom: core::marker::PhantomData,
97 callback: crate::closure::CallbackOwnership::Owned,
98 value,
99 }
100 }
101
102 pub(crate) fn wrap_once_encode_decode_mut<FnPtr>(
104 mut encode_decode: impl FnMut(&mut DecodedData, &mut EncodedData) -> Result<(), DecodeError>
105 + 'static,
106 ) -> Self
107 where
108 CallbackKey<FnPtr>: BinaryEncode + EncodeTypeDef,
109 {
110 let handle_cell = alloc::rc::Rc::new(core::cell::Cell::new(None));
111 let handle_for_callback = handle_cell.clone();
112 let key = insert_object(RustCallback::new_fn_mut(move |decoder, encoder| {
113 let result = encode_decode(decoder, encoder);
114 if let Some(handle) = handle_for_callback.take() {
116 crate::batch::queue_rust_object_drop(handle);
117 }
118 result
119 }));
120 handle_cell.set(Some(key));
121 let value = crate::__rt::wbg_cast::<CallbackKey<FnPtr>, crate::JsValue>(
122 CallbackKey::new_with_policy(key, crate::encode::CallbackPolicy::JsOwnedOnce),
123 );
124 Self {
129 _phantom: core::marker::PhantomData,
130 callback: crate::closure::CallbackOwnership::Owned,
131 value,
132 }
133 }
134}
135
136impl<'a, T> ScopedClosure<'a, T>
137where
138 T: ?Sized + WasmClosure,
139{
140 pub fn as_js_value(&self) -> &JsValue {
142 &self.value
143 }
144}
145
146impl<T: ?Sized> Drop for ScopedClosure<'_, T> {
147 fn drop(&mut self) {
148 if let crate::closure::CallbackOwnership::Owned = self.callback {
149 crate::batch::queue_js_dispose_rust_function(self.value.id());
150 }
151 }
154}
155
156impl<T: ?Sized> Unpin for ScopedClosure<'_, T> {}
157
158#[doc(hidden)]
160pub trait MaybeUnwindSafe {}
161
162impl<T: ?Sized> MaybeUnwindSafe for T {}
163
164#[doc(hidden)]
166pub trait IntoWasmClosure<T: ?Sized> {
167 fn into_closure(self) -> Closure<T>
168 where
169 Self: Sized,
170 {
171 unreachable!("unsized closure objects must be converted from Box<Self>")
172 }
173
174 fn into_closure_box(self: Box<Self>) -> Closure<T>;
175}
176
177#[doc(hidden)]
179pub trait IntoWasmClosureRef<T: ?Sized> {
180 fn into_scoped_closure_ref<'a>(t: &'a Self) -> ScopedClosure<'a, T::Static>
181 where
182 T: WasmClosure;
183}
184
185#[doc(hidden)]
187pub trait IntoWasmClosureRefMut<T: ?Sized> {
188 fn into_scoped_closure_ref_mut<'a>(t: &'a mut Self) -> ScopedClosure<'a, T::Static>
189 where
190 T: WasmClosure;
191}
192
193#[doc(hidden)]
195pub trait WasmClosureFnOnce<T: ?Sized, A, R>: Sized + 'static {
196 fn into_closure(self) -> Closure<T>;
197}
198
199#[doc(hidden)]
201pub trait WasmClosureFnOnceAbort<T: ?Sized, A, R>: Sized + 'static {
202 fn into_closure(self) -> Closure<T>;
203}
204
205impl<T: ?Sized> AsRef<JsValue> for ScopedClosure<'_, T> {
206 fn as_ref(&self) -> &JsValue {
207 &self.value
208 }
209}
210
211impl<T> core::fmt::Debug for ScopedClosure<'_, T>
212where
213 T: ?Sized,
214{
215 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
216 f.debug_struct("Closure")
217 .field("value", &self.value)
218 .finish()
219 }
220}
221
222#[doc(hidden)]
224pub trait WasmClosure {
225 type Static: ?Sized;
227 type AsMut: ?Sized;
229}
230
231#[doc(hidden)]
233pub trait WryWasmClosure<M> {
234 fn into_js_closure(boxed: Box<Self>) -> Closure<Self>;
236}
237
238impl<T> ScopedClosure<'static, T>
239where
240 T: ?Sized + WasmClosure,
241{
242 pub fn new<F>(t: F) -> Self
243 where
244 F: IntoWasmClosure<T> + MaybeUnwindSafe + 'static,
245 {
246 Self::own(t)
247 }
248
249 pub fn own<F>(t: F) -> Self
250 where
251 F: IntoWasmClosure<T> + MaybeUnwindSafe + 'static,
252 {
253 <F as IntoWasmClosure<T>>::into_closure(t)
254 }
255
256 pub fn own_aborting<F>(t: F) -> Self
257 where
258 F: IntoWasmClosure<T> + 'static,
259 {
260 <F as IntoWasmClosure<T>>::into_closure(t)
261 }
262
263 pub fn own_assert_unwind_safe<F>(t: F) -> Self
264 where
265 F: IntoWasmClosure<T> + 'static,
266 {
267 <F as IntoWasmClosure<T>>::into_closure(t)
268 }
269
270 pub fn wrap<F>(data: Box<F>) -> Self
271 where
272 F: IntoWasmClosure<T> + ?Sized + MaybeUnwindSafe,
273 {
274 <F as IntoWasmClosure<T>>::into_closure_box(data)
275 }
276
277 pub fn wrap_aborting<F>(data: Box<F>) -> Self
278 where
279 F: IntoWasmClosure<T> + ?Sized,
280 {
281 <F as IntoWasmClosure<T>>::into_closure_box(data)
282 }
283
284 pub fn wrap_assert_unwind_safe<F>(data: Box<F>) -> Self
285 where
286 F: IntoWasmClosure<T> + ?Sized,
287 {
288 <F as IntoWasmClosure<T>>::into_closure_box(data)
289 }
290
291 pub fn borrow<'a, F>(t: &'a F) -> ScopedClosure<'a, T::Static>
292 where
293 F: IntoWasmClosureRef<T> + MaybeUnwindSafe + ?Sized,
294 {
295 F::into_scoped_closure_ref(t)
296 }
297
298 pub fn borrow_aborting<'a, F>(t: &'a F) -> ScopedClosure<'a, T::Static>
299 where
300 F: IntoWasmClosureRef<T> + ?Sized,
301 {
302 F::into_scoped_closure_ref(t)
303 }
304
305 pub fn borrow_assert_unwind_safe<'a, F>(t: &'a F) -> ScopedClosure<'a, T::Static>
306 where
307 F: IntoWasmClosureRef<T> + ?Sized,
308 {
309 F::into_scoped_closure_ref(t)
310 }
311
312 pub fn borrow_mut<'a, F>(t: &'a mut F) -> ScopedClosure<'a, T::Static>
313 where
314 F: IntoWasmClosureRefMut<T> + MaybeUnwindSafe + ?Sized,
315 {
316 F::into_scoped_closure_ref_mut(t)
317 }
318
319 pub fn borrow_mut_aborting<'a, F>(t: &'a mut F) -> ScopedClosure<'a, T::Static>
320 where
321 F: IntoWasmClosureRefMut<T> + ?Sized,
322 {
323 F::into_scoped_closure_ref_mut(t)
324 }
325
326 pub fn borrow_mut_assert_unwind_safe<'a, F>(t: &'a mut F) -> ScopedClosure<'a, T::Static>
327 where
328 F: IntoWasmClosureRefMut<T> + ?Sized,
329 {
330 F::into_scoped_closure_ref_mut(t)
331 }
332
333 pub fn once<F, A, R>(fn_once: F) -> Self
339 where
340 F: WasmClosureFnOnce<T, A, R> + MaybeUnwindSafe,
341 {
342 <F as WasmClosureFnOnce<T, A, R>>::into_closure(fn_once)
343 }
344
345 pub fn once_aborting<F, A, R>(fn_once: F) -> Self
346 where
347 F: WasmClosureFnOnceAbort<T, A, R>,
348 {
349 <F as WasmClosureFnOnceAbort<T, A, R>>::into_closure(fn_once)
350 }
351
352 pub fn once_assert_unwind_safe<F, A, R>(fn_once: F) -> Self
353 where
354 F: WasmClosureFnOnceAbort<T, A, R>,
355 {
356 Self::once_aborting(fn_once)
357 }
358
359 pub fn forget(self) {
361 core::mem::forget(self);
362 }
363
364 pub fn into_js_value(self) -> JsValue {
366 let value = core::mem::ManuallyDrop::new(self);
367 value.value.clone()
369 }
370
371 pub fn once_into_js<F, A, R>(fn_once: F) -> JsValue
376 where
377 F: WasmClosureFnOnce<T, A, R> + MaybeUnwindSafe,
378 {
379 Self::once(fn_once).into_js_value()
380 }
381}