use std::cell::UnsafeCell;
use std::marker::Unsize;
use std::mem::{self, ManuallyDrop};
use JsValue;
use convert::*;
use describe::*;
pub struct Closure<T: ?Sized> {
inner: UnsafeCell<Box<T>>,
js: UnsafeCell<ManuallyDrop<JsValue>>,
}
impl<T> Closure<T>
where T: ?Sized,
{
pub fn new<F>(t: F) -> Closure<T>
where F: Unsize<T> + 'static
{
Closure::wrap(Box::new(t) as Box<T>)
}
pub fn wrap(t: Box<T>) -> Closure<T> {
Closure {
inner: UnsafeCell::new(t),
js: UnsafeCell::new(ManuallyDrop::new(JsValue { idx: !0 })),
}
}
pub fn forget(self) {
unsafe {
let idx = (*self.js.get()).idx;
if idx != !0 {
super::__wbindgen_cb_forget(idx);
}
mem::forget(self);
}
}
}
impl<T> WasmDescribe for Closure<T>
where T: WasmClosure + ?Sized,
{
fn describe() {
inform(CLOSURE);
T::describe();
}
}
impl<'a, T> IntoWasmAbi for &'a Closure<T>
where T: WasmClosure + ?Sized,
{
type Abi = u32;
fn into_abi(self, extra: &mut Stack) -> u32 {
unsafe {
let fnptr = WasmClosure::into_abi(&mut **self.inner.get(), extra);
extra.push(fnptr);
&mut (*self.js.get()).idx as *const u32 as u32
}
}
}
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 {
let idx = (*self.js.get()).idx;
if idx != !0 {
super::__wbindgen_cb_drop(idx);
}
}
}
}
pub unsafe trait WasmClosure: 'static {
fn describe();
unsafe fn into_abi(me: *mut Self, extra: &mut Stack) -> u32;
}
macro_rules! doit {
($(
($($var:ident)*)
)*) => ($(
// Fn with no return
unsafe impl<$($var),*> WasmClosure for Fn($($var),*)
where $($var: FromWasmAbi + 'static,)*
{
fn describe() {
<&Self>::describe();
}
unsafe fn into_abi(me: *mut Self, extra: &mut Stack) -> u32 {
IntoWasmAbi::into_abi(&*me, extra)
}
}
unsafe impl<$($var,)* R> WasmClosure for Fn($($var),*) -> R
where $($var: FromWasmAbi + 'static,)*
R: IntoWasmAbi + 'static,
{
fn describe() {
<&Self>::describe();
}
unsafe fn into_abi(me: *mut Self, extra: &mut Stack) -> u32 {
IntoWasmAbi::into_abi(&*me, extra)
}
}
unsafe impl<$($var),*> WasmClosure for FnMut($($var),*)
where $($var: FromWasmAbi + 'static,)*
{
fn describe() {
<&mut Self>::describe();
}
unsafe fn into_abi(me: *mut Self, extra: &mut Stack) -> u32 {
IntoWasmAbi::into_abi(&mut *me, extra)
}
}
unsafe impl<$($var,)* R> WasmClosure for FnMut($($var),*) -> R
where $($var: FromWasmAbi + 'static,)*
R: IntoWasmAbi + 'static,
{
fn describe() {
<&Self>::describe();
}
unsafe fn into_abi(me: *mut Self, extra: &mut Stack) -> u32 {
IntoWasmAbi::into_abi(&mut *me, extra)
}
}
)*)
}
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)
}