#[cfg(feature = "nightly")]
use std::marker::Unsize;
use std::mem::{self, ManuallyDrop};
use std::prelude::v1::*;
use JsValue;
use convert::*;
use describe::*;
use throw_str;
pub struct Closure<T: ?Sized> {
js: ManuallyDrop<JsValue>,
data: ManuallyDrop<Box<T>>,
}
union FatPtr<T: ?Sized> {
ptr: *mut T,
fields: (usize, usize),
}
impl<T> Closure<T>
where T: ?Sized + WasmClosure,
{
#[cfg(feature = "nightly")]
pub fn new<F>(t: F) -> Closure<T>
where F: Unsize<T> + 'static
{
Closure::wrap(Box::new(t) as Box<T>)
}
pub fn wrap(mut data: Box<T>) -> Closure<T> {
assert_eq!(mem::size_of::<*const T>(), mem::size_of::<FatPtr<T>>());
let (a, b) = unsafe {
FatPtr { ptr: &mut *data as *mut T }.fields
};
extern "C" fn describe<T: WasmClosure + ?Sized>() {
inform(CLOSURE);
T::describe()
}
#[inline(never)]
unsafe fn breaks_if_inlined<T: WasmClosure + ?Sized>(
a: usize,
b: usize,
) -> u32 {
super::__wbindgen_describe_closure(
a as u32,
b as u32,
describe::<T> as u32,
)
}
let idx = unsafe {
breaks_if_inlined::<T>(a, b)
};
Closure {
js: ManuallyDrop::new(JsValue::_new(idx)),
data: ManuallyDrop::new(data),
}
}
pub fn forget(self) {
unsafe {
super::__wbindgen_cb_forget(self.js.idx);
mem::forget(self);
}
}
}
impl<T: ?Sized> AsRef<JsValue> for Closure<T> {
fn as_ref(&self) -> &JsValue {
&self.js
}
}
impl<T> WasmDescribe for Closure<T>
where T: WasmClosure + ?Sized,
{
fn describe() {
inform(ANYREF);
}
}
impl<'a, T> IntoWasmAbi for &'a Closure<T>
where T: WasmClosure + ?Sized,
{
type Abi = u32;
fn into_abi(self, extra: &mut Stack) -> u32 {
(&*self.js).into_abi(extra)
}
}
fn _check() {
fn _assert<T: IntoWasmAbi>() {}
_assert::<&Closure<Fn()>>();
_assert::<&Closure<Fn(String)>>();
_assert::<&Closure<Fn() -> String>>();
_assert::<&Closure<FnMut()>>();
_assert::<&Closure<FnMut(String)>>();
_assert::<&Closure<FnMut() -> String>>();
}
impl<T> Drop for Closure<T>
where T: ?Sized,
{
fn drop(&mut self) {
unsafe {
if super::__wbindgen_cb_drop(self.js.idx) != 0 {
ManuallyDrop::drop(&mut self.data);
}
}
}
}
#[doc(hidden)]
pub unsafe trait WasmClosure: 'static {
fn describe();
}
macro_rules! doit {
($(
($($var:ident)*)
)*) => ($(
unsafe impl<$($var,)* R> WasmClosure for Fn($($var),*) -> R
where $($var: FromWasmAbi + 'static,)*
R: ReturnWasmAbi + 'static,
{
fn describe() {
#[allow(non_snake_case)]
unsafe extern "C" fn invoke<$($var: FromWasmAbi,)* R: ReturnWasmAbi>(
a: usize,
b: usize,
$($var: <$var as FromWasmAbi>::Abi),*
) -> <R as ReturnWasmAbi>::Abi {
if a == 0 {
throw_str("closure invoked recursively or destroyed already");
}
let ret = {
let f: *const Fn($($var),*) -> R =
FatPtr { fields: (a, b) }.ptr;
let mut _stack = GlobalStack::new();
$(
let $var = <$var as FromWasmAbi>::from_abi($var, &mut _stack);
)*
(*f)($($var),*)
};
ret.return_abi(&mut GlobalStack::new())
}
inform(invoke::<$($var,)* R> as u32);
unsafe extern fn destroy<$($var: FromWasmAbi,)* R: ReturnWasmAbi>(
a: usize,
b: usize,
) {
debug_assert!(a != 0);
drop(Box::from_raw(FatPtr::<Fn($($var,)*) -> R> {
fields: (a, b)
}.ptr));
}
inform(destroy::<$($var,)* R> as u32);
<&Self>::describe();
}
}
unsafe impl<$($var,)* R> WasmClosure for FnMut($($var),*) -> R
where $($var: FromWasmAbi + 'static,)*
R: ReturnWasmAbi + 'static,
{
fn describe() {
#[allow(non_snake_case)]
unsafe extern "C" fn invoke<$($var: FromWasmAbi,)* R: ReturnWasmAbi>(
a: usize,
b: usize,
$($var: <$var as FromWasmAbi>::Abi),*
) -> <R as ReturnWasmAbi>::Abi {
if a == 0 {
throw_str("closure invoked recursively or destroyed already");
}
let ret = {
let f: *const FnMut($($var),*) -> R =
FatPtr { fields: (a, b) }.ptr;
let f = f as *mut FnMut($($var),*) -> R;
let mut _stack = GlobalStack::new();
$(
let $var = <$var as FromWasmAbi>::from_abi($var, &mut _stack);
)*
(*f)($($var),*)
};
ret.return_abi(&mut GlobalStack::new())
}
inform(invoke::<$($var,)* R> as u32);
unsafe extern fn destroy<$($var: FromWasmAbi,)* R: ReturnWasmAbi>(
a: usize,
b: usize,
) {
debug_assert!(a != 0);
drop(Box::from_raw(FatPtr::<FnMut($($var,)*) -> R> {
fields: (a, b)
}.ptr));
}
inform(destroy::<$($var,)* R> as u32);
<&mut Self>::describe();
}
}
)*)
}
doit! {
()
(A)
(A B)
(A B C)
(A B C D)
(A B C D E)
(A B C D E F)
(A B C D E F G)
}