mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-03-16 02:00:51 +00:00
Support long-lived closures
Docs coming soon!
This commit is contained in:
parent
28d6c1bc12
commit
f7f0d578e7
@ -220,6 +220,37 @@ impl<'a> Context<'a> {
|
||||
return ptr;
|
||||
}")
|
||||
});
|
||||
|
||||
for i in 0..8 {
|
||||
let name = format!("__wbindgen_cb_arity{}", i);
|
||||
bind(&name, &|me| {
|
||||
me.expose_add_heap_object();
|
||||
me.function_table_needed = true;
|
||||
let args = (0..i)
|
||||
.map(|x| format!("arg{}", x))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
format!("function(a, b, c) {{
|
||||
const cb = function({0}) {{
|
||||
return this.f(this.a, this.b {1} {0});
|
||||
}};
|
||||
cb.a = b;
|
||||
cb.b = c;
|
||||
cb.f = wasm.__wbg_function_table.get(a);
|
||||
let real = cb.bind(cb);
|
||||
real.original = cb;
|
||||
return addHeapObject(real);
|
||||
}}", args, if i == 0 {""} else {","})
|
||||
});
|
||||
}
|
||||
bind("__wbindgen_cb_drop", &|me| {
|
||||
me.expose_drop_ref();
|
||||
String::from("function(i) {
|
||||
let obj = getObject(i).original;
|
||||
obj.a = obj.b = 0;
|
||||
dropRef(i);
|
||||
}")
|
||||
});
|
||||
}
|
||||
|
||||
self.rewrite_imports(module_name);
|
||||
@ -1438,6 +1469,10 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
||||
self.cx.expose_get_object();
|
||||
format!("getObject(arg{})", i)
|
||||
}
|
||||
shared::TYPE_FUNC => {
|
||||
self.cx.expose_get_object();
|
||||
format!("getObject(arg{})", i)
|
||||
}
|
||||
shared::TYPE_STACK_FUNC0 |
|
||||
shared::TYPE_STACK_FUNC1 |
|
||||
shared::TYPE_STACK_FUNC2 |
|
||||
|
@ -154,8 +154,9 @@ pub const TYPE_STACK_FUNC4: u32 = 28;
|
||||
pub const TYPE_STACK_FUNC5: u32 = 29;
|
||||
pub const TYPE_STACK_FUNC6: u32 = 30;
|
||||
pub const TYPE_STACK_FUNC7: u32 = 31;
|
||||
pub const TYPE_FUNC: u32 = 32;
|
||||
|
||||
pub const TYPE_CUSTOM_START: u32 = 32;
|
||||
pub const TYPE_CUSTOM_START: u32 = 40;
|
||||
pub const TYPE_CUSTOM_REF_FLAG: u32 = 1;
|
||||
|
||||
pub fn name_to_descriptor(name: &str) -> u32 {
|
||||
|
241
src/closure.rs
Normal file
241
src/closure.rs
Normal file
@ -0,0 +1,241 @@
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::marker::{self, Unsize};
|
||||
|
||||
use {throw, JsValue};
|
||||
use convert::*;
|
||||
use __rt::WasmRefCell;
|
||||
|
||||
pub unsafe trait WasmShim<'a> {
|
||||
#[doc(hidden)]
|
||||
const DESCRIPTOR: Descriptor;
|
||||
#[doc(hidden)]
|
||||
type Wrapper;
|
||||
#[doc(hidden)]
|
||||
fn shim() -> u32;
|
||||
#[doc(hidden)]
|
||||
fn factory() -> unsafe extern fn(u32, u32, u32) -> u32;
|
||||
#[doc(hidden)]
|
||||
fn wrap<U>(u: U) -> Self::Wrapper where U: Unsize<Self> + 'a;
|
||||
#[doc(hidden)]
|
||||
fn data(t: &Self::Wrapper) -> [u32; 2];
|
||||
}
|
||||
|
||||
union RawPtr<T: ?Sized> {
|
||||
ptr: *const T,
|
||||
data: [u32; 2]
|
||||
}
|
||||
|
||||
macro_rules! doit {
|
||||
($(
|
||||
($($var:ident)*) => $arity:ident
|
||||
)*) => ($(
|
||||
// Fn with no return
|
||||
unsafe impl<'a, $($var: WasmAbi),*> WasmShim<'a> for Fn($($var),*) + 'a {
|
||||
const DESCRIPTOR: Descriptor = DESCRIPTOR_FUNC;
|
||||
type Wrapper = Box<Fn($($var),*) + 'a>;
|
||||
|
||||
fn shim() -> u32 {
|
||||
#[allow(non_snake_case)]
|
||||
unsafe extern fn shim<$($var),*>(
|
||||
a: u32,
|
||||
b: u32,
|
||||
$($var:$var),*
|
||||
) {
|
||||
if a == 0 {
|
||||
throw("closure has been destroyed already");
|
||||
}
|
||||
(*RawPtr::<Fn($($var),*)> { data: [a, b] }.ptr)($($var),*)
|
||||
}
|
||||
shim::<$($var),*> as u32
|
||||
}
|
||||
|
||||
fn factory() -> unsafe extern fn(u32, u32, u32) -> u32 {
|
||||
super::$arity
|
||||
}
|
||||
|
||||
fn wrap<U>(u: U) -> Self::Wrapper where U: Unsize<Self> + 'a {
|
||||
Box::new(u) as Box<Self>
|
||||
}
|
||||
|
||||
fn data(t: &Self::Wrapper) -> [u32; 2] {
|
||||
unsafe {
|
||||
RawPtr::<Self> { ptr: &**t }.data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fn with a return
|
||||
unsafe impl<'a, $($var: WasmAbi,)* R: WasmAbi> WasmShim<'a> for Fn($($var),*) -> R + 'a {
|
||||
const DESCRIPTOR: Descriptor = DESCRIPTOR_FUNC;
|
||||
type Wrapper = Box<Fn($($var),*) -> R + 'a>;
|
||||
|
||||
fn shim() -> u32 {
|
||||
#[allow(non_snake_case)]
|
||||
unsafe extern fn shim<$($var,)* R>(
|
||||
a: u32,
|
||||
b: u32,
|
||||
$($var:$var),*
|
||||
) -> R {
|
||||
if a == 0 {
|
||||
throw("closure has been destroyed already");
|
||||
}
|
||||
(*RawPtr::<Fn($($var),*) -> R> { data: [a, b] }.ptr)($($var),*)
|
||||
}
|
||||
shim::<$($var,)* R> as u32
|
||||
}
|
||||
|
||||
fn factory() -> unsafe extern fn(u32, u32, u32) -> u32 {
|
||||
super::$arity
|
||||
}
|
||||
|
||||
fn wrap<U>(u: U) -> Self::Wrapper where U: Unsize<Self> + 'a {
|
||||
Box::new(u) as Box<Self>
|
||||
}
|
||||
|
||||
fn data(t: &Self::Wrapper) -> [u32; 2] {
|
||||
unsafe {
|
||||
RawPtr::<Self> { ptr: &**t }.data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FnMut with no return
|
||||
unsafe impl<'a, $($var: WasmAbi),*> WasmShim<'a> for FnMut($($var),*) + 'a {
|
||||
const DESCRIPTOR: Descriptor = DESCRIPTOR_FUNC;
|
||||
type Wrapper = Box<WasmRefCell<FnMut($($var),*) + 'a>>;
|
||||
|
||||
fn shim() -> u32 {
|
||||
#[allow(non_snake_case)]
|
||||
unsafe extern fn shim<$($var),*>(
|
||||
a: u32,
|
||||
b: u32,
|
||||
$($var:$var),*
|
||||
) {
|
||||
if a == 0 {
|
||||
throw("closure has been destroyed already");
|
||||
}
|
||||
let ptr: *const WasmRefCell<FnMut($($var),*)> = RawPtr {
|
||||
data: [a, b],
|
||||
}.ptr;
|
||||
let mut ptr = (*ptr).borrow_mut();
|
||||
(&mut *ptr)($($var),*)
|
||||
}
|
||||
shim::<$($var),*> as u32
|
||||
}
|
||||
|
||||
fn factory() -> unsafe extern fn(u32, u32, u32) -> u32 {
|
||||
super::$arity
|
||||
}
|
||||
|
||||
fn wrap<U>(u: U) -> Self::Wrapper where U: Unsize<Self> + 'a {
|
||||
Box::new(WasmRefCell::new(u)) as Box<_>
|
||||
}
|
||||
|
||||
fn data(t: &Self::Wrapper) -> [u32; 2] {
|
||||
unsafe {
|
||||
RawPtr::<WasmRefCell<Self>> { ptr: &**t }.data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FnMut with a return
|
||||
unsafe impl<'a, $($var: WasmAbi,)* R: WasmAbi> WasmShim<'a> for FnMut($($var),*) -> R + 'a {
|
||||
const DESCRIPTOR: Descriptor = DESCRIPTOR_FUNC;
|
||||
type Wrapper = Box<WasmRefCell<FnMut($($var),*) -> R + 'a>>;
|
||||
|
||||
fn shim() -> u32 {
|
||||
#[allow(non_snake_case)]
|
||||
unsafe extern fn shim<$($var,)* R>(
|
||||
a: u32,
|
||||
b: u32,
|
||||
$($var:$var),*
|
||||
) -> R {
|
||||
if a == 0 {
|
||||
throw("closure has been destroyed already");
|
||||
}
|
||||
let ptr: *const WasmRefCell<FnMut($($var),*) -> R> = RawPtr {
|
||||
data: [a, b],
|
||||
}.ptr;
|
||||
let mut ptr = (*ptr).borrow_mut();
|
||||
(&mut *ptr)($($var),*)
|
||||
}
|
||||
shim::<$($var,)* R> as u32
|
||||
}
|
||||
|
||||
fn factory() -> unsafe extern fn(u32, u32, u32) -> u32 {
|
||||
super::$arity
|
||||
}
|
||||
|
||||
fn wrap<U>(u: U) -> Self::Wrapper where U: Unsize<Self> + 'a {
|
||||
Box::new(WasmRefCell::new(u)) as Box<_>
|
||||
}
|
||||
|
||||
fn data(t: &Self::Wrapper) -> [u32; 2] {
|
||||
unsafe {
|
||||
RawPtr::<WasmRefCell<Self>> { ptr: &**t }.data
|
||||
}
|
||||
}
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
doit! {
|
||||
() => __wbindgen_cb_arity0
|
||||
(A) => __wbindgen_cb_arity1
|
||||
(A B) => __wbindgen_cb_arity2
|
||||
(A B C) => __wbindgen_cb_arity3
|
||||
(A B C D) => __wbindgen_cb_arity4
|
||||
(A B C D E) => __wbindgen_cb_arity5
|
||||
(A B C D E F) => __wbindgen_cb_arity6
|
||||
(A B C D E F G) => __wbindgen_cb_arity7
|
||||
}
|
||||
|
||||
pub struct Closure<'a, T: WasmShim<'a> + ?Sized + 'a> {
|
||||
_inner: T::Wrapper,
|
||||
js: ManuallyDrop<JsValue>,
|
||||
_marker: marker::PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl<'a, T> Closure<'a, T>
|
||||
where T: WasmShim<'a> + ?Sized,
|
||||
{
|
||||
pub fn new<U>(t: U) -> Closure<'a, T>
|
||||
where U: Unsize<T> + 'a
|
||||
{
|
||||
Closure::wrap(T::wrap(t))
|
||||
}
|
||||
|
||||
pub fn wrap(t: T::Wrapper) -> Closure<'a, T> {
|
||||
unsafe {
|
||||
let data = T::data(&t);
|
||||
let js = T::factory()(T::shim(), data[0], data[1]);
|
||||
Closure {
|
||||
_inner: t,
|
||||
js: ManuallyDrop::new(JsValue::from_abi(js, &mut GlobalStack::new())),
|
||||
_marker: marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> ToRefWasmBoundary for Closure<'a, T>
|
||||
where T: WasmShim<'a> + ?Sized,
|
||||
{
|
||||
type Abi = u32;
|
||||
const DESCRIPTOR: Descriptor = T::DESCRIPTOR;
|
||||
|
||||
fn to_abi_ref(&self, extra: &mut Stack) -> u32 {
|
||||
self.js.to_abi_ref(extra)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for Closure<'a, T>
|
||||
where T: WasmShim<'a> + ?Sized,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let idx = self.js.to_abi_ref(&mut GlobalStack::new());
|
||||
super::__wbindgen_cb_drop(idx);
|
||||
}
|
||||
}
|
||||
}
|
@ -30,6 +30,8 @@ pub const DESCRIPTOR_STACK_FUNC5: Descriptor = Descriptor { __x: *b" 29", };
|
||||
pub const DESCRIPTOR_STACK_FUNC6: Descriptor = Descriptor { __x: *b" 30", };
|
||||
pub const DESCRIPTOR_STACK_FUNC7: Descriptor = Descriptor { __x: *b" 31", };
|
||||
|
||||
pub const DESCRIPTOR_FUNC: Descriptor = Descriptor { __x: *b" 32", };
|
||||
|
||||
pub trait WasmBoundary {
|
||||
type Abi: WasmAbi;
|
||||
const DESCRIPTOR: Descriptor;
|
||||
@ -366,7 +368,7 @@ macro_rules! stack_closures {
|
||||
$($var: $var),*
|
||||
) -> R {
|
||||
if a == 0 {
|
||||
throw("stack closure has been destroyed already");
|
||||
throw("closure has been destroyed already");
|
||||
}
|
||||
let f: &Fn($($var),*) -> R = mem::transmute((a, b));
|
||||
f($($var),*)
|
||||
@ -394,7 +396,7 @@ macro_rules! stack_closures {
|
||||
$($var: $var),*
|
||||
) {
|
||||
if a == 0 {
|
||||
throw("stack closure has been destroyed already");
|
||||
throw("closure has been destroyed already");
|
||||
}
|
||||
let f: &Fn($($var),*) = mem::transmute((a, b));
|
||||
f($($var),*)
|
||||
|
36
src/lib.rs
36
src/lib.rs
@ -5,7 +5,7 @@
|
||||
//! this crate and this crate also provides JS bindings through the `JsValue`
|
||||
//! interface.
|
||||
|
||||
#![feature(use_extern_macros, wasm_import_module, try_reserve)]
|
||||
#![feature(use_extern_macros, wasm_import_module, try_reserve, unsize)]
|
||||
|
||||
extern crate wasm_bindgen_macro;
|
||||
|
||||
@ -23,9 +23,11 @@ use convert::WasmBoundary;
|
||||
pub mod prelude {
|
||||
pub use wasm_bindgen_macro::wasm_bindgen;
|
||||
pub use JsValue;
|
||||
pub use closure::Closure;
|
||||
}
|
||||
|
||||
pub mod convert;
|
||||
pub mod closure;
|
||||
|
||||
/// Representation of an object owned by JS.
|
||||
///
|
||||
@ -230,6 +232,16 @@ extern {
|
||||
fn __wbindgen_is_symbol(idx: u32) -> u32;
|
||||
fn __wbindgen_string_get(idx: u32, len: *mut usize) -> *mut u8;
|
||||
fn __wbindgen_throw(a: *const u8, b: usize) -> !;
|
||||
|
||||
fn __wbindgen_cb_arity0(a: u32, b: u32, c: u32) -> u32;
|
||||
fn __wbindgen_cb_arity1(a: u32, b: u32, c: u32) -> u32;
|
||||
fn __wbindgen_cb_arity2(a: u32, b: u32, c: u32) -> u32;
|
||||
fn __wbindgen_cb_arity3(a: u32, b: u32, c: u32) -> u32;
|
||||
fn __wbindgen_cb_arity4(a: u32, b: u32, c: u32) -> u32;
|
||||
fn __wbindgen_cb_arity5(a: u32, b: u32, c: u32) -> u32;
|
||||
fn __wbindgen_cb_arity6(a: u32, b: u32, c: u32) -> u32;
|
||||
fn __wbindgen_cb_arity7(a: u32, b: u32, c: u32) -> u32;
|
||||
fn __wbindgen_cb_drop(idx: u32);
|
||||
}
|
||||
|
||||
impl Clone for JsValue {
|
||||
@ -341,13 +353,13 @@ pub mod __rt {
|
||||
/// guard accidental reentrancy, so this vendored version is intended solely
|
||||
/// to not panic in libstd. Instead when it "panics" it calls our `throw`
|
||||
/// function in this crate which raises an error in JS.
|
||||
pub struct WasmRefCell<T> {
|
||||
pub struct WasmRefCell<T: ?Sized> {
|
||||
borrow: Cell<usize>,
|
||||
value: UnsafeCell<T>,
|
||||
}
|
||||
|
||||
impl<T> WasmRefCell<T> {
|
||||
pub fn new(value: T) -> WasmRefCell<T> {
|
||||
impl<T: ?Sized> WasmRefCell<T> {
|
||||
pub fn new(value: T) -> WasmRefCell<T> where T: Sized {
|
||||
WasmRefCell {
|
||||
value: UnsafeCell::new(value),
|
||||
borrow: Cell::new(0),
|
||||
@ -386,17 +398,17 @@ pub mod __rt {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> T {
|
||||
pub fn into_inner(self) -> T where T: Sized {
|
||||
self.value.into_inner()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Ref<'b, T: 'b> {
|
||||
pub struct Ref<'b, T: ?Sized + 'b> {
|
||||
value: &'b T,
|
||||
borrow: &'b Cell<usize>,
|
||||
}
|
||||
|
||||
impl<'b, T> Deref for Ref<'b, T> {
|
||||
impl<'b, T: ?Sized> Deref for Ref<'b, T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline]
|
||||
@ -405,18 +417,18 @@ pub mod __rt {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, T> Drop for Ref<'b, T> {
|
||||
impl<'b, T: ?Sized> Drop for Ref<'b, T> {
|
||||
fn drop(&mut self) {
|
||||
self.borrow.set(self.borrow.get() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RefMut<'b, T: 'b> {
|
||||
pub struct RefMut<'b, T: ?Sized + 'b> {
|
||||
value: &'b mut T,
|
||||
borrow: &'b Cell<usize>,
|
||||
}
|
||||
|
||||
impl<'b, T> Deref for RefMut<'b, T> {
|
||||
impl<'b, T: ?Sized> Deref for RefMut<'b, T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline]
|
||||
@ -425,14 +437,14 @@ pub mod __rt {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, T> DerefMut for RefMut<'b, T> {
|
||||
impl<'b, T: ?Sized> DerefMut for RefMut<'b, T> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, T> Drop for RefMut<'b, T> {
|
||||
impl<'b, T: ?Sized> Drop for RefMut<'b, T> {
|
||||
fn drop(&mut self) {
|
||||
self.borrow.set(0);
|
||||
}
|
||||
|
@ -88,3 +88,238 @@ fn cannot_reuse() {
|
||||
.test();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn long_lived() {
|
||||
test_support::project()
|
||||
.file("src/lib.rs", r#"
|
||||
#![feature(proc_macro, wasm_custom_section, wasm_import_module)]
|
||||
|
||||
extern crate wasm_bindgen;
|
||||
|
||||
use std::cell::Cell;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen(module = "./test")]
|
||||
extern {
|
||||
fn call1(a: &Closure<Fn()>);
|
||||
fn call2(a: &Closure<FnMut(u32) -> u32>) -> u32;
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn run() {
|
||||
let hit = Cell::new(false);
|
||||
let a = Closure::new(|| hit.set(true));
|
||||
assert!(!hit.get());
|
||||
call1(&a);
|
||||
assert!(hit.get());
|
||||
|
||||
let mut hit = false;
|
||||
{
|
||||
let a = Closure::new(|x| {
|
||||
hit = true;
|
||||
x + 3
|
||||
});
|
||||
assert_eq!(call2(&a), 5);
|
||||
}
|
||||
assert!(hit);
|
||||
}
|
||||
"#)
|
||||
.file("test.ts", r#"
|
||||
import { run } from "./out";
|
||||
|
||||
export function call1(a: any) {
|
||||
a();
|
||||
}
|
||||
|
||||
export function call2(a: any) {
|
||||
return a(2);
|
||||
}
|
||||
|
||||
export function test() {
|
||||
run();
|
||||
}
|
||||
"#)
|
||||
.test();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn many_arity() {
|
||||
test_support::project()
|
||||
.file("src/lib.rs", r#"
|
||||
#![feature(proc_macro, wasm_custom_section, wasm_import_module)]
|
||||
|
||||
extern crate wasm_bindgen;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen(module = "./test")]
|
||||
extern {
|
||||
fn call1(a: &Closure<Fn()>);
|
||||
fn call2(a: &Closure<Fn(u32)>);
|
||||
fn call3(a: &Closure<Fn(u32, u32)>);
|
||||
fn call4(a: &Closure<Fn(u32, u32, u32)>);
|
||||
fn call5(a: &Closure<Fn(u32, u32, u32, u32)>);
|
||||
fn call6(a: &Closure<Fn(u32, u32, u32, u32, u32)>);
|
||||
fn call7(a: &Closure<Fn(u32, u32, u32, u32, u32, u32)>);
|
||||
fn call8(a: &Closure<Fn(u32, u32, u32, u32, u32, u32, u32)>);
|
||||
|
||||
#[wasm_bindgen(js_name = call1)]
|
||||
fn stack1(a: &Fn());
|
||||
#[wasm_bindgen(js_name = call2)]
|
||||
fn stack2(a: &Fn(u32));
|
||||
#[wasm_bindgen(js_name = call3)]
|
||||
fn stack3(a: &Fn(u32, u32));
|
||||
#[wasm_bindgen(js_name = call4)]
|
||||
fn stack4(a: &Fn(u32, u32, u32));
|
||||
#[wasm_bindgen(js_name = call5)]
|
||||
fn stack5(a: &Fn(u32, u32, u32, u32));
|
||||
#[wasm_bindgen(js_name = call6)]
|
||||
fn stack6(a: &Fn(u32, u32, u32, u32, u32));
|
||||
#[wasm_bindgen(js_name = call7)]
|
||||
fn stack7(a: &Fn(u32, u32, u32, u32, u32, u32));
|
||||
#[wasm_bindgen(js_name = call8)]
|
||||
fn stack8(a: &Fn(u32, u32, u32, u32, u32, u32, u32));
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn run() {
|
||||
call1(&Closure::new(|| {}));
|
||||
call2(&Closure::new(|a| assert_eq!(a, 1)));
|
||||
call3(&Closure::new(|a, b| assert_eq!((a, b), (1, 2))));
|
||||
call4(&Closure::new(|a, b, c| assert_eq!((a, b, c), (1, 2, 3))));
|
||||
call5(&Closure::new(|a, b, c, d| {
|
||||
assert_eq!((a, b, c, d), (1, 2, 3, 4))
|
||||
}));
|
||||
call6(&Closure::new(|a, b, c, d, e| {
|
||||
assert_eq!((a, b, c, d, e), (1, 2, 3, 4, 5))
|
||||
}));
|
||||
call7(&Closure::new(|a, b, c, d, e, f| {
|
||||
assert_eq!((a, b, c, d, e, f), (1, 2, 3, 4, 5, 6))
|
||||
}));
|
||||
call8(&Closure::new(|a, b, c, d, e, f, g| {
|
||||
assert_eq!((a, b, c, d, e, f, g), (1, 2, 3, 4, 5, 6, 7))
|
||||
}));
|
||||
|
||||
stack1(&(|| {}));
|
||||
stack2(&(|a| assert_eq!(a, 1)));
|
||||
stack3(&(|a, b| assert_eq!((a, b), (1, 2))));
|
||||
stack4(&(|a, b, c| assert_eq!((a, b, c), (1, 2, 3))));
|
||||
stack5(&(|a, b, c, d| {
|
||||
assert_eq!((a, b, c, d), (1, 2, 3, 4))
|
||||
}));
|
||||
stack6(&(|a, b, c, d, e| {
|
||||
assert_eq!((a, b, c, d, e), (1, 2, 3, 4, 5))
|
||||
}));
|
||||
stack7(&(|a, b, c, d, e, f| {
|
||||
assert_eq!((a, b, c, d, e, f), (1, 2, 3, 4, 5, 6))
|
||||
}));
|
||||
stack8(&(|a, b, c, d, e, f, g| {
|
||||
assert_eq!((a, b, c, d, e, f, g), (1, 2, 3, 4, 5, 6, 7))
|
||||
}));
|
||||
}
|
||||
"#)
|
||||
.file("test.ts", r#"
|
||||
import { run } from "./out";
|
||||
|
||||
export function call1(a: any) { a() }
|
||||
export function call2(a: any) { a(1) }
|
||||
export function call3(a: any) { a(1, 2) }
|
||||
export function call4(a: any) { a(1, 2, 3) }
|
||||
export function call5(a: any) { a(1, 2, 3, 4) }
|
||||
export function call6(a: any) { a(1, 2, 3, 4, 5) }
|
||||
export function call7(a: any) { a(1, 2, 3, 4, 5, 6) }
|
||||
export function call8(a: any) { a(1, 2, 3, 4, 5, 6, 7) }
|
||||
|
||||
export function test() {
|
||||
run();
|
||||
}
|
||||
"#)
|
||||
.test();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn long_lived_dropping() {
|
||||
test_support::project()
|
||||
.file("src/lib.rs", r#"
|
||||
#![feature(proc_macro, wasm_custom_section, wasm_import_module)]
|
||||
|
||||
extern crate wasm_bindgen;
|
||||
|
||||
use std::cell::Cell;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen(module = "./test")]
|
||||
extern {
|
||||
fn cache(a: &Closure<Fn()>);
|
||||
#[wasm_bindgen(catch)]
|
||||
fn call() -> Result<(), JsValue>;
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn run() {
|
||||
let hit = Cell::new(false);
|
||||
let a = Closure::new(|| hit.set(true));
|
||||
cache(&a);
|
||||
assert!(!hit.get());
|
||||
assert!(call().is_ok());
|
||||
assert!(hit.get());
|
||||
drop(a);
|
||||
assert!(call().is_err());
|
||||
}
|
||||
"#)
|
||||
.file("test.ts", r#"
|
||||
import { run } from "./out";
|
||||
|
||||
let CACHE: any = null;
|
||||
|
||||
export function cache(a: any) { CACHE = a; }
|
||||
export function call() { CACHE() }
|
||||
|
||||
export function test() {
|
||||
run();
|
||||
}
|
||||
"#)
|
||||
.test();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn long_fnmut_recursive() {
|
||||
test_support::project()
|
||||
.file("src/lib.rs", r#"
|
||||
#![feature(proc_macro, wasm_custom_section, wasm_import_module)]
|
||||
|
||||
extern crate wasm_bindgen;
|
||||
|
||||
use std::cell::Cell;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen(module = "./test")]
|
||||
extern {
|
||||
fn cache(a: &Closure<FnMut()>);
|
||||
#[wasm_bindgen(catch)]
|
||||
fn call() -> Result<(), JsValue>;
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn run() {
|
||||
let a = Closure::new(|| {
|
||||
assert!(call().is_err());
|
||||
});
|
||||
cache(&a);
|
||||
assert!(call().is_ok());
|
||||
}
|
||||
"#)
|
||||
.file("test.ts", r#"
|
||||
import { run } from "./out";
|
||||
|
||||
let CACHE: any = null;
|
||||
|
||||
export function cache(a: any) { CACHE = a; }
|
||||
export function call() { CACHE() }
|
||||
|
||||
export function test() {
|
||||
run();
|
||||
}
|
||||
"#)
|
||||
.test();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user