Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add math-related intrinsics/functions for JsValues #2629

Merged
merged 27 commits into from
Sep 2, 2021
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
40d38f3
Allow accessing JS math operators from Rust
Jules-Bertholet Jul 19, 2021
6277e62
Add `typeof` and `in` methods/intrinsics
Jules-Bertholet Jul 19, 2021
098aef7
Add comparison operators
Jules-Bertholet Jul 19, 2021
2587439
Remove Object.is intrinsic
Jules-Bertholet Jul 19, 2021
9184409
Make conversion into f64 faillible
Jules-Bertholet Jul 19, 2021
9aee606
Add `#[inline]`s
Jules-Bertholet Jul 19, 2021
945bcfd
Fix methods to make them take references
Jules-Bertholet Jul 21, 2021
cd65747
cargo fmt
Jules-Bertholet Jul 21, 2021
073dd08
Add BigInt to js-sys (no constructor yet)
Jules-Bertholet Jul 21, 2021
2b59886
Remove useless import
Jules-Bertholet Jul 23, 2021
6a5681f
Fix UI tests
Jules-Bertholet Jul 21, 2021
09ebff7
Add BigInt constructor
Jules-Bertholet Jul 23, 2021
5bcb6da
Allow catching `to_string` method for BigInt
Jules-Bertholet Jul 23, 2021
d304dec
Fix tests again
Jules-Bertholet Jul 23, 2021
55a22d3
Add inlines
Jules-Bertholet Jul 23, 2021
2157e95
Rework PartialEq impl
Jules-Bertholet Jul 23, 2021
1cc0f5b
Implement FromStr for BigInt
Jules-Bertholet Jul 23, 2021
118dab0
Add more inlines
Jules-Bertholet Jul 23, 2021
11c7de3
Update formatting
Jules-Bertholet Jul 23, 2021
747459a
Add more trait impls and feature for integration with `rust-num`
Jules-Bertholet Jul 31, 2021
f976076
Add `PartialOrd` and `Ord` impls for more types
Jules-Bertholet Aug 6, 2021
7185873
Cargo fmt
Jules-Bertholet Aug 27, 2021
5455ae3
Remove `num-traits` from `wasm-bindgen`, integrate `js-sys` with `rus…
Jules-Bertholet Sep 1, 2021
589532e
Update Cargo.toml
Jules-Bertholet Sep 2, 2021
087d291
Update Rust version for CI (to allow proc-macro2 to build again)
Jules-Bertholet Sep 2, 2021
76b8065
Fix link in Markdown
Jules-Bertholet Sep 2, 2021
2dc02ff
Remove all `rust-num` code from `js-sys`
Jules-Bertholet Sep 2, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ jobs:
steps:
- template: ci/azure-install-rust.yml
parameters:
toolchain: nightly-2021-05-09
toolchain: nightly-2021-09-02
- template: ci/azure-install-node.yml
- script: cargo test --target wasm32-unknown-unknown --features nightly --test wasm

Expand Down Expand Up @@ -210,7 +210,7 @@ jobs:
steps:
- template: ci/azure-install-rust.yml
parameters:
toolchain: nightly-2021-05-09
toolchain: nightly-2021-09-02
- script: rustup component add rust-src
displayName: "install rust-src"
- script: |
Expand Down
78 changes: 78 additions & 0 deletions crates/cli-support/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ intrinsics! {
#[symbol = "__wbindgen_jsval_eq"]
#[signature = fn(ref_externref(), ref_externref()) -> Boolean]
JsvalEq,
#[symbol = "__wbindgen_jsval_loose_eq"]
#[signature = fn(ref_externref(), ref_externref()) -> Boolean]
JsvalLooseEq,
#[symbol = "__wbindgen_is_function"]
#[signature = fn(ref_externref()) -> Boolean]
IsFunction,
Expand All @@ -103,9 +106,81 @@ intrinsics! {
#[symbol = "__wbindgen_is_string"]
#[signature = fn(ref_externref()) -> Boolean]
IsString,
#[symbol = "__wbindgen_is_bigint"]
#[signature = fn(ref_externref()) -> Boolean]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why special-case this? __wbindgen_typeof can be used to implement this.

Copy link
Contributor Author

@Jules-Bertholet Jules-Bertholet Jul 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@crimsoncodes0 The other types are already special-cased, so I special-cased this one too for consistency
Edit: also, maybe JS engines might have special optimizations for typeof to avoid a full string comparison? (No idea, but presumably they could do this)

IsBigInt,
#[symbol = "__wbindgen_typeof"]
#[signature = fn(ref_externref()) -> Externref]
Typeof,
#[symbol = "__wbindgen_in"]
#[signature = fn(ref_externref(), ref_externref()) -> Boolean]
In,
#[symbol = "__wbindgen_is_falsy"]
#[signature = fn(ref_externref()) -> Boolean]
IsFalsy,
#[symbol = "__wbindgen_as_number"]
#[signature = fn(ref_externref()) -> F64]
AsNumber,
#[symbol = "__wbindgen_try_into_number"]
#[signature = fn(ref_externref()) -> Externref]
TryIntoNumber,
#[symbol = "__wbindgen_neg"]
#[signature = fn(ref_externref()) -> Externref]
Neg,
#[symbol = "__wbindgen_bit_and"]
#[signature = fn(ref_externref(), ref_externref()) -> Externref]
Copy link

@ghost ghost Jul 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These bitwise operators always return an i32, besides unsigned_shr, which yields u32.
They're currently typed as yielding Externref.

But, on another note, these are already native Rust operators, why use the significantly slower, more unsound JS operators? Is there anything that can't be done without these?

Copy link
Contributor Author

@Jules-Bertholet Jules-Bertholet Jul 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@crimsoncodes0 These operators only return 32-bit ints when passed JS numbers. When passed bigints they return bigints. The only exception is >>> (unsigned_shr), which does not accept bigints; I included it for completeness but if it's deemed unnecessary I can remove it

BitAnd,
#[symbol = "__wbindgen_bit_or"]
#[signature = fn(ref_externref(), ref_externref()) -> Externref]
BitOr,
#[symbol = "__wbindgen_bit_xor"]
#[signature = fn(ref_externref(), ref_externref()) -> Externref]
BitXor,
#[symbol = "__wbindgen_bit_not"]
#[signature = fn(ref_externref()) -> Externref]
BitNot,
#[symbol = "__wbindgen_shl"]
#[signature = fn(ref_externref(), ref_externref()) -> Externref]
Shl,
#[symbol = "__wbindgen_shr"]
#[signature = fn(ref_externref(), ref_externref()) -> Externref]
Shr,
#[symbol = "__wbindgen_unsigned_shr"]
#[signature = fn(ref_externref(), ref_externref()) -> U32]
UnsignedShr,
#[symbol = "__wbindgen_add"]
#[signature = fn(ref_externref(), ref_externref()) -> Externref]
Add,
#[symbol = "__wbindgen_sub"]
#[signature = fn(ref_externref(), ref_externref()) -> Externref]
Sub,
#[symbol = "__wbindgen_div"]
#[signature = fn(ref_externref(), ref_externref()) -> Externref]
Div,
#[symbol = "__wbindgen_checked_div"]
#[signature = fn(ref_externref(), ref_externref()) -> Externref]
CheckedDiv,
#[symbol = "__wbindgen_mul"]
#[signature = fn(ref_externref(), ref_externref()) -> Externref]
Mul,
#[symbol = "__wbindgen_rem"]
#[signature = fn(ref_externref(), ref_externref()) -> Externref]
Rem,
#[symbol = "__wbindgen_pow"]
#[signature = fn(ref_externref(), ref_externref()) -> Externref]
Pow,
#[symbol = "__wbindgen_lt"]
#[signature = fn(ref_externref(), ref_externref()) -> Boolean]
LT,
#[symbol = "__wbindgen_le"]
#[signature = fn(ref_externref(), ref_externref()) -> Boolean]
LE,
#[symbol = "__wbindgen_ge"]
#[signature = fn(ref_externref(), ref_externref()) -> Boolean]
GE,
#[symbol = "__wbindgen_gt"]
#[signature = fn(ref_externref(), ref_externref()) -> Boolean]
GT,
#[symbol = "__wbindgen_object_clone_ref"]
#[signature = fn(ref_externref()) -> Externref]
ObjectCloneRef,
Expand All @@ -118,6 +193,9 @@ intrinsics! {
#[symbol = "__wbindgen_number_new"]
#[signature = fn(F64) -> Externref]
NumberNew,
#[symbol = "__wbindgen_bigint_new"]
#[signature = fn(ref_string()) -> Externref]
BigIntNew,
#[symbol = "__wbindgen_string_new"]
#[signature = fn(ref_string()) -> Externref]
StringNew,
Expand Down
130 changes: 130 additions & 0 deletions crates/cli-support/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2907,6 +2907,11 @@ impl<'a> Context<'a> {
format!("{} === {}", args[0], args[1])
}

Intrinsic::JsvalLooseEq => {
assert_eq!(args.len(), 2);
format!("{} == {}", args[0], args[1])
}

Intrinsic::IsFunction => {
assert_eq!(args.len(), 1);
format!("typeof({}) === 'function'", args[0])
Expand Down Expand Up @@ -2938,11 +2943,131 @@ impl<'a> Context<'a> {
format!("typeof({}) === 'string'", args[0])
}

Intrinsic::IsBigInt => {
assert_eq!(args.len(), 1);
format!("typeof({}) === 'bigint'", args[0])
}

Intrinsic::Typeof => {
assert_eq!(args.len(), 1);
format!("typeof {}", args[0])
}

Intrinsic::In => {
assert_eq!(args.len(), 2);
format!("{} in {}", args[0], args[1])
}

Intrinsic::IsFalsy => {
assert_eq!(args.len(), 1);
format!("!{}", args[0])
}

Intrinsic::AsNumber => {
assert_eq!(args.len(), 1);
format!("+{}", args[0])
}

Intrinsic::TryIntoNumber => {
assert_eq!(args.len(), 1);
format!("try {{ +{} }} catch(e) {{ e }}", args[0])
}

Intrinsic::Neg => {
assert_eq!(args.len(), 1);
format!("-{}", args[0])
}

Intrinsic::BitAnd => {
assert_eq!(args.len(), 2);
format!("{} & {}", args[0], args[1])
}

Intrinsic::BitOr => {
assert_eq!(args.len(), 2);
format!("{} | {}", args[0], args[1])
}

Intrinsic::BitXor => {
assert_eq!(args.len(), 2);
format!("{} ^ {}", args[0], args[1])
}

Intrinsic::BitNot => {
assert_eq!(args.len(), 1);
format!("~{}", args[0])
}

Intrinsic::Shl => {
assert_eq!(args.len(), 2);
format!("{} << {}", args[0], args[1])
}

Intrinsic::Shr => {
assert_eq!(args.len(), 2);
format!("{} >> {}", args[0], args[1])
}

Intrinsic::UnsignedShr => {
assert_eq!(args.len(), 2);
format!("{} >>> {}", args[0], args[1])
}

Intrinsic::Add => {
assert_eq!(args.len(), 2);
format!("{} + {}", args[0], args[1])
}

Intrinsic::Sub => {
assert_eq!(args.len(), 2);
format!("{} - {}", args[0], args[1])
}

Intrinsic::Div => {
assert_eq!(args.len(), 2);
format!("{} / {}", args[0], args[1])
}

Intrinsic::CheckedDiv => {
assert_eq!(args.len(), 2);
format!("try {{ {} / {} }} catch (e) {{ if (e instanceof RangeError) {{ e }} else {{ throw e }} }}", args[0], args[1])
}

Intrinsic::Mul => {
assert_eq!(args.len(), 2);
format!("{} * {}", args[0], args[1])
}

Intrinsic::Rem => {
assert_eq!(args.len(), 2);
format!("{} % {}", args[0], args[1])
}

Intrinsic::Pow => {
assert_eq!(args.len(), 2);
format!("{} ** {}", args[0], args[1])
}

Intrinsic::LT => {
assert_eq!(args.len(), 2);
format!("{} < {}", args[0], args[1])
}

Intrinsic::LE => {
assert_eq!(args.len(), 2);
format!("{} <= {}", args[0], args[1])
}

Intrinsic::GE => {
assert_eq!(args.len(), 2);
format!("{} >= {}", args[0], args[1])
}

Intrinsic::GT => {
assert_eq!(args.len(), 2);
format!("{} > {}", args[0], args[1])
}

Intrinsic::ObjectCloneRef => {
assert_eq!(args.len(), 1);
args[0].clone()
Expand All @@ -2968,6 +3093,11 @@ impl<'a> Context<'a> {
args[0].clone()
}

Intrinsic::BigIntNew => {
assert_eq!(args.len(), 1);
format!("BigInt({})", args[0])
}

Intrinsic::StringNew => {
assert_eq!(args.len(), 1);
args[0].clone()
Expand Down
5 changes: 5 additions & 0 deletions crates/js-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@ edition = "2018"
test = false
doctest = false

[features]
rust-num = ["num-bigint", "num-traits"]

[dependencies]
wasm-bindgen = { path = "../..", version = "0.2.76" }
num-bigint = { version = "0.4.1", optional = true }
num-traits = { version = "0.2.14", optional = true }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry but personally I do not want to add new public dependencies to these crates. There is no story for landing breaking changes to js-sys at this time and having new public dependencies increases the risk that a breaking change may be needed (in case these deps have a major-version-bump)

I realize these are optional but it's still part of the public API and something that I'm not willing to commit to.


[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test = { path = '../test', version = '=0.3.26' }
Expand Down
Loading