From 9f9fe8f45c58bfda29a31876b994b583516d93c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Gaspard?= Date: Tue, 20 Feb 2024 06:42:34 +0100 Subject: [PATCH 01/12] Introduce impl TryFrom for Number that succeeds iff the value is within the safe range --- crates/js-sys/src/lib.rs | 18 ++++++++++++++++++ crates/js-sys/tests/wasm/Number.rs | 20 +++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index b18faf6cae0..4f2b8fc53b7 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -2793,6 +2793,24 @@ macro_rules! number_from { } number_from!(i8 u8 i16 u16 i32 u32 f32 f64); +macro_rules! number_try_from { + ($($x:ident)*) => ($( + impl TryFrom<$x> for Number { + type Error = $x; + + #[inline] + fn try_from(x: $x) -> Result { + if x as f64 >= Number::MIN_SAFE_INTEGER && x as f64 <= Number::MAX_SAFE_INTEGER { + Ok(Number::unchecked_from_js(JsValue::from(x as f64))) + } else { + Err(x) + } + } + } + )*) +} +number_try_from!(i64 u64 i128 u128); + // TODO: add this on the next major version, when blanket impl is removed /* impl convert::TryFrom for Number { diff --git a/crates/js-sys/tests/wasm/Number.rs b/crates/js-sys/tests/wasm/Number.rs index 94fd551f33e..31f3f565fe8 100644 --- a/crates/js-sys/tests/wasm/Number.rs +++ b/crates/js-sys/tests/wasm/Number.rs @@ -1,4 +1,7 @@ -use std::f64::{INFINITY, NAN}; +use std::{ + convert::TryFrom, + f64::{INFINITY, NAN}, +}; use js_sys::*; use wasm_bindgen::prelude::*; @@ -71,6 +74,21 @@ fn new() { assert_eq!(Number::from(v).value_of(), 42.); } +#[wasm_bindgen_test] +fn try_from() { + assert_eq!(Number::try_from(42u128).unwrap(), 42.); + assert_eq!( + Number::try_from(Number::MAX_SAFE_INTEGER as u64).unwrap(), + Number::MAX_SAFE_INTEGER + ); + assert_eq!( + Number::try_from(Number::MIN_SAFE_INTEGER as i128).unwrap(), + Number::MIN_SAFE_INTEGER + ); + assert!(Number::try_from(Number::MAX_SAFE_INTEGER as u128 + 1).is_err()); + assert!(Number::try_from(Number::MIN_SAFE_INTEGER as i64 - 1).is_err()); +} + #[wasm_bindgen_test] fn parse_int_float() { assert_eq!(Number::parse_int("42", 10), 42.); From bd8ee729cce7df0a3f7e7d3ae76a1d86ba18ada4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Gaspard?= Date: Tue, 20 Feb 2024 19:48:17 +0100 Subject: [PATCH 02/12] apply review suggestion --- crates/js-sys/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index 4f2b8fc53b7..1510b1f7d68 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -2800,8 +2800,9 @@ macro_rules! number_try_from { #[inline] fn try_from(x: $x) -> Result { - if x as f64 >= Number::MIN_SAFE_INTEGER && x as f64 <= Number::MAX_SAFE_INTEGER { - Ok(Number::unchecked_from_js(JsValue::from(x as f64))) + let x_f64 = x as f64; + if x_f64 >= Number::MIN_SAFE_INTEGER && x_f64 <= Number::MAX_SAFE_INTEGER { + Ok(Number::unchecked_from_js(JsValue::from(x_f64))) } else { Err(x) } From 464d68cc7d85f34a1c2bf9efdb4a8f1b17ca45b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Gaspard?= Date: Tue, 20 Feb 2024 19:49:06 +0100 Subject: [PATCH 03/12] add changelog entry --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56fb600f0c3..0fe6896b1a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ * Add bindings for `CanvasState.reset()`, affecting `CanvasRenderingContext2D` and `OffscreenCanvasRenderingContext2D`. [#3844](https://github.com/rustwasm/wasm-bindgen/pull/3844) +* Add `TryFrom` implementations for `Number`, that allow losslessly converting from 64- and 128-bits numbers + -------------------------------------------------------------------------------- ## [0.2.91](https://github.com/rustwasm/wasm-bindgen/compare/0.2.90...0.2.91) From d582f8363f769aea2ea413fe3978232a5c49a54f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Gaspard?= Date: Tue, 20 Feb 2024 19:53:15 +0100 Subject: [PATCH 04/12] introduce a real error type --- crates/js-sys/src/lib.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index 1510b1f7d68..0b03e479050 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -2793,6 +2793,26 @@ macro_rules! number_from { } number_from!(i8 u8 i16 u16 i32 u32 f32 f64); +/// The error type returned when a checked integral type conversion fails. +/// +/// This type is copy-pasted from the standard library +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct TryFromIntError(pub(crate) ()); + +impl fmt::Display for TryFromIntError { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + #[allow(deprecated)] + std::error::Error::description(&self).fmt(fmt) + } +} + +impl std::error::Error for TryFromIntError { + #[allow(deprecated)] + fn description(&self) -> &str { + "out of range integral type conversion attempted" + } +} + macro_rules! number_try_from { ($($x:ident)*) => ($( impl TryFrom<$x> for Number { From 978288ab761066fb01272151fbeebc4eb5885d6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Gaspard?= Date: Tue, 20 Feb 2024 19:58:50 +0100 Subject: [PATCH 05/12] restart ci after transient failure From 0d02e119b542d2bd1d1ea28d37583dbd42653b91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Gaspard?= Date: Tue, 20 Feb 2024 23:50:35 +0100 Subject: [PATCH 06/12] Update CHANGELOG.md Co-authored-by: daxpedda --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fe6896b1a6..c5e305a33be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,8 @@ * Add bindings for `CanvasState.reset()`, affecting `CanvasRenderingContext2D` and `OffscreenCanvasRenderingContext2D`. [#3844](https://github.com/rustwasm/wasm-bindgen/pull/3844) -* Add `TryFrom` implementations for `Number`, that allow losslessly converting from 64- and 128-bits numbers +* Add `TryFrom` implementations for `Number`, that allow losslessly converting from 64- and 128-bits numbers. + [#3847](https://github.com/rustwasm/wasm-bindgen/pull/3847) -------------------------------------------------------------------------------- From 4630593e6d6181462879c5ecea1e07f393942264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Gaspard?= Date: Tue, 20 Feb 2024 23:50:47 +0100 Subject: [PATCH 07/12] Update crates/js-sys/src/lib.rs Co-authored-by: daxpedda --- crates/js-sys/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index 0b03e479050..58c6e5c6992 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -2794,8 +2794,6 @@ macro_rules! number_from { number_from!(i8 u8 i16 u16 i32 u32 f32 f64); /// The error type returned when a checked integral type conversion fails. -/// -/// This type is copy-pasted from the standard library #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct TryFromIntError(pub(crate) ()); From d0650dd3a6361e2ded81760ee09f2050de70317e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Gaspard?= Date: Tue, 20 Feb 2024 23:51:22 +0100 Subject: [PATCH 08/12] Update crates/js-sys/src/lib.rs Co-authored-by: daxpedda --- 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 58c6e5c6992..f5e9141e8c5 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -2820,7 +2820,7 @@ macro_rules! number_try_from { fn try_from(x: $x) -> Result { let x_f64 = x as f64; if x_f64 >= Number::MIN_SAFE_INTEGER && x_f64 <= Number::MAX_SAFE_INTEGER { - Ok(Number::unchecked_from_js(JsValue::from(x_f64))) + Ok(Number::from(x_f64)) } else { Err(x) } From c92798e0fe0111d96c21582092fed4bab1c51f1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Gaspard?= Date: Tue, 20 Feb 2024 23:54:37 +0100 Subject: [PATCH 09/12] handle review comments --- crates/js-sys/src/lib.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index f5e9141e8c5..004c961acc0 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -2799,17 +2799,11 @@ pub struct TryFromIntError(pub(crate) ()); impl fmt::Display for TryFromIntError { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - #[allow(deprecated)] - std::error::Error::description(&self).fmt(fmt) + fmt.write_str("out of range integral type conversion attempted") } } -impl std::error::Error for TryFromIntError { - #[allow(deprecated)] - fn description(&self) -> &str { - "out of range integral type conversion attempted" - } -} +impl std::error::Error for TryFromIntError {} macro_rules! number_try_from { ($($x:ident)*) => ($( From 15332dd1bee5320088492a8528ec5b732c045f6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Gaspard?= Date: Wed, 21 Feb 2024 00:02:30 +0100 Subject: [PATCH 10/12] restart ci after transient failure From b3e8fcd4c593af61aaf483a4fe6cde1cf4a4c710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Gaspard?= Date: Thu, 22 Feb 2024 00:09:24 +0100 Subject: [PATCH 11/12] handle review comments --- 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 004c961acc0..d6e823e6889 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -2795,7 +2795,7 @@ number_from!(i8 u8 i16 u16 i32 u32 f32 f64); /// The error type returned when a checked integral type conversion fails. #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct TryFromIntError(pub(crate) ()); +pub struct TryFromIntError(()); impl fmt::Display for TryFromIntError { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { From 6418adb62dda50cbc2a19604a5f268c8996f1300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Gaspard?= Date: Thu, 22 Feb 2024 21:37:27 +0100 Subject: [PATCH 12/12] adjust error type --- 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 d6e823e6889..a244b7b70a0 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -2808,7 +2808,7 @@ impl std::error::Error for TryFromIntError {} macro_rules! number_try_from { ($($x:ident)*) => ($( impl TryFrom<$x> for Number { - type Error = $x; + type Error = TryFromIntError; #[inline] fn try_from(x: $x) -> Result { @@ -2816,7 +2816,7 @@ macro_rules! number_try_from { if x_f64 >= Number::MIN_SAFE_INTEGER && x_f64 <= Number::MAX_SAFE_INTEGER { Ok(Number::from(x_f64)) } else { - Err(x) + Err(TryFromIntError(())) } } }