Skip to content

Commit

Permalink
Merge branch 'main' into wasm-to-ts-impr
Browse files Browse the repository at this point in the history
  • Loading branch information
RunDevelopment committed Nov 13, 2024
2 parents bf7becc + 2a1c7ac commit baedfaf
Show file tree
Hide file tree
Showing 68 changed files with 1,530 additions and 182 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@
* Added JSDoc type annotations to C-style enums.
[#4192](https://github.com/rustwasm/wasm-bindgen/pull/4192)

* Added support for C-style enums with negative discriminants.
[#4204](https://github.com/rustwasm/wasm-bindgen/pull/4204)

* Added bindings for `MediaStreamTrack.getCapabilities`.
[#4236](https://github.com/rustwasm/wasm-bindgen/pull/4236)

* Added WASM ABI support for `u128` and `i128`
[#4222](https://github.com/rustwasm/wasm-bindgen/pull/4222)

### Changed

* String enums now generate private TypeScript types but only if used.
Expand Down Expand Up @@ -66,6 +75,9 @@
* Fixed calls to `JsCast::instanceof()` not respecting JavaScript namespaces.
[#4241](https://github.com/rustwasm/wasm-bindgen/pull/4241)

* Fixed imports for functions using `this` and late binding.
[#4225](https://github.com/rustwasm/wasm-bindgen/pull/4225)

--------------------------------------------------------------------------------

## [0.2.95](https://github.com/rustwasm/wasm-bindgen/compare/0.2.94...0.2.95)
Expand Down
3 changes: 3 additions & 0 deletions crates/backend/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,9 @@ pub struct Enum {
pub rust_name: Ident,
/// The name of this enum in JS code
pub js_name: String,
/// Whether the variant values and hole are signed, meaning that they
/// represent the bits of a `i32` value.
pub signed: bool,
/// The variants provided by this enum
pub variants: Vec<Variant>,
/// The doc comments on this enum, if any
Expand Down
29 changes: 17 additions & 12 deletions crates/backend/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1535,10 +1535,15 @@ impl ToTokens for ast::Enum {
let name_len = name_str.len() as u32;
let name_chars = name_str.chars().map(|c| c as u32);
let hole = &self.hole;
let underlying = if self.signed {
quote! { i32 }
} else {
quote! { u32 }
};
let cast_clauses = self.variants.iter().map(|variant| {
let variant_name = &variant.name;
quote! {
if js == #enum_name::#variant_name as u32 {
if js == #enum_name::#variant_name as #underlying {
#enum_name::#variant_name
}
}
Expand All @@ -1548,20 +1553,20 @@ impl ToTokens for ast::Enum {
(quote! {
#[automatically_derived]
impl #wasm_bindgen::convert::IntoWasmAbi for #enum_name {
type Abi = u32;
type Abi = #underlying;

#[inline]
fn into_abi(self) -> u32 {
self as u32
fn into_abi(self) -> #underlying {
self as #underlying
}
}

#[automatically_derived]
impl #wasm_bindgen::convert::FromWasmAbi for #enum_name {
type Abi = u32;
type Abi = #underlying;

#[inline]
unsafe fn from_abi(js: u32) -> Self {
unsafe fn from_abi(js: #underlying) -> Self {
#(#cast_clauses else)* {
#wasm_bindgen::throw_str("invalid enum value passed")
}
Expand All @@ -1571,13 +1576,13 @@ impl ToTokens for ast::Enum {
#[automatically_derived]
impl #wasm_bindgen::convert::OptionFromWasmAbi for #enum_name {
#[inline]
fn is_none(val: &u32) -> bool { *val == #hole }
fn is_none(val: &Self::Abi) -> bool { *val == #hole as #underlying }
}

#[automatically_derived]
impl #wasm_bindgen::convert::OptionIntoWasmAbi for #enum_name {
#[inline]
fn none() -> Self::Abi { #hole }
fn none() -> Self::Abi { #hole as #underlying }
}

#[automatically_derived]
Expand All @@ -1597,7 +1602,7 @@ impl ToTokens for ast::Enum {
#wasm_bindgen::JsValue
{
fn from(value: #enum_name) -> Self {
#wasm_bindgen::JsValue::from_f64((value as u32).into())
#wasm_bindgen::JsValue::from_f64((value as #underlying).into())
}
}

Expand All @@ -1608,7 +1613,7 @@ impl ToTokens for ast::Enum {
fn try_from_js_value(value: #wasm_bindgen::JsValue)
-> #wasm_bindgen::__rt::core::result::Result<Self, <#enum_name as #wasm_bindgen::convert::TryFromJsValue>::Error> {
use #wasm_bindgen::__rt::core::convert::TryFrom;
let js = f64::try_from(&value)? as u32;
let js = f64::try_from(&value)? as #underlying;

#wasm_bindgen::__rt::core::result::Result::Ok(
#(#try_from_cast_clauses else)* {
Expand Down Expand Up @@ -1894,9 +1899,9 @@ fn respan(input: TokenStream, span: &dyn ToTokens) -> TokenStream {

for (i, token) in spans.into_iter().enumerate() {
if i == 0 {
first_span = token.span();
first_span = Span::call_site().located_at(token.span());
}
last_span = token.span();
last_span = Span::call_site().located_at(token.span());
}

let mut new_tokens = Vec::new();
Expand Down
1 change: 1 addition & 0 deletions crates/backend/src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ fn shared_function<'a>(func: &'a ast::Function, _intern: &'a Interner) -> Functi
fn shared_enum<'a>(e: &'a ast::Enum, intern: &'a Interner) -> Enum<'a> {
Enum {
name: &e.js_name,
signed: e.signed,
variants: e
.variants
.iter()
Expand Down
6 changes: 6 additions & 0 deletions crates/cli-support/src/descriptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ tys! {
U32
I64
U64
I128
U128
F32
F64
BOOLEAN
Expand Down Expand Up @@ -55,6 +57,8 @@ pub enum Descriptor {
U32,
I64,
U64,
I128,
U128,
F32,
F64,
Boolean,
Expand Down Expand Up @@ -132,11 +136,13 @@ impl Descriptor {
I16 => Descriptor::I16,
I32 => Descriptor::I32,
I64 => Descriptor::I64,
I128 => Descriptor::I128,
U8 if clamped => Descriptor::ClampedU8,
U8 => Descriptor::U8,
U16 => Descriptor::U16,
U32 => Descriptor::U32,
U64 => Descriptor::U64,
U128 => Descriptor::U128,
F32 => Descriptor::F32,
F64 => Descriptor::F64,
BOOLEAN => Descriptor::Boolean,
Expand Down
55 changes: 54 additions & 1 deletion crates/cli-support/src/js/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,23 @@ fn instruction(
)
}

fn int128_to_int64x2(val: &str) -> (String, String) {
// we don't need to perform any conversion here, because the JS
// WebAssembly API will automatically convert the bigints to 64 bits
// for us. This even allows us to ignore signedness.
let low = val.to_owned();
let high = format!("{val} >> BigInt(64)");
(low, high)
}
fn int64x2_to_int128(low: String, high: String, signed: bool) -> String {
let low = format!("BigInt.asUintN(64, {low})");
if signed {
format!("({low} | ({high} << BigInt(64)))")
} else {
format!("({low} | (BigInt.asUintN(64, {high}) << BigInt(64)))")
}
}

match instr {
Instruction::ArgGet(n) => {
let arg = js.arg(*n).to_string();
Expand Down Expand Up @@ -712,6 +729,36 @@ fn instruction(
}
}

Instruction::Int128ToWasm => {
let val = js.pop();
js.assert_bigint(&val);
let (low, high) = int128_to_int64x2(&val);
js.push(low);
js.push(high);
}
Instruction::WasmToInt128 { signed } => {
let high = js.pop();
let low = js.pop();
js.push(int64x2_to_int128(low, high, *signed));
}

Instruction::OptionInt128ToWasm => {
let val = js.pop();
js.cx.expose_is_like_none();
js.assert_optional_bigint(&val);
let (low, high) = int128_to_int64x2(&val);
js.push(format!("!isLikeNone({val})"));
js.push(format!("isLikeNone({val}) ? BigInt(0) : {low}"));
js.push(format!("isLikeNone({val}) ? BigInt(0) : {high}"));
}
Instruction::OptionWasmToInt128 { signed } => {
let high = js.pop();
let low = js.pop();
let present = js.pop();
let val = int64x2_to_int128(low, high, *signed);
js.push(format!("{present} === 0 ? undefined : {val}"));
}

Instruction::WasmToStringEnum { name } => {
let index = js.pop();
js.cx.expose_string_enum(name);
Expand Down Expand Up @@ -983,6 +1030,8 @@ fn instruction(
js.push(format!(
"isLikeNone({val}) ? {zero} : {val}",
zero = if *ty == ValType::I64 {
// We can't use bigint literals for now. See:
// https://github.com/rustwasm/wasm-bindgen/issues/4246
"BigInt(0)"
} else {
"0"
Expand Down Expand Up @@ -1500,7 +1549,11 @@ fn adapter2ts(ty: &AdapterType, dst: &mut String, refs: Option<&mut HashSet<TsRe
| AdapterType::F32
| AdapterType::F64
| AdapterType::NonNull => dst.push_str("number"),
AdapterType::I64 | AdapterType::S64 | AdapterType::U64 => dst.push_str("bigint"),
AdapterType::I64
| AdapterType::S64
| AdapterType::U64
| AdapterType::S128
| AdapterType::U128 => dst.push_str("bigint"),
AdapterType::String => dst.push_str("string"),
AdapterType::Externref => dst.push_str("any"),
AdapterType::Bool => dst.push_str("boolean"),
Expand Down
15 changes: 15 additions & 0 deletions crates/cli-support/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3062,6 +3062,21 @@ __wbg_set_wasm(wasm);"
}
}

if let JsImportName::Global { .. } | JsImportName::VendorPrefixed { .. } = js.name {
// We generally cannot import globals directly, because users can
// change most globals at runtime.
//
// An obvious example of this when the object literally changes
// (e.g. binding `foo.bar`), but polyfills can also change the
// object or fundtion.
//
// Late binding is another issue. The function might not even be
// defined when the Wasm module is instantiated. In such cases,
// there is an observable difference between a direct import and a
// JS shim calling the function.
return Ok(false);
}

self.expose_not_defined();
let name = self.import_name(js)?;
let js = format!(
Expand Down
28 changes: 28 additions & 0 deletions crates/cli-support/src/wit/incoming.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,20 @@ impl InstructionBuilder<'_, '_> {
Descriptor::U32 => self.number(AdapterType::U32, WasmVT::I32),
Descriptor::I64 => self.number(AdapterType::S64, WasmVT::I64),
Descriptor::U64 => self.number(AdapterType::U64, WasmVT::I64),
Descriptor::I128 => {
self.instruction(
&[AdapterType::S128],
Instruction::Int128ToWasm,
&[AdapterType::I64, AdapterType::I64],
);
}
Descriptor::U128 => {
self.instruction(
&[AdapterType::U128],
Instruction::Int128ToWasm,
&[AdapterType::I64, AdapterType::I64],
);
}
Descriptor::F32 => {
self.get(AdapterType::F32);
self.output.push(AdapterType::F32);
Expand Down Expand Up @@ -285,6 +299,20 @@ impl InstructionBuilder<'_, '_> {
Descriptor::F32 => self.in_option_sentinel64_f32(AdapterType::F32),
Descriptor::F64 => self.in_option_native(ValType::F64),
Descriptor::I64 | Descriptor::U64 => self.in_option_native(ValType::I64),
Descriptor::I128 => {
self.instruction(
&[AdapterType::S128.option()],
Instruction::OptionInt128ToWasm,
&[AdapterType::I32, AdapterType::I64, AdapterType::I64],
);
}
Descriptor::U128 => {
self.instruction(
&[AdapterType::U128.option()],
Instruction::OptionInt128ToWasm,
&[AdapterType::I32, AdapterType::I64, AdapterType::I64],
);
}
Descriptor::Boolean => {
self.instruction(
&[AdapterType::Bool.option()],
Expand Down
12 changes: 7 additions & 5 deletions crates/cli-support/src/wit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -894,18 +894,20 @@ impl<'a> Context<'a> {
}

fn enum_(&mut self, enum_: decode::Enum<'_>) -> Result<(), Error> {
let signed = enum_.signed;
let aux = AuxEnum {
name: enum_.name.to_string(),
comments: concatenate_comments(&enum_.comments),
variants: enum_
.variants
.iter()
.map(|v| {
(
v.name.to_string(),
v.value,
concatenate_comments(&v.comments),
)
let value = if signed {
v.value as i32 as i64
} else {
v.value as i64
};
(v.name.to_string(), value, concatenate_comments(&v.comments))
})
.collect(),
generate_typescript: enum_.generate_typescript,
Expand Down
2 changes: 1 addition & 1 deletion crates/cli-support/src/wit/nonstandard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ pub struct AuxEnum {
pub comments: String,
/// A list of variants with their name, value and comments
/// and whether typescript bindings should be generated for each variant
pub variants: Vec<(String, u32, String)>,
pub variants: Vec<(String, i64, String)>,
/// Whether typescript bindings should be generated for this enum.
pub generate_typescript: bool,
}
Expand Down
30 changes: 30 additions & 0 deletions crates/cli-support/src/wit/outgoing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,20 @@ impl InstructionBuilder<'_, '_> {
Descriptor::U32 => self.outgoing_i32(AdapterType::U32),
Descriptor::I64 => self.outgoing_i64(AdapterType::I64),
Descriptor::U64 => self.outgoing_i64(AdapterType::U64),
Descriptor::I128 => {
self.instruction(
&[AdapterType::I64, AdapterType::I64],
Instruction::WasmToInt128 { signed: true },
&[AdapterType::S128],
);
}
Descriptor::U128 => {
self.instruction(
&[AdapterType::I64, AdapterType::I64],
Instruction::WasmToInt128 { signed: false },
&[AdapterType::U128],
);
}
Descriptor::F32 => {
self.get(AdapterType::F32);
self.output.push(AdapterType::F32);
Expand Down Expand Up @@ -267,6 +281,20 @@ impl InstructionBuilder<'_, '_> {
Descriptor::U64 => self.option_native(false, ValType::I64),
Descriptor::F32 => self.out_option_sentinel64(AdapterType::F32),
Descriptor::F64 => self.option_native(true, ValType::F64),
Descriptor::I128 => {
self.instruction(
&[AdapterType::I32, AdapterType::I64, AdapterType::I64],
Instruction::OptionWasmToInt128 { signed: true },
&[AdapterType::S128.option()],
);
}
Descriptor::U128 => {
self.instruction(
&[AdapterType::I32, AdapterType::I64, AdapterType::I64],
Instruction::OptionWasmToInt128 { signed: false },
&[AdapterType::U128.option()],
);
}
Descriptor::Boolean => {
self.instruction(
&[AdapterType::I32],
Expand Down Expand Up @@ -360,6 +388,8 @@ impl InstructionBuilder<'_, '_> {
| Descriptor::F64
| Descriptor::I64
| Descriptor::U64
| Descriptor::I128
| Descriptor::U128
| Descriptor::Boolean
| Descriptor::Char
| Descriptor::Enum { .. }
Expand Down
Loading

0 comments on commit baedfaf

Please sign in to comment.