mirror of
https://github.com/rustwasm/wasm-bindgen.git
synced 2024-11-28 05:52:21 +03:00
Don't use the global stack for string lengths
This commit updates the `Abi` associated type for all slice types to a `WasmSlice` type, an aggregate of two `u32` integers. This translates to an ABI where when passed as a function argument it expands to two integer arguments, and when passed as a return value it passes a return pointer as the first argument to get filled in. This is hopefully more forwards-compatible with the host bindings proposal which uses this strategy for passing string arguments at least. It's a little sketchy what we're doing as there's not really a stable ABI yet, but hopefully this'll all be relatively stable for awhile!
This commit is contained in:
parent
4304a262c6
commit
139b7a1aae
@ -23,10 +23,6 @@ pub struct Js2Rust<'a, 'b: 'a> {
|
|||||||
/// finishes. This is scheduled in a `finally` block.
|
/// finishes. This is scheduled in a `finally` block.
|
||||||
finally: String,
|
finally: String,
|
||||||
|
|
||||||
/// Next global index to write to when passing arguments via the single
|
|
||||||
/// global stack.
|
|
||||||
global_idx: usize,
|
|
||||||
|
|
||||||
/// Index of the next argument for unique name generation purposes.
|
/// Index of the next argument for unique name generation purposes.
|
||||||
arg_idx: usize,
|
arg_idx: usize,
|
||||||
|
|
||||||
@ -52,7 +48,6 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
|||||||
js_arguments: Vec::new(),
|
js_arguments: Vec::new(),
|
||||||
prelude: String::new(),
|
prelude: String::new(),
|
||||||
finally: String::new(),
|
finally: String::new(),
|
||||||
global_idx: 0,
|
|
||||||
arg_idx: 0,
|
arg_idx: 0,
|
||||||
ret_ty: String::new(),
|
ret_ty: String::new(),
|
||||||
ret_expr: String::new(),
|
ret_expr: String::new(),
|
||||||
@ -102,21 +97,23 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn abi_arg(&mut self) -> String {
|
||||||
|
let s = format!("arg{}", self.arg_idx);
|
||||||
|
self.arg_idx += 1;
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
pub fn argument(&mut self, arg: &Descriptor) -> Result<&mut Self, Error> {
|
pub fn argument(&mut self, arg: &Descriptor) -> Result<&mut Self, Error> {
|
||||||
let i = self.arg_idx;
|
let i = self.arg_idx;
|
||||||
self.arg_idx += 1;
|
let name = self.abi_arg();
|
||||||
let name = format!("arg{}", i);
|
|
||||||
|
|
||||||
if let Some(kind) = arg.vector_kind() {
|
if let Some(kind) = arg.vector_kind() {
|
||||||
self.js_arguments.push((name.clone(), kind.js_ty().to_string()));
|
self.js_arguments.push((name.clone(), kind.js_ty().to_string()));
|
||||||
|
|
||||||
let func = self.cx.pass_to_wasm_function(kind)?;
|
let func = self.cx.pass_to_wasm_function(kind)?;
|
||||||
self.cx.expose_set_global_argument()?;
|
|
||||||
let global_idx = self.global_idx();
|
|
||||||
self.prelude(&format!("\
|
self.prelude(&format!("\
|
||||||
const [ptr{i}, len{i}] = {func}({arg});\n\
|
const [ptr{i}, len{i}] = {func}({arg});\n\
|
||||||
setGlobalArgument(len{i}, {global_idx});\n\
|
", i = i, func = func, arg = name));
|
||||||
", i = i, func = func, arg = name, global_idx = global_idx));
|
|
||||||
if arg.is_by_ref() {
|
if arg.is_by_ref() {
|
||||||
if arg.is_mut_ref() {
|
if arg.is_mut_ref() {
|
||||||
let get = self.cx.memview_function(kind);
|
let get = self.cx.memview_function(kind);
|
||||||
@ -133,6 +130,7 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
|||||||
self.cx.require_internal_export("__wbindgen_free")?;
|
self.cx.require_internal_export("__wbindgen_free")?;
|
||||||
}
|
}
|
||||||
self.rust_arguments.push(format!("ptr{}", i));
|
self.rust_arguments.push(format!("ptr{}", i));
|
||||||
|
self.rust_arguments.push(format!("len{}", i));
|
||||||
return Ok(self)
|
return Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +185,7 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
|||||||
_assertBoolean({name});\n\
|
_assertBoolean({name});\n\
|
||||||
", name = name));
|
", name = name));
|
||||||
}
|
}
|
||||||
self.rust_arguments.push(format!("arg{i} ? 1 : 0", i = i));
|
self.rust_arguments.push(format!("{} ? 1 : 0", name));
|
||||||
}
|
}
|
||||||
Descriptor::Anyref => {
|
Descriptor::Anyref => {
|
||||||
self.js_arguments.push((name.clone(), "any".to_string()));
|
self.js_arguments.push((name.clone(), "any".to_string()));
|
||||||
@ -225,13 +223,18 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
|||||||
if let Some(ty) = ty.vector_kind() {
|
if let Some(ty) = ty.vector_kind() {
|
||||||
self.ret_ty = ty.js_ty().to_string();
|
self.ret_ty = ty.js_ty().to_string();
|
||||||
let f = self.cx.expose_get_vector_from_wasm(ty);
|
let f = self.cx.expose_get_vector_from_wasm(ty);
|
||||||
self.cx.expose_get_global_argument()?;
|
self.cx.expose_global_argument_ptr()?;
|
||||||
|
self.cx.expose_uint32_memory();
|
||||||
self.cx.require_internal_export("__wbindgen_free")?;
|
self.cx.require_internal_export("__wbindgen_free")?;
|
||||||
|
self.prelude("const retptr = globalArgumentPtr();");
|
||||||
|
self.rust_arguments.insert(0, "retptr".to_string());
|
||||||
self.ret_expr = format!("\
|
self.ret_expr = format!("\
|
||||||
const ret = RET;\n\
|
RET;\n\
|
||||||
const len = getGlobalArgument(0);\n\
|
const mem = getUint32Memory();\n\
|
||||||
const realRet = {}(ret, len);\n\
|
const ptr = mem[retptr / 4];\n\
|
||||||
wasm.__wbindgen_free(ret, len * {});\n\
|
const len = mem[retptr / 4 + 1];\n\
|
||||||
|
const realRet = {}(ptr, len);\n\
|
||||||
|
wasm.__wbindgen_free(ptr, len * {});\n\
|
||||||
return realRet;\n\
|
return realRet;\n\
|
||||||
", f, ty.size());
|
", f, ty.size());
|
||||||
return Ok(self)
|
return Ok(self)
|
||||||
@ -309,10 +312,4 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
|
|||||||
let ts = format!("{} {}({}): {};\n", prefix, self.js_name, ts_args, self.ret_ty);
|
let ts = format!("{} {}({}): {};\n", prefix, self.js_name, ts_args, self.ret_ty);
|
||||||
(js, ts)
|
(js, ts)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn global_idx(&mut self) -> usize {
|
|
||||||
let ret = self.global_idx;
|
|
||||||
self.global_idx += 1;
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1318,21 +1318,6 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expose_set_global_argument(&mut self) -> Result<(), Error> {
|
|
||||||
if !self.exposed_globals.insert("set_global_argument") {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
self.expose_uint32_memory();
|
|
||||||
self.expose_global_argument_ptr()?;
|
|
||||||
self.global("
|
|
||||||
function setGlobalArgument(arg, i) {
|
|
||||||
const idx = globalArgumentPtr() / 4 + i;
|
|
||||||
getUint32Memory()[idx] = arg;
|
|
||||||
}
|
|
||||||
");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expose_get_global_argument(&mut self) -> Result<(), Error> {
|
fn expose_get_global_argument(&mut self) -> Result<(), Error> {
|
||||||
if !self.exposed_globals.insert("get_global_argument") {
|
if !self.exposed_globals.insert("get_global_argument") {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -72,31 +72,32 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
|
|||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn argument(&mut self, arg: &Descriptor) -> Result<(), Error> {
|
fn shim_argument(&mut self) -> String {
|
||||||
let i = self.arg_idx;
|
let s = format!("arg{}", self.arg_idx);
|
||||||
self.arg_idx += 1;
|
self.arg_idx += 1;
|
||||||
|
self.shim_arguments.push(s.clone());
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
self.shim_arguments.push(format!("arg{}", i));
|
fn argument(&mut self, arg: &Descriptor) -> Result<(), Error> {
|
||||||
|
let abi = self.shim_argument();
|
||||||
|
|
||||||
if let Some(ty) = arg.vector_kind() {
|
if let Some(ty) = arg.vector_kind() {
|
||||||
|
let abi2 = self.shim_argument();
|
||||||
let f = self.cx.expose_get_vector_from_wasm(ty);
|
let f = self.cx.expose_get_vector_from_wasm(ty);
|
||||||
self.cx.expose_get_global_argument()?;
|
self.prelude(&format!("let v{0} = {func}({0}, {1});",
|
||||||
let next_global = self.global_idx();
|
abi, abi2, func = f));
|
||||||
self.prelude(&format!("\
|
|
||||||
let len{0} = getGlobalArgument({next_global});\n\
|
|
||||||
let v{0} = {func}(arg{0}, len{0});\n\
|
|
||||||
", i, func = f, next_global = next_global));
|
|
||||||
|
|
||||||
if !arg.is_by_ref() {
|
if !arg.is_by_ref() {
|
||||||
self.prelude(&format!("\
|
self.prelude(&format!("\
|
||||||
wasm.__wbindgen_free(arg{0}, len{0} * {size});\
|
wasm.__wbindgen_free({0}, {1} * {size});\
|
||||||
", i, size = ty.size()));
|
", abi, abi2, size = ty.size()));
|
||||||
self.cx.require_internal_export("__wbindgen_free")?;
|
self.cx.require_internal_export("__wbindgen_free")?;
|
||||||
} else if arg.is_mut_ref() {
|
} else if arg.is_mut_ref() {
|
||||||
let f = self.cx.expose_commit_slice_to_wasm(ty)?;
|
let f = self.cx.expose_commit_slice_to_wasm(ty)?;
|
||||||
self.finally(&format!("{}(arg{i}, v{i});", f, i = i));
|
self.finally(&format!("{}({1}, v{1});", f, abi));
|
||||||
}
|
}
|
||||||
self.js_arguments.push(format!("v{}", i));
|
self.js_arguments.push(format!("v{}", abi));
|
||||||
return Ok(())
|
return Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,9 +105,9 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
|
|||||||
if arg.is_by_ref() {
|
if arg.is_by_ref() {
|
||||||
bail!("cannot invoke JS functions with custom ref types yet")
|
bail!("cannot invoke JS functions with custom ref types yet")
|
||||||
}
|
}
|
||||||
let assign = format!("let c{0} = {1}.__construct(arg{0});", i, class);
|
let assign = format!("let c{0} = {1}.__construct({0});", abi, class);
|
||||||
self.prelude(&assign);
|
self.prelude(&assign);
|
||||||
self.js_arguments.push(format!("c{}", i));
|
self.js_arguments.push(format!("c{}", abi));
|
||||||
return Ok(())
|
return Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,12 +133,12 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
|
|||||||
self.global_idx();
|
self.global_idx();
|
||||||
self.prelude(&format!("\
|
self.prelude(&format!("\
|
||||||
let cb{0} = {js};\n\
|
let cb{0} = {js};\n\
|
||||||
cb{0}.f = wasm.__wbg_function_table.get(arg{0});\n\
|
cb{0}.f = wasm.__wbg_function_table.get({0});\n\
|
||||||
cb{0}.a = getGlobalArgument({next_global});\n\
|
cb{0}.a = getGlobalArgument({next_global});\n\
|
||||||
cb{0}.b = getGlobalArgument({next_global} + 1);\n\
|
cb{0}.b = getGlobalArgument({next_global} + 1);\n\
|
||||||
", i, js = js, next_global = next_global));
|
", abi, js = js, next_global = next_global));
|
||||||
self.finally(&format!("cb{0}.a = cb{0}.b = 0;", i));
|
self.finally(&format!("cb{0}.a = cb{0}.b = 0;", abi));
|
||||||
self.js_arguments.push(format!("cb{0}.bind(cb{0})", i));
|
self.js_arguments.push(format!("cb{0}.bind(cb{0})", abi));
|
||||||
return Ok(())
|
return Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,35 +169,35 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
|
|||||||
cb{0}.f = wasm.__wbg_function_table.get(getGlobalArgument({c}));\n\
|
cb{0}.f = wasm.__wbg_function_table.get(getGlobalArgument({c}));\n\
|
||||||
let real = cb{0}.bind(cb{0});\n\
|
let real = cb{0}.bind(cb{0});\n\
|
||||||
real.original = cb{0};\n\
|
real.original = cb{0};\n\
|
||||||
idx{0} = getUint32Memory()[arg{0} / 4] = addHeapObject(real);\n\
|
idx{0} = getUint32Memory()[{0} / 4] = addHeapObject(real);\n\
|
||||||
",
|
",
|
||||||
i,
|
abi,
|
||||||
js = js,
|
js = js,
|
||||||
a = self.global_idx(),
|
a = self.global_idx(),
|
||||||
b = self.global_idx(),
|
b = self.global_idx(),
|
||||||
c = self.global_idx(),
|
c = self.global_idx(),
|
||||||
);
|
);
|
||||||
self.prelude(&format!("\
|
self.prelude(&format!("\
|
||||||
let idx{0} = getUint32Memory()[arg{0} / 4];\n\
|
let idx{0} = getUint32Memory()[{0} / 4];\n\
|
||||||
if (idx{0} === 0xffffffff) {{\n\
|
if (idx{0} === 0xffffffff) {{\n\
|
||||||
{1}\
|
{1}\
|
||||||
}}\n\
|
}}\n\
|
||||||
", i, indent(&reset_idx)));
|
", abi, indent(&reset_idx)));
|
||||||
self.cx.expose_get_object();
|
self.cx.expose_get_object();
|
||||||
self.js_arguments.push(format!("getObject(idx{})", i));
|
self.js_arguments.push(format!("getObject(idx{})", abi));
|
||||||
return Ok(())
|
return Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
let invoc_arg = match *arg {
|
let invoc_arg = match *arg {
|
||||||
ref d if d.is_number() => format!("arg{}", i),
|
ref d if d.is_number() => abi,
|
||||||
Descriptor::Boolean => format!("arg{} !== 0", i),
|
Descriptor::Boolean => format!("{} !== 0", abi),
|
||||||
Descriptor::Anyref => {
|
Descriptor::Anyref => {
|
||||||
self.cx.expose_take_object();
|
self.cx.expose_take_object();
|
||||||
format!("takeObject(arg{})", i)
|
format!("takeObject({})", abi)
|
||||||
}
|
}
|
||||||
ref d if d.is_ref_anyref() => {
|
ref d if d.is_ref_anyref() => {
|
||||||
self.cx.expose_get_object();
|
self.cx.expose_get_object();
|
||||||
format!("getObject(arg{})", i)
|
format!("getObject({})", abi)
|
||||||
}
|
}
|
||||||
_ => bail!("unimplemented argument type in imported function: {:?}", arg),
|
_ => bail!("unimplemented argument type in imported function: {:?}", arg),
|
||||||
};
|
};
|
||||||
@ -218,11 +219,12 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
|
|||||||
if let Some(ty) = ty.vector_kind() {
|
if let Some(ty) = ty.vector_kind() {
|
||||||
let f = self.cx.pass_to_wasm_function(ty)?;
|
let f = self.cx.pass_to_wasm_function(ty)?;
|
||||||
self.cx.expose_uint32_memory();
|
self.cx.expose_uint32_memory();
|
||||||
self.cx.expose_set_global_argument()?;
|
self.shim_arguments.insert(0, "ret".to_string());
|
||||||
self.ret_expr = format!("\
|
self.ret_expr = format!("\
|
||||||
const [retptr, retlen] = {}(JS);\n\
|
const [retptr, retlen] = {}(JS);\n\
|
||||||
setGlobalArgument(retlen, 0);\n\
|
const mem = getUint32Memory();
|
||||||
return retptr;\n\
|
mem[ret / 4] = retptr;
|
||||||
|
mem[ret / 4 + 1] = retlen;
|
||||||
", f);
|
", f);
|
||||||
return Ok(())
|
return Ok(())
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,14 @@ unsafe impl WasmAbi for i64 {}
|
|||||||
unsafe impl WasmAbi for f32 {}
|
unsafe impl WasmAbi for f32 {}
|
||||||
unsafe impl WasmAbi for f64 {}
|
unsafe impl WasmAbi for f64 {}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct WasmSlice {
|
||||||
|
pub ptr: u32,
|
||||||
|
pub len: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl WasmAbi for WasmSlice {}
|
||||||
|
|
||||||
macro_rules! simple {
|
macro_rules! simple {
|
||||||
($($t:tt)*) => ($(
|
($($t:tt)*) => ($(
|
||||||
impl IntoWasmAbi for $t {
|
impl IntoWasmAbi for $t {
|
||||||
@ -137,67 +145,71 @@ macro_rules! vectors {
|
|||||||
($($t:ident)*) => ($(
|
($($t:ident)*) => ($(
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
impl IntoWasmAbi for Box<[$t]> {
|
impl IntoWasmAbi for Box<[$t]> {
|
||||||
type Abi = u32;
|
type Abi = WasmSlice;
|
||||||
|
|
||||||
fn into_abi(self, extra: &mut Stack) -> u32 {
|
fn into_abi(self, extra: &mut Stack) -> WasmSlice {
|
||||||
let ptr = self.as_ptr();
|
let ptr = self.as_ptr();
|
||||||
let len = self.len();
|
let len = self.len();
|
||||||
mem::forget(self);
|
mem::forget(self);
|
||||||
extra.push(len as u32);
|
WasmSlice {
|
||||||
ptr.into_abi(extra)
|
ptr: ptr.into_abi(extra),
|
||||||
|
len: len as u32,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
impl FromWasmAbi for Box<[$t]> {
|
impl FromWasmAbi for Box<[$t]> {
|
||||||
type Abi = u32;
|
type Abi = WasmSlice;
|
||||||
|
|
||||||
unsafe fn from_abi(js: u32, extra: &mut Stack) -> Self {
|
unsafe fn from_abi(js: WasmSlice, extra: &mut Stack) -> Self {
|
||||||
let ptr = <*mut $t>::from_abi(js, extra);
|
let ptr = <*mut $t>::from_abi(js.ptr, extra);
|
||||||
let len = extra.pop() as usize;
|
let len = js.len as usize;
|
||||||
Vec::from_raw_parts(ptr, len, len).into_boxed_slice()
|
Vec::from_raw_parts(ptr, len, len).into_boxed_slice()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> IntoWasmAbi for &'a [$t] {
|
impl<'a> IntoWasmAbi for &'a [$t] {
|
||||||
type Abi = u32;
|
type Abi = WasmSlice;
|
||||||
|
|
||||||
fn into_abi(self, extra: &mut Stack) -> u32 {
|
fn into_abi(self, extra: &mut Stack) -> WasmSlice {
|
||||||
let ptr = self.as_ptr();
|
WasmSlice {
|
||||||
let len = self.len();
|
ptr: self.as_ptr().into_abi(extra),
|
||||||
extra.push(len as u32);
|
len: self.len() as u32,
|
||||||
ptr.into_abi(extra)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> IntoWasmAbi for &'a mut [$t] {
|
impl<'a> IntoWasmAbi for &'a mut [$t] {
|
||||||
type Abi = u32;
|
type Abi = WasmSlice;
|
||||||
|
|
||||||
fn into_abi(self, extra: &mut Stack) -> u32 {
|
fn into_abi(self, extra: &mut Stack) -> WasmSlice {
|
||||||
(&*self).into_abi(extra)
|
(&*self).into_abi(extra)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RefFromWasmAbi for [$t] {
|
impl RefFromWasmAbi for [$t] {
|
||||||
type Abi = u32;
|
type Abi = WasmSlice;
|
||||||
type Anchor = &'static [$t];
|
type Anchor = &'static [$t];
|
||||||
|
|
||||||
unsafe fn ref_from_abi(js: u32, extra: &mut Stack) -> &'static [$t] {
|
unsafe fn ref_from_abi(js: WasmSlice, extra: &mut Stack) -> &'static [$t] {
|
||||||
slice::from_raw_parts(
|
slice::from_raw_parts(
|
||||||
<*const $t>::from_abi(js, extra),
|
<*const $t>::from_abi(js.ptr, extra),
|
||||||
extra.pop() as usize,
|
js.len as usize,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RefMutFromWasmAbi for [$t] {
|
impl RefMutFromWasmAbi for [$t] {
|
||||||
type Abi = u32;
|
type Abi = WasmSlice;
|
||||||
type Anchor = &'static mut [$t];
|
type Anchor = &'static mut [$t];
|
||||||
|
|
||||||
unsafe fn ref_mut_from_abi(js: u32, extra: &mut Stack) -> &'static mut [$t] {
|
unsafe fn ref_mut_from_abi(js: WasmSlice, extra: &mut Stack)
|
||||||
|
-> &'static mut [$t]
|
||||||
|
{
|
||||||
slice::from_raw_parts_mut(
|
slice::from_raw_parts_mut(
|
||||||
<*mut $t>::from_abi(js, extra),
|
<*mut $t>::from_abi(js.ptr, extra),
|
||||||
extra.pop() as usize,
|
js.len as usize,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,17 +237,17 @@ if_std! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl IntoWasmAbi for String {
|
impl IntoWasmAbi for String {
|
||||||
type Abi = u32;
|
type Abi = <Vec<u8> as IntoWasmAbi>::Abi;
|
||||||
|
|
||||||
fn into_abi(self, extra: &mut Stack) -> u32 {
|
fn into_abi(self, extra: &mut Stack) -> Self::Abi {
|
||||||
self.into_bytes().into_abi(extra)
|
self.into_bytes().into_abi(extra)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromWasmAbi for String {
|
impl FromWasmAbi for String {
|
||||||
type Abi = u32;
|
type Abi = <Vec<u8> as FromWasmAbi>::Abi;
|
||||||
|
|
||||||
unsafe fn from_abi(js: u32, extra: &mut Stack) -> Self {
|
unsafe fn from_abi(js: Self::Abi, extra: &mut Stack) -> Self {
|
||||||
String::from_utf8_unchecked(<Vec<u8>>::from_abi(js, extra))
|
String::from_utf8_unchecked(<Vec<u8>>::from_abi(js, extra))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -294,23 +306,25 @@ impl RefFromWasmAbi for JsValue {
|
|||||||
|
|
||||||
if_std! {
|
if_std! {
|
||||||
impl IntoWasmAbi for Box<[JsValue]> {
|
impl IntoWasmAbi for Box<[JsValue]> {
|
||||||
type Abi = u32;
|
type Abi = WasmSlice;
|
||||||
|
|
||||||
fn into_abi(self, extra: &mut Stack) -> u32 {
|
fn into_abi(self, extra: &mut Stack) -> WasmSlice {
|
||||||
let ptr = self.as_ptr();
|
let ptr = self.as_ptr();
|
||||||
let len = self.len();
|
let len = self.len();
|
||||||
mem::forget(self);
|
mem::forget(self);
|
||||||
extra.push(len as u32);
|
WasmSlice {
|
||||||
ptr.into_abi(extra)
|
ptr: ptr.into_abi(extra),
|
||||||
|
len: len as u32,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromWasmAbi for Box<[JsValue]> {
|
impl FromWasmAbi for Box<[JsValue]> {
|
||||||
type Abi = u32;
|
type Abi = WasmSlice;
|
||||||
|
|
||||||
unsafe fn from_abi(js: u32, extra: &mut Stack) -> Self {
|
unsafe fn from_abi(js: WasmSlice, extra: &mut Stack) -> Self {
|
||||||
let ptr = <*mut JsValue>::from_abi(js, extra);
|
let ptr = <*mut JsValue>::from_abi(js.ptr, extra);
|
||||||
let len = extra.pop() as usize;
|
let len = js.len as usize;
|
||||||
Vec::from_raw_parts(ptr, len, len).into_boxed_slice()
|
Vec::from_raw_parts(ptr, len, len).into_boxed_slice()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,6 +113,40 @@ fn unused() {
|
|||||||
.test();
|
.test();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn string_ret() {
|
||||||
|
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 foo() -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn run() {
|
||||||
|
assert_eq!(foo(), "bar");
|
||||||
|
}
|
||||||
|
"#)
|
||||||
|
.file("test.ts", r#"
|
||||||
|
import * as wasm from "./out";
|
||||||
|
|
||||||
|
export function foo(): string {
|
||||||
|
return 'bar';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test() {
|
||||||
|
wasm.run();
|
||||||
|
}
|
||||||
|
"#)
|
||||||
|
.test();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn strings() {
|
fn strings() {
|
||||||
project()
|
project()
|
||||||
|
Loading…
Reference in New Issue
Block a user