From 40d38f39db9f19dd087e5843a154e1435df56362 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 19 Jul 2021 11:03:35 +0200 Subject: [PATCH 01/27] Allow accessing JS math operators from Rust Useful for dealing with JS `BigInt`s --- crates/cli-support/src/intrinsic.rs | 54 ++++++ crates/cli-support/src/js/mod.rs | 90 +++++++++ src/lib.rs | 291 +++++++++++++++++++++++++++- 3 files changed, 433 insertions(+), 2 deletions(-) diff --git a/crates/cli-support/src/intrinsic.rs b/crates/cli-support/src/intrinsic.rs index 748e313f950..714d09cbf32 100644 --- a/crates/cli-support/src/intrinsic.rs +++ b/crates/cli-support/src/intrinsic.rs @@ -85,6 +85,12 @@ 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_jsval_is"] + #[signature = fn(ref_externref(), ref_externref()) -> Boolean] + JsvalStrictEq, #[symbol = "__wbindgen_is_function"] #[signature = fn(ref_externref()) -> Boolean] IsFunction, @@ -103,9 +109,57 @@ intrinsics! { #[symbol = "__wbindgen_is_string"] #[signature = fn(ref_externref()) -> Boolean] IsString, + #[symbol = "__wbindgen_is_bigint"] + #[signature = fn(ref_externref()) -> Boolean] + IsBigint, #[symbol = "__wbindgen_is_falsy"] #[signature = fn(ref_externref()) -> Boolean] IsFalsy, + #[symbol = "__wbindgen_as_number"] + #[signature = fn(ref_externref()) -> F64] + AsNumber, + #[symbol = "__wbindgen_neg"] + #[signature = fn(ref_externref()) -> Externref] + Neg, + #[symbol = "__wbindgen_bit_and"] + #[signature = fn(ref_externref(), ref_externref()) -> Externref] + 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_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_object_clone_ref"] #[signature = fn(ref_externref()) -> Externref] ObjectCloneRef, diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 1e12d158c43..022d2793148 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -2907,6 +2907,16 @@ impl<'a> Context<'a> { format!("{} === {}", args[0], args[1]) } + Intrinsic::JsvalLooseEq => { + assert_eq!(args.len(), 2); + format!("{} == {}", args[0], args[1]) + } + + Intrinsic::JsvalStrictEq => { + assert_eq!(args.len(), 2); + format!("Object.is({}, {})", args[0], args[1]) + } + Intrinsic::IsFunction => { assert_eq!(args.len(), 1); format!("typeof({}) === 'function'", args[0]) @@ -2938,11 +2948,91 @@ impl<'a> Context<'a> { format!("typeof({}) === 'string'", args[0]) } + Intrinsic::IsBigint => { + assert_eq!(args.len(), 1); + format!("typeof({}) === 'bigint'", args[0]) + } + Intrinsic::IsFalsy => { assert_eq!(args.len(), 1); format!("!{}", args[0]) } + Intrinsic::AsNumber => { + assert_eq!(args.len(), 1); + format!("+{}", 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::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::ObjectCloneRef => { assert_eq!(args.len(), 1); args[0].clone() diff --git a/src/lib.rs b/src/lib.rs index f0ee406445e..08f56707de7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,10 @@ use core::fmt; use core::marker; use core::mem; -use core::ops::{Deref, DerefMut}; +use core::ops::{ + Add, BitAnd, BitOr, BitXor, Deref, DerefMut, Div, Mul, Neg, Not, Rem, Shl, Shr, Sub, +}; +use core::u32; use crate::convert::{FromWasmAbi, WasmOptionalF64, WasmSlice}; @@ -317,6 +320,12 @@ impl JsValue { unsafe { __wbindgen_is_function(self.idx) == 1 } } + /// Tests whether the type of this JS value is `function`. + #[inline] + pub fn is_bigint(&self) -> bool { + unsafe { __wbindgen_is_bigint(self.idx) == 1 } + } + /// Tests whether the value is ["truthy"]. /// /// ["truthy"]: https://developer.mozilla.org/en-US/docs/Glossary/Truthy @@ -343,11 +352,51 @@ impl JsValue { String::from_utf8_unchecked(data) } } + + /// Compare two `JsValue`s for equality, using the `==` operator in JS. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Equality) + pub fn loose_eq(&self, other: &Self) -> bool { + unsafe { __wbindgen_jsval_loose_eq(self.idx, other.idx) != 0 } + } + + /// Compares two `JsValue`s for equality, using `Object.is`. + /// This comparison method fulfills the requirements of the [`Eq`](std::cmp::Eq) trait. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) + pub fn is(&self, other: &Self) -> bool { + unsafe { __wbindgen_jsval_is(self.idx, other.idx) != 0 } + } + + /// Applies the unary `~` JS operator on a `JsValue`. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_NOT) + #[inline] + pub fn bit_not(self) -> JsValue { + unsafe { JsValue::_new( __wbindgen_bit_not(self.idx)) } + } + + /// Applies the binary `>>>` JS operator on the two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unsigned_right_shift) + pub fn unsigned_shr(self, rhs: &Self) -> u32 { + unsafe { __wbindgen_unsigned_shr(self.idx, rhs.idx) } + } + + /// Applies the binary `**` JS operator on the two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Exponentiation) + pub fn pow(self, rhs: &Self) -> Self { + unsafe { JsValue::_new(__wbindgen_pow(self.idx, rhs.idx)) } + } } impl PartialEq for JsValue { + /// Compares two `JsValue`s for equality, using the `===` operator in JS. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality) #[inline] - fn eq(&self, other: &JsValue) -> bool { + fn eq(&self, other: &Self) -> bool { unsafe { __wbindgen_jsval_eq(self.idx, other.idx) != 0 } } } @@ -388,6 +437,224 @@ if_std! { } } +macro_rules! forward_deref_unop { + (impl $imp:ident, $method:ident for $t:ty) => { + impl $imp for $t { + type Output = <&'static $t as $imp>::Output; + + #[inline] + fn $method(self) -> <&'static $t as $imp>::Output { + $imp::$method(&self) + } + } + }; +} + +macro_rules! forward_deref_binop { + (impl $imp:ident, $method:ident for $t:ty, $u:ty) => { + impl<'a> $imp<$u> for &'a $t { + type Output = <&'static $t as $imp<&'static $u>>::Output; + #[inline] + fn $method(self, other: $u) -> <&'static $t as $imp<&'static $u>>::Output { + $imp::$method(self, &other) + } + } + + impl $imp<&$u> for $t { + type Output = <&'static $t as $imp<&'static $u>>::Output; + + #[inline] + fn $method(self, other: &$u) -> <&'static $t as $imp<&'static $u>>::Output { + $imp::$method(&self, other) + } + } + + impl $imp<$u> for $t { + type Output = <&'static $t as $imp<&'static $u>>::Output; + + #[inline] + fn $method(self, other: $u) -> <&'static $t as $imp<&'static $u>>::Output { + $imp::$method(&self, &other) + } + } + }; +} + +impl Not for &JsValue { + type Output = bool; + + /// Applies the `!` JS operator on a `JsValue`. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_NOT) + #[inline] + fn not(self) -> Self::Output { + JsValue::is_falsy(self) + } +} + +forward_deref_unop!(impl Not, not for JsValue); + +impl From for f64 { + /// Applies the unary `+` JS operator on a `JsValue`. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus) + fn from(val: JsValue) -> Self { + (&val).into() + } +} + +impl From<&JsValue> for f64 { + /// Applies the unary `+` JS operator on a `JsValue`. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus) + fn from(val: &JsValue) -> Self { + unsafe { __wbindgen_as_number(val.idx) } + } +} + +impl Neg for &JsValue { + type Output = JsValue; + + /// Applies the unary `-` JS operator on a `JsValue`. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_negation) + fn neg(self) -> Self::Output { + unsafe { JsValue::_new(__wbindgen_neg(self.idx)) } + } +} + +forward_deref_unop!(impl Neg, neg for JsValue); + +impl BitAnd for &JsValue { + type Output = JsValue; + + /// Applies the binary `&` JS operator on two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_AND) + fn bitand(self, rhs: Self) -> Self::Output { + unsafe { JsValue::_new(__wbindgen_bit_and(self.idx, rhs.idx)) } + } +} + +forward_deref_binop!(impl BitAnd, bitand for JsValue, JsValue); + +impl BitOr for &JsValue { + type Output = JsValue; + + /// Applies the binary `|` JS operator on two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_OR) + fn bitor(self, rhs: Self) -> Self::Output { + unsafe { JsValue::_new(__wbindgen_bit_or(self.idx, rhs.idx)) } + } +} + +forward_deref_binop!(impl BitOr, bitor for JsValue, JsValue); + +impl BitXor for &JsValue { + type Output = JsValue; + + /// Applies the binary `^` JS operator on two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_XOR) + fn bitxor(self, rhs: Self) -> Self::Output { + unsafe { JsValue::_new(__wbindgen_bit_xor(self.idx, rhs.idx)) } + } +} + +forward_deref_binop!(impl BitXor, bitxor for JsValue, JsValue); + +impl Shl for &JsValue { + type Output = JsValue; + + /// Applies the binary `<<` JS operator on two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Left_shift) + fn shl(self, rhs: Self) -> Self::Output { + unsafe { JsValue::_new(__wbindgen_shl(self.idx, rhs.idx)) } + } +} + +forward_deref_binop!(impl Shl, shl for JsValue, JsValue); + +impl Shr for &JsValue { + type Output = JsValue; + + /// Applies the binary `>>` JS operator on two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Right_shift) + fn shr(self, rhs: Self) -> Self::Output { + unsafe { JsValue::_new(__wbindgen_shr(self.idx, rhs.idx)) } + } +} + +forward_deref_binop!(impl Shr, shr for JsValue, JsValue); + +impl Add for &JsValue { + type Output = JsValue; + + /// Applies the binary `+` JS operator on two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Addition) + fn add(self, rhs: Self) -> Self::Output { + unsafe { JsValue::_new(__wbindgen_add(self.idx, rhs.idx)) } + } +} + +forward_deref_binop!(impl Add, add for JsValue, JsValue); + +impl Sub for &JsValue { + type Output = JsValue; + + /// Applies the binary `-` JS operator on two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Subtraction) + fn sub(self, rhs: Self) -> Self::Output { + unsafe { JsValue::_new(__wbindgen_sub(self.idx, rhs.idx)) } + } +} + +forward_deref_binop!(impl Sub, sub for JsValue, JsValue); + +impl Div for &JsValue { + type Output = JsValue; + + /// Applies the binary `/` JS operator on two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Division) + fn div(self, rhs: Self) -> Self::Output { + unsafe { JsValue::_new(__wbindgen_div(self.idx, rhs.idx)) } + } +} + +forward_deref_binop!(impl Div, div for JsValue, JsValue); + +impl Mul for &JsValue { + type Output = JsValue; + + /// Applies the binary `*` JS operator on two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Multiplication) + fn mul(self, rhs: Self) -> Self::Output { + unsafe { JsValue::_new(__wbindgen_mul(self.idx, rhs.idx)) } + } +} + +forward_deref_binop!(impl Mul, mul for JsValue, JsValue); + +impl Rem for &JsValue { + type Output = JsValue; + + /// Applies the binary `%` JS operator on two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Remainder) + fn rem(self, rhs: Self) -> Self::Output { + unsafe { JsValue::_new(__wbindgen_rem(self.idx, rhs.idx)) } + } +} + +forward_deref_binop!(impl Rem, rem for JsValue, JsValue); + impl<'a> From<&'a str> for JsValue { #[inline] fn from(s: &'a str) -> JsValue { @@ -503,7 +770,23 @@ externs! { fn __wbindgen_is_object(idx: u32) -> u32; fn __wbindgen_is_function(idx: u32) -> u32; fn __wbindgen_is_string(idx: u32) -> u32; + fn __wbindgen_is_bigint(idx: u32) -> u32; fn __wbindgen_is_falsy(idx: u32) -> u32; + fn __wbindgen_as_number(idx: u32) -> f64; + fn __wbindgen_neg(idx: u32) -> u32; + fn __wbindgen_bit_and(a: u32, b: u32) -> u32; + fn __wbindgen_bit_or(a: u32, b: u32) -> u32; + fn __wbindgen_bit_xor(a: u32, b: u32) -> u32; + fn __wbindgen_bit_not(idx: u32) -> u32; + fn __wbindgen_shl(a: u32, b: u32) -> u32; + fn __wbindgen_shr(a: u32, b: u32) -> u32; + fn __wbindgen_unsigned_shr(a: u32, b: u32) -> u32; + fn __wbindgen_add(a: u32, b: u32) -> u32; + fn __wbindgen_sub(a: u32, b: u32) -> u32; + fn __wbindgen_div(a: u32, b: u32) -> u32; + fn __wbindgen_mul(a: u32, b: u32) -> u32; + fn __wbindgen_rem(a: u32, b: u32) -> u32; + fn __wbindgen_pow(a: u32, b: u32) -> u32; fn __wbindgen_number_get(idx: u32) -> WasmOptionalF64; fn __wbindgen_boolean_get(idx: u32) -> u32; @@ -522,6 +805,10 @@ externs! { fn __wbindgen_json_parse(ptr: *const u8, len: usize) -> u32; fn __wbindgen_json_serialize(idx: u32) -> WasmSlice; fn __wbindgen_jsval_eq(a: u32, b: u32) -> u32; + fn __wbindgen_jsval_loose_eq(a: u32, b: u32) -> u32; + fn __wbindgen_jsval_is(a: u32, b: u32) -> u32; + + fn __wbindgen_not(idx: u32) -> u32; fn __wbindgen_memory() -> u32; fn __wbindgen_module() -> u32; From 6277e6281358eaf99eea4c7eb1a27cb08eb505b5 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 19 Jul 2021 12:12:49 +0200 Subject: [PATCH 02/27] Add `typeof` and `in` methods/intrinsics --- crates/cli-support/src/intrinsic.rs | 6 ++++++ crates/cli-support/src/js/mod.rs | 10 ++++++++++ src/lib.rs | 22 +++++++++++++++++++++- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/crates/cli-support/src/intrinsic.rs b/crates/cli-support/src/intrinsic.rs index 714d09cbf32..cb4357098cc 100644 --- a/crates/cli-support/src/intrinsic.rs +++ b/crates/cli-support/src/intrinsic.rs @@ -112,6 +112,12 @@ intrinsics! { #[symbol = "__wbindgen_is_bigint"] #[signature = fn(ref_externref()) -> Boolean] 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, diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 022d2793148..ba433ad4b58 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -2953,6 +2953,16 @@ impl<'a> Context<'a> { 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]) diff --git a/src/lib.rs b/src/lib.rs index 08f56707de7..40fc4c8a489 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -326,6 +326,22 @@ impl JsValue { unsafe { __wbindgen_is_bigint(self.idx) == 1 } } + /// Applies the unary `typeof` JS operator on a `JsValue`. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof) + #[inline] + pub fn js_typeof(&self) -> JsValue { + unsafe { JsValue::_new(__wbindgen_typeof(self.idx)) } + } + + /// Applies the binary `in` JS operator on the two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof) + #[inline] + pub fn js_in(&self, obj: &JsValue) -> bool { + unsafe { __wbindgen_in(self.idx, obj.idx) == 1 } + } + /// Tests whether the value is ["truthy"]. /// /// ["truthy"]: https://developer.mozilla.org/en-US/docs/Glossary/Truthy @@ -342,7 +358,7 @@ impl JsValue { unsafe { __wbindgen_is_falsy(self.idx) == 1 } } - /// Get a string representation of the JavaScript object for debugging + /// Get a string representation of the JavaScript object for debugging. #[cfg(feature = "std")] fn as_debug_string(&self) -> String { unsafe { @@ -771,6 +787,10 @@ externs! { fn __wbindgen_is_function(idx: u32) -> u32; fn __wbindgen_is_string(idx: u32) -> u32; fn __wbindgen_is_bigint(idx: u32) -> u32; + fn __wbindgen_typeof(idx: u32) -> u32; + + fn __wbindgen_in(prop: u32, obj: u32) -> u32; + fn __wbindgen_is_falsy(idx: u32) -> u32; fn __wbindgen_as_number(idx: u32) -> f64; fn __wbindgen_neg(idx: u32) -> u32; From 098aef756d666372f809fb4af7d2fbca8952370d Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 19 Jul 2021 12:26:23 +0200 Subject: [PATCH 03/27] Add comparison operators --- crates/cli-support/src/intrinsic.rs | 12 +++++++++++ crates/cli-support/src/js/mod.rs | 20 ++++++++++++++++++ src/lib.rs | 32 +++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/crates/cli-support/src/intrinsic.rs b/crates/cli-support/src/intrinsic.rs index cb4357098cc..7d7f05edc39 100644 --- a/crates/cli-support/src/intrinsic.rs +++ b/crates/cli-support/src/intrinsic.rs @@ -166,6 +166,18 @@ intrinsics! { #[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, diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index ba433ad4b58..03763e461e7 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -3043,6 +3043,26 @@ impl<'a> Context<'a> { 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() diff --git a/src/lib.rs b/src/lib.rs index 40fc4c8a489..ec020ce69c0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -405,6 +405,34 @@ impl JsValue { pub fn pow(self, rhs: &Self) -> Self { unsafe { JsValue::_new(__wbindgen_pow(self.idx, rhs.idx)) } } + + /// Applies the binary `<` JS operator on the two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Less_than) + pub fn lt(&self, other: &Self) -> bool { + unsafe { __wbindgen_lt(self.idx, other.idx) == 1 } + } + + /// Applies the binary `<=` JS operator on the two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Less_than_or_equal) + pub fn le(&self, other: &Self) -> bool { + unsafe { __wbindgen_le(self.idx, other.idx) == 1 } + } + + /// Applies the binary `>=` JS operator on the two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Greater_than_or_equal) + pub fn ge(&self, other: &Self) -> bool { + unsafe { __wbindgen_ge(self.idx, other.idx) == 1 } + } + + /// Applies the binary `>` JS operator on the two `JsValue`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Greater_than) + pub fn gt(&self, other: &Self) -> bool { + unsafe { __wbindgen_gt(self.idx, other.idx) == 1 } + } } impl PartialEq for JsValue { @@ -807,6 +835,10 @@ externs! { fn __wbindgen_mul(a: u32, b: u32) -> u32; fn __wbindgen_rem(a: u32, b: u32) -> u32; fn __wbindgen_pow(a: u32, b: u32) -> u32; + fn __wbindgen_lt(a: u32, b: u32) -> u32; + fn __wbindgen_le(a: u32, b: u32) -> u32; + fn __wbindgen_ge(a: u32, b: u32) -> u32; + fn __wbindgen_gt(a: u32, b: u32) -> u32; fn __wbindgen_number_get(idx: u32) -> WasmOptionalF64; fn __wbindgen_boolean_get(idx: u32) -> u32; From 2587439039ed3a24b298ef80fb3dcb9e942224d9 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 19 Jul 2021 17:37:05 +0200 Subject: [PATCH 04/27] Remove Object.is intrinsic --- crates/cli-support/src/intrinsic.rs | 3 --- crates/cli-support/src/js/mod.rs | 5 ----- src/lib.rs | 9 --------- 3 files changed, 17 deletions(-) diff --git a/crates/cli-support/src/intrinsic.rs b/crates/cli-support/src/intrinsic.rs index 7d7f05edc39..5c8139e82eb 100644 --- a/crates/cli-support/src/intrinsic.rs +++ b/crates/cli-support/src/intrinsic.rs @@ -88,9 +88,6 @@ intrinsics! { #[symbol = "__wbindgen_jsval_loose_eq"] #[signature = fn(ref_externref(), ref_externref()) -> Boolean] JsvalLooseEq, - #[symbol = "__wbindgen_jsval_is"] - #[signature = fn(ref_externref(), ref_externref()) -> Boolean] - JsvalStrictEq, #[symbol = "__wbindgen_is_function"] #[signature = fn(ref_externref()) -> Boolean] IsFunction, diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 03763e461e7..b24770a5a27 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -2912,11 +2912,6 @@ impl<'a> Context<'a> { format!("{} == {}", args[0], args[1]) } - Intrinsic::JsvalStrictEq => { - assert_eq!(args.len(), 2); - format!("Object.is({}, {})", args[0], args[1]) - } - Intrinsic::IsFunction => { assert_eq!(args.len(), 1); format!("typeof({}) === 'function'", args[0]) diff --git a/src/lib.rs b/src/lib.rs index ec020ce69c0..9a12884394f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -376,14 +376,6 @@ impl JsValue { unsafe { __wbindgen_jsval_loose_eq(self.idx, other.idx) != 0 } } - /// Compares two `JsValue`s for equality, using `Object.is`. - /// This comparison method fulfills the requirements of the [`Eq`](std::cmp::Eq) trait. - /// - /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) - pub fn is(&self, other: &Self) -> bool { - unsafe { __wbindgen_jsval_is(self.idx, other.idx) != 0 } - } - /// Applies the unary `~` JS operator on a `JsValue`. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_NOT) @@ -858,7 +850,6 @@ externs! { fn __wbindgen_json_serialize(idx: u32) -> WasmSlice; fn __wbindgen_jsval_eq(a: u32, b: u32) -> u32; fn __wbindgen_jsval_loose_eq(a: u32, b: u32) -> u32; - fn __wbindgen_jsval_is(a: u32, b: u32) -> u32; fn __wbindgen_not(idx: u32) -> u32; From 9184409bedbd5dfac895e2451724168d60061882 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 19 Jul 2021 19:26:34 +0200 Subject: [PATCH 05/27] Make conversion into f64 faillible --- crates/cli-support/src/intrinsic.rs | 3 +++ crates/cli-support/src/js/mod.rs | 5 +++++ src/lib.rs | 31 +++++++++++++++++++++++------ 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/crates/cli-support/src/intrinsic.rs b/crates/cli-support/src/intrinsic.rs index 5c8139e82eb..be6cd729415 100644 --- a/crates/cli-support/src/intrinsic.rs +++ b/crates/cli-support/src/intrinsic.rs @@ -121,6 +121,9 @@ intrinsics! { #[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, diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index b24770a5a27..1bbc4db58eb 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -2968,6 +2968,11 @@ impl<'a> Context<'a> { 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]) diff --git a/src/lib.rs b/src/lib.rs index 9a12884394f..3eac2901836 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ #![doc(html_root_url = "https://docs.rs/wasm-bindgen/0.2")] #![cfg_attr(feature = "nightly", feature(unsize))] +use core::convert::TryFrom; use core::fmt; use core::marker; use core::mem; @@ -425,6 +426,13 @@ impl JsValue { pub fn gt(&self, other: &Self) -> bool { unsafe { __wbindgen_gt(self.idx, other.idx) == 1 } } + + /// Applies the unary `+` JS operator on a `JsValue`. Can throw. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus) + pub fn unchecked_into_f64(&self) -> f64 { + unsafe { __wbindgen_as_number(self.idx) } + } } impl PartialEq for JsValue { @@ -530,21 +538,31 @@ impl Not for &JsValue { forward_deref_unop!(impl Not, not for JsValue); -impl From for f64 { +impl TryFrom for f64 { + type Error = JsValue; + /// Applies the unary `+` JS operator on a `JsValue`. + /// Returns the numeric result on success, or the JS error value on error. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus) - fn from(val: JsValue) -> Self { - (&val).into() + fn try_from(val: JsValue) -> Result { + f64::try_from(&val) } } -impl From<&JsValue> for f64 { +impl TryFrom<&JsValue> for f64 { + type Error = JsValue; + /// Applies the unary `+` JS operator on a `JsValue`. + /// Returns the numeric result on success, or the JS error value on error. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus) - fn from(val: &JsValue) -> Self { - unsafe { __wbindgen_as_number(val.idx) } + fn try_from(val: &JsValue) -> Result { + let jsval = unsafe { JsValue::_new(__wbindgen_try_into_number(val.idx)) }; + return match jsval.as_f64() { + Some(num) => Ok(num), + None => Err(jsval), + }; } } @@ -813,6 +831,7 @@ externs! { fn __wbindgen_is_falsy(idx: u32) -> u32; fn __wbindgen_as_number(idx: u32) -> f64; + fn __wbindgen_try_into_number(idx: u32) -> u32; fn __wbindgen_neg(idx: u32) -> u32; fn __wbindgen_bit_and(a: u32, b: u32) -> u32; fn __wbindgen_bit_or(a: u32, b: u32) -> u32; From 9aee6069008ec352d6707ad69d1fea760871edef Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 19 Jul 2021 22:32:08 +0200 Subject: [PATCH 06/27] Add `#[inline]`s --- src/lib.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 3eac2901836..07cbe0ece6a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -242,11 +242,13 @@ impl JsValue { /// /// If this JS value is not an instance of a number then this returns /// `None`. + #[inline] pub fn as_f64(&self) -> Option { unsafe { FromWasmAbi::from_abi(__wbindgen_number_get(self.idx)) } } /// Tests whether this JS value is a JS string. + #[inline] pub fn is_string(&self) -> bool { unsafe { __wbindgen_is_string(self.idx) == 1 } } @@ -272,6 +274,7 @@ impl JsValue { /// /// [caveats]: https://rustwasm.github.io/docs/wasm-bindgen/reference/types/str.html #[cfg(feature = "std")] + #[inline] pub fn as_string(&self) -> Option { unsafe { FromWasmAbi::from_abi(__wbindgen_string_get(self.idx)) } } @@ -281,6 +284,7 @@ impl JsValue { /// /// If this JS value is not an instance of a boolean then this returns /// `None`. + #[inline] pub fn as_bool(&self) -> Option { unsafe { match __wbindgen_boolean_get(self.idx) { @@ -373,6 +377,7 @@ impl JsValue { /// Compare two `JsValue`s for equality, using the `==` operator in JS. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Equality) + #[inline] pub fn loose_eq(&self, other: &Self) -> bool { unsafe { __wbindgen_jsval_loose_eq(self.idx, other.idx) != 0 } } @@ -388,6 +393,7 @@ impl JsValue { /// Applies the binary `>>>` JS operator on the two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unsigned_right_shift) + #[inline] pub fn unsigned_shr(self, rhs: &Self) -> u32 { unsafe { __wbindgen_unsigned_shr(self.idx, rhs.idx) } } @@ -395,6 +401,7 @@ impl JsValue { /// Applies the binary `**` JS operator on the two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Exponentiation) + #[inline] pub fn pow(self, rhs: &Self) -> Self { unsafe { JsValue::_new(__wbindgen_pow(self.idx, rhs.idx)) } } @@ -402,6 +409,7 @@ impl JsValue { /// Applies the binary `<` JS operator on the two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Less_than) + #[inline] pub fn lt(&self, other: &Self) -> bool { unsafe { __wbindgen_lt(self.idx, other.idx) == 1 } } @@ -409,6 +417,7 @@ impl JsValue { /// Applies the binary `<=` JS operator on the two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Less_than_or_equal) + #[inline] pub fn le(&self, other: &Self) -> bool { unsafe { __wbindgen_le(self.idx, other.idx) == 1 } } @@ -416,6 +425,7 @@ impl JsValue { /// Applies the binary `>=` JS operator on the two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Greater_than_or_equal) + #[inline] pub fn ge(&self, other: &Self) -> bool { unsafe { __wbindgen_ge(self.idx, other.idx) == 1 } } @@ -423,6 +433,7 @@ impl JsValue { /// Applies the binary `>` JS operator on the two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Greater_than) + #[inline] pub fn gt(&self, other: &Self) -> bool { unsafe { __wbindgen_gt(self.idx, other.idx) == 1 } } @@ -430,6 +441,7 @@ impl JsValue { /// Applies the unary `+` JS operator on a `JsValue`. Can throw. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus) + #[inline] pub fn unchecked_into_f64(&self) -> f64 { unsafe { __wbindgen_as_number(self.idx) } } @@ -545,6 +557,7 @@ impl TryFrom for f64 { /// Returns the numeric result on success, or the JS error value on error. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus) + #[inline] fn try_from(val: JsValue) -> Result { f64::try_from(&val) } @@ -557,6 +570,7 @@ impl TryFrom<&JsValue> for f64 { /// Returns the numeric result on success, or the JS error value on error. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus) + #[inline] fn try_from(val: &JsValue) -> Result { let jsval = unsafe { JsValue::_new(__wbindgen_try_into_number(val.idx)) }; return match jsval.as_f64() { @@ -572,6 +586,7 @@ impl Neg for &JsValue { /// Applies the unary `-` JS operator on a `JsValue`. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_negation) + #[inline] fn neg(self) -> Self::Output { unsafe { JsValue::_new(__wbindgen_neg(self.idx)) } } @@ -585,6 +600,7 @@ impl BitAnd for &JsValue { /// Applies the binary `&` JS operator on two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_AND) + #[inline] fn bitand(self, rhs: Self) -> Self::Output { unsafe { JsValue::_new(__wbindgen_bit_and(self.idx, rhs.idx)) } } @@ -598,6 +614,7 @@ impl BitOr for &JsValue { /// Applies the binary `|` JS operator on two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_OR) + #[inline] fn bitor(self, rhs: Self) -> Self::Output { unsafe { JsValue::_new(__wbindgen_bit_or(self.idx, rhs.idx)) } } @@ -611,6 +628,7 @@ impl BitXor for &JsValue { /// Applies the binary `^` JS operator on two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_XOR) + #[inline] fn bitxor(self, rhs: Self) -> Self::Output { unsafe { JsValue::_new(__wbindgen_bit_xor(self.idx, rhs.idx)) } } @@ -624,6 +642,7 @@ impl Shl for &JsValue { /// Applies the binary `<<` JS operator on two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Left_shift) + #[inline] fn shl(self, rhs: Self) -> Self::Output { unsafe { JsValue::_new(__wbindgen_shl(self.idx, rhs.idx)) } } @@ -637,6 +656,7 @@ impl Shr for &JsValue { /// Applies the binary `>>` JS operator on two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Right_shift) + #[inline] fn shr(self, rhs: Self) -> Self::Output { unsafe { JsValue::_new(__wbindgen_shr(self.idx, rhs.idx)) } } @@ -650,6 +670,7 @@ impl Add for &JsValue { /// Applies the binary `+` JS operator on two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Addition) + #[inline] fn add(self, rhs: Self) -> Self::Output { unsafe { JsValue::_new(__wbindgen_add(self.idx, rhs.idx)) } } @@ -663,6 +684,7 @@ impl Sub for &JsValue { /// Applies the binary `-` JS operator on two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Subtraction) + #[inline] fn sub(self, rhs: Self) -> Self::Output { unsafe { JsValue::_new(__wbindgen_sub(self.idx, rhs.idx)) } } @@ -676,6 +698,7 @@ impl Div for &JsValue { /// Applies the binary `/` JS operator on two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Division) + #[inline] fn div(self, rhs: Self) -> Self::Output { unsafe { JsValue::_new(__wbindgen_div(self.idx, rhs.idx)) } } @@ -689,6 +712,7 @@ impl Mul for &JsValue { /// Applies the binary `*` JS operator on two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Multiplication) + #[inline] fn mul(self, rhs: Self) -> Self::Output { unsafe { JsValue::_new(__wbindgen_mul(self.idx, rhs.idx)) } } @@ -702,6 +726,7 @@ impl Rem for &JsValue { /// Applies the binary `%` JS operator on two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Remainder) + #[inline] fn rem(self, rhs: Self) -> Self::Output { unsafe { JsValue::_new(__wbindgen_rem(self.idx, rhs.idx)) } } From 945bcfd170036c21bbba6a83da47847404e545ae Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 21 Jul 2021 12:02:14 +0200 Subject: [PATCH 07/27] Fix methods to make them take references --- src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 07cbe0ece6a..247d3cea9db 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -386,7 +386,7 @@ impl JsValue { /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_NOT) #[inline] - pub fn bit_not(self) -> JsValue { + pub fn bit_not(&self) -> JsValue { unsafe { JsValue::_new( __wbindgen_bit_not(self.idx)) } } @@ -394,7 +394,7 @@ impl JsValue { /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unsigned_right_shift) #[inline] - pub fn unsigned_shr(self, rhs: &Self) -> u32 { + pub fn unsigned_shr(&self, rhs: &Self) -> u32 { unsafe { __wbindgen_unsigned_shr(self.idx, rhs.idx) } } @@ -402,7 +402,7 @@ impl JsValue { /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Exponentiation) #[inline] - pub fn pow(self, rhs: &Self) -> Self { + pub fn pow(&self, rhs: &Self) -> Self { unsafe { JsValue::_new(__wbindgen_pow(self.idx, rhs.idx)) } } From cd65747aa2e313d761e9ffad0fe4d47abc99826b Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 21 Jul 2021 13:39:29 +0200 Subject: [PATCH 08/27] cargo fmt --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 247d3cea9db..4a20971f8f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -387,7 +387,7 @@ impl JsValue { /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_NOT) #[inline] pub fn bit_not(&self) -> JsValue { - unsafe { JsValue::_new( __wbindgen_bit_not(self.idx)) } + unsafe { JsValue::_new(__wbindgen_bit_not(self.idx)) } } /// Applies the binary `>>>` JS operator on the two `JsValue`s. From 073dd08c8c60cf765e9cd538e4ad97f5757824b7 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 21 Jul 2021 18:34:02 +0200 Subject: [PATCH 09/27] Add BigInt to js-sys (no constructor yet) --- crates/cli-support/src/intrinsic.rs | 5 +- crates/cli-support/src/js/mod.rs | 7 +- crates/js-sys/src/lib.rs | 358 +++++++++++++++++++++++++++- src/lib.rs | 70 ++++-- 4 files changed, 417 insertions(+), 23 deletions(-) diff --git a/crates/cli-support/src/intrinsic.rs b/crates/cli-support/src/intrinsic.rs index be6cd729415..ac01369a5db 100644 --- a/crates/cli-support/src/intrinsic.rs +++ b/crates/cli-support/src/intrinsic.rs @@ -108,7 +108,7 @@ intrinsics! { IsString, #[symbol = "__wbindgen_is_bigint"] #[signature = fn(ref_externref()) -> Boolean] - IsBigint, + IsBigInt, #[symbol = "__wbindgen_typeof"] #[signature = fn(ref_externref()) -> Externref] Typeof, @@ -190,6 +190,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, diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 1bbc4db58eb..8a0eb8cb89a 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -2943,7 +2943,7 @@ impl<'a> Context<'a> { format!("typeof({}) === 'string'", args[0]) } - Intrinsic::IsBigint => { + Intrinsic::IsBigInt => { assert_eq!(args.len(), 1); format!("typeof({}) === 'bigint'", args[0]) } @@ -3088,6 +3088,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() diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index 16d44988c1b..e89983a2156 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -18,12 +18,17 @@ #![doc(html_root_url = "https://docs.rs/js-sys/0.2")] +use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Rem, Shl, Shr, Sub}; +use std::cmp::Ordering; use std::convert; +use std::convert::Infallible; use std::f64; use std::fmt; use std::mem; use std::str; +use std::str::FromStr; +use wasm_bindgen::JsStatic; use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; @@ -47,6 +52,79 @@ use wasm_bindgen::JsCast; // * Arguments that are `JsValue`s or imported JavaScript types should be taken // by reference. +macro_rules! forward_deref_unop { + (impl $imp:ident, $method:ident for $t:ty) => { + impl $imp for $t { + type Output = <&'static $t as $imp>::Output; + + #[inline] + fn $method(self) -> Self::Output { + $imp::$method(&self) + } + } + }; +} + +macro_rules! forward_deref_binop { + (impl $imp:ident, $method:ident for $t:ty) => { + impl<'a> $imp<$t> for &'a $t { + type Output = <&'static $t as $imp<&'static $t>>::Output; + #[inline] + fn $method(self, other: $t) -> Self::Output { + $imp::$method(self, &other) + } + } + + impl $imp<&$t> for $t { + type Output = <&'static $t as $imp<&'static $t>>::Output; + + #[inline] + fn $method(self, other: &$t) -> Self::Output { + $imp::$method(&self, other) + } + } + + impl $imp<$t> for $t { + type Output = <&'static $t as $imp<&'static $t>>::Output; + + #[inline] + fn $method(self, other: $t) -> Self::Output { + $imp::$method(&self, &other) + } + } + }; +} + +macro_rules! forward_js_unop { + (impl $imp:ident, $method:ident for $t:ty) => { + impl $imp for &$t { + type Output = $t; + + #[inline] + fn $method(self) -> Self::Output { + $imp::$method(JsValue::as_ref(self)).unchecked_into() + } + } + + forward_deref_unop!(impl $imp, $method for $t); + }; +} + +macro_rules! forward_js_binop { + (impl $imp:ident, $method:ident for $t:ty) => { + impl $imp for &$t { + type Output = $t; + + #[inline] + fn $method(self, other: &$t) -> Self::Output { + $imp::$method(JsValue::as_ref(self), JsValue::as_ref(other)).unchecked_into() + } + } + + forward_deref_binop!(impl $imp, $method for $t); + }; +} + #[wasm_bindgen] extern "C" { /// The `decodeURI()` function decodes a Uniform Resource Identifier (URI) @@ -774,6 +852,164 @@ pub mod Atomics { } } +// BigInt +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(extends = Object, is_type_of = |v| v.is_bigint(), typescript_type = "bigint")] + #[derive(Clone, PartialEq, Eq)] + pub type BigInt; + + /*/// Creates a new BigInt value. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/BigInt) + //#[wasm_bindgen(js_name = "BigInt")] + #[wasm_bindgen(static_method_of = BigInt, js_name = "")] + pub fn new(value: &JsValue) -> BigInt;*/ + + /// Clamps a BigInt value to a signed integer value, and returns that value. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/asIntN) + #[wasm_bindgen(static_method_of = BigInt, js_name = asIntN)] + pub fn as_int_n(bits: f64, bigint: &BigInt) -> BigInt; + + /// Clamps a BigInt value to an unsigned integer value, and returns that value. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/asUintN) + #[wasm_bindgen(static_method_of = BigInt, js_name = asUintN)] + pub fn as_uint_n(bits: f64, bigint: &BigInt) -> BigInt; + + /// Returns a string with a language-sensitive representation of this BigInt value. Overrides the [`Object.prototype.toLocaleString()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/toLocaleString) method. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/toLocaleString) + #[wasm_bindgen(method, js_name = toLocaleString)] + pub fn to_locale_string(this: &BigInt, locales: &JsValue, options: &JsValue) -> JsString; + + /// Returns a string representing this BigInt value in the specified radix (base). Overrides the [`Object.prototype.toString()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString) method. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/toString) + #[wasm_bindgen(method, js_name = toString)] + pub fn to_string(this: &BigInt, radix: u8) -> JsString; + + /// Returns this BigInt value. Overrides the [`Object.prototype.valueOf()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf) method. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/valueOf) + #[wasm_bindgen(method, js_name = valueOf)] + pub fn value_of(this: &BigInt, radix: u8) -> BigInt; +} + +impl BigInt { + /// Applies the binary `**` JS operator on the two `BigInt`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Exponentiation) + pub fn pow(&self, rhs: &Self) -> Self { + JsValue::as_ref(self) + .pow(JsValue::as_ref(rhs)) + .unchecked_into() + } +} + +/* +macro_rules! bigint_from { + ($($x:ident)*) => ($( + impl From<$x> for BigInt { + #[inline] + fn from(x: $x) -> BigInt { + BigInt::new(&JsValue::from(x)) + } + } + + impl PartialEq<$x> for BigInt { + #[inline] + fn eq(&self, other: &$x) -> bool { + JsValue::from(self) == JsValue::from(BigInt::from(*other)) + } + } + )*) +} +bigint_from!(i8 u8 i16 u16 i32 u32); + +macro_rules! bigint_from_big { + ($($x:ident)*) => ($( + impl From<$x> for BigInt { + #[inline] + fn from(x: $x) -> BigInt { + JsValue::from(x).unchecked_into() + } + } + + impl PartialEq<$x> for BigInt { + #[inline] + fn eq(&self, other: &$x) -> bool { + self == &BigInt::from(*other) + } + } + )*) +} +bigint_from_big!(i64 u64 i128 u128 isize usize); +*/ + +impl PartialEq for BigInt { + #[inline] + fn eq(&self, other: &Number) -> bool { + JsValue::as_ref(self).loose_eq(JsValue::as_ref(other)) + } +} + +impl Not for &BigInt { + type Output = BigInt; + + fn not(self) -> Self::Output { + JsValue::as_ref(self).bit_not().unchecked_into() + } +} + +forward_deref_unop!(impl Not, not for BigInt); +forward_js_unop!(impl Neg, neg for BigInt); +forward_js_binop!(impl BitAnd, bitand for BigInt); +forward_js_binop!(impl BitOr, bitor for BigInt); +forward_js_binop!(impl BitXor, bitxor for BigInt); +forward_js_binop!(impl Shl, shl for BigInt); +forward_js_binop!(impl Shr, shr for BigInt); +forward_js_binop!(impl Add, add for BigInt); +forward_js_binop!(impl Sub, sub for BigInt); +forward_js_binop!(impl Div, div for BigInt); +forward_js_binop!(impl Mul, mul for BigInt); +forward_js_binop!(impl Rem, rem for BigInt); + +impl PartialOrd for BigInt { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } + + fn lt(&self, other: &Self) -> bool { + JsValue::as_ref(self).lt(JsValue::as_ref(other)) + } + + fn le(&self, other: &Self) -> bool { + JsValue::as_ref(self).le(JsValue::as_ref(other)) + } + + fn ge(&self, other: &Self) -> bool { + JsValue::as_ref(self).ge(JsValue::as_ref(other)) + } + + fn gt(&self, other: &Self) -> bool { + JsValue::as_ref(self).gt(JsValue::as_ref(other)) + } +} + +impl Ord for BigInt { + fn cmp(&self, other: &Self) -> Ordering { + if self == other { + Ordering::Equal + } else if self.lt(other) { + Ordering::Less + } else { + Ordering::Greater + } + } +} + // Boolean #[wasm_bindgen] extern "C" { @@ -829,6 +1065,16 @@ impl Default for Boolean { } } +impl Not for &Boolean { + type Output = Boolean; + + fn not(self) -> Self::Output { + (!JsValue::as_ref(self)).into() + } +} + +forward_deref_unop!(impl Not, not for Boolean); + // DataView #[wasm_bindgen] extern "C" { @@ -1841,7 +2087,7 @@ pub mod Math { #[wasm_bindgen] extern "C" { #[wasm_bindgen(extends = Object, is_type_of = |v| v.as_f64().is_some(), typescript_type = "number")] - #[derive(Clone)] + #[derive(Clone, PartialEq)] pub type Number; /// The `Number.isFinite()` method determines whether the passed value is a finite number. @@ -1880,6 +2126,9 @@ extern "C" { #[allow(deprecated)] pub fn new(value: &JsValue) -> Number; + #[wasm_bindgen(constructor)] + fn new_from_str(value: &str) -> Number; + /// The `Number.parseInt()` method parses a string argument and returns an /// integer of the specified radix or base. /// @@ -1972,6 +2221,22 @@ impl Number { /// /// [MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/POSITIVE_INFINITY) pub const POSITIVE_INFINITY: f64 = f64::INFINITY; + + /// Applies the binary `**` JS operator on the two `Number`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Exponentiation) + pub fn pow(&self, rhs: &Self) -> Self { + JsValue::as_ref(self) + .pow(JsValue::as_ref(rhs)) + .unchecked_into() + } + + /// Applies the binary `>>>` JS operator on the two `Number`s. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unsigned_right_shift) + pub fn unsigned_shr(&self, rhs: &Self) -> Self { + Number::from(JsValue::as_ref(self).unsigned_shr(JsValue::as_ref(rhs))) + } } macro_rules! number_from { @@ -1993,6 +2258,20 @@ macro_rules! number_from { } number_from!(i8 u8 i16 u16 i32 u32 f32 f64); +// TODO: add this on the next major version, when blanket impl is removed +/* +impl convert::TryFrom for Number { + type Error = Error; + + fn try_from(value: JsValue) -> Result { + return match f64::try_from(value) { + Ok(num) => Ok(Number::from(num)), + Err(jsval) => Err(jsval.unchecked_into()) + } + } +} +*/ + impl From for f64 { #[inline] fn from(n: Number) -> f64 { @@ -2012,6 +2291,73 @@ impl Default for Number { } } +impl PartialEq for Number { + #[inline] + fn eq(&self, other: &BigInt) -> bool { + JsValue::as_ref(self).loose_eq(JsValue::as_ref(other)) + } +} + +impl Not for &Number { + type Output = BigInt; + + fn not(self) -> Self::Output { + JsValue::as_ref(self).bit_not().unchecked_into() + } +} + +forward_deref_unop!(impl Not, not for Number); +forward_js_unop!(impl Neg, neg for Number); +forward_js_binop!(impl BitAnd, bitand for Number); +forward_js_binop!(impl BitOr, bitor for Number); +forward_js_binop!(impl BitXor, bitxor for Number); +forward_js_binop!(impl Shl, shl for Number); +forward_js_binop!(impl Shr, shr for Number); +forward_js_binop!(impl Add, add for Number); +forward_js_binop!(impl Sub, sub for Number); +forward_js_binop!(impl Div, div for Number); +forward_js_binop!(impl Mul, mul for Number); +forward_js_binop!(impl Rem, rem for Number); + +impl PartialOrd for Number { + fn partial_cmp(&self, other: &Self) -> Option { + if Number::is_nan(self) || Number::is_nan(other) { + None + } else if self == other { + Some(Ordering::Equal) + } else if self.lt(other) { + Some(Ordering::Less) + } else { + Some(Ordering::Greater) + } + } + + fn lt(&self, other: &Self) -> bool { + JsValue::as_ref(self).lt(JsValue::as_ref(other)) + } + + fn le(&self, other: &Self) -> bool { + JsValue::as_ref(self).le(JsValue::as_ref(other)) + } + + fn ge(&self, other: &Self) -> bool { + JsValue::as_ref(self).ge(JsValue::as_ref(other)) + } + + fn gt(&self, other: &Self) -> bool { + JsValue::as_ref(self).gt(JsValue::as_ref(other)) + } +} + +impl FromStr for Number { + type Err = Infallible; + + #[allow(deprecated)] + fn from_str(s: &str) -> Result { + Ok(Number::new_from_str(s)) + } +} + // Date. #[wasm_bindgen] extern "C" { @@ -5205,4 +5551,14 @@ arrays! { /// `Float64Array()` /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float64Array Float64Array: f64, + + /* + /// `BigInt64Array()` + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt64Array + BigInt64Array: BigInt, + + /// `BigUint64Array()` + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigUint64Array + BigUint64Array: BigInt, + */ } diff --git a/src/lib.rs b/src/lib.rs index 4a20971f8f7..16783606793 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -147,6 +147,15 @@ impl JsValue { unsafe { JsValue::_new(__wbindgen_number_new(n)) } } + /// Creates a new JS value which is a bigint from a string representing a number. + /// + /// This function creates a JS value representing a bigint (a heap + /// allocated large integer) and returns a handle to the JS version of it. + #[inline] + pub fn bigint_from_str(s: &str) -> JsValue { + unsafe { JsValue::_new(__wbindgen_bigint_new(s.as_ptr(), s.len())) } + } + /// Creates a new JS value which is a boolean. /// /// This function creates a JS object representing a boolean (a heap @@ -507,29 +516,29 @@ macro_rules! forward_deref_unop { } macro_rules! forward_deref_binop { - (impl $imp:ident, $method:ident for $t:ty, $u:ty) => { - impl<'a> $imp<$u> for &'a $t { - type Output = <&'static $t as $imp<&'static $u>>::Output; + (impl $imp:ident, $method:ident for $t:ty) => { + impl<'a> $imp<$t> for &'a $t { + type Output = <&'static $t as $imp<&'static $t>>::Output; #[inline] - fn $method(self, other: $u) -> <&'static $t as $imp<&'static $u>>::Output { + fn $method(self, other: $t) -> <&'static $t as $imp<&'static $t>>::Output { $imp::$method(self, &other) } } - impl $imp<&$u> for $t { - type Output = <&'static $t as $imp<&'static $u>>::Output; + impl $imp<&$t> for $t { + type Output = <&'static $t as $imp<&'static $t>>::Output; #[inline] - fn $method(self, other: &$u) -> <&'static $t as $imp<&'static $u>>::Output { + fn $method(self, other: &$t) -> <&'static $t as $imp<&'static $t>>::Output { $imp::$method(&self, other) } } - impl $imp<$u> for $t { - type Output = <&'static $t as $imp<&'static $u>>::Output; + impl $imp<$t> for $t { + type Output = <&'static $t as $imp<&'static $t>>::Output; #[inline] - fn $method(self, other: $u) -> <&'static $t as $imp<&'static $u>>::Output { + fn $method(self, other: $t) -> <&'static $t as $imp<&'static $t>>::Output { $imp::$method(&self, &other) } } @@ -606,7 +615,7 @@ impl BitAnd for &JsValue { } } -forward_deref_binop!(impl BitAnd, bitand for JsValue, JsValue); +forward_deref_binop!(impl BitAnd, bitand for JsValue); impl BitOr for &JsValue { type Output = JsValue; @@ -620,7 +629,7 @@ impl BitOr for &JsValue { } } -forward_deref_binop!(impl BitOr, bitor for JsValue, JsValue); +forward_deref_binop!(impl BitOr, bitor for JsValue); impl BitXor for &JsValue { type Output = JsValue; @@ -634,7 +643,7 @@ impl BitXor for &JsValue { } } -forward_deref_binop!(impl BitXor, bitxor for JsValue, JsValue); +forward_deref_binop!(impl BitXor, bitxor for JsValue); impl Shl for &JsValue { type Output = JsValue; @@ -648,7 +657,7 @@ impl Shl for &JsValue { } } -forward_deref_binop!(impl Shl, shl for JsValue, JsValue); +forward_deref_binop!(impl Shl, shl for JsValue); impl Shr for &JsValue { type Output = JsValue; @@ -662,7 +671,7 @@ impl Shr for &JsValue { } } -forward_deref_binop!(impl Shr, shr for JsValue, JsValue); +forward_deref_binop!(impl Shr, shr for JsValue); impl Add for &JsValue { type Output = JsValue; @@ -676,7 +685,7 @@ impl Add for &JsValue { } } -forward_deref_binop!(impl Add, add for JsValue, JsValue); +forward_deref_binop!(impl Add, add for JsValue); impl Sub for &JsValue { type Output = JsValue; @@ -690,7 +699,7 @@ impl Sub for &JsValue { } } -forward_deref_binop!(impl Sub, sub for JsValue, JsValue); +forward_deref_binop!(impl Sub, sub for JsValue); impl Div for &JsValue { type Output = JsValue; @@ -704,7 +713,7 @@ impl Div for &JsValue { } } -forward_deref_binop!(impl Div, div for JsValue, JsValue); +forward_deref_binop!(impl Div, div for JsValue); impl Mul for &JsValue { type Output = JsValue; @@ -718,7 +727,7 @@ impl Mul for &JsValue { } } -forward_deref_binop!(impl Mul, mul for JsValue, JsValue); +forward_deref_binop!(impl Mul, mul for JsValue); impl Rem for &JsValue { type Output = JsValue; @@ -732,7 +741,7 @@ impl Rem for &JsValue { } } -forward_deref_binop!(impl Rem, rem for JsValue, JsValue); +forward_deref_binop!(impl Rem, rem for JsValue); impl<'a> From<&'a str> for JsValue { #[inline] @@ -830,6 +839,26 @@ macro_rules! numbers { numbers! { i8 u8 i16 u16 i32 u32 f32 f64 } +macro_rules! big_numbers { + ($($n:ident)*) => ($( + impl PartialEq<$n> for JsValue { + #[inline] + fn eq(&self, other: &$n) -> bool { + self == &JsValue::from(*other) + } + } + + impl From<$n> for JsValue { + #[inline] + fn from(n: $n) -> JsValue { + JsValue::bigint_from_str(&n.to_string()) + } + } + )*) +} + +big_numbers! { i64 u64 i128 u128 isize usize } + externs! { #[link(wasm_import_module = "__wbindgen_placeholder__")] extern "C" { @@ -838,6 +867,7 @@ externs! { fn __wbindgen_string_new(ptr: *const u8, len: usize) -> u32; fn __wbindgen_number_new(f: f64) -> u32; + fn __wbindgen_bigint_new(ptr: *const u8, len: usize) -> u32; fn __wbindgen_symbol_named_new(ptr: *const u8, len: usize) -> u32; fn __wbindgen_symbol_anonymous_new() -> u32; From 2b59886434a8da10d9891370ff0e503f1484a20d Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Fri, 23 Jul 2021 13:28:50 +0200 Subject: [PATCH 10/27] Remove useless import --- crates/js-sys/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index e89983a2156..c28340afee3 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -28,7 +28,6 @@ use std::mem; use std::str; use std::str::FromStr; -use wasm_bindgen::JsStatic; use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; From 6a5681f065bafe2eb3670fec75827fd90eb0a3c1 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 21 Jul 2021 21:34:11 +0200 Subject: [PATCH 11/27] Fix UI tests --- crates/macro/ui-tests/async-errors.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/macro/ui-tests/async-errors.stderr b/crates/macro/ui-tests/async-errors.stderr index 74d016db05d..f9b40d78e04 100644 --- a/crates/macro/ui-tests/async-errors.stderr +++ b/crates/macro/ui-tests/async-errors.stderr @@ -33,7 +33,7 @@ error[E0277]: the trait bound `wasm_bindgen::JsValue: From` is not sati > > > - and 63 others + and 70 others = note: required because of the requirements on the impl of `Into` for `BadType` = note: required because of the requirements on the impl of `IntoJsResult` for `BadType` = note: required by `into_js_result` From 09ebff757223c583c8a31b02e618ae61027814ca Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Fri, 23 Jul 2021 12:53:17 +0200 Subject: [PATCH 12/27] Add BigInt constructor --- crates/js-sys/src/lib.rs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index c28340afee3..a863975dd1b 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -858,12 +858,8 @@ extern "C" { #[derive(Clone, PartialEq, Eq)] pub type BigInt; - /*/// Creates a new BigInt value. - /// - /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/BigInt) - //#[wasm_bindgen(js_name = "BigInt")] - #[wasm_bindgen(static_method_of = BigInt, js_name = "")] - pub fn new(value: &JsValue) -> BigInt;*/ + #[wasm_bindgen(js_name = BigInt)] + fn new_bigint(value: &JsValue) -> BigInt; /// Clamps a BigInt value to a signed integer value, and returns that value. /// @@ -897,6 +893,13 @@ extern "C" { } impl BigInt { + /// Creates a new BigInt value. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/BigInt) + pub fn new(value: &JsValue) -> BigInt { + new_bigint(value) + } + /// Applies the binary `**` JS operator on the two `BigInt`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Exponentiation) @@ -907,7 +910,6 @@ impl BigInt { } } -/* macro_rules! bigint_from { ($($x:ident)*) => ($( impl From<$x> for BigInt { @@ -945,7 +947,6 @@ macro_rules! bigint_from_big { )*) } bigint_from_big!(i64 u64 i128 u128 isize usize); -*/ impl PartialEq for BigInt { #[inline] @@ -1009,6 +1010,12 @@ impl Ord for BigInt { } } +impl Default for BigInt { + fn default() -> Self { + BigInt::from(i32::default()) + } +} + // Boolean #[wasm_bindgen] extern "C" { @@ -5551,7 +5558,6 @@ arrays! { /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float64Array Float64Array: f64, - /* /// `BigInt64Array()` /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt64Array BigInt64Array: BigInt, @@ -5559,5 +5565,4 @@ arrays! { /// `BigUint64Array()` /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigUint64Array BigUint64Array: BigInt, - */ } From 5bcb6dabb89290ba1cd32864b92acb30634ce33a Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Fri, 23 Jul 2021 16:50:22 +0200 Subject: [PATCH 13/27] Allow catching `to_string` method for BigInt --- crates/js-sys/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index a863975dd1b..553de15415b 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -882,8 +882,8 @@ extern "C" { /// Returns a string representing this BigInt value in the specified radix (base). Overrides the [`Object.prototype.toString()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString) method. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/toString) - #[wasm_bindgen(method, js_name = toString)] - pub fn to_string(this: &BigInt, radix: u8) -> JsString; + #[wasm_bindgen(catch, method, js_name = toString)] + pub fn to_string(this: &BigInt, radix: u8) -> Result; /// Returns this BigInt value. Overrides the [`Object.prototype.valueOf()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf) method. /// From d304deca435d7a597200a644b5f2009aabeca9de Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Fri, 23 Jul 2021 17:02:48 +0200 Subject: [PATCH 14/27] Fix tests again --- crates/macro/ui-tests/async-errors.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/macro/ui-tests/async-errors.stderr b/crates/macro/ui-tests/async-errors.stderr index f9b40d78e04..b2fe6f99984 100644 --- a/crates/macro/ui-tests/async-errors.stderr +++ b/crates/macro/ui-tests/async-errors.stderr @@ -33,7 +33,7 @@ error[E0277]: the trait bound `wasm_bindgen::JsValue: From` is not sati > > > - and 70 others + and 72 others = note: required because of the requirements on the impl of `Into` for `BadType` = note: required because of the requirements on the impl of `IntoJsResult` for `BadType` = note: required by `into_js_result` From 55a22d3de16a15fda2a65d944c08a57a32e8a98f Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Fri, 23 Jul 2021 17:15:55 +0200 Subject: [PATCH 15/27] Add inlines --- crates/js-sys/src/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index 553de15415b..5a7ecd31bdb 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -896,6 +896,7 @@ impl BigInt { /// Creates a new BigInt value. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/BigInt) + #[inline] pub fn new(value: &JsValue) -> BigInt { new_bigint(value) } @@ -958,6 +959,7 @@ impl PartialEq for BigInt { impl Not for &BigInt { type Output = BigInt; + #[inline] fn not(self) -> Self::Output { JsValue::as_ref(self).bit_not().unchecked_into() } @@ -977,28 +979,34 @@ forward_js_binop!(impl Mul, mul for BigInt); forward_js_binop!(impl Rem, rem for BigInt); impl PartialOrd for BigInt { + #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } + #[inline] fn lt(&self, other: &Self) -> bool { JsValue::as_ref(self).lt(JsValue::as_ref(other)) } + #[inline] fn le(&self, other: &Self) -> bool { JsValue::as_ref(self).le(JsValue::as_ref(other)) } + #[inline] fn ge(&self, other: &Self) -> bool { JsValue::as_ref(self).ge(JsValue::as_ref(other)) } + #[inline] fn gt(&self, other: &Self) -> bool { JsValue::as_ref(self).gt(JsValue::as_ref(other)) } } impl Ord for BigInt { + #[inline] fn cmp(&self, other: &Self) -> Ordering { if self == other { Ordering::Equal From 2157e95f1772a1f5651bcbf581a71c41cc4ddb97 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Fri, 23 Jul 2021 17:21:45 +0200 Subject: [PATCH 16/27] Rework PartialEq impl --- crates/js-sys/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index 5a7ecd31bdb..dd3215150b5 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -923,7 +923,7 @@ macro_rules! bigint_from { impl PartialEq<$x> for BigInt { #[inline] fn eq(&self, other: &$x) -> bool { - JsValue::from(self) == JsValue::from(BigInt::from(*other)) + JsValue::from(self) == BigInt::from(*other).unchecked_into::() } } )*) From 1cc0f5bf9ece017bcc3f0a1ecc73db41c20e8c0c Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Fri, 23 Jul 2021 17:45:07 +0200 Subject: [PATCH 17/27] Implement FromStr for BigInt --- crates/js-sys/src/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index dd3215150b5..6fbff4beab6 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -1024,6 +1024,14 @@ impl Default for BigInt { } } +impl FromStr for BigInt { + type Err = Infallible; + + fn from_str(s: &str) -> Result { + Ok(BigInt::new(&s.into())) + } +} + // Boolean #[wasm_bindgen] extern "C" { From 118dab0ada87f1ccdae0731c8d233b3b5679d55f Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Fri, 23 Jul 2021 17:58:59 +0200 Subject: [PATCH 18/27] Add more inlines --- crates/js-sys/src/lib.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index 6fbff4beab6..da5060047f7 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -904,6 +904,7 @@ impl BigInt { /// Applies the binary `**` JS operator on the two `BigInt`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Exponentiation) + #[inline] pub fn pow(&self, rhs: &Self) -> Self { JsValue::as_ref(self) .pow(JsValue::as_ref(rhs)) @@ -1027,6 +1028,7 @@ impl Default for BigInt { impl FromStr for BigInt { type Err = Infallible; + #[inline] fn from_str(s: &str) -> Result { Ok(BigInt::new(&s.into())) } @@ -1090,6 +1092,7 @@ impl Default for Boolean { impl Not for &Boolean { type Output = Boolean; + #[inline] fn not(self) -> Self::Output { (!JsValue::as_ref(self)).into() } @@ -2247,6 +2250,7 @@ impl Number { /// Applies the binary `**` JS operator on the two `Number`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Exponentiation) + #[inline] pub fn pow(&self, rhs: &Self) -> Self { JsValue::as_ref(self) .pow(JsValue::as_ref(rhs)) @@ -2256,6 +2260,7 @@ impl Number { /// Applies the binary `>>>` JS operator on the two `Number`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unsigned_right_shift) + #[inline] pub fn unsigned_shr(&self, rhs: &Self) -> Self { Number::from(JsValue::as_ref(self).unsigned_shr(JsValue::as_ref(rhs))) } @@ -2323,6 +2328,7 @@ impl PartialEq for Number { impl Not for &Number { type Output = BigInt; + #[inline] fn not(self) -> Self::Output { JsValue::as_ref(self).bit_not().unchecked_into() } @@ -2342,6 +2348,7 @@ forward_js_binop!(impl Mul, mul for Number); forward_js_binop!(impl Rem, rem for Number); impl PartialOrd for Number { + #[inline] fn partial_cmp(&self, other: &Self) -> Option { if Number::is_nan(self) || Number::is_nan(other) { None @@ -2354,18 +2361,22 @@ impl PartialOrd for Number { } } + #[inline] fn lt(&self, other: &Self) -> bool { JsValue::as_ref(self).lt(JsValue::as_ref(other)) } + #[inline] fn le(&self, other: &Self) -> bool { JsValue::as_ref(self).le(JsValue::as_ref(other)) } + #[inline] fn ge(&self, other: &Self) -> bool { JsValue::as_ref(self).ge(JsValue::as_ref(other)) } + #[inline] fn gt(&self, other: &Self) -> bool { JsValue::as_ref(self).gt(JsValue::as_ref(other)) } @@ -2375,6 +2386,7 @@ impl FromStr for Number { type Err = Infallible; #[allow(deprecated)] + #[inline] fn from_str(s: &str) -> Result { Ok(Number::new_from_str(s)) } From 11c7de38c609cb8240f86d77c4536c8484480acc Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Fri, 23 Jul 2021 18:23:16 +0200 Subject: [PATCH 19/27] Update formatting --- crates/js-sys/src/lib.rs | 1 + src/lib.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index da5060047f7..29eb180554c 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -68,6 +68,7 @@ macro_rules! forward_deref_binop { (impl $imp:ident, $method:ident for $t:ty) => { impl<'a> $imp<$t> for &'a $t { type Output = <&'static $t as $imp<&'static $t>>::Output; + #[inline] fn $method(self, other: $t) -> Self::Output { $imp::$method(self, &other) diff --git a/src/lib.rs b/src/lib.rs index 16783606793..ff0d5c53dc2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -519,6 +519,7 @@ macro_rules! forward_deref_binop { (impl $imp:ident, $method:ident for $t:ty) => { impl<'a> $imp<$t> for &'a $t { type Output = <&'static $t as $imp<&'static $t>>::Output; + #[inline] fn $method(self, other: $t) -> <&'static $t as $imp<&'static $t>>::Output { $imp::$method(self, &other) From 747459ab41f886a63015ab1586a17dcb72812cc2 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sat, 31 Jul 2021 21:56:17 +0200 Subject: [PATCH 20/27] Add more trait impls and feature for integration with `rust-num` --- Cargo.toml | 1 + crates/cli-support/src/intrinsic.rs | 3 + crates/cli-support/src/js/mod.rs | 5 + crates/js-sys/Cargo.toml | 8 +- crates/js-sys/src/lib.rs | 372 +++++++++++++++++++++++++++- src/lib.rs | 25 ++ 6 files changed, 402 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ad9d1da96a3..0b51b1e039c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] js-sys = { path = 'crates/js-sys', version = '0.3.53' } diff --git a/crates/cli-support/src/intrinsic.rs b/crates/cli-support/src/intrinsic.rs index ac01369a5db..538e32d1e92 100644 --- a/crates/cli-support/src/intrinsic.rs +++ b/crates/cli-support/src/intrinsic.rs @@ -157,6 +157,9 @@ intrinsics! { #[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, diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 8a0eb8cb89a..724aafbef3e 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -3028,6 +3028,11 @@ impl<'a> Context<'a> { 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]) diff --git a/crates/js-sys/Cargo.toml b/crates/js-sys/Cargo.toml index 8c2b2de1dd6..39a9e626fe5 100644 --- a/crates/js-sys/Cargo.toml +++ b/crates/js-sys/Cargo.toml @@ -18,8 +18,14 @@ edition = "2018" test = false doctest = false +[features] +rust-num = ["num-bigint", "num-traits", "wasm-bindgen/num-traits"] +num-traits-full = ["num-traits", "wasm-bindgen/num-traits"] + [dependencies] -wasm-bindgen = { path = "../..", version = "0.2.76" } +wasm-bindgen = { path = "../..", version = "0.2.75" } +num-bigint = { version = "0.4.0", optional = true } +num-traits = { version = "0.2.14", optional = true } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] wasm-bindgen-test = { path = '../test', version = '=0.3.26' } diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index 29eb180554c..d99a8c551c8 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -20,10 +20,10 @@ use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Rem, Shl, Shr, Sub}; use std::cmp::Ordering; -use std::convert; -use std::convert::Infallible; +use std::convert::{self, Infallible}; use std::f64; use std::fmt; +use std::iter::{self, Product, Sum}; use std::mem; use std::str; use std::str::FromStr; @@ -31,6 +31,13 @@ use std::str::FromStr; use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; +#[cfg(feature = "rust-num")] +use num_traits::Num; +#[cfg(feature = "num-traits-full")] +use num_traits::Pow; +#[cfg(feature = "num-traits")] +use num_traits::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, FromPrimitive, One, Zero}; + // When adding new imports: // // * Keep imports in alphabetical order. @@ -112,7 +119,7 @@ macro_rules! forward_js_unop { macro_rules! forward_js_binop { (impl $imp:ident, $method:ident for $t:ty) => { - impl $imp for &$t { + impl $imp<&$t> for &$t { type Output = $t; #[inline] @@ -125,6 +132,49 @@ macro_rules! forward_js_binop { }; } +macro_rules! sum_product { + ($($a:ident)*) => ($( + impl Sum for $a { + #[inline] + fn sum>(iter: I) -> Self { + iter.fold( + $a::from(0), + |a, b| a + b, + ) + } + } + + impl Product for $a { + #[inline] + fn product>(iter: I) -> Self { + iter.fold( + $a::from(1), + |a, b| a * b, + ) + } + } + + impl<'a> Sum<&'a $a> for $a { + fn sum>(iter: I) -> Self { + iter.fold( + $a::from(0), + |a, b| a + b, + ) + } + } + + impl<'a> Product<&'a $a> for $a { + #[inline] + fn product>(iter: I) -> Self { + iter.fold( + $a::from(1), + |a, b| a * b, + ) + } + } + )*) +} + #[wasm_bindgen] extern "C" { /// The `decodeURI()` function decodes a Uniform Resource Identifier (URI) @@ -859,8 +909,11 @@ extern "C" { #[derive(Clone, PartialEq, Eq)] pub type BigInt; + #[wasm_bindgen(catch, js_name = BigInt)] + fn new_bigint(value: &JsValue) -> Result; + #[wasm_bindgen(js_name = BigInt)] - fn new_bigint(value: &JsValue) -> BigInt; + fn new_bigint_unchecked(value: &JsValue) -> BigInt; /// Clamps a BigInt value to a signed integer value, and returns that value. /// @@ -886,6 +939,9 @@ extern "C" { #[wasm_bindgen(catch, method, js_name = toString)] pub fn to_string(this: &BigInt, radix: u8) -> Result; + #[wasm_bindgen(method, js_name = toString)] + fn to_string_unchecked(this: &BigInt, radix: u8) -> String; + /// Returns this BigInt value. Overrides the [`Object.prototype.valueOf()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf) method. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/valueOf) @@ -898,10 +954,23 @@ impl BigInt { /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/BigInt) #[inline] - pub fn new(value: &JsValue) -> BigInt { + pub fn new(value: &JsValue) -> Result { new_bigint(value) } + /// Applies the binary `/` JS operator on two `BigInt`s, catching and returning any `RangeError` thrown. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Division) + pub fn checked_div(&self, rhs: &Self) -> Result { + let result = JsValue::as_ref(self).checked_div(JsValue::as_ref(rhs)); + + if result.is_instance_of::() { + Err(result.unchecked_into()) + } else { + Ok(result.unchecked_into()) + } + } + /// Applies the binary `**` JS operator on the two `BigInt`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Exponentiation) @@ -918,7 +987,7 @@ macro_rules! bigint_from { impl From<$x> for BigInt { #[inline] fn from(x: $x) -> BigInt { - BigInt::new(&JsValue::from(x)) + new_bigint_unchecked(&JsValue::from(x)) } } @@ -979,6 +1048,7 @@ forward_js_binop!(impl Sub, sub for BigInt); forward_js_binop!(impl Div, div for BigInt); forward_js_binop!(impl Mul, mul for BigInt); forward_js_binop!(impl Rem, rem for BigInt); +sum_product!(BigInt); impl PartialOrd for BigInt { #[inline] @@ -1027,11 +1097,243 @@ impl Default for BigInt { } impl FromStr for BigInt { - type Err = Infallible; + type Err = Error; #[inline] fn from_str(s: &str) -> Result { - Ok(BigInt::new(&s.into())) + BigInt::new(&s.into()) + } +} + +impl fmt::Debug for BigInt { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + +impl fmt::Display for BigInt { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad_integral(self >= &BigInt::from(0), "", &self.to_string_unchecked(10)) + } +} + +impl fmt::Binary for BigInt { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad_integral(self >= &BigInt::from(0), "0b", &self.to_string_unchecked(2)) + } +} + +impl fmt::Octal for BigInt { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad_integral(self >= &BigInt::from(0), "0o", &self.to_string_unchecked(8)) + } +} + +impl fmt::LowerHex for BigInt { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad_integral( + self >= &BigInt::from(0), + "0x", + &self.to_string_unchecked(16), + ) + } +} + +impl fmt::UpperHex for BigInt { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut s: String = self.to_string_unchecked(16); + s.make_ascii_uppercase(); + f.pad_integral(self >= &BigInt::from(0), "0x", &s) + } +} + +#[cfg(feature = "num-traits-full")] +forward_js_binop!(impl Pow, pow for BigInt); + +#[cfg(feature = "num-traits")] +impl CheckedAdd for BigInt { + #[inline] + fn checked_add(&self, v: &Self) -> Option { + Some(self + v) + } +} + +#[cfg(feature = "num-traits")] +impl CheckedSub for BigInt { + #[inline] + fn checked_sub(&self, v: &Self) -> Option { + Some(self - v) + } +} + +#[cfg(feature = "num-traits")] +impl CheckedMul for BigInt { + #[inline] + fn checked_mul(&self, v: &Self) -> Option { + Some(self * v) + } +} + +#[cfg(feature = "num-traits")] +impl CheckedDiv for BigInt { + #[inline] + fn checked_div(&self, v: &Self) -> Option { + BigInt::checked_div(&self, v).ok() + } +} + +#[cfg(feature = "num-traits")] +impl FromPrimitive for BigInt { + #[inline] + fn from_i8(n: i8) -> Option { + Some(Self::from(n)) + } + + #[inline] + fn from_i16(n: i16) -> Option { + Some(Self::from(n)) + } + + #[inline] + fn from_i32(n: i32) -> Option { + Some(Self::from(n)) + } + + #[inline] + fn from_i64(n: i64) -> Option { + Some(Self::from(n)) + } + + #[inline] + fn from_i128(n: i128) -> Option { + Some(Self::from(n)) + } + + #[inline] + fn from_isize(n: isize) -> Option { + Some(Self::from(n)) + } + + #[inline] + fn from_u8(n: u8) -> Option { + Some(Self::from(n)) + } + + #[inline] + fn from_u16(n: u16) -> Option { + Some(Self::from(n)) + } + + #[inline] + fn from_u32(n: u32) -> Option { + Some(Self::from(n)) + } + + #[inline] + fn from_u64(n: u64) -> Option { + Some(Self::from(n)) + } + + #[inline] + fn from_u128(n: u128) -> Option { + Some(Self::from(n)) + } + + #[inline] + fn from_usize(n: usize) -> Option { + Some(Self::from(n)) + } + + #[inline] + fn from_f32(n: f32) -> Option { + Self::new(&n.into()).ok() + } + + #[inline] + fn from_f64(n: f64) -> Option { + Self::new(&n.into()).ok() + } +} + +#[cfg(feature = "num-traits")] +impl Zero for BigInt { + #[inline] + fn zero() -> Self { + Self::from(0) + } + + #[inline] + fn is_zero(&self) -> bool { + self == &Self::zero() + } +} + +#[cfg(feature = "num-traits")] +impl One for BigInt { + #[inline] + fn one() -> Self { + Self::from(1) + } +} + +#[cfg(feature = "rust-num")] +impl From for num_bigint::BigInt { + #[inline] + fn from(value: BigInt) -> Self { + num_bigint::BigInt::from(&value) + } +} +#[cfg(feature = "rust-num")] +impl From<&BigInt> for num_bigint::BigInt { + #[inline] + fn from(value: &BigInt) -> Self { + num_bigint::BigInt::from_str_radix(&value.to_string_unchecked(36), 36).unwrap() + } +} + +#[cfg(feature = "rust-num")] +impl num_bigint::ToBigInt for BigInt { + #[inline] + fn to_bigint(&self) -> Option { + Some(num_bigint::BigInt::from(self)) + } +} + +#[cfg(feature = "num-bigint")] +impl From<&num_bigint::BigInt> for BigInt { + #[inline] + fn from(value: &num_bigint::BigInt) -> Self { + BigInt::from(JsValue::from(value.to_str_radix(10))) + } +} + +#[cfg(feature = "num-bigint")] +impl From for BigInt { + #[inline] + fn from(value: num_bigint::BigInt) -> Self { + BigInt::from(&value) + } +} + +#[cfg(feature = "num-bigint")] +impl From<&num_bigint::BigUint> for BigInt { + #[inline] + fn from(value: &num_bigint::BigUint) -> Self { + BigInt::from(JsValue::from(value.to_str_radix(10))) + } +} + +#[cfg(feature = "num-bigint")] +impl From for BigInt { + #[inline] + fn from(value: num_bigint::BigUint) -> Self { + BigInt::from(&value) } } @@ -1080,7 +1382,13 @@ impl PartialEq for Boolean { impl fmt::Debug for Boolean { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.value_of().fmt(f) + fmt::Debug::fmt(&self.value_of(), f) + } +} + +impl fmt::Display for Boolean { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.value_of(), f) } } @@ -2308,8 +2616,16 @@ impl From for f64 { } impl fmt::Debug for Number { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.value_of(), f) + } +} + +impl fmt::Display for Number { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.value_of().fmt(f) + fmt::Display::fmt(&self.value_of(), f) } } @@ -2348,6 +2664,8 @@ forward_js_binop!(impl Div, div for Number); forward_js_binop!(impl Mul, mul for Number); forward_js_binop!(impl Rem, rem for Number); +sum_product!(Number); + impl PartialOrd for Number { #[inline] fn partial_cmp(&self, other: &Self) -> Option { @@ -2393,6 +2711,30 @@ impl FromStr for Number { } } +#[cfg(feature = "num-traits-full")] +forward_js_binop!(impl Pow, pow for Number); + +#[cfg(feature = "num-traits")] +impl Zero for Number { + #[inline] + fn zero() -> Self { + Self::from(0.0) + } + + #[inline] + fn is_zero(&self) -> bool { + self == &Self::zero() + } +} + +#[cfg(feature = "num-traits")] +impl One for Number { + #[inline] + fn one() -> Self { + Self::from(1.0) + } +} + // Date. #[wasm_bindgen] extern "C" { @@ -4729,8 +5071,16 @@ impl From for String { } impl fmt::Debug for JsString { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&String::from(self), f) + } +} + +impl fmt::Display for JsString { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - String::from(self).fmt(f) + fmt::Display::fmt(&String::from(self), f) } } diff --git a/src/lib.rs b/src/lib.rs index ff0d5c53dc2..368b32d029e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -407,6 +407,14 @@ impl JsValue { unsafe { __wbindgen_unsigned_shr(self.idx, rhs.idx) } } + /// Applies the binary `/` JS operator on two `JsValue`s, catching and returning any `RangeError` thrown. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Division) + #[inline] + pub fn checked_div(&self, rhs: &Self) -> Self { + unsafe { JsValue::_new(__wbindgen_checked_div(self.idx, rhs.idx)) } + } + /// Applies the binary `**` JS operator on the two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Exponentiation) @@ -744,6 +752,22 @@ impl Rem for &JsValue { forward_deref_binop!(impl Rem, rem for JsValue); +#[cfg(feature = "num-traits")] +use num_traits::Pow; + +#[cfg(feature = "num-traits")] +impl num_traits::Pow<&JsValue> for &JsValue { + type Output = JsValue; + + #[inline] + fn pow(self, rhs: &JsValue) -> Self::Output { + JsValue::pow(self, rhs) + } +} + +#[cfg(feature = "num-traits")] +forward_deref_binop!(impl Pow, pow for JsValue); + impl<'a> From<&'a str> for JsValue { #[inline] fn from(s: &'a str) -> JsValue { @@ -899,6 +923,7 @@ externs! { fn __wbindgen_add(a: u32, b: u32) -> u32; fn __wbindgen_sub(a: u32, b: u32) -> u32; fn __wbindgen_div(a: u32, b: u32) -> u32; + fn __wbindgen_checked_div(a: u32, b: u32) -> u32; fn __wbindgen_mul(a: u32, b: u32) -> u32; fn __wbindgen_rem(a: u32, b: u32) -> u32; fn __wbindgen_pow(a: u32, b: u32) -> u32; From f976076b5a619609f12e82b7a8dd33dddc12fae2 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Fri, 6 Aug 2021 15:53:17 +0200 Subject: [PATCH 21/27] Add `PartialOrd` and `Ord` impls for more types --- crates/js-sys/src/lib.rs | 88 ++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 39 deletions(-) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index d99a8c551c8..d5c22591d0e 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -175,6 +175,50 @@ macro_rules! sum_product { )*) } +macro_rules! partialord_ord { + ($t:ident) => { + impl PartialOrd for $t { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } + + #[inline] + fn lt(&self, other: &Self) -> bool { + JsValue::as_ref(self).lt(JsValue::as_ref(other)) + } + + #[inline] + fn le(&self, other: &Self) -> bool { + JsValue::as_ref(self).le(JsValue::as_ref(other)) + } + + #[inline] + fn ge(&self, other: &Self) -> bool { + JsValue::as_ref(self).ge(JsValue::as_ref(other)) + } + + #[inline] + fn gt(&self, other: &Self) -> bool { + JsValue::as_ref(self).gt(JsValue::as_ref(other)) + } + } + + impl Ord for $t { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + if self == other { + Ordering::Equal + } else if self.lt(other) { + Ordering::Less + } else { + Ordering::Greater + } + } + } + }; +} + #[wasm_bindgen] extern "C" { /// The `decodeURI()` function decodes a Uniform Resource Identifier (URI) @@ -1050,45 +1094,7 @@ forward_js_binop!(impl Mul, mul for BigInt); forward_js_binop!(impl Rem, rem for BigInt); sum_product!(BigInt); -impl PartialOrd for BigInt { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } - - #[inline] - fn lt(&self, other: &Self) -> bool { - JsValue::as_ref(self).lt(JsValue::as_ref(other)) - } - - #[inline] - fn le(&self, other: &Self) -> bool { - JsValue::as_ref(self).le(JsValue::as_ref(other)) - } - - #[inline] - fn ge(&self, other: &Self) -> bool { - JsValue::as_ref(self).ge(JsValue::as_ref(other)) - } - - #[inline] - fn gt(&self, other: &Self) -> bool { - JsValue::as_ref(self).gt(JsValue::as_ref(other)) - } -} - -impl Ord for BigInt { - #[inline] - fn cmp(&self, other: &Self) -> Ordering { - if self == other { - Ordering::Equal - } else if self.lt(other) { - Ordering::Less - } else { - Ordering::Greater - } - } -} +partialord_ord!(BigInt); impl Default for BigInt { fn default() -> Self { @@ -1409,6 +1415,8 @@ impl Not for &Boolean { forward_deref_unop!(impl Not, not for Boolean); +partialord_ord!(Boolean); + // DataView #[wasm_bindgen] extern "C" { @@ -1680,6 +1688,8 @@ extern "C" { pub fn to_string(this: &Error) -> JsString; } +partialord_ord!(JsString); + // EvalError #[wasm_bindgen] extern "C" { From 7185873731dcc222d70d4acf1d5a8bf1bdc00645 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Fri, 27 Aug 2021 10:16:15 -0400 Subject: [PATCH 22/27] Cargo fmt --- crates/js-sys/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index d5c22591d0e..7a9c63d09c1 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -182,28 +182,28 @@ macro_rules! partialord_ord { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } - + #[inline] fn lt(&self, other: &Self) -> bool { JsValue::as_ref(self).lt(JsValue::as_ref(other)) } - + #[inline] fn le(&self, other: &Self) -> bool { JsValue::as_ref(self).le(JsValue::as_ref(other)) } - + #[inline] fn ge(&self, other: &Self) -> bool { JsValue::as_ref(self).ge(JsValue::as_ref(other)) } - + #[inline] fn gt(&self, other: &Self) -> bool { JsValue::as_ref(self).gt(JsValue::as_ref(other)) } } - + impl Ord for $t { #[inline] fn cmp(&self, other: &Self) -> Ordering { From 5455ae307c1988bb04a26baac207492d6ca2bd0d Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 1 Sep 2021 19:37:44 -0400 Subject: [PATCH 23/27] Remove `num-traits` from `wasm-bindgen`, integrate `js-sys` with `rust-num` further --- Cargo.toml | 1 - crates/js-sys/Cargo.toml | 3 +- crates/js-sys/src/lib.rs | 393 +++++++++++++++++++++++++++++++++++---- src/lib.rs | 16 -- 4 files changed, 357 insertions(+), 56 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0b51b1e039c..ad9d1da96a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,6 @@ 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 } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] js-sys = { path = 'crates/js-sys', version = '0.3.53' } diff --git a/crates/js-sys/Cargo.toml b/crates/js-sys/Cargo.toml index 39a9e626fe5..0dc2e58cd9f 100644 --- a/crates/js-sys/Cargo.toml +++ b/crates/js-sys/Cargo.toml @@ -19,8 +19,7 @@ test = false doctest = false [features] -rust-num = ["num-bigint", "num-traits", "wasm-bindgen/num-traits"] -num-traits-full = ["num-traits", "wasm-bindgen/num-traits"] +rust-num = ["num-bigint", "num-traits"] [dependencies] wasm-bindgen = { path = "../..", version = "0.2.75" } diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index 7a9c63d09c1..53567277bcf 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -31,12 +31,10 @@ use std::str::FromStr; use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; -#[cfg(feature = "rust-num")] +#[cfg(all(feature = "num-bigint", feature = "num-traits"))] use num_traits::Num; -#[cfg(feature = "num-traits-full")] -use num_traits::Pow; #[cfg(feature = "num-traits")] -use num_traits::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, FromPrimitive, One, Zero}; +use num_traits::{Inv, Pow}; // When adding new imports: // @@ -1159,11 +1157,8 @@ impl fmt::UpperHex for BigInt { } } -#[cfg(feature = "num-traits-full")] -forward_js_binop!(impl Pow, pow for BigInt); - #[cfg(feature = "num-traits")] -impl CheckedAdd for BigInt { +impl num_traits::CheckedAdd for BigInt { #[inline] fn checked_add(&self, v: &Self) -> Option { Some(self + v) @@ -1171,15 +1166,15 @@ impl CheckedAdd for BigInt { } #[cfg(feature = "num-traits")] -impl CheckedSub for BigInt { +impl num_traits::CheckedDiv for BigInt { #[inline] - fn checked_sub(&self, v: &Self) -> Option { - Some(self - v) + fn checked_div(&self, v: &Self) -> Option { + BigInt::checked_div(&self, v).ok() } } #[cfg(feature = "num-traits")] -impl CheckedMul for BigInt { +impl num_traits::CheckedMul for BigInt { #[inline] fn checked_mul(&self, v: &Self) -> Option { Some(self * v) @@ -1187,15 +1182,15 @@ impl CheckedMul for BigInt { } #[cfg(feature = "num-traits")] -impl CheckedDiv for BigInt { +impl num_traits::CheckedSub for BigInt { #[inline] - fn checked_div(&self, v: &Self) -> Option { - BigInt::checked_div(&self, v).ok() + fn checked_sub(&self, v: &Self) -> Option { + Some(self - v) } } #[cfg(feature = "num-traits")] -impl FromPrimitive for BigInt { +impl num_traits::FromPrimitive for BigInt { #[inline] fn from_i8(n: i8) -> Option { Some(Self::from(n)) @@ -1267,35 +1262,143 @@ impl FromPrimitive for BigInt { } } +#[cfg(all(feature = "num-bigint", feature = "num-traits"))] +pub enum ParseBigIntError { + JsError(crate::Error), + NumBigIntError(num_bigint::ParseBigIntError), +} + +#[cfg(all(feature = "num-bigint", feature = "num-traits"))] +impl num_traits::Num for BigInt { + type FromStrRadixErr = ParseBigIntError; + + fn from_str_radix(str: &str, radix: u32) -> Result { + if radix == 10 { + match BigInt::from_str(str) { + Ok(bigint) => Ok(bigint), + Err(error) => Err(ParseBigIntError::JsError(error)), + } + } else { + match num_bigint::BigInt::from_str_radix(str, radix) { + Ok(num_bigint) => Ok(num_bigint.into()), + Err(parse_err) => Err(ParseBigIntError::NumBigIntError(parse_err)), + } + } + } +} + #[cfg(feature = "num-traits")] -impl Zero for BigInt { +impl num_traits::One for BigInt { #[inline] - fn zero() -> Self { - Self::from(0) + fn one() -> Self { + Self::from(1) } +} - #[inline] - fn is_zero(&self) -> bool { - self == &Self::zero() +#[cfg(feature = "num-traits")] +impl num_traits::Pow<&BigInt> for &BigInt { + type Output = BigInt; + + fn pow(self, rhs: &BigInt) -> Self::Output { + JsValue::as_ref(self) + .pow(JsValue::as_ref(&rhs)) + .unchecked_into() + } +} + +#[cfg(feature = "num-traits")] +forward_deref_binop!(impl Pow, pow for BigInt); + +#[cfg(feature = "num-traits")] +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(method, js_name = "valueOf")] + fn unchecked_as_i64(this: &BigInt) -> i64; + + #[wasm_bindgen(method, js_name = "valueOf")] + fn unchecked_as_u64(this: &BigInt) -> u64; +} + +#[cfg(all(feature = "num-bigint", feature = "num-traits"))] +impl num_traits::Signed for BigInt { + fn abs(&self) -> Self { + if self < &num_traits::Zero::zero() { + -self + } else { + --self + } + } + + fn abs_sub(&self, other: &Self) -> Self { + if self <= other { + num_traits::Zero::zero() + } else { + self - other + } + } + + fn signum(&self) -> Self { + let zero = num_traits::Zero::zero(); + if self > &zero { + num_traits::One::one() + } else if self < &zero { + -::one() + } else { + zero + } + } + + fn is_positive(&self) -> bool { + self > &num_traits::Zero::zero() + } + + fn is_negative(&self) -> bool { + self < &num_traits::Zero::zero() + } +} + +#[cfg(feature = "num-traits")] +impl num_traits::ToPrimitive for BigInt { + fn to_i64(&self) -> Option { + let self_truncated = BigInt::as_int_n(64.0, self); + if self == &self_truncated { + Some(self.unchecked_as_i64()) + } else { + None + } + } + + fn to_u64(&self) -> Option { + let self_truncated = BigInt::as_uint_n(64.0, self); + if self == &self_truncated { + Some(self.unchecked_as_u64()) + } else { + None + } } } #[cfg(feature = "num-traits")] -impl One for BigInt { +impl num_traits::Zero for BigInt { #[inline] - fn one() -> Self { - Self::from(1) + fn zero() -> Self { + Self::from(0) + } + + #[inline] + fn is_zero(&self) -> bool { + self == &Self::zero() } } -#[cfg(feature = "rust-num")] +#[cfg(all(feature = "num-bigint", feature = "num-traits"))] impl From for num_bigint::BigInt { #[inline] fn from(value: BigInt) -> Self { num_bigint::BigInt::from(&value) } } -#[cfg(feature = "rust-num")] +#[cfg(all(feature = "num-bigint", feature = "num-traits"))] impl From<&BigInt> for num_bigint::BigInt { #[inline] fn from(value: &BigInt) -> Self { @@ -1303,7 +1406,7 @@ impl From<&BigInt> for num_bigint::BigInt { } } -#[cfg(feature = "rust-num")] +#[cfg(all(feature = "num-bigint", feature = "num-traits"))] impl num_bigint::ToBigInt for BigInt { #[inline] fn to_bigint(&self) -> Option { @@ -2618,10 +2721,17 @@ impl convert::TryFrom for Number { } */ +impl From<&Number> for f64 { + #[inline] + fn from(n: &Number) -> f64 { + n.value_of() + } +} + impl From for f64 { #[inline] fn from(n: Number) -> f64 { - n.value_of() + n.into() } } @@ -2721,30 +2831,239 @@ impl FromStr for Number { } } -#[cfg(feature = "num-traits-full")] -forward_js_binop!(impl Pow, pow for Number); +#[cfg(feature = "num-traits")] +impl num_traits::Bounded for Number { + fn min_value() -> Self { + Self::MIN_VALUE.into() + } + + fn max_value() -> Self { + Self::MAX_VALUE.into() + } +} #[cfg(feature = "num-traits")] -impl Zero for Number { +impl num_traits::FromPrimitive for Number { #[inline] - fn zero() -> Self { - Self::from(0.0) + fn from_i8(n: i8) -> Option { + Some(Self::from(n)) } #[inline] - fn is_zero(&self) -> bool { - self == &Self::zero() + fn from_i16(n: i16) -> Option { + Some(Self::from(n)) + } + + #[inline] + fn from_i32(n: i32) -> Option { + Some(Self::from(n)) + } + + #[inline] + fn from_i64(n: i64) -> Option { + Some(Self::from(n as f64)) + } + + #[inline] + fn from_i128(n: i128) -> Option { + Some(Self::from(n as f64)) + } + + #[inline] + fn from_isize(n: isize) -> Option { + Some(Self::from(n as f64)) + } + + #[inline] + fn from_u8(n: u8) -> Option { + Some(Self::from(n)) + } + + #[inline] + fn from_u16(n: u16) -> Option { + Some(Self::from(n)) + } + + #[inline] + fn from_u32(n: u32) -> Option { + Some(Self::from(n)) + } + + #[inline] + fn from_u64(n: u64) -> Option { + Some(Self::from(n as f64)) + } + + #[inline] + fn from_u128(n: u128) -> Option { + Some(Self::from(n as f64)) + } + + #[inline] + fn from_usize(n: usize) -> Option { + Some(Self::from(n as f64)) + } + + #[inline] + fn from_f32(n: f32) -> Option { + Some(Self::from(n)) + } + + #[inline] + fn from_f64(n: f64) -> Option { + Some(Self::from(n)) } } #[cfg(feature = "num-traits")] -impl One for Number { +impl num_traits::Inv for &Number { + type Output = Number; + + fn inv(self) -> Self::Output { + f64::from(self).inv().into() + } +} + +#[cfg(feature = "num-traits")] +forward_deref_unop!(impl Inv, inv for Number); + +#[cfg(feature = "num-traits")] +impl num_traits::Num for Number { + type FromStrRadixErr = ::FromStrRadixErr; + + fn from_str_radix(str: &str, radix: u32) -> Result { + Ok(f64::from_str_radix(str, radix)?.into()) + } +} + +#[cfg(feature = "num-traits")] +impl num_traits::NumCast for Number { + fn from(n: T) -> Option { + Some(n.to_f64()?.into()) + } +} + +#[cfg(feature = "num-traits")] +impl num_traits::One for Number { #[inline] fn one() -> Self { Self::from(1.0) } } +#[cfg(feature = "num-traits")] +impl num_traits::Pow<&Number> for &Number { + type Output = Number; + + fn pow(self, rhs: &Number) -> Self::Output { + JsValue::as_ref(self) + .pow(JsValue::as_ref(&rhs)) + .unchecked_into() + } +} + +#[cfg(feature = "num-traits")] +forward_deref_binop!(impl Pow, pow for Number); + +#[cfg(feature = "num-traits")] +impl num_traits::Signed for Number { + fn abs(&self) -> Self { + Math::abs(self.into()).into() + } + + fn abs_sub(&self, other: &Self) -> Self { + if self <= other { + num_traits::Zero::zero() + } else { + self - other + } + } + + fn signum(&self) -> Self { + f64::from(self).signum().into() + } + + fn is_positive(&self) -> bool { + f64::from(self).is_sign_positive() + } + + fn is_negative(&self) -> bool { + f64::from(self).is_sign_negative() + } +} + +#[cfg(feature = "num-traits")] +impl num_traits::ToPrimitive for Number { + fn to_isize(&self) -> Option { + f64::from(self).to_isize() + } + + fn to_i8(&self) -> Option { + f64::from(self).to_i8() + } + + fn to_i16(&self) -> Option { + f64::from(self).to_i16() + } + + fn to_i32(&self) -> Option { + f64::from(self).to_i32() + } + + fn to_i64(&self) -> Option { + f64::from(self).to_i64() + } + + fn to_i128(&self) -> Option { + f64::from(self).to_i128() + } + + fn to_usize(&self) -> Option { + f64::from(self).to_usize() + } + + fn to_u8(&self) -> Option { + f64::from(self).to_u8() + } + + fn to_u16(&self) -> Option { + f64::from(self).to_u16() + } + + fn to_u32(&self) -> Option { + f64::from(self).to_u32() + } + + fn to_u64(&self) -> Option { + f64::from(self).to_u64() + } + + fn to_u128(&self) -> Option { + f64::from(self).to_u128() + } + + fn to_f32(&self) -> Option { + f64::from(self).to_f32() + } + + fn to_f64(&self) -> Option { + f64::from(self).to_f64() + } +} + +#[cfg(feature = "num-traits")] +impl num_traits::Zero for Number { + #[inline] + fn zero() -> Self { + Self::from(0.0) + } + + #[inline] + fn is_zero(&self) -> bool { + self == &::zero() + } +} + // Date. #[wasm_bindgen] extern "C" { diff --git a/src/lib.rs b/src/lib.rs index 368b32d029e..087a85bd589 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -752,22 +752,6 @@ impl Rem for &JsValue { forward_deref_binop!(impl Rem, rem for JsValue); -#[cfg(feature = "num-traits")] -use num_traits::Pow; - -#[cfg(feature = "num-traits")] -impl num_traits::Pow<&JsValue> for &JsValue { - type Output = JsValue; - - #[inline] - fn pow(self, rhs: &JsValue) -> Self::Output { - JsValue::pow(self, rhs) - } -} - -#[cfg(feature = "num-traits")] -forward_deref_binop!(impl Pow, pow for JsValue); - impl<'a> From<&'a str> for JsValue { #[inline] fn from(s: &'a str) -> JsValue { From 589532ec85bb90ab52aeefa37bc559593c8a559e Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 1 Sep 2021 21:12:37 -0400 Subject: [PATCH 24/27] Update Cargo.toml --- crates/js-sys/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/js-sys/Cargo.toml b/crates/js-sys/Cargo.toml index 0dc2e58cd9f..4cb1edc3a11 100644 --- a/crates/js-sys/Cargo.toml +++ b/crates/js-sys/Cargo.toml @@ -22,8 +22,8 @@ doctest = false rust-num = ["num-bigint", "num-traits"] [dependencies] -wasm-bindgen = { path = "../..", version = "0.2.75" } -num-bigint = { version = "0.4.0", optional = true } +wasm-bindgen = { path = "../..", version = "0.2.76" } +num-bigint = { version = "0.4.1", optional = true } num-traits = { version = "0.2.14", optional = true } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] From 087d29191cc5b5bcad9480f6572b681a03926d40 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 1 Sep 2021 21:22:04 -0400 Subject: [PATCH 25/27] Update Rust version for CI (to allow proc-macro2 to build again) --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8d6ec65f24e..db3496e1f7a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -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 @@ -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: | From 76b8065396f82fbcc887274e1bd6271bea681773 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 1 Sep 2021 21:27:09 -0400 Subject: [PATCH 26/27] Fix link in Markdown --- crates/js-sys/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index 53567277bcf..a7002e2e479 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -5,7 +5,7 @@ //! APIs. Only the things that are guaranteed to exist in the global scope by //! the ECMAScript standard. //! -//! https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects +//! //! //! ## A Note About `camelCase`, `snake_case`, and Naming Conventions //! From 2dc02ffd0f862df7867bc9938998c8531f11596c Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Thu, 2 Sep 2021 11:14:08 -0400 Subject: [PATCH 27/27] Remove all `rust-num` code from `js-sys` --- crates/js-sys/Cargo.toml | 5 - crates/js-sys/src/lib.rs | 527 --------------------------------------- 2 files changed, 532 deletions(-) diff --git a/crates/js-sys/Cargo.toml b/crates/js-sys/Cargo.toml index 4cb1edc3a11..8c2b2de1dd6 100644 --- a/crates/js-sys/Cargo.toml +++ b/crates/js-sys/Cargo.toml @@ -18,13 +18,8 @@ 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 } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] wasm-bindgen-test = { path = '../test', version = '=0.3.26' } diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index a7002e2e479..71db35e51d9 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -31,11 +31,6 @@ use std::str::FromStr; use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; -#[cfg(all(feature = "num-bigint", feature = "num-traits"))] -use num_traits::Num; -#[cfg(feature = "num-traits")] -use num_traits::{Inv, Pow}; - // When adding new imports: // // * Keep imports in alphabetical order. @@ -1157,295 +1152,6 @@ impl fmt::UpperHex for BigInt { } } -#[cfg(feature = "num-traits")] -impl num_traits::CheckedAdd for BigInt { - #[inline] - fn checked_add(&self, v: &Self) -> Option { - Some(self + v) - } -} - -#[cfg(feature = "num-traits")] -impl num_traits::CheckedDiv for BigInt { - #[inline] - fn checked_div(&self, v: &Self) -> Option { - BigInt::checked_div(&self, v).ok() - } -} - -#[cfg(feature = "num-traits")] -impl num_traits::CheckedMul for BigInt { - #[inline] - fn checked_mul(&self, v: &Self) -> Option { - Some(self * v) - } -} - -#[cfg(feature = "num-traits")] -impl num_traits::CheckedSub for BigInt { - #[inline] - fn checked_sub(&self, v: &Self) -> Option { - Some(self - v) - } -} - -#[cfg(feature = "num-traits")] -impl num_traits::FromPrimitive for BigInt { - #[inline] - fn from_i8(n: i8) -> Option { - Some(Self::from(n)) - } - - #[inline] - fn from_i16(n: i16) -> Option { - Some(Self::from(n)) - } - - #[inline] - fn from_i32(n: i32) -> Option { - Some(Self::from(n)) - } - - #[inline] - fn from_i64(n: i64) -> Option { - Some(Self::from(n)) - } - - #[inline] - fn from_i128(n: i128) -> Option { - Some(Self::from(n)) - } - - #[inline] - fn from_isize(n: isize) -> Option { - Some(Self::from(n)) - } - - #[inline] - fn from_u8(n: u8) -> Option { - Some(Self::from(n)) - } - - #[inline] - fn from_u16(n: u16) -> Option { - Some(Self::from(n)) - } - - #[inline] - fn from_u32(n: u32) -> Option { - Some(Self::from(n)) - } - - #[inline] - fn from_u64(n: u64) -> Option { - Some(Self::from(n)) - } - - #[inline] - fn from_u128(n: u128) -> Option { - Some(Self::from(n)) - } - - #[inline] - fn from_usize(n: usize) -> Option { - Some(Self::from(n)) - } - - #[inline] - fn from_f32(n: f32) -> Option { - Self::new(&n.into()).ok() - } - - #[inline] - fn from_f64(n: f64) -> Option { - Self::new(&n.into()).ok() - } -} - -#[cfg(all(feature = "num-bigint", feature = "num-traits"))] -pub enum ParseBigIntError { - JsError(crate::Error), - NumBigIntError(num_bigint::ParseBigIntError), -} - -#[cfg(all(feature = "num-bigint", feature = "num-traits"))] -impl num_traits::Num for BigInt { - type FromStrRadixErr = ParseBigIntError; - - fn from_str_radix(str: &str, radix: u32) -> Result { - if radix == 10 { - match BigInt::from_str(str) { - Ok(bigint) => Ok(bigint), - Err(error) => Err(ParseBigIntError::JsError(error)), - } - } else { - match num_bigint::BigInt::from_str_radix(str, radix) { - Ok(num_bigint) => Ok(num_bigint.into()), - Err(parse_err) => Err(ParseBigIntError::NumBigIntError(parse_err)), - } - } - } -} - -#[cfg(feature = "num-traits")] -impl num_traits::One for BigInt { - #[inline] - fn one() -> Self { - Self::from(1) - } -} - -#[cfg(feature = "num-traits")] -impl num_traits::Pow<&BigInt> for &BigInt { - type Output = BigInt; - - fn pow(self, rhs: &BigInt) -> Self::Output { - JsValue::as_ref(self) - .pow(JsValue::as_ref(&rhs)) - .unchecked_into() - } -} - -#[cfg(feature = "num-traits")] -forward_deref_binop!(impl Pow, pow for BigInt); - -#[cfg(feature = "num-traits")] -#[wasm_bindgen] -extern "C" { - #[wasm_bindgen(method, js_name = "valueOf")] - fn unchecked_as_i64(this: &BigInt) -> i64; - - #[wasm_bindgen(method, js_name = "valueOf")] - fn unchecked_as_u64(this: &BigInt) -> u64; -} - -#[cfg(all(feature = "num-bigint", feature = "num-traits"))] -impl num_traits::Signed for BigInt { - fn abs(&self) -> Self { - if self < &num_traits::Zero::zero() { - -self - } else { - --self - } - } - - fn abs_sub(&self, other: &Self) -> Self { - if self <= other { - num_traits::Zero::zero() - } else { - self - other - } - } - - fn signum(&self) -> Self { - let zero = num_traits::Zero::zero(); - if self > &zero { - num_traits::One::one() - } else if self < &zero { - -::one() - } else { - zero - } - } - - fn is_positive(&self) -> bool { - self > &num_traits::Zero::zero() - } - - fn is_negative(&self) -> bool { - self < &num_traits::Zero::zero() - } -} - -#[cfg(feature = "num-traits")] -impl num_traits::ToPrimitive for BigInt { - fn to_i64(&self) -> Option { - let self_truncated = BigInt::as_int_n(64.0, self); - if self == &self_truncated { - Some(self.unchecked_as_i64()) - } else { - None - } - } - - fn to_u64(&self) -> Option { - let self_truncated = BigInt::as_uint_n(64.0, self); - if self == &self_truncated { - Some(self.unchecked_as_u64()) - } else { - None - } - } -} - -#[cfg(feature = "num-traits")] -impl num_traits::Zero for BigInt { - #[inline] - fn zero() -> Self { - Self::from(0) - } - - #[inline] - fn is_zero(&self) -> bool { - self == &Self::zero() - } -} - -#[cfg(all(feature = "num-bigint", feature = "num-traits"))] -impl From for num_bigint::BigInt { - #[inline] - fn from(value: BigInt) -> Self { - num_bigint::BigInt::from(&value) - } -} -#[cfg(all(feature = "num-bigint", feature = "num-traits"))] -impl From<&BigInt> for num_bigint::BigInt { - #[inline] - fn from(value: &BigInt) -> Self { - num_bigint::BigInt::from_str_radix(&value.to_string_unchecked(36), 36).unwrap() - } -} - -#[cfg(all(feature = "num-bigint", feature = "num-traits"))] -impl num_bigint::ToBigInt for BigInt { - #[inline] - fn to_bigint(&self) -> Option { - Some(num_bigint::BigInt::from(self)) - } -} - -#[cfg(feature = "num-bigint")] -impl From<&num_bigint::BigInt> for BigInt { - #[inline] - fn from(value: &num_bigint::BigInt) -> Self { - BigInt::from(JsValue::from(value.to_str_radix(10))) - } -} - -#[cfg(feature = "num-bigint")] -impl From for BigInt { - #[inline] - fn from(value: num_bigint::BigInt) -> Self { - BigInt::from(&value) - } -} - -#[cfg(feature = "num-bigint")] -impl From<&num_bigint::BigUint> for BigInt { - #[inline] - fn from(value: &num_bigint::BigUint) -> Self { - BigInt::from(JsValue::from(value.to_str_radix(10))) - } -} - -#[cfg(feature = "num-bigint")] -impl From for BigInt { - #[inline] - fn from(value: num_bigint::BigUint) -> Self { - BigInt::from(&value) - } -} - // Boolean #[wasm_bindgen] extern "C" { @@ -2831,239 +2537,6 @@ impl FromStr for Number { } } -#[cfg(feature = "num-traits")] -impl num_traits::Bounded for Number { - fn min_value() -> Self { - Self::MIN_VALUE.into() - } - - fn max_value() -> Self { - Self::MAX_VALUE.into() - } -} - -#[cfg(feature = "num-traits")] -impl num_traits::FromPrimitive for Number { - #[inline] - fn from_i8(n: i8) -> Option { - Some(Self::from(n)) - } - - #[inline] - fn from_i16(n: i16) -> Option { - Some(Self::from(n)) - } - - #[inline] - fn from_i32(n: i32) -> Option { - Some(Self::from(n)) - } - - #[inline] - fn from_i64(n: i64) -> Option { - Some(Self::from(n as f64)) - } - - #[inline] - fn from_i128(n: i128) -> Option { - Some(Self::from(n as f64)) - } - - #[inline] - fn from_isize(n: isize) -> Option { - Some(Self::from(n as f64)) - } - - #[inline] - fn from_u8(n: u8) -> Option { - Some(Self::from(n)) - } - - #[inline] - fn from_u16(n: u16) -> Option { - Some(Self::from(n)) - } - - #[inline] - fn from_u32(n: u32) -> Option { - Some(Self::from(n)) - } - - #[inline] - fn from_u64(n: u64) -> Option { - Some(Self::from(n as f64)) - } - - #[inline] - fn from_u128(n: u128) -> Option { - Some(Self::from(n as f64)) - } - - #[inline] - fn from_usize(n: usize) -> Option { - Some(Self::from(n as f64)) - } - - #[inline] - fn from_f32(n: f32) -> Option { - Some(Self::from(n)) - } - - #[inline] - fn from_f64(n: f64) -> Option { - Some(Self::from(n)) - } -} - -#[cfg(feature = "num-traits")] -impl num_traits::Inv for &Number { - type Output = Number; - - fn inv(self) -> Self::Output { - f64::from(self).inv().into() - } -} - -#[cfg(feature = "num-traits")] -forward_deref_unop!(impl Inv, inv for Number); - -#[cfg(feature = "num-traits")] -impl num_traits::Num for Number { - type FromStrRadixErr = ::FromStrRadixErr; - - fn from_str_radix(str: &str, radix: u32) -> Result { - Ok(f64::from_str_radix(str, radix)?.into()) - } -} - -#[cfg(feature = "num-traits")] -impl num_traits::NumCast for Number { - fn from(n: T) -> Option { - Some(n.to_f64()?.into()) - } -} - -#[cfg(feature = "num-traits")] -impl num_traits::One for Number { - #[inline] - fn one() -> Self { - Self::from(1.0) - } -} - -#[cfg(feature = "num-traits")] -impl num_traits::Pow<&Number> for &Number { - type Output = Number; - - fn pow(self, rhs: &Number) -> Self::Output { - JsValue::as_ref(self) - .pow(JsValue::as_ref(&rhs)) - .unchecked_into() - } -} - -#[cfg(feature = "num-traits")] -forward_deref_binop!(impl Pow, pow for Number); - -#[cfg(feature = "num-traits")] -impl num_traits::Signed for Number { - fn abs(&self) -> Self { - Math::abs(self.into()).into() - } - - fn abs_sub(&self, other: &Self) -> Self { - if self <= other { - num_traits::Zero::zero() - } else { - self - other - } - } - - fn signum(&self) -> Self { - f64::from(self).signum().into() - } - - fn is_positive(&self) -> bool { - f64::from(self).is_sign_positive() - } - - fn is_negative(&self) -> bool { - f64::from(self).is_sign_negative() - } -} - -#[cfg(feature = "num-traits")] -impl num_traits::ToPrimitive for Number { - fn to_isize(&self) -> Option { - f64::from(self).to_isize() - } - - fn to_i8(&self) -> Option { - f64::from(self).to_i8() - } - - fn to_i16(&self) -> Option { - f64::from(self).to_i16() - } - - fn to_i32(&self) -> Option { - f64::from(self).to_i32() - } - - fn to_i64(&self) -> Option { - f64::from(self).to_i64() - } - - fn to_i128(&self) -> Option { - f64::from(self).to_i128() - } - - fn to_usize(&self) -> Option { - f64::from(self).to_usize() - } - - fn to_u8(&self) -> Option { - f64::from(self).to_u8() - } - - fn to_u16(&self) -> Option { - f64::from(self).to_u16() - } - - fn to_u32(&self) -> Option { - f64::from(self).to_u32() - } - - fn to_u64(&self) -> Option { - f64::from(self).to_u64() - } - - fn to_u128(&self) -> Option { - f64::from(self).to_u128() - } - - fn to_f32(&self) -> Option { - f64::from(self).to_f32() - } - - fn to_f64(&self) -> Option { - f64::from(self).to_f64() - } -} - -#[cfg(feature = "num-traits")] -impl num_traits::Zero for Number { - #[inline] - fn zero() -> Self { - Self::from(0.0) - } - - #[inline] - fn is_zero(&self) -> bool { - self == &::zero() - } -} - // Date. #[wasm_bindgen] extern "C" {