Work with #![no_std] contexts

This commit adds support for both `#![no_std]` in the wasm-bindgen runtime
support (disabled by default with an on-by-default `std` feature). This also
adds support to work and compile in the context of `#![no_std]` crates.

Closes #146
This commit is contained in:
Alex Crichton 2018-04-19 13:08:54 -07:00
parent 792a8e132e
commit 748184ae66
11 changed files with 318 additions and 127 deletions

View File

@ -16,6 +16,10 @@ Easy support for interacting between JS and Rust.
test = false test = false
doctest = false doctest = false
[features]
default = ["std"]
std = []
[dependencies] [dependencies]
wasm-bindgen-macro = { path = "crates/macro", version = "=0.2.4" } wasm-bindgen-macro = { path = "crates/macro", version = "=0.2.4" }

View File

@ -116,13 +116,22 @@ impl ToTokens for ast::Struct {
} }
} }
::wasm_bindgen::__wbindgen_if_not_std! {
compile_error! {
"exporting a class to JS requires the `std` feature to \
be enabled in the `wasm-bindgen` crate"
}
}
impl ::wasm_bindgen::convert::IntoWasmAbi for #name { impl ::wasm_bindgen::convert::IntoWasmAbi for #name {
type Abi = u32; type Abi = u32;
fn into_abi(self, _extra: &mut ::wasm_bindgen::convert::Stack) fn into_abi(self, _extra: &mut ::wasm_bindgen::convert::Stack)
-> u32 -> u32
{ {
Box::into_raw(Box::new(::wasm_bindgen::__rt::WasmRefCell::new(self))) as u32 use wasm_bindgen::__rt::std::boxed::Box;
use wasm_bindgen::__rt::WasmRefCell;
Box::into_raw(Box::new(WasmRefCell::new(self))) as u32
} }
} }
@ -132,14 +141,49 @@ impl ToTokens for ast::Struct {
unsafe fn from_abi(js: u32, _extra: &mut ::wasm_bindgen::convert::Stack) unsafe fn from_abi(js: u32, _extra: &mut ::wasm_bindgen::convert::Stack)
-> Self -> Self
{ {
let ptr = js as *mut ::wasm_bindgen::__rt::WasmRefCell<#name>; use wasm_bindgen::__rt::std::boxed::Box;
::wasm_bindgen::__rt::assert_not_null(ptr); use wasm_bindgen::__rt::{assert_not_null, WasmRefCell};
let ptr = js as *mut WasmRefCell<#name>;
assert_not_null(ptr);
let js = Box::from_raw(ptr); let js = Box::from_raw(ptr);
js.borrow_mut(); // make sure no one's borrowing js.borrow_mut(); // make sure no one's borrowing
js.into_inner() js.into_inner()
} }
} }
impl ::wasm_bindgen::__rt::core::convert::From<#name> for
::wasm_bindgen::JsValue
{
fn from(value: #name) -> Self {
let ptr = ::wasm_bindgen::convert::IntoWasmAbi::into_abi(
value,
unsafe { &mut ::wasm_bindgen::convert::GlobalStack::new() },
);
#[wasm_import_module = "__wbindgen_placeholder__"]
extern {
fn #new_fn(ptr: u32) -> u32;
}
unsafe {
<::wasm_bindgen::JsValue as ::wasm_bindgen::convert::FromWasmAbi>
::from_abi(
#new_fn(ptr),
&mut ::wasm_bindgen::convert::GlobalStack::new(),
)
}
}
}
#[no_mangle]
pub unsafe extern fn #free_fn(ptr: u32) {
<#name as ::wasm_bindgen::convert::FromWasmAbi>::from_abi(
ptr,
&mut ::wasm_bindgen::convert::GlobalStack::new(),
);
}
impl ::wasm_bindgen::convert::RefFromWasmAbi for #name { impl ::wasm_bindgen::convert::RefFromWasmAbi for #name {
type Abi = u32; type Abi = u32;
type Anchor = ::wasm_bindgen::__rt::Ref<'static, #name>; type Anchor = ::wasm_bindgen::__rt::Ref<'static, #name>;
@ -167,36 +211,6 @@ impl ToTokens for ast::Struct {
(*js).borrow_mut() (*js).borrow_mut()
} }
} }
impl ::std::convert::From<#name> for ::wasm_bindgen::JsValue {
fn from(value: #name) -> Self {
let ptr = ::wasm_bindgen::convert::IntoWasmAbi::into_abi(
value,
unsafe { &mut ::wasm_bindgen::convert::GlobalStack::new() },
);
#[wasm_import_module = "__wbindgen_placeholder__"]
extern {
fn #new_fn(ptr: u32) -> u32;
}
unsafe {
<::wasm_bindgen::JsValue as ::wasm_bindgen::convert::FromWasmAbi>
::from_abi(
#new_fn(ptr),
&mut ::wasm_bindgen::convert::GlobalStack::new(),
)
}
}
}
#[no_mangle]
pub unsafe extern fn #free_fn(ptr: u32) {
<#name as ::wasm_bindgen::convert::FromWasmAbi>::from_abi(
ptr,
&mut ::wasm_bindgen::convert::GlobalStack::new(),
);
}
}).to_tokens(tokens); }).to_tokens(tokens);
} }
} }
@ -419,7 +433,7 @@ impl ToTokens for ast::ImportType {
impl ::wasm_bindgen::convert::RefFromWasmAbi for #name { impl ::wasm_bindgen::convert::RefFromWasmAbi for #name {
type Abi = <::wasm_bindgen::JsValue as type Abi = <::wasm_bindgen::JsValue as
::wasm_bindgen::convert::RefFromWasmAbi>::Abi; ::wasm_bindgen::convert::RefFromWasmAbi>::Abi;
type Anchor = ::std::mem::ManuallyDrop<#name>; type Anchor = ::wasm_bindgen::__rt::core::mem::ManuallyDrop<#name>;
unsafe fn ref_from_abi( unsafe fn ref_from_abi(
js: Self::Abi, js: Self::Abi,
@ -427,8 +441,8 @@ impl ToTokens for ast::ImportType {
) -> Self::Anchor { ) -> Self::Anchor {
let tmp = <::wasm_bindgen::JsValue as ::wasm_bindgen::convert::RefFromWasmAbi> let tmp = <::wasm_bindgen::JsValue as ::wasm_bindgen::convert::RefFromWasmAbi>
::ref_from_abi(js, extra); ::ref_from_abi(js, extra);
::std::mem::ManuallyDrop::new(#name { ::wasm_bindgen::__rt::core::mem::ManuallyDrop::new(#name {
obj: ::std::mem::ManuallyDrop::into_inner(tmp), obj: ::wasm_bindgen::__rt::core::mem::ManuallyDrop::into_inner(tmp),
}) })
} }
} }
@ -702,7 +716,7 @@ impl ToTokens for ast::ImportStatic {
} }
} }
::wasm_bindgen::JsStatic { ::wasm_bindgen::JsStatic {
__inner: ::std::cell::UnsafeCell::new(None), __inner: ::wasm_bindgen::__rt::core::cell::UnsafeCell::new(None),
__init: init, __init: init,
} }
}; };

View File

@ -119,9 +119,7 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
self.finally(&format!("\ self.finally(&format!("\
wasm.__wbindgen_free(ptr{i}, len{i} * {size});\n\ wasm.__wbindgen_free(ptr{i}, len{i} * {size});\n\
", i = i, size = kind.size())); ", i = i, size = kind.size()));
self.cx.required_internal_exports.insert( self.cx.require_internal_export("__wbindgen_free");
"__wbindgen_free",
);
} }
self.rust_arguments.push(format!("ptr{}", i)); self.rust_arguments.push(format!("ptr{}", i));
return return
@ -216,7 +214,7 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
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_get_global_argument();
self.cx.required_internal_exports.insert("__wbindgen_free"); self.cx.require_internal_export("__wbindgen_free");
self.ret_expr = format!("\ self.ret_expr = format!("\
const ret = RET;\n\ const ret = RET;\n\
const len = getGlobalArgument(0);\n\ const len = getGlobalArgument(0);\n\

View File

@ -62,6 +62,22 @@ impl<'a> Context<'a> {
self.global(&global); self.global(&global);
} }
fn require_internal_export(&mut self, name: &'static str) {
if !self.required_internal_exports.insert(name) {
return
}
if let Some(s) = self.module.export_section() {
if s.entries().iter().any(|e| e.field() == name) {
return
}
}
panic!("\n\nthe exported function `{}` is required to generate bindings \
but it was not found in the wasm file, perhaps the `std` feature \
of the `wasm-bindgen` crate needs to be enabled?\n\n",
name);
}
pub fn finalize(&mut self, module_name: &str) -> (String, String) { pub fn finalize(&mut self, module_name: &str) -> (String, String) {
self.unexport_unused_internal_exports(); self.unexport_unused_internal_exports();
self.gc(); self.gc();
@ -642,7 +658,7 @@ impl<'a> Context<'a> {
if !self.exposed_globals.insert("pass_string_to_wasm") { if !self.exposed_globals.insert("pass_string_to_wasm") {
return; return;
} }
self.required_internal_exports.insert("__wbindgen_malloc"); self.require_internal_export("__wbindgen_malloc");
self.expose_text_encoder(); self.expose_text_encoder();
self.expose_uint8_memory(); self.expose_uint8_memory();
let debug = if self.config.debug { let debug = if self.config.debug {
@ -668,7 +684,7 @@ impl<'a> Context<'a> {
if !self.exposed_globals.insert("pass_array8_to_wasm") { if !self.exposed_globals.insert("pass_array8_to_wasm") {
return; return;
} }
self.required_internal_exports.insert("__wbindgen_malloc"); self.require_internal_export("__wbindgen_malloc");
self.expose_uint8_memory(); self.expose_uint8_memory();
self.global(&format!(" self.global(&format!("
function passArray8ToWasm(arg) {{ function passArray8ToWasm(arg) {{
@ -683,7 +699,7 @@ impl<'a> Context<'a> {
if !self.exposed_globals.insert("pass_array16_to_wasm") { if !self.exposed_globals.insert("pass_array16_to_wasm") {
return; return;
} }
self.required_internal_exports.insert("__wbindgen_malloc"); self.require_internal_export("__wbindgen_malloc");
self.expose_uint16_memory(); self.expose_uint16_memory();
self.global(&format!(" self.global(&format!("
function passArray16ToWasm(arg) {{ function passArray16ToWasm(arg) {{
@ -698,7 +714,7 @@ impl<'a> Context<'a> {
if !self.exposed_globals.insert("pass_array32_to_wasm") { if !self.exposed_globals.insert("pass_array32_to_wasm") {
return; return;
} }
self.required_internal_exports.insert("__wbindgen_malloc"); self.require_internal_export("__wbindgen_malloc");
self.expose_uint32_memory(); self.expose_uint32_memory();
self.global(&format!(" self.global(&format!("
function passArray32ToWasm(arg) {{ function passArray32ToWasm(arg) {{
@ -713,7 +729,7 @@ impl<'a> Context<'a> {
if !self.exposed_globals.insert("pass_array_f32_to_wasm") { if !self.exposed_globals.insert("pass_array_f32_to_wasm") {
return; return;
} }
self.required_internal_exports.insert("__wbindgen_malloc"); self.require_internal_export("__wbindgen_malloc");
self.global(&format!(" self.global(&format!("
function passArrayF32ToWasm(arg) {{ function passArrayF32ToWasm(arg) {{
const ptr = wasm.__wbindgen_malloc(arg.length * 4); const ptr = wasm.__wbindgen_malloc(arg.length * 4);
@ -727,7 +743,7 @@ impl<'a> Context<'a> {
if !self.exposed_globals.insert("pass_array_f64_to_wasm") { if !self.exposed_globals.insert("pass_array_f64_to_wasm") {
return; return;
} }
self.required_internal_exports.insert("__wbindgen_malloc"); self.require_internal_export("__wbindgen_malloc");
self.global(&format!(" self.global(&format!("
function passArrayF64ToWasm(arg) {{ function passArrayF64ToWasm(arg) {{
const ptr = wasm.__wbindgen_malloc(arg.length * 8); const ptr = wasm.__wbindgen_malloc(arg.length * 8);
@ -1172,7 +1188,7 @@ impl<'a> Context<'a> {
if !self.exposed_globals.insert("global_argument_ptr") { if !self.exposed_globals.insert("global_argument_ptr") {
return; return;
} }
self.required_internal_exports.insert("__wbindgen_global_argument_ptr"); self.require_internal_export("__wbindgen_global_argument_ptr");
self.global(" self.global("
let cachedGlobalArgumentPtr = null; let cachedGlobalArgumentPtr = null;
function globalArgumentPtr() { function globalArgumentPtr() {

View File

@ -91,9 +91,7 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
self.prelude(&format!("\ self.prelude(&format!("\
wasm.__wbindgen_free(arg{0}, len{0} * {size});\ wasm.__wbindgen_free(arg{0}, len{0} * {size});\
", i, size = ty.size())); ", i, size = ty.size()));
self.cx.required_internal_exports.insert( self.cx.require_internal_export("__wbindgen_free");
"__wbindgen_free"
);
} }
self.js_arguments.push(format!("v{}", i)); self.js_arguments.push(format!("v{}", i));
return return

View File

@ -7,6 +7,7 @@
use std::cell::UnsafeCell; use std::cell::UnsafeCell;
use std::marker::Unsize; use std::marker::Unsize;
use std::mem::{self, ManuallyDrop}; use std::mem::{self, ManuallyDrop};
use std::prelude::v1::*;
use JsValue; use JsValue;
use convert::*; use convert::*;

View File

@ -1,14 +1,17 @@
//! This is mostly an internal module, no stability guarantees are provied. Use //! This is mostly an internal module, no stability guarantees are provied. Use
//! at your own risk. //! at your own risk.
use std::mem::{self, ManuallyDrop}; use core::mem::{self, ManuallyDrop};
use std::ops::{Deref, DerefMut}; use core::ops::{Deref, DerefMut};
use std::slice; use core::slice;
use std::str; use core::str;
use {JsValue, throw}; use {JsValue, throw};
use describe::*; use describe::*;
#[cfg(feature = "std")]
use std::prelude::v1::*;
#[derive(PartialEq, Eq, Copy, Clone)] #[derive(PartialEq, Eq, Copy, Clone)]
pub struct Descriptor { pub struct Descriptor {
#[doc(hidden)] #[doc(hidden)]
@ -132,6 +135,7 @@ impl<T> FromWasmAbi for *mut T {
macro_rules! vectors { macro_rules! vectors {
($($t:ident)*) => ($( ($($t:ident)*) => ($(
#[cfg(feature = "std")]
impl IntoWasmAbi for Box<[$t]> { impl IntoWasmAbi for Box<[$t]> {
type Abi = u32; type Abi = u32;
@ -144,6 +148,7 @@ macro_rules! vectors {
} }
} }
#[cfg(feature = "std")]
impl FromWasmAbi for Box<[$t]> { impl FromWasmAbi for Box<[$t]> {
type Abi = u32; type Abi = u32;
@ -183,6 +188,7 @@ vectors! {
u8 i8 u16 i16 u32 i32 f32 f64 u8 i8 u16 i16 u32 i32 f32 f64
} }
if_std! {
impl<T> IntoWasmAbi for Vec<T> where Box<[T]>: IntoWasmAbi { impl<T> IntoWasmAbi for Vec<T> where Box<[T]>: IntoWasmAbi {
type Abi = <Box<[T]> as IntoWasmAbi>::Abi; type Abi = <Box<[T]> as IntoWasmAbi>::Abi;
fn into_abi(self, extra: &mut Stack) -> Self::Abi { fn into_abi(self, extra: &mut Stack) -> Self::Abi {
@ -213,6 +219,7 @@ impl FromWasmAbi for String {
String::from_utf8_unchecked(<Vec<u8>>::from_abi(js, extra)) String::from_utf8_unchecked(<Vec<u8>>::from_abi(js, extra))
} }
} }
}
impl<'a> IntoWasmAbi for &'a str { impl<'a> IntoWasmAbi for &'a str {
type Abi = <&'a [u8] as IntoWasmAbi>::Abi; type Abi = <&'a [u8] as IntoWasmAbi>::Abi;
@ -265,6 +272,7 @@ impl RefFromWasmAbi for JsValue {
} }
} }
if_std! {
impl IntoWasmAbi for Box<[JsValue]> { impl IntoWasmAbi for Box<[JsValue]> {
type Abi = u32; type Abi = u32;
@ -286,6 +294,7 @@ impl FromWasmAbi for Box<[JsValue]> {
Vec::from_raw_parts(ptr, len, len).into_boxed_slice() Vec::from_raw_parts(ptr, len, len).into_boxed_slice()
} }
} }
}
pub struct GlobalStack { next: usize } pub struct GlobalStack { next: usize }

View File

@ -72,7 +72,6 @@ simple! {
f64 => F64 f64 => F64
bool => BOOLEAN bool => BOOLEAN
str => STRING str => STRING
String => STRING
JsValue => ANYREF JsValue => ANYREF
} }
@ -105,6 +104,13 @@ impl<'a, T: WasmDescribe + ?Sized> WasmDescribe for &'a mut T {
} }
} }
if_std! {
use std::prelude::v1::*;
impl WasmDescribe for String {
fn describe() { inform(STRING) }
}
impl<T: WasmDescribe> WasmDescribe for Box<[T]> { impl<T: WasmDescribe> WasmDescribe for Box<[T]> {
fn describe() { fn describe() {
inform(VECTOR); inform(VECTOR);
@ -117,6 +123,7 @@ impl<T> WasmDescribe for Vec<T> where Box<[T]>: WasmDescribe {
<Box<[T]>>::describe(); <Box<[T]>>::describe();
} }
} }
}
fn _cnt<T: WasmDescribe>() -> u32 { 1 } fn _cnt<T: WasmDescribe>() -> u32 { 1 }

View File

@ -6,15 +6,22 @@
//! interface. //! interface.
#![feature(use_extern_macros, wasm_import_module, try_reserve, unsize)] #![feature(use_extern_macros, wasm_import_module, try_reserve, unsize)]
#![no_std]
extern crate wasm_bindgen_macro; extern crate wasm_bindgen_macro;
use std::cell::UnsafeCell; use core::cell::UnsafeCell;
use std::ops::Deref; use core::ops::Deref;
use std::ptr; use core::ptr;
use convert::FromWasmAbi; use convert::FromWasmAbi;
macro_rules! if_std {
($($i:item)*) => ($(
#[cfg(feature = "std")] $i
)*)
}
/// A module which is typically glob imported from: /// A module which is typically glob imported from:
/// ///
/// ``` /// ```
@ -23,13 +30,21 @@ use convert::FromWasmAbi;
pub mod prelude { pub mod prelude {
pub use wasm_bindgen_macro::wasm_bindgen; pub use wasm_bindgen_macro::wasm_bindgen;
pub use JsValue; pub use JsValue;
if_std! {
pub use closure::Closure; pub use closure::Closure;
} }
}
pub mod convert; pub mod convert;
pub mod closure;
pub mod describe; pub mod describe;
if_std! {
extern crate std;
use std::prelude::v1::*;
pub mod closure;
}
/// Representation of an object owned by JS. /// Representation of an object owned by JS.
/// ///
/// A `JsValue` doesn't actually live in Rust right now but actually in a table /// A `JsValue` doesn't actually live in Rust right now but actually in a table
@ -136,6 +151,7 @@ impl JsValue {
/// ///
/// If this JS value is not an instance of a string or if it's not valid /// If this JS value is not an instance of a string or if it's not valid
/// utf-8 then this returns `None`. /// utf-8 then this returns `None`.
#[cfg(feature = "std")]
pub fn as_string(&self) -> Option<String> { pub fn as_string(&self) -> Option<String> {
unsafe { unsafe {
let mut len = 0; let mut len = 0;
@ -192,11 +208,13 @@ impl<'a> From<&'a str> for JsValue {
} }
} }
if_std! {
impl<'a> From<&'a String> for JsValue { impl<'a> From<&'a String> for JsValue {
fn from(s: &'a String) -> JsValue { fn from(s: &'a String) -> JsValue {
JsValue::from_str(s) JsValue::from_str(s)
} }
} }
}
impl From<bool> for JsValue { impl From<bool> for JsValue {
fn from(s: bool) -> JsValue { fn from(s: bool) -> JsValue {
@ -321,9 +339,23 @@ pub fn throw(s: &str) -> ! {
#[doc(hidden)] #[doc(hidden)]
pub mod __rt { pub mod __rt {
use std::cell::{Cell, UnsafeCell}; use core::cell::{Cell, UnsafeCell};
use std::mem; use core::ops::{Deref, DerefMut};
use std::ops::{Deref, DerefMut}; pub extern crate core;
#[cfg(feature = "std")]
pub extern crate std;
#[macro_export]
#[cfg(feature = "std")]
macro_rules! __wbindgen_if_not_std {
($($i:item)*) => ()
}
#[macro_export]
#[cfg(not(feature = "std"))]
macro_rules! __wbindgen_if_not_std {
($($i:item)*) => ($($i)*)
}
#[inline] #[inline]
pub fn assert_not_null<T>(s: *mut T) { pub fn assert_not_null<T>(s: *mut T) {
@ -457,8 +489,13 @@ pub mod __rt {
unsafe aliasing in rust"); unsafe aliasing in rust");
} }
if_std! {
use std::prelude::v1::*;
#[no_mangle] #[no_mangle]
pub extern fn __wbindgen_malloc(size: usize) -> *mut u8 { pub extern fn __wbindgen_malloc(size: usize) -> *mut u8 {
use core::mem;
let mut ret = Vec::new(); let mut ret = Vec::new();
if ret.try_reserve_exact(size).is_err() { if ret.try_reserve_exact(size).is_err() {
super::throw("invalid malloc request"); super::throw("invalid malloc request");
@ -472,6 +509,7 @@ pub mod __rt {
pub unsafe extern fn __wbindgen_free(ptr: *mut u8, size: usize) { pub unsafe extern fn __wbindgen_free(ptr: *mut u8, size: usize) {
drop(Vec::<u8>::from_raw_parts(ptr, 0, size)); drop(Vec::<u8>::from_raw_parts(ptr, 0, size));
} }
}
pub fn link_this_library() {} pub fn link_this_library() {}
} }

View File

@ -15,6 +15,7 @@ struct Project {
files: Vec<(String, String)>, files: Vec<(String, String)>,
debug: bool, debug: bool,
node: bool, node: bool,
no_std: bool,
} }
fn project() -> Project { fn project() -> Project {
@ -25,6 +26,7 @@ fn project() -> Project {
Project { Project {
debug: true, debug: true,
node: false, node: false,
no_std: false,
files: vec![ files: vec![
("Cargo.toml".to_string(), format!(r#" ("Cargo.toml".to_string(), format!(r#"
[package] [package]
@ -40,8 +42,7 @@ fn project() -> Project {
# XXX: It is important that `[dependencies]` is the last section # XXX: It is important that `[dependencies]` is the last section
# here, so that `add_local_dependency` functions correctly! # here, so that `add_local_dependency` functions correctly!
[dependencies] [dependencies]
wasm-bindgen = {{ path = '{}' }} "#, IDX.with(|x| *x))),
"#, IDX.with(|x| *x), dir.display())),
("Cargo.lock".to_string(), lockfile), ("Cargo.lock".to_string(), lockfile),
@ -138,6 +139,11 @@ impl Project {
self self
} }
fn no_std(&mut self, no_std: bool) -> &mut Project {
self.no_std = no_std;
self
}
fn add_local_dependency(&mut self, name: &str, path: &str) -> &mut Project { fn add_local_dependency(&mut self, name: &str, path: &str) -> &mut Project {
{ {
let cargo_toml = self.files let cargo_toml = self.files
@ -145,14 +151,28 @@ impl Project {
.find(|f| f.0 == "Cargo.toml") .find(|f| f.0 == "Cargo.toml")
.expect("should have Cargo.toml file!"); .expect("should have Cargo.toml file!");
cargo_toml.1.push_str(name); cargo_toml.1.push_str(name);
cargo_toml.1.push_str(" = { path = \""); cargo_toml.1.push_str(" = { path = '");
cargo_toml.1.push_str(path); cargo_toml.1.push_str(path);
cargo_toml.1.push_str("\" }"); cargo_toml.1.push_str("' }\n");
} }
self self
} }
fn test(&mut self) { fn test(&mut self) {
{
let cargo_toml = self.files
.iter_mut()
.find(|f| f.0 == "Cargo.toml")
.expect("should have Cargo.toml file!");
cargo_toml.1.push_str("wasm-bindgen = { path = '");
cargo_toml.1.push_str(env!("CARGO_MANIFEST_DIR"));
if self.no_std {
cargo_toml.1.push_str("', default-features = false");
} else {
cargo_toml.1.push_str("'");
}
cargo_toml.1.push_str(" }\n");
}
let root = root(); let root = root();
drop(fs::remove_dir_all(&root)); drop(fs::remove_dir_all(&root));
for &(ref file, ref contents) in self.files.iter() { for &(ref file, ref contents) in self.files.iter() {

View File

@ -201,3 +201,89 @@ fn other_exports() {
"#) "#)
.test(); .test();
} }
#[test]
fn no_std() {
project()
.no_std(true)
.file("src/lib.rs", r#"
#![feature(proc_macro, wasm_custom_section, wasm_import_module)]
#![no_std]
#![allow(dead_code)]
extern crate wasm_bindgen;
extern crate std as _some_other_name;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern {
fn test(a: &str);
type Js;
#[wasm_bindgen(constructor)]
fn new() -> Js;
#[wasm_bindgen(method)]
fn init(this: &Js);
}
#[wasm_bindgen]
pub fn foo(_a: u32) {}
"#)
.file("test.ts", r#"
import * as wasm from "./out_bg";
export function test() {
// mostly just testing the project compiles here
wasm.foo(1);
}
"#)
.test();
}
#[test]
fn no_std_class() {
project()
.file("src/lib.rs", r#"
#![feature(proc_macro, wasm_custom_section, wasm_import_module)]
#![no_std]
#![allow(dead_code)]
extern crate wasm_bindgen;
extern crate std as _some_other_name;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern {
fn test(a: &str);
type Js;
#[wasm_bindgen(constructor)]
fn new() -> Js;
#[wasm_bindgen(method, structural)]
fn init(this: &Js);
}
#[wasm_bindgen]
pub fn foo(_a: u32) {}
#[wasm_bindgen]
pub struct A {}
#[wasm_bindgen]
impl A {
pub fn foo(&self) {}
pub fn bar(&mut self) {}
}
"#)
.file("test.ts", r#"
import * as wasm from "./out_bg";
export function test() {
// mostly just testing the project compiles here
wasm.foo(1);
}
"#)
.test();
}