Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Introduce impl TryFrom for Number that succeeds iff the value is within the safe range #3847

Merged
merged 14 commits into from
Feb 23, 2024
Merged
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
* 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.
[#3847](https://github.com/rustwasm/wasm-bindgen/pull/3847)

### Fixed

* Make .wasm output deterministic when using `--reference-types`.
Expand Down
31 changes: 31 additions & 0 deletions crates/js-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2793,6 +2793,37 @@ 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.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct TryFromIntError(());

impl fmt::Display for TryFromIntError {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str("out of range integral type conversion attempted")
}
}

impl std::error::Error for TryFromIntError {}

macro_rules! number_try_from {
($($x:ident)*) => ($(
impl TryFrom<$x> for Number {
type Error = TryFromIntError;

#[inline]
fn try_from(x: $x) -> Result<Number, Self::Error> {
let x_f64 = x as f64;
if x_f64 >= Number::MIN_SAFE_INTEGER && x_f64 <= Number::MAX_SAFE_INTEGER {
Ok(Number::from(x_f64))
} else {
Err(TryFromIntError(()))
}
}
}
)*)
}
number_try_from!(i64 u64 i128 u128);

// TODO: add this on the next major version, when blanket impl is removed
/*
impl convert::TryFrom<JsValue> for Number {
Expand Down
20 changes: 19 additions & 1 deletion crates/js-sys/tests/wasm/Number.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::f64::{INFINITY, NAN};
use std::{
convert::TryFrom,
f64::{INFINITY, NAN},
daxpedda marked this conversation as resolved.
Show resolved Hide resolved
};

use js_sys::*;
use wasm_bindgen::prelude::*;
Expand Down Expand Up @@ -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.);
Expand Down