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

Conversation

Jules-Bertholet
Copy link
Contributor

@Jules-Bertholet Jules-Bertholet commented Jul 19, 2021

Adds handling for BigInt, among other things.

@alexcrichton
Copy link
Contributor

Thanks! Overall though I'd prefer to keep the set of intrinsics and such to a minimum unless there's a good reason to expand things. Could you elaborate a bit more on the motivation for this? It seems, for example, that some of the conversions (e.g. From<JsValue> for f64 aren't necessarily idiomatic in Rust since they can be fallible. If it's applying to a specific JS operation then ideally that'd either be done with the Reflect structure from js-sys but if necessary it seems fine to have an intrinsic.

@Jules-Bertholet
Copy link
Contributor Author

@alexcrichton JS operators generally don't have corresponding methods, so Reflect isn't an option in those cases. I could remove the Object.is intrinsic, though. From definitely shouldn't be fallible, I'll fix that. But do you think it's a problem if traits like Add are fallible?

@@ -102,9 +105,75 @@ 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)

#[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

@Jules-Bertholet
Copy link
Contributor Author

I've removed the Object.is intrinsic and made the From<JsValue> f64 impl into a TryFrom

@alexcrichton
Copy link
Contributor

Can you elaborate more on the motivation for this? This is a lot of library support with a lot of traits and a lot of intrinsics. It's a good deal to maintain in what should ideally be a pretty lean core library.

@Jules-Bertholet
Copy link
Contributor Author

Jules-Bertholet commented Jul 20, 2021

The motivation for this is to allow performing mathematical operations on JS bigints. There currently isn't any other method in wasm-bindgen for handling these values. And the only way to add that functionality is to allow accessing the JS math operators, because there aren't any equivalent methods. I plan to make a follow-up PR to add a BigInt type to js-sys to expose this functionality in a more strongly-typed manner, so I'm not particularly attached to the current API in this PR. If it's deemed better to expose these as methods on JsValue rather than as trait impls, that's fine.

The only two intrinsics this PR adds that aren't useful for bigints are the unary +, >>>, and in. I added these for completeness (if every other JS operator is going to be made available, why leave out these three?), but I'm not attached to them. I suppose + and >>> could be marginally useful when dealing with objects with a custom Symbol.toPrimitive, but I don't think that's a very common use case.

@Jules-Bertholet Jules-Bertholet force-pushed the jsvalue-math branch 2 times, most recently from 98d4a2d to f72e74b Compare July 21, 2021 09:23
@Jules-Bertholet
Copy link
Contributor Author

follow-up PR to add a BigInt type to js-sys to expose this functionality in a more strongly-typed manner

I've been working on this, but I've run into a roadblock: the BigInt() constructor doesn't use new, and as far as I can tell wasm-bindgen doesn't have any facilities to account for this.

@alexcrichton
Copy link
Contributor

Ah ok, if possible then I think it would be best to bind BigInt in js-sys without adding new features to wasm-bindgen itself. Perhaps we could try to work through the issues that you're seeing there?

For example for the BigInt constructor you could do something like:

impl BigInt {
    pub fn new(arg: &JsValue) -> BigInt {
        // manually call the `BigInt` name bound as a function
    }
}

where it's not necessarily pure extern "C" { ... } blocks but that's ok.

@Jules-Bertholet Jules-Bertholet force-pushed the jsvalue-math branch 6 times, most recently from 09fae07 to ac4bb37 Compare July 23, 2021 16:07
@Jules-Bertholet
Copy link
Contributor Author

Ready for review

@Jules-Bertholet Jules-Bertholet force-pushed the jsvalue-math branch 4 times, most recently from 7b8f8f5 to 14fec9b Compare August 6, 2021 11:59
@trevyn
Copy link
Contributor

trevyn commented Aug 27, 2021

I think it would be best to bind BigInt in js-sys without adding new features to wasm-bindgen itself.

@Jules-Bertholet Are you still working to get this PR merged? I have a need for a straightforward BigInt binding, and it looks like you've included that here.

xref: #1087

@Jules-Bertholet
Copy link
Contributor Author

@trevyn This PR should be ready for review

@trevyn
Copy link
Contributor

trevyn commented Aug 27, 2021

This PR should be ready for review

Thanks! ping @alexcrichton

@trevyn
Copy link
Contributor

trevyn commented Aug 28, 2021

This BigInt support is working perfectly for me! 👍🏼

Copy link
Contributor

@alexcrichton alexcrichton left a comment

Choose a reason for hiding this comment

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

Sorry for the delay. I'm not overly in love with how this is such a large increase in the API surface area, but I dunno I don't really have anything against it. I would prefer to avoid the num-traits dep but other than that seems fine I guess?

Cargo.toml Outdated
@@ -40,6 +40,7 @@ wasm-bindgen-macro = { path = "crates/macro", version = "=0.2.76" }
serde = { version = "1.0", optional = true }
serde_json = { version = "1.0", optional = true }
cfg-if = "1.0.0"
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.

This is a small enough addition could this be a method instead of a trait implementation?

@Jules-Bertholet
Copy link
Contributor Author

@alexcrichton The num-traits dep is just there to allow easier integration with other Rust crates that also use num-traits, you don't miss out on features by not enabling it. There's a standalone pow method you can use instead of its Pow trait, and all of the other trait impls are trivial.

@alexcrichton
Copy link
Contributor

Makes sense, yeah, but I'd prefer to leave it out and keep wasm-bindgen at least somewhat slim in deps.

[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.

@alexcrichton alexcrichton merged commit d6d056c into rustwasm:master Sep 2, 2021
@Jules-Bertholet Jules-Bertholet deleted the jsvalue-math branch September 2, 2021 18:51
ishitatsuyuki added a commit to ishitatsuyuki/wasm-bindgen that referenced this pull request Jul 29, 2022
Using BigInt as the macro parameters leads to absurd signatures like
slices of BigInt objects (can't exist). Instead, just use the numeric
types. bindgen already converts them to bigint when appropriate.

Closes: rustwasm#3009
Fixes: d6d056c ("Add math-related intrinsics/functions for `JsValue`s (rustwasm#2629)")
ishitatsuyuki added a commit to ishitatsuyuki/wasm-bindgen that referenced this pull request Jul 29, 2022
Using BigInt as the macro parameters leads to absurd signatures like
slices of BigInt objects (can't exist). Instead, just use the numeric
types. bindgen already converts them to bigint when appropriate.

Closes: rustwasm#3009
Fixes: d6d056c ("Add math-related intrinsics/functions for `JsValue`s (rustwasm#2629)")
alexcrichton pushed a commit that referenced this pull request Jul 29, 2022
Using BigInt as the macro parameters leads to absurd signatures like
slices of BigInt objects (can't exist). Instead, just use the numeric
types. bindgen already converts them to bigint when appropriate.

Closes: #3009
Fixes: d6d056c ("Add math-related intrinsics/functions for `JsValue`s (#2629)")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants