Skip to content

Commit

Permalink
Introduce impl TryFrom for Number that succeeds iff the value is with…
Browse files Browse the repository at this point in the history
…in the safe range (#3847)
  • Loading branch information
Ekleog authored Feb 23, 2024
1 parent b5a74c8 commit 557e2e6
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 1 deletion.
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},
};

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

0 comments on commit 557e2e6

Please sign in to comment.