#![allow(clippy::fn_to_numeric_cast)]
use alloc::boxed::Box;
use alloc::string::String;
use core::fmt;
use core::mem::{self, ManuallyDrop};
use crate::__rt::marker::ErasableGeneric;
use crate::__rt::marker::MaybeUnwindSafe;
use crate::describe::*;
use crate::JsValue;
use crate::{convert::*, JsCast};
use core::marker::PhantomData;
use core::panic::AssertUnwindSafe;
#[wasm_bindgen_macro::wasm_bindgen(wasm_bindgen = crate)]
extern "C" {
type JsClosure;
#[wasm_bindgen(method)]
fn _wbg_cb_unref(js: &JsClosure);
}
pub struct ScopedClosure<'a, T: ?Sized> {
js: JsClosure,
_marker: PhantomData<Box<T>>,
_lifetime: PhantomData<&'a ()>,
}
pub type Closure<T> = ScopedClosure<'static, T>;
impl<T: ?Sized> Unpin for ScopedClosure<'_, T> {}
fn _assert_compiles<T>(pin: core::pin::Pin<&mut ScopedClosure<'static, T>>) {
let _ = &mut *pin.get_mut();
}
impl<T: ?Sized> Drop for ScopedClosure<'_, T> {
fn drop(&mut self) {
self.js._wbg_cb_unref();
}
}
impl<'a, T> ScopedClosure<'a, T>
where
T: ?Sized + WasmClosure,
{
pub fn as_js_value(&self) -> &JsValue {
self.js.unchecked_ref()
}
}
impl<T> ScopedClosure<'static, T>
where
T: ?Sized + WasmClosure,
{
pub fn new<F>(t: F) -> Self
where
F: IntoWasmClosure<T> + MaybeUnwindSafe + 'static,
{
Self::own(t)
}
pub fn own<F>(t: F) -> Self
where
F: IntoWasmClosure<T> + MaybeUnwindSafe + 'static,
{
Self::wrap_maybe_aborting::<true>(Box::new(t))
}
pub fn own_aborting<F>(t: F) -> Self
where
F: IntoWasmClosure<T> + 'static,
{
Self::wrap_maybe_aborting::<false>(Box::new(t))
}
pub fn own_assert_unwind_safe<F>(t: F) -> Self
where
F: IntoWasmClosure<T> + 'static,
{
Self::wrap_maybe_aborting::<true>(Box::new(t))
}
pub fn wrap<F>(data: Box<F>) -> Self
where
F: IntoWasmClosure<T> + ?Sized + MaybeUnwindSafe,
{
Self::wrap_maybe_aborting::<true>(data)
}
pub fn wrap_aborting<F>(data: Box<F>) -> Self
where
F: IntoWasmClosure<T> + ?Sized,
{
Self::wrap_maybe_aborting::<false>(data)
}
pub fn wrap_assert_unwind_safe<F>(data: Box<F>) -> Self
where
F: IntoWasmClosure<T> + ?Sized,
{
Self::wrap_maybe_aborting::<true>(data)
}
fn wrap_maybe_aborting<const UNWIND_SAFE: bool>(
data: Box<impl IntoWasmClosure<T> + ?Sized>,
) -> Self {
Self {
js: crate::__rt::wbg_cast(OwnedClosure::<T, UNWIND_SAFE>(data.unsize())),
_marker: PhantomData,
_lifetime: PhantomData,
}
}
pub fn borrow<'a, F>(t: &'a F) -> ScopedClosure<'a, T::Static>
where
F: IntoWasmClosureRef<T> + MaybeUnwindSafe + ?Sized,
{
Self::borrow_assert_unwind_safe(t)
}
pub fn borrow_aborting<'a, F>(t: &'a F) -> ScopedClosure<'a, T::Static>
where
F: IntoWasmClosureRef<T> + ?Sized,
{
Self::wrap_borrow::<_, false>(t)
}
pub fn borrow_assert_unwind_safe<'a, F>(t: &'a F) -> ScopedClosure<'a, T::Static>
where
F: IntoWasmClosureRef<T> + ?Sized,
{
Self::wrap_borrow::<_, true>(t)
}
fn wrap_borrow<'a, F, const UNWIND_SAFE: bool>(t: &'a F) -> ScopedClosure<'a, T::Static>
where
F: IntoWasmClosureRef<T> + ?Sized,
{
let t: &T = t.unsize_closure_ref();
let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&t) };
ScopedClosure {
js: crate::__rt::wbg_cast(BorrowedClosure::<T, UNWIND_SAFE> {
data: WasmSlice { ptr, len },
_marker: PhantomData,
}),
_marker: PhantomData,
_lifetime: PhantomData,
}
}
pub fn borrow_mut<'a, F>(t: &'a mut F) -> ScopedClosure<'a, T::Static>
where
F: IntoWasmClosureRefMut<T> + MaybeUnwindSafe + ?Sized,
{
Self::borrow_mut_assert_unwind_safe(t)
}
pub fn borrow_mut_aborting<'a, F>(t: &'a mut F) -> ScopedClosure<'a, T::Static>
where
F: IntoWasmClosureRefMut<T> + ?Sized,
{
Self::wrap_borrow_mut::<_, false>(t)
}
pub fn borrow_mut_assert_unwind_safe<'a, F>(t: &'a mut F) -> ScopedClosure<'a, T::Static>
where
F: IntoWasmClosureRefMut<T> + ?Sized,
{
Self::wrap_borrow_mut::<_, true>(t)
}
fn wrap_borrow_mut<'a, F, const UNWIND_SAFE: bool>(t: &'a mut F) -> ScopedClosure<'a, T::Static>
where
F: IntoWasmClosureRefMut<T> + ?Sized,
{
let t: &mut T = t.unsize_closure_ref();
let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&t) };
ScopedClosure {
js: crate::__rt::wbg_cast(BorrowedClosure::<T, UNWIND_SAFE> {
data: WasmSlice { ptr, len },
_marker: PhantomData,
}),
_marker: PhantomData,
_lifetime: PhantomData,
}
}
pub fn into_js_value(self) -> JsValue {
let idx = self.js.idx;
mem::forget(self);
JsValue::_new(idx)
}
pub fn forget(self) {
mem::forget(self);
}
pub fn once<F, A, R>(fn_once: F) -> Self
where
F: WasmClosureFnOnce<T, A, R> + MaybeUnwindSafe,
{
Closure::wrap_maybe_aborting::<true>(fn_once.into_fn_mut())
}
pub fn once_aborting<F, A, R>(fn_once: F) -> Self
where
F: WasmClosureFnOnceAbort<T, A, R>,
{
Closure::wrap_maybe_aborting::<false>(fn_once.into_fn_mut())
}
pub fn once_assert_unwind_safe<F, A, R>(fn_once: F) -> Self
where
F: WasmClosureFnOnceAbort<T, A, R>,
{
Closure::wrap_maybe_aborting::<true>(fn_once.into_fn_mut())
}
pub fn once_into_js<F, A, R>(fn_once: F) -> JsValue
where
F: WasmClosureFnOnce<T, A, R> + MaybeUnwindSafe,
{
fn_once.into_js_function()
}
}
#[doc(hidden)]
pub trait WasmClosureFnOnce<FnMut: ?Sized, A, R>: 'static {
fn into_fn_mut(self) -> Box<FnMut>;
fn into_js_function(self) -> JsValue;
}
#[doc(hidden)]
pub trait WasmClosureFnOnceAbort<FnMut: ?Sized, A, R>: 'static {
fn into_fn_mut(self) -> Box<FnMut>;
fn into_js_function(self) -> JsValue;
}
impl<T: ?Sized> AsRef<JsValue> for ScopedClosure<'_, T> {
fn as_ref(&self) -> &JsValue {
&self.js
}
}
#[repr(transparent)]
struct OwnedClosure<T: ?Sized, const UNWIND_SAFE: bool>(Box<T>);
struct BorrowedClosure<T: ?Sized, const UNWIND_SAFE: bool> {
data: WasmSlice,
_marker: PhantomData<T>,
}
#[no_mangle]
pub unsafe extern "C" fn __wbindgen_destroy_closure(a: usize, b: usize) {
if a == 0 {
return;
}
trait ErasedPlaceholderForDrop {}
drop(mem::transmute_copy::<_, Box<dyn ErasedPlaceholderForDrop>>(
&(a, b),
));
}
impl<T, const UNWIND_SAFE: bool> WasmDescribe for OwnedClosure<T, UNWIND_SAFE>
where
T: WasmClosure + ?Sized,
{
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe() {
inform(CLOSURE);
inform(1);
inform(T::IS_MUT as u32);
T::describe_invoke::<UNWIND_SAFE>();
}
}
impl<T, const UNWIND_SAFE: bool> WasmDescribe for BorrowedClosure<T, UNWIND_SAFE>
where
T: WasmClosure + ?Sized,
{
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe() {
inform(CLOSURE);
inform(0);
inform(T::IS_MUT as u32);
T::describe_invoke::<UNWIND_SAFE>();
}
}
impl<T, const UNWIND_SAFE: bool> IntoWasmAbi for OwnedClosure<T, UNWIND_SAFE>
where
T: WasmClosure + ?Sized,
{
type Abi = WasmSlice;
fn into_abi(self) -> WasmSlice {
let (a, b): (usize, usize) = unsafe { mem::transmute_copy(&ManuallyDrop::new(self)) };
WasmSlice {
ptr: a as u32,
len: b as u32,
}
}
}
impl<T, const UNWIND_SAFE: bool> IntoWasmAbi for BorrowedClosure<T, UNWIND_SAFE>
where
T: WasmClosure + ?Sized,
{
type Abi = WasmSlice;
fn into_abi(self) -> WasmSlice {
self.data
}
}
impl<T> WasmDescribe for ScopedClosure<'_, T>
where
T: WasmClosure + ?Sized,
{
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe() {
inform(EXTERNREF);
}
}
impl<T> IntoWasmAbi for &ScopedClosure<'_, T>
where
T: WasmClosure + ?Sized,
{
type Abi = u32;
fn into_abi(self) -> u32 {
(&self.js).into_abi()
}
}
impl<T> OptionIntoWasmAbi for &ScopedClosure<'_, T>
where
T: WasmClosure + ?Sized,
{
fn none() -> Self::Abi {
0
}
}
impl<T> IntoWasmAbi for ScopedClosure<'static, T>
where
T: WasmClosure + ?Sized,
{
type Abi = u32;
fn into_abi(self) -> u32 {
let idx = self.js.idx;
mem::forget(self);
idx
}
}
impl<T> OptionIntoWasmAbi for ScopedClosure<'static, T>
where
T: WasmClosure + ?Sized,
{
fn none() -> Self::Abi {
0
}
}
fn _check() {
fn _assert<T: IntoWasmAbi>() {}
_assert::<&ScopedClosure<dyn Fn()>>();
_assert::<&ScopedClosure<dyn Fn(String)>>();
_assert::<&ScopedClosure<dyn Fn() -> String>>();
_assert::<&ScopedClosure<dyn FnMut()>>();
_assert::<&ScopedClosure<dyn FnMut(String)>>();
_assert::<&ScopedClosure<dyn FnMut() -> String>>();
_assert::<ScopedClosure<'static, dyn Fn()>>();
_assert::<ScopedClosure<'static, dyn FnMut()>>();
_assert::<Closure<dyn Fn()>>();
_assert::<Closure<dyn FnMut()>>();
}
impl<T> fmt::Debug for ScopedClosure<'_, T>
where
T: ?Sized,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Closure {{ ... }}")
}
}
#[doc(hidden)]
pub unsafe trait WasmClosure: WasmDescribe {
const IS_MUT: bool;
type Static: ?Sized + WasmClosure;
type AsMut: ?Sized;
fn describe_invoke<const UNWIND_SAFE: bool>();
}
unsafe impl<T: WasmClosure> WasmClosure for AssertUnwindSafe<T> {
type Static = T::Static;
const IS_MUT: bool = T::IS_MUT;
type AsMut = T::AsMut;
fn describe_invoke<const UNWIND_SAFE: bool>() {
T::describe_invoke::<UNWIND_SAFE>();
}
}
#[doc(hidden)]
pub trait IntoWasmClosure<T: ?Sized> {
fn unsize(self: Box<Self>) -> Box<T>;
}
impl<T: ?Sized + WasmClosure> IntoWasmClosure<T> for T {
fn unsize(self: Box<Self>) -> Box<T> {
self
}
}
#[doc(hidden)]
pub trait IntoWasmClosureRef<T: ?Sized> {
fn unsize_closure_ref(&self) -> &T;
}
#[doc(hidden)]
pub trait IntoWasmClosureRefMut<T: ?Sized> {
fn unsize_closure_ref(&mut self) -> &mut T;
}
impl<T: ?Sized, F> IntoWasmClosureRef<T> for AssertUnwindSafe<F>
where
F: IntoWasmClosureRef<T>,
{
fn unsize_closure_ref(&self) -> &T {
self.0.unsize_closure_ref()
}
}
impl<T: ?Sized, F> IntoWasmClosureRefMut<T> for AssertUnwindSafe<F>
where
F: IntoWasmClosureRefMut<T>,
{
fn unsize_closure_ref(&mut self) -> &mut T {
self.0.unsize_closure_ref()
}
}
unsafe impl<T: ?Sized + WasmClosure> ErasableGeneric for ScopedClosure<'_, T> {
type Repr = ScopedClosure<'static, dyn FnMut()>;
}