Merge remote-tracking branch 'origin/master' into webidl_partial_mixins

This commit is contained in:
R. Andrew Ohana 2018-07-13 21:55:46 -07:00
commit 0c908bb951
24 changed files with 733 additions and 41 deletions

View File

@ -42,6 +42,7 @@ pub enum ImportKind {
Static(ImportStatic),
Type(ImportType),
Enum(ImportEnum),
Const(Const),
}
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
@ -174,6 +175,24 @@ pub struct TypeAlias {
pub src: syn::Type,
}
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
pub struct Const {
pub vis: syn::Visibility,
pub name: Ident,
pub interface_name: Ident,
pub ty: syn::Type,
pub value: ConstValue,
}
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
/// same as webidl::ast::ConstValue
pub enum ConstValue {
BooleanLiteral(bool),
FloatLiteral(f64),
IntegerLiteral(i64),
Null,
}
impl Program {
pub(crate) fn shared(&self) -> shared::Program {
shared::Program {
@ -293,6 +312,7 @@ impl ImportKind {
ImportKind::Static(_) => false,
ImportKind::Type(_) => false,
ImportKind::Enum(_) => false,
ImportKind::Const(_) => false,
}
}
@ -302,6 +322,7 @@ impl ImportKind {
ImportKind::Static(ref f) => shared::ImportKind::Static(f.shared()),
ImportKind::Type(ref f) => shared::ImportKind::Type(f.shared()),
ImportKind::Enum(ref f) => shared::ImportKind::Enum(f.shared()),
ImportKind::Const(ref f) => shared::ImportKind::Const(f.shared()),
}
}
}
@ -404,3 +425,9 @@ impl StructField {
}
}
}
impl Const {
fn shared(&self) -> shared::Const {
shared::Const {}
}
}

View File

@ -501,6 +501,7 @@ impl ToTokens for ast::ImportKind {
ast::ImportKind::Static(ref s) => s.to_tokens(tokens),
ast::ImportKind::Type(ref t) => t.to_tokens(tokens),
ast::ImportKind::Enum(ref e) => e.to_tokens(tokens),
ast::ImportKind::Const(ref c) => c.to_tokens(tokens),
}
}
}
@ -842,6 +843,7 @@ impl<'a> ToTokens for DescribeImport<'a> {
ast::ImportKind::Static(_) => return,
ast::ImportKind::Type(_) => return,
ast::ImportKind::Enum(_) => return,
ast::ImportKind::Const(_) => return,
};
let describe_name = format!("__wbindgen_describe_{}", f.shim);
let describe_name = Ident::new(&describe_name, Span::call_site());
@ -958,3 +960,41 @@ impl ToTokens for ast::TypeAlias {
}).to_tokens(into);
}
}
impl ToTokens for ast::Const {
fn to_tokens(&self, tokens: &mut TokenStream) {
use ast::ConstValue::*;
let vis = &self.vis;
let name = &self.name;
let interface_name = &self.interface_name;
let ty = &self.ty;
let value: TokenStream = match self.value {
BooleanLiteral(false) => quote!(false),
BooleanLiteral(true) => quote!(true),
// the actual type is unknown because of typedefs
// so we cannot use std::fxx::INFINITY
// but we can use type inference
FloatLiteral(f) if f.is_infinite() && f.is_sign_positive() => quote!(1.0 / 0.0),
FloatLiteral(f) if f.is_infinite() && f.is_sign_negative() => quote!(-1.0 / 0.0),
FloatLiteral(f) if f.is_nan() => quote!(0.0 / 0.0),
// again no suffix
// panics on +-inf, nan
FloatLiteral(f) => {
let f = Literal::f64_unsuffixed(f);
quote!(#f)
},
IntegerLiteral(i) => {
let i = Literal::i64_unsuffixed(i);
quote!(#i)
},
Null => unimplemented!(),
};
(quote! {
impl #interface_name {
#vis const #name: #ty = #value;
}
}).to_tokens(tokens);
}
}

View File

@ -106,6 +106,7 @@ impl ImportedTypes for ast::ImportKind {
ast::ImportKind::Function(fun) => fun.imported_types(f),
ast::ImportKind::Type(ty) => ty.imported_types(f),
ast::ImportKind::Enum(enm) => enm.imported_types(f),
ast::ImportKind::Const(c) => c.imported_types(f),
}
}
}
@ -229,6 +230,15 @@ impl ImportedTypes for ast::TypeAlias {
}
}
impl ImportedTypes for ast::Const {
fn imported_types<F>(&self, f: &mut F)
where
F: FnMut(&Ident, ImportedTypeKind),
{
self.ty.imported_types(f);
}
}
/// Remove any methods, statics, &c, that reference types that are *not*
/// defined.
pub trait RemoveUndefinedImports {

View File

@ -19,5 +19,5 @@ serde_derive = "1.0"
serde_json = "1.0"
tempfile = "3.0"
wasm-bindgen-shared = { path = "../shared", version = '=0.2.11' }
wasm-gc-api = "0.1"
wasm-gc-api = "0.1.8"
wasmi = "0.3"

View File

@ -1580,6 +1580,7 @@ impl<'a> Context<'a> {
let wasm_bytes = parity_wasm::serialize(module)?;
let bytes = wasm_gc::Config::new()
.demangle(self.config.demangle)
.keep_debug(self.config.keep_debug || self.config.debug)
.gc(&wasm_bytes)?;
*self.module = deserialize_buffer(&bytes)?;
Ok(())
@ -1757,6 +1758,7 @@ impl<'a, 'b> SubContext<'a, 'b> {
}
shared::ImportKind::Type(_) => {}
shared::ImportKind::Enum(_) => {}
shared::ImportKind::Const(_) => {}
}
Ok(())
}

View File

@ -31,6 +31,7 @@ pub struct Bindgen {
debug: bool,
typescript: bool,
demangle: bool,
keep_debug: bool,
}
impl Bindgen {
@ -45,6 +46,7 @@ impl Bindgen {
debug: false,
typescript: false,
demangle: true,
keep_debug: false,
}
}
@ -93,6 +95,11 @@ impl Bindgen {
self
}
pub fn keep_debug(&mut self, keep_debug: bool) -> &mut Bindgen {
self.keep_debug = keep_debug;
self
}
pub fn generate<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Error> {
self._generate(path.as_ref())
}

View File

@ -32,6 +32,7 @@ Options:
--no-typescript Don't emit a *.d.ts file
--debug Include otherwise-extraneous debug checks in output
--no-demangle Don't demangle Rust symbol names
--keep-debug Keep debug sections in wasm files
-V --version Print the version number of wasm-bindgen
";
@ -47,6 +48,7 @@ struct Args {
flag_version: bool,
flag_no_demangle: bool,
flag_no_modules_global: Option<String>,
flag_keep_debug: bool,
arg_input: Option<PathBuf>,
}
@ -85,6 +87,7 @@ fn rmain(args: &Args) -> Result<(), Error> {
.no_modules(args.flag_no_modules)
.debug(args.flag_debug)
.demangle(!args.flag_no_demangle)
.keep_debug(args.flag_keep_debug)
.typescript(typescript);
if let Some(ref name) = args.flag_no_modules_global {
b.no_modules_global(name);

View File

@ -34,6 +34,7 @@ pub enum ImportKind {
Static(ImportStatic),
Type(ImportType),
Enum(ImportEnum),
Const(Const)
}
#[derive(Deserialize, Serialize)]
@ -124,6 +125,9 @@ pub struct StructField {
pub comments: Vec<String>,
}
#[derive(Deserialize, Serialize)]
pub struct Const {}
pub fn new_function(struct_name: &str) -> String {
let mut name = format!("__wbg_");
name.extend(struct_name.chars().flat_map(|s| s.to_lowercase()));

View File

@ -0,0 +1,33 @@
use super::websys_project;
#[test]
fn headers() {
websys_project()
.file(
"src/lib.rs",
r#"
#![feature(proc_macro, wasm_custom_section)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
extern crate web_sys;
#[wasm_bindgen]
pub fn test_headers(_headers: &web_sys::Headers) {
// empty for now...
}
"#,
)
.file(
"test.js",
r#"
import * as assert from "assert";
import * as wasm from "./out";
export function test() {
let headers = new Headers({'Content-Type': 'text/plain'});
wasm.test_headers(headers);
}
"#,
)
.test();
}

View File

@ -2,6 +2,7 @@ extern crate wasm_bindgen_test_project_builder as project_builder;
use project_builder::{project, Project};
mod event;
mod headers;
mod response;
fn websys_project() -> Project {

View File

@ -30,11 +30,11 @@ use std::path::Path;
use backend::defined::{ImportedTypeDefinitions, RemoveUndefinedImports};
use backend::util::{ident_ty, rust_ident, wrap_import_function};
use failure::ResultExt;
use heck::CamelCase;
use heck::{CamelCase, ShoutySnakeCase};
use quote::ToTokens;
use first_pass::{FirstPass, FirstPassRecord};
use util::{public, TypePosition};
use util::{public, webidl_const_ty_to_syn_ty, webidl_const_v_to_backend_const_v, TypePosition};
/// Either `Ok(t)` or `Err(failure::Error)`.
pub type Result<T> = ::std::result::Result<T, failure::Error>;
@ -250,7 +250,7 @@ impl WebidlParse<()> for webidl::ast::NonPartialInterface {
js_namespace: None,
kind: backend::ast::ImportKind::Type(backend::ast::ImportType {
vis: public(),
name: rust_ident(&self.name),
name: rust_ident(self.name.to_camel_case().as_str()),
attrs: Vec::new(),
}),
});
@ -343,7 +343,8 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte
match self {
webidl::ast::ExtendedAttribute::ArgumentList(
webidl::ast::ArgumentListExtendedAttribute { arguments, name },
) if name == "Constructor" =>
)
if name == "Constructor" =>
{
add_constructor(arguments, &interface.name)
}
@ -358,7 +359,8 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte
rhs_arguments,
rhs_name,
},
) if lhs_name == "NamedConstructor" =>
)
if lhs_name == "NamedConstructor" =>
{
add_constructor(rhs_arguments, rhs_name)
}
@ -389,9 +391,11 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::InterfaceMember {
webidl::ast::InterfaceMember::Operation(op) => {
op.webidl_parse(program, first_pass, self_name)
}
webidl::ast::InterfaceMember::Const(cnst) => {
cnst.webidl_parse(program, first_pass, self_name)
}
// TODO
webidl::ast::InterfaceMember::Const(_)
| webidl::ast::InterfaceMember::Iterable(_)
webidl::ast::InterfaceMember::Iterable(_)
| webidl::ast::InterfaceMember::Maplike(_)
| webidl::ast::InterfaceMember::Setlike(_) => {
warn!("Unsupported WebIDL interface member: {:?}", self);
@ -637,3 +641,29 @@ impl<'a> WebidlParse<()> for webidl::ast::Enum {
Ok(())
}
}
impl<'a> WebidlParse<&'a str> for webidl::ast::Const {
fn webidl_parse(
&self,
program: &mut backend::ast::Program,
_: &FirstPassRecord<'_>,
interface_name: &'a str,
) -> Result<()> {
let syn_ty = webidl_const_ty_to_syn_ty(&self.type_);
program.imports.push(backend::ast::Import {
module: None,
version: None,
js_namespace: None,
kind: backend::ast::ImportKind::Const(backend::ast::Const {
vis: syn::Visibility::Public(syn::VisPublic {
pub_token: Default::default(),
}),
name: rust_ident(self.name.to_shouty_snake_case().as_str()),
interface_name: rust_ident(interface_name.to_camel_case().as_str()),
ty: syn_ty,
value: webidl_const_v_to_backend_const_v(&self.value),
}),
});
Ok(())
}
}

View File

@ -19,6 +19,35 @@ fn shared_ref(ty: syn::Type) -> syn::Type {
}.into()
}
pub fn webidl_const_ty_to_syn_ty(ty: &webidl::ast::ConstType) -> syn::Type {
use webidl::ast::ConstType::*;
// similar to webidl_ty_to_syn_ty
match ty {
Boolean => ident_ty(raw_ident("bool")),
Byte => ident_ty(raw_ident("i8")),
Octet => ident_ty(raw_ident("u8")),
RestrictedDouble | UnrestrictedDouble => ident_ty(raw_ident("f64")),
RestrictedFloat | UnrestrictedFloat => ident_ty(raw_ident("f32")),
SignedLong => ident_ty(raw_ident("i32")),
SignedLongLong => ident_ty(raw_ident("i64")),
SignedShort => ident_ty(raw_ident("i16")),
UnsignedLong => ident_ty(raw_ident("u32")),
UnsignedLongLong => ident_ty(raw_ident("u64")),
UnsignedShort => ident_ty(raw_ident("u16")),
Identifier(ref id) => ident_ty(rust_ident(id)),
}
}
pub fn webidl_const_v_to_backend_const_v(v: &webidl::ast::ConstValue) -> backend::ast::ConstValue {
match *v {
webidl::ast::ConstValue::BooleanLiteral(b) => backend::ast::ConstValue::BooleanLiteral(b),
webidl::ast::ConstValue::FloatLiteral(f) => backend::ast::ConstValue::FloatLiteral(f),
webidl::ast::ConstValue::IntegerLiteral(i) => backend::ast::ConstValue::IntegerLiteral(i),
webidl::ast::ConstValue::Null => backend::ast::ConstValue::Null,
}
}
fn simple_fn_arg(ident: Ident, ty: syn::Type) -> syn::ArgCaptured {
syn::ArgCaptured {
pat: syn::Pat::Ident(syn::PatIdent {

View File

@ -0,0 +1,190 @@
use super::project;
#[test]
fn bool() {
project()
.file(
"foo.webidl",
r#"
interface Foo {
const boolean not_true = false;
const boolean not_false = true;
};
"#,
)
// a corresponding const in the js implementation is not required
// value is taken directly from idl
.file(
"foo.js",
r#"
export class Foo {
}
"#,
)
.file(
"src/lib.rs",
r#"
#![feature(proc_macro, wasm_custom_section, wasm_import_module)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
pub mod foo;
use foo::Foo;
#[wasm_bindgen]
pub fn test() {
let falsish: bool = Foo::NOT_TRUE;
assert!(!falsish);
let trueish: bool = Foo::NOT_FALSE;
assert!(trueish);
}
"#,
)
.test();
}
#[test]
fn ints() {
project()
.file(
"foo.webidl",
r#"
interface Byte {
const byte imin = -128;
const byte imax = 127;
const octet umin = 0;
const octet umax = 255;
};
interface Short {
const short imin = -32768;
const short imax = 32767;
const unsigned short umin = 0;
const unsigned short umax = 65535;
};
interface Long {
const long imin = -2147483648;
const long imax = 2147483647;
const unsigned long umin = 0;
const unsigned long umax = 4294967295;
};
interface LongLong {
const long long imin = -9223372036854775808;
const long long imax = 9223372036854775807;
const unsigned long long umin = 0;
// bug in webidl
// https://github.com/sgodwincs/webidl-rs/issues/15
//const unsigned long long umax = 18446744073709551615;
};
"#,
)
// a corresponding const in the js implementation is not required
// value is taken directly from idl
.file(
"foo.js",
r#"
export class Byte {
}
export class Short {
}
export class Long {
}
export class LongLong {
}
"#,
)
.file(
"src/lib.rs",
r#"
#![feature(proc_macro, wasm_custom_section, wasm_import_module)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
pub mod foo;
#[wasm_bindgen]
pub fn test() {
assert_eq!(foo::Byte::IMIN, i8::min_value());
assert_eq!(foo::Byte::IMAX, i8::max_value());
assert_eq!(foo::Byte::UMIN, u8::min_value());
assert_eq!(foo::Byte::UMAX, u8::max_value());
assert_eq!(foo::Short::IMIN, i16::min_value());
assert_eq!(foo::Short::IMAX, i16::max_value());
assert_eq!(foo::Short::UMIN, u16::min_value());
assert_eq!(foo::Short::UMAX, u16::max_value());
assert_eq!(foo::Long::IMIN, i32::min_value());
assert_eq!(foo::Long::IMAX, i32::max_value());
assert_eq!(foo::Long::UMIN, u32::min_value());
assert_eq!(foo::Long::UMAX, u32::max_value());
assert_eq!(foo::LongLong::IMIN, i64::min_value());
assert_eq!(foo::LongLong::IMAX, i64::max_value());
assert_eq!(foo::LongLong::UMIN, u64::min_value());
//assert_eq!(foo::LongLong::UMAX, u64::max_value());
}
"#,
)
.test();
}
#[test]
fn floats() {
project()
.file(
"foo.webidl",
r#"
interface floats {
const float f = 0.0;
const unrestricted float neg_inf = -Infinity;
const unrestricted float inf = Infinity;
const unrestricted float nan = NaN;
};
interface doubles {
const double d = 0.0;
const unrestricted double neg_inf = -Infinity;
const unrestricted double inf = Infinity;
const unrestricted double nan = NaN;
};
"#,
)
// a corresponding const in the js implementation is not required
// value is taken directly from idl
.file(
"foo.js",
r#"
export class floats {
}
export class doubles {
}
"#,
)
.file(
"src/lib.rs",
r#"
#![feature(proc_macro, wasm_custom_section, wasm_import_module)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
pub mod foo;
#[wasm_bindgen]
pub fn test() {
assert_eq!(foo::Floats::F, 0.0_f32);
assert!(foo::Floats::NEG_INF.is_infinite());
assert!(foo::Floats::NEG_INF.is_sign_negative());
assert!(foo::Floats::INF.is_infinite());
assert!(foo::Floats::INF.is_sign_positive());
assert!(foo::Floats::NAN.is_nan());
assert_eq!(foo::Doubles::D, 0.0_f64);
assert!(foo::Doubles::NEG_INF.is_infinite());
assert!(foo::Doubles::NEG_INF.is_sign_negative());
assert!(foo::Doubles::INF.is_infinite());
assert!(foo::Doubles::INF.is_sign_positive());
assert!(foo::Doubles::NAN.is_nan());
}
"#,
)
.test();
}

View File

@ -1,6 +1,7 @@
extern crate wasm_bindgen_test_project_builder as project_builder;
use project_builder::project;
mod simple;
mod consts;
mod enums;
mod simple;
mod throws;

View File

@ -14,7 +14,7 @@ development.
[install Rust]: https://www.rust-lang.org/en-US/install.html
2. The tests for this project use Node. Make sure you have node >= 8 installed,
2. The tests for this project use Node. Make sure you have node >= 10 installed,
as that is when WebAssembly support was introduced. [Install Node].
[Install Node]: https://nodejs.org/en/

View File

@ -9,13 +9,13 @@
},
"devDependencies": {
"@types/node": "^10.5.2",
"babel-eslint": "^8.2.5",
"babel-eslint": "^8.2.6",
"eslint": "^5.1.0",
"geckodriver": "^1.11.0",
"selenium-webdriver": "^4.0.0-alpha.1",
"ts-loader": "^4.4.2",
"typescript": "^2.7.2",
"webpack": "^4.15.1",
"webpack": "^4.16.0",
"webpack-cli": "^3.0.8",
"webpack-dev-server": "^3.1.4"
}

View File

@ -77,7 +77,6 @@ pub trait RefMutFromWasmAbi: WasmDescribe {
pub trait Stack {
fn push(&mut self, bits: u32);
fn pop(&mut self) -> u32;
}
/// An unsafe trait which represents types that are ABI-safe to pass via wasm
@ -105,11 +104,15 @@ macro_rules! simple {
($($t:tt)*) => ($(
impl IntoWasmAbi for $t {
type Abi = $t;
#[inline]
fn into_abi(self, _extra: &mut Stack) -> $t { self }
}
impl FromWasmAbi for $t {
type Abi = $t;
#[inline]
unsafe fn from_abi(js: $t, _extra: &mut Stack) -> $t { js }
}
)*)
@ -121,6 +124,8 @@ macro_rules! sixtyfour {
($($t:tt)*) => ($(
impl IntoWasmAbi for $t {
type Abi = WasmSlice;
#[inline]
fn into_abi(self, _extra: &mut Stack) -> WasmSlice {
WasmSlice {
ptr: self as u32,
@ -131,6 +136,8 @@ macro_rules! sixtyfour {
impl FromWasmAbi for $t {
type Abi = WasmSlice;
#[inline]
unsafe fn from_abi(js: WasmSlice, _extra: &mut Stack) -> $t {
(js.ptr as $t) | ((js.len as $t) << 32)
}
@ -144,11 +151,15 @@ macro_rules! as_u32 {
($($t:tt)*) => ($(
impl IntoWasmAbi for $t {
type Abi = u32;
#[inline]
fn into_abi(self, _extra: &mut Stack) -> u32 { self as u32 }
}
impl FromWasmAbi for $t {
type Abi = u32;
#[inline]
unsafe fn from_abi(js: u32, _extra: &mut Stack) -> $t { js as $t }
}
)*)
@ -159,6 +170,7 @@ as_u32!(i8 u8 i16 u16 isize usize);
impl IntoWasmAbi for bool {
type Abi = u32;
#[inline]
fn into_abi(self, _extra: &mut Stack) -> u32 {
self as u32
}
@ -167,6 +179,7 @@ impl IntoWasmAbi for bool {
impl FromWasmAbi for bool {
type Abi = u32;
#[inline]
unsafe fn from_abi(js: u32, _extra: &mut Stack) -> bool {
js != 0
}
@ -174,6 +187,8 @@ impl FromWasmAbi for bool {
impl IntoWasmAbi for char {
type Abi = u32;
#[inline]
fn into_abi(self, _extra: &mut Stack) -> u32 {
self as u32
}
@ -181,6 +196,8 @@ impl IntoWasmAbi for char {
impl FromWasmAbi for char {
type Abi = u32;
#[inline]
unsafe fn from_abi(js: u32, _extra: &mut Stack) -> char {
char::from_u32_unchecked(js)
}
@ -224,6 +241,7 @@ macro_rules! vectors {
impl IntoWasmAbi for Box<[$t]> {
type Abi = WasmSlice;
#[inline]
fn into_abi(self, extra: &mut Stack) -> WasmSlice {
let ptr = self.as_ptr();
let len = self.len();
@ -239,6 +257,7 @@ macro_rules! vectors {
impl FromWasmAbi for Box<[$t]> {
type Abi = WasmSlice;
#[inline]
unsafe fn from_abi(js: WasmSlice, extra: &mut Stack) -> Self {
let ptr = <*mut $t>::from_abi(js.ptr, extra);
let len = js.len as usize;
@ -249,6 +268,7 @@ macro_rules! vectors {
impl<'a> IntoWasmAbi for &'a [$t] {
type Abi = WasmSlice;
#[inline]
fn into_abi(self, extra: &mut Stack) -> WasmSlice {
WasmSlice {
ptr: self.as_ptr().into_abi(extra),
@ -260,6 +280,7 @@ macro_rules! vectors {
impl<'a> IntoWasmAbi for &'a mut [$t] {
type Abi = WasmSlice;
#[inline]
fn into_abi(self, extra: &mut Stack) -> WasmSlice {
(&*self).into_abi(extra)
}
@ -269,6 +290,7 @@ macro_rules! vectors {
type Abi = WasmSlice;
type Anchor = &'static [$t];
#[inline]
unsafe fn ref_from_abi(js: WasmSlice, extra: &mut Stack) -> &'static [$t] {
slice::from_raw_parts(
<*const $t>::from_abi(js.ptr, extra),
@ -281,6 +303,7 @@ macro_rules! vectors {
type Abi = WasmSlice;
type Anchor = &'static mut [$t];
#[inline]
unsafe fn ref_mut_from_abi(js: WasmSlice, extra: &mut Stack)
-> &'static mut [$t]
{
@ -300,6 +323,7 @@ vectors! {
if_std! {
impl<T> IntoWasmAbi for Vec<T> where Box<[T]>: IntoWasmAbi {
type Abi = <Box<[T]> as IntoWasmAbi>::Abi;
fn into_abi(self, extra: &mut Stack) -> Self::Abi {
self.into_boxed_slice().into_abi(extra)
}
@ -316,6 +340,7 @@ if_std! {
impl IntoWasmAbi for String {
type Abi = <Vec<u8> as IntoWasmAbi>::Abi;
#[inline]
fn into_abi(self, extra: &mut Stack) -> Self::Abi {
self.into_bytes().into_abi(extra)
}
@ -324,6 +349,7 @@ if_std! {
impl FromWasmAbi for String {
type Abi = <Vec<u8> as FromWasmAbi>::Abi;
#[inline]
unsafe fn from_abi(js: Self::Abi, extra: &mut Stack) -> Self {
String::from_utf8_unchecked(<Vec<u8>>::from_abi(js, extra))
}
@ -333,6 +359,7 @@ if_std! {
impl<'a> IntoWasmAbi for &'a str {
type Abi = <&'a [u8] as IntoWasmAbi>::Abi;
#[inline]
fn into_abi(self, extra: &mut Stack) -> Self::Abi {
self.as_bytes().into_abi(extra)
}
@ -342,6 +369,7 @@ impl RefFromWasmAbi for str {
type Abi = <[u8] as RefFromWasmAbi>::Abi;
type Anchor = &'static str;
#[inline]
unsafe fn ref_from_abi(js: Self::Abi, extra: &mut Stack) -> Self::Anchor {
str::from_utf8_unchecked(<[u8]>::ref_from_abi(js, extra))
}
@ -350,6 +378,7 @@ impl RefFromWasmAbi for str {
impl IntoWasmAbi for JsValue {
type Abi = u32;
#[inline]
fn into_abi(self, _extra: &mut Stack) -> u32 {
let ret = self.idx;
mem::forget(self);
@ -360,6 +389,7 @@ impl IntoWasmAbi for JsValue {
impl FromWasmAbi for JsValue {
type Abi = u32;
#[inline]
unsafe fn from_abi(js: u32, _extra: &mut Stack) -> JsValue {
JsValue { idx: js }
}
@ -367,6 +397,8 @@ impl FromWasmAbi for JsValue {
impl<'a> IntoWasmAbi for &'a JsValue {
type Abi = u32;
#[inline]
fn into_abi(self, _extra: &mut Stack) -> u32 {
self.idx
}
@ -376,6 +408,7 @@ impl RefFromWasmAbi for JsValue {
type Abi = u32;
type Anchor = ManuallyDrop<JsValue>;
#[inline]
unsafe fn ref_from_abi(js: u32, _extra: &mut Stack) -> Self::Anchor {
ManuallyDrop::new(JsValue { idx: js })
}
@ -385,6 +418,7 @@ if_std! {
impl IntoWasmAbi for Box<[JsValue]> {
type Abi = WasmSlice;
#[inline]
fn into_abi(self, extra: &mut Stack) -> WasmSlice {
let ptr = self.as_ptr();
let len = self.len();
@ -399,6 +433,7 @@ if_std! {
impl FromWasmAbi for Box<[JsValue]> {
type Abi = WasmSlice;
#[inline]
unsafe fn from_abi(js: WasmSlice, extra: &mut Stack) -> Self {
let ptr = <*mut JsValue>::from_abi(js.ptr, extra);
let len = js.len as usize;
@ -415,12 +450,14 @@ const GLOBAL_STACK_CAP: usize = 16;
static mut GLOBAL_STACK: [u32; GLOBAL_STACK_CAP] = [0; GLOBAL_STACK_CAP];
impl GlobalStack {
#[inline]
pub unsafe fn new() -> GlobalStack {
GlobalStack { next: 0 }
}
}
impl Stack for GlobalStack {
#[inline]
fn push(&mut self, val: u32) {
unsafe {
assert!(self.next < GLOBAL_STACK_CAP);
@ -428,15 +465,6 @@ impl Stack for GlobalStack {
self.next += 1;
}
}
fn pop(&mut self) -> u32 {
unsafe {
assert!(self.next < GLOBAL_STACK_CAP);
let ret = GLOBAL_STACK[self.next];
self.next += 1;
ret
}
}
}
#[doc(hidden)]

160
src/js.rs
View File

@ -240,6 +240,20 @@ extern "C" {
#[wasm_bindgen(method)]
pub fn push(this: &Array, value: JsValue) -> u32;
/// The reduce() method applies a function against an accumulator and each element in
/// the array (from left to right) to reduce it to a single value.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
#[wasm_bindgen(method)]
pub fn reduce(this: &Array, predicate: &mut FnMut(JsValue, JsValue, u32, Array) -> JsValue, initial_value: JsValue) -> JsValue;
/// The reduceRight() method applies a function against an accumulator and each value
/// of the array (from right-to-left) to reduce it to a single value.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/ReduceRight
#[wasm_bindgen(method, js_name = reduceRight)]
pub fn reduce_right(this: &Array, predicate: &mut FnMut(JsValue, JsValue, u32, Array) -> JsValue, initial_value: JsValue) -> JsValue;
/// The reverse() method reverses an array in place. The first array
/// element becomes the last, and the last array element becomes the first.
///
@ -378,6 +392,152 @@ extern "C" {
pub fn value_of(this: &Boolean) -> bool;
}
// DataView
#[wasm_bindgen]
extern "C" {
pub type DataView;
/// The `DataView` view provides a low-level interface for reading and
/// writing multiple number types in an `ArrayBuffer` irrespective of the
/// platform's endianness.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView
#[wasm_bindgen(constructor)]
pub fn new(buffer: &ArrayBuffer, byteOffset: usize, byteLength: usize) -> DataView;
/// The ArrayBuffer referenced by this view. Fixed at construction time and thus read only.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/buffer
#[wasm_bindgen(method, getter, structural)]
pub fn buffer(this: &DataView) -> ArrayBuffer;
/// The length (in bytes) of this view from the start of its ArrayBuffer.
/// Fixed at construction time and thus read only.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/byteLength
#[wasm_bindgen(method, getter, structural, js_name = byteLength)]
pub fn byte_length(this: &DataView) -> usize;
/// The offset (in bytes) of this view from the start of its ArrayBuffer.
/// Fixed at construction time and thus read only.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/byteOffset
#[wasm_bindgen(method, getter, structural, js_name = byteOffset)]
pub fn byte_offset(this: &DataView) -> usize;
/// The getInt8() method gets a signed 8-bit integer (byte) at the
/// specified byte offset from the start of the DataView.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/getInt8
#[wasm_bindgen(method, js_name = getInt8)]
pub fn get_int8(this: &DataView, byte_offset: usize) -> i8;
/// The getUint8() method gets a unsigned 8-bit integer (byte) at the specified
/// byte offset from the start of the DataView.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/getUint8
#[wasm_bindgen(method, js_name = getUint8)]
pub fn get_uint8(this: &DataView, byte_offset: usize) -> u8;
/// The getInt16() method gets a signed 16-bit integer (byte) at the specified
/// byte offset from the start of the DataView.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/getInt16
#[wasm_bindgen(method, js_name = getInt16)]
pub fn get_int16(this: &DataView, byte_offset: usize) -> i16;
/// The getUint16() an unsigned 16-bit integer (unsigned byte) at the specified
/// byte offset from the start of the view.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/getUint16
#[wasm_bindgen(method, js_name = getUint16)]
pub fn get_uint16(this: &DataView, byte_offset: usize) -> u16;
/// The getInt32() method gets a signed 16-bit integer (byte) at the specified
/// byte offset from the start of the DataView.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/getInt32
#[wasm_bindgen(method, js_name = getInt32)]
pub fn get_int32(this: &DataView, byte_offset: usize) -> i32;
/// The getUint32() an unsigned 16-bit integer (unsigned byte) at the specified
/// byte offset from the start of the view.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/getUint32
#[wasm_bindgen(method, js_name = getUint32)]
pub fn get_uint32(this: &DataView, byte_offset: usize) -> u32;
/// The getFloat32() method gets a signed 32-bit float (float) at the specified
/// byte offset from the start of the DataView.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/getFloat32
#[wasm_bindgen(method, js_name = getFloat32)]
pub fn get_float32(this: &DataView, byte_offset: usize) -> f32;
/// The getFloat64() method gets a signed 32-bit float (float) at the specified
/// byte offset from the start of the DataView.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/getFloat64
#[wasm_bindgen(method, js_name = getFloat64)]
pub fn get_float64(this: &DataView, byte_offset: usize) -> f64;
/// The setInt8() method stores a signed 8-bit integer (byte) value at the
/// specified byte offset from the start of the DataView.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/setInt8
#[wasm_bindgen(method, js_name = setInt8)]
pub fn set_int8(this: &DataView, byte_offset: usize, value: i8);
/// The setUint8() method stores an unsigned 8-bit integer (byte) value at the
/// specified byte offset from the start of the DataView.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/setUint8
#[wasm_bindgen(method, js_name = setUint8)]
pub fn set_uint8(this: &DataView, byte_offset: usize, value: u8);
/// The setInt16() method stores a signed 16-bit integer (byte) value at the
/// specified byte offset from the start of the DataView.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/setInt16
#[wasm_bindgen(method, js_name = setInt16)]
pub fn set_int16(this: &DataView, byte_offset: usize, value: i16);
/// The setUint16() method stores an unsigned 16-bit integer (byte) value at the
/// specified byte offset from the start of the DataView.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/setUint16
#[wasm_bindgen(method, js_name = setUint16)]
pub fn set_uint16(this: &DataView, byte_offset: usize, value: u16);
/// The setInt32() method stores a signed 32-bit integer (byte) value at the
/// specified byte offset from the start of the DataView.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/setInt32
#[wasm_bindgen(method, js_name = setInt32)]
pub fn set_int32(this: &DataView, byte_offset: usize, value: i32);
/// The setUint32() method stores an unsigned 32-bit integer (byte) value at the
/// specified byte offset from the start of the DataView.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/setUint32
#[wasm_bindgen(method, js_name = setUint32)]
pub fn set_uint32(this: &DataView, byte_offset: usize, value: u32);
/// The setFloat32() method stores a signed 32-bit float (float) value at the
/// specified byte offset from the start of the DataView.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/setFloat32
#[wasm_bindgen(method, js_name = setFloat32)]
pub fn set_float32(this: &DataView, byte_offset: usize, value: f32);
/// The setFloat64() method stores a signed 64-bit float (float) value at the
/// specified byte offset from the start of the DataView.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/setFloat64
#[wasm_bindgen(method, js_name = setFloat64)]
pub fn set_float64(this: &DataView, byte_offset: usize, value: f64);
}
// Error
#[wasm_bindgen]
extern "C" {

View File

@ -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, unsize)]
#![feature(use_extern_macros, wasm_import_module, unsize)]
#![cfg_attr(feature = "js_globals", feature(proc_macro, wasm_custom_section))]
#![no_std]
@ -661,24 +661,29 @@ pub mod __rt {
}
if_std! {
use std::prelude::v1::*;
use std::alloc::{System, GlobalAlloc, Layout};
use std::mem;
#[no_mangle]
pub extern fn __wbindgen_malloc(size: usize) -> *mut u8 {
use core::mem;
let mut ret = Vec::new();
if ret.try_reserve_exact(size).is_err() {
super::throw("invalid malloc request");
}
let ptr = ret.as_mut_ptr();
mem::forget(ret);
let align = mem::align_of::<usize>();
if let Ok(layout) = Layout::from_size_align(size, align) {
unsafe {
let ptr = System.alloc(layout);
if !ptr.is_null() {
return ptr
}
}
}
super::throw("invalid malloc request");
}
#[no_mangle]
pub unsafe extern fn __wbindgen_free(ptr: *mut u8, size: usize) {
drop(Vec::<u8>::from_raw_parts(ptr, 0, size));
let align = mem::align_of::<usize>();
let layout = Layout::from_size_align_unchecked(size, align);
System.dealloc(ptr, layout);
}
}

View File

@ -830,3 +830,69 @@ fn map() {
)
.test()
}
#[test]
fn reduce() {
project()
.file(
"src/lib.rs",
r#"
#![feature(proc_macro, wasm_custom_section)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
use wasm_bindgen::js;
use JsValue;
#[wasm_bindgen]
pub fn array_reduce(array: &js::Array) -> JsValue {
array.reduce(&mut |ac, cr, _, _| JsValue::from_str(&format!("{}{}", &ac.as_string().unwrap(), &cr.as_string().unwrap().as_str())), JsValue::from_str(""))
}
"#,
)
.file(
"test.js",
r#"
import * as assert from "assert";
import * as wasm from "./out";
export function test() {
assert.equal(wasm.array_reduce(['0', '1', '2', '3', '4']), '01234');
}
"#,
)
.test()
}
#[test]
fn reduce_right() {
project()
.file(
"src/lib.rs",
r#"
#![feature(proc_macro, wasm_custom_section)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
use wasm_bindgen::js;
use JsValue;
#[wasm_bindgen]
pub fn array_reduce_right(array: &js::Array) -> JsValue {
array.reduce_right(&mut |ac, cr, _, _| JsValue::from_str(&format!("{}{}", &ac.as_string().unwrap(), &cr.as_string().unwrap().as_str())), JsValue::from_str(""))
}
"#,
)
.file(
"test.js",
r#"
import * as assert from "assert";
import * as wasm from "./out";
export function test() {
assert.equal(wasm.array_reduce_right(['0', '1', '2', '3', '4']), '43210');
}
"#,
)
.test()
}

View File

@ -0,0 +1,55 @@
#![allow(non_snake_case)]
use super::project;
#[test]
fn test() {
project()
.file("src/lib.rs", r#"
#![feature(proc_macro, wasm_custom_section)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
use wasm_bindgen::js::{ArrayBuffer, DataView};
#[wasm_bindgen]
pub fn test_data_view(buffer: &ArrayBuffer, offset: usize, len: usize) {
let v = DataView::new(buffer, offset, len);
assert_eq!(v.byte_offset(), offset);
assert_eq!(v.byte_length(), len);
assert_eq!(v.get_int8(0), 2);
assert_eq!(v.get_uint8(0), 2);
v.set_int8(0, 42);
assert_eq!(v.get_int8(0), 42);
v.set_uint8(0, 255);
assert_eq!(v.get_uint8(0), 255);
v.set_int16(0, 32767);
assert_eq!(v.get_int16(0), 32767);
v.set_uint16(0, 65535);
assert_eq!(v.get_uint16(0), 65535);
v.set_int32(0, 123456789);
assert_eq!(v.get_int32(0), 123456789);
v.set_uint32(0, 3_123_456_789);
assert_eq!(v.get_uint32(0), 3_123_456_789);
v.set_float32(0, 100.123);
assert_eq!(v.get_float32(0), 100.123);
v.set_float64(0, 123456789.123456);
assert_eq!(v.get_float64(0), 123456789.123456);
v.set_int8(0, 42);
}
"#)
.file("test.js", r#"
import * as assert from "assert";
import * as wasm from "./out";
export function test() {
const bytes = new Int8Array(10);
bytes[2] = 2;
wasm.test_data_view(bytes.buffer, 2, 8);
assert.equal(bytes[2], 42);
}
"#)
.test()
}

View File

@ -6,6 +6,7 @@ mod Array;
mod ArrayBuffer;
mod ArrayIterator;
mod Boolean;
mod DataView;
mod Date;
mod Error;
mod Function;

View File

@ -408,15 +408,15 @@ babel-code-frame@^6.26.0:
esutils "^2.0.2"
js-tokens "^3.0.2"
babel-eslint@^8.2.5:
version "8.2.5"
resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.2.5.tgz#dc2331c259d36782aa189da510c43dedd5adc7a3"
babel-eslint@^8.2.6:
version "8.2.6"
resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.2.6.tgz#6270d0c73205628067c0f7ae1693a9e797acefd9"
dependencies:
"@babel/code-frame" "7.0.0-beta.44"
"@babel/traverse" "7.0.0-beta.44"
"@babel/types" "7.0.0-beta.44"
babylon "7.0.0-beta.44"
eslint-scope "~3.7.1"
eslint-scope "3.7.1"
eslint-visitor-keys "^1.0.0"
babylon@7.0.0-beta.44:
@ -1239,7 +1239,7 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
eslint-scope@^3.7.1, eslint-scope@~3.7.1:
eslint-scope@3.7.1, eslint-scope@^3.7.1:
version "3.7.1"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8"
dependencies:
@ -4150,9 +4150,9 @@ webpack-sources@^1.0.1, webpack-sources@^1.1.0:
source-list-map "^2.0.0"
source-map "~0.6.1"
webpack@^4.15.1:
version "4.15.1"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.15.1.tgz#dc716779a3b88827c369f18c71a6137fa7e582fd"
webpack@^4.16.0:
version "4.16.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.16.0.tgz#660dae90890e55b8ed17c6f9d17bebb01dab5b4c"
dependencies:
"@webassemblyjs/ast" "1.5.13"
"@webassemblyjs/helper-module-context" "1.5.13"