├── .gitignore
├── .rustfmt.toml
├── Cargo.toml
├── .github
└── workflows
│ ├── nightly.yml
│ ├── msrv.yml
│ └── stable.yml
├── LICENSE
├── Cargo.lock
├── README.md
├── src
├── error.rs
├── lib.rs
├── macros.rs
├── uint.rs
└── int.rs
├── tests
├── uint.rs
├── int.rs
└── test_serializer.rs
└── CHANGELOG.md
/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | **/*.rs.bk
3 | Cargo.lock
4 | .idea
5 |
--------------------------------------------------------------------------------
/.rustfmt.toml:
--------------------------------------------------------------------------------
1 | edition = "2018"
2 | imports_granularity = "Crate"
3 | newline_style = "Unix"
4 | use_small_heuristics = "Max"
5 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "js_int"
3 | description = "JavaScript-interoperable integer types"
4 | version = "0.2.2"
5 | edition = "2021"
6 | license = "MIT"
7 | readme = "README.md"
8 | repository = "https://github.com/ruma/js_int"
9 | keywords = ["integer", "no_std"]
10 | categories = ["no-std"]
11 | rust-version = "1.60.0"
12 |
13 | [dependencies.serde_core]
14 | version = "1.0.220"
15 | optional = true
16 | default-features = false
17 |
18 | [features]
19 | default = ["std"]
20 | "rust_1.81" = []
21 | std = []
22 | serde = ["dep:serde_core"]
23 |
--------------------------------------------------------------------------------
/.github/workflows/nightly.yml:
--------------------------------------------------------------------------------
1 | name: Rust Nightly
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | pull_request:
7 | branches: [main]
8 |
9 | jobs:
10 | check:
11 | name: Check
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v2
15 | - uses: dtolnay/rust-toolchain@nightly
16 | with:
17 | components: rustfmt, clippy
18 | - name: Check formatting
19 | run: cargo fmt -- --check
20 | - name: Catch common mistakes
21 | run: cargo clippy --all-features --all-targets -- -D warnings
22 |
--------------------------------------------------------------------------------
/.github/workflows/msrv.yml:
--------------------------------------------------------------------------------
1 | name: Rust 1.60
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | pull_request:
7 | branches: [main]
8 |
9 | jobs:
10 | check:
11 | name: Test
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v2
15 | - uses: dtolnay/rust-toolchain@1.60
16 | - name: Run tests (no default features)
17 | run: cargo test --no-default-features
18 | - name: Run tests (default features)
19 | run: cargo test
20 | - name: Run tests (serde)
21 | run: cargo test --features serde
22 | - name: Run tests (all features)
23 | run: cargo test --all-features
24 | - name: Run tests (release build)
25 | run: cargo test --release
26 |
--------------------------------------------------------------------------------
/.github/workflows/stable.yml:
--------------------------------------------------------------------------------
1 | name: Rust Stable
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | pull_request:
7 | branches: [main]
8 |
9 | jobs:
10 | check:
11 | name: Test
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v2
15 | - uses: dtolnay/rust-toolchain@stable
16 | - name: Run tests (no default features)
17 | run: cargo test --no-default-features
18 | - name: Run tests (default features)
19 | run: cargo test
20 | - name: Run tests (serde)
21 | run: cargo test --features serde
22 | - name: Run tests (all features)
23 | run: cargo test --all-features
24 | - name: Run tests (release build)
25 | run: cargo test --release
26 |
27 |
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2019 Jonas Platte, Jimmy Cuadra
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 3
4 |
5 | [[package]]
6 | name = "js_int"
7 | version = "0.2.2"
8 | dependencies = [
9 | "serde_core",
10 | ]
11 |
12 | [[package]]
13 | name = "proc-macro2"
14 | version = "1.0.103"
15 | source = "registry+https://github.com/rust-lang/crates.io-index"
16 | checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
17 | dependencies = [
18 | "unicode-ident",
19 | ]
20 |
21 | [[package]]
22 | name = "quote"
23 | version = "1.0.41"
24 | source = "registry+https://github.com/rust-lang/crates.io-index"
25 | checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
26 | dependencies = [
27 | "proc-macro2",
28 | ]
29 |
30 | [[package]]
31 | name = "serde_core"
32 | version = "1.0.228"
33 | source = "registry+https://github.com/rust-lang/crates.io-index"
34 | checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
35 | dependencies = [
36 | "serde_derive",
37 | ]
38 |
39 | [[package]]
40 | name = "serde_derive"
41 | version = "1.0.228"
42 | source = "registry+https://github.com/rust-lang/crates.io-index"
43 | checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
44 | dependencies = [
45 | "proc-macro2",
46 | "quote",
47 | "syn",
48 | ]
49 |
50 | [[package]]
51 | name = "syn"
52 | version = "2.0.108"
53 | source = "registry+https://github.com/rust-lang/crates.io-index"
54 | checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917"
55 | dependencies = [
56 | "proc-macro2",
57 | "quote",
58 | "unicode-ident",
59 | ]
60 |
61 | [[package]]
62 | name = "unicode-ident"
63 | version = "1.0.22"
64 | source = "registry+https://github.com/rust-lang/crates.io-index"
65 | checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
66 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # js_int
2 |
3 | [][crates-io]
4 | [][docs-rs]
5 |
6 | Crate `js_int` provides JavaScript-interoperable integer types.
7 |
8 | JavaScript does not have native integers. Instead it represents all numeric
9 | values with a single `Number` type which is represented as an
10 | [IEEE 754 floating-point](https://en.wikipedia.org/wiki/IEEE_754) value.\*
11 | Rust's `i64` and `u64` types can contain values outside the range of what can be
12 | represented in a JavaScript `Number`.
13 |
14 | This crate provides the types `Int` and `UInt` which wrap `i64` and `u64`,
15 | respectively. These types add bounds checking to ensure the contained value is
16 | within the range representable by a JavaScript `Number`. They provide useful
17 | trait implementations to easily convert from Rust's primitive integer types.
18 |
19 | * Since the creation of this crate, JavaScript has gained support for
20 | larger integers in the form of the [`BigInt`][mdn] type.
21 | It doesn't make this crate obsolete in any way though, since there is still
22 | lots of code that operates on JS `Number`s or puts the same bounds on integers
23 | as the types from this crate do.
24 |
25 |
26 | This crate requires rustc >= 1.60.
27 |
28 | This crate is `no_std`-compatible with `default-features = false`. This will
29 | disable the `std` feature, which at the time of writing will only omit the
30 | implementations of `std::error::Error` for `ParseIntError` and
31 | `TryFromIntError`.
32 |
33 | (De-)Serialization via `serde` is supported via the `serde` feature, even
34 | without the `std` feature.
35 |
36 | Deserialization can be routed through `f64` instead of `u64` with the
37 | `(U)Int::deserialize_via_float` methods. This will still not deserialize numbers with a
38 | non-zero fractional component. Please be aware that
39 | `serde_json` doesn't losslessly parse large floats with a fractional part by
40 | default (even if the fractional part is `.0`). To fix that, enable its
41 | `float_roundtrip` feature.
42 |
43 | [travis]: https://travis-ci.org/jplatte/js_int
44 | [crates-io]: https://crates.io/crates/js_int
45 | [docs-rs]: https://docs.rs/js_int
46 | [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt
47 |
48 | ## License
49 |
50 | [MIT](https://opensource.org/licenses/MIT)
51 |
--------------------------------------------------------------------------------
/src/error.rs:
--------------------------------------------------------------------------------
1 | use core::{
2 | fmt::{self, Debug, Display, Formatter},
3 | num::ParseIntError as StdParseIntError,
4 | };
5 |
6 | #[cfg(all(feature = "rust_1.81", not(feature = "std")))]
7 | use core::error::Error;
8 | #[cfg(feature = "std")]
9 | use std::error::Error;
10 |
11 | /// The error type returned when when parsing an integer fails.
12 | #[derive(Debug, Clone, PartialEq, Eq)]
13 | pub struct ParseIntError {
14 | pub(crate) kind: ParseIntErrorKind,
15 | }
16 |
17 | // When https://github.com/rust-lang/rust/issues/22639 is resolved, the error kind can be provided
18 | // publicly as well. For now, distinguishing between overflow / underflow and anything else doesn't
19 | // seem very useful.
20 | #[derive(Debug, Clone, PartialEq, Eq)]
21 | pub(crate) enum ParseIntErrorKind {
22 | Overflow,
23 | Underflow,
24 | Unknown(StdParseIntError),
25 | }
26 |
27 | impl From for ParseIntError {
28 | fn from(e: StdParseIntError) -> Self {
29 | ParseIntError { kind: ParseIntErrorKind::Unknown(e) }
30 | }
31 | }
32 |
33 | impl Display for ParseIntError {
34 | #[allow(clippy::uninlined_format_args)] // Not supported in Rust 1.46
35 | fn fmt(&self, f: &mut Formatter) -> fmt::Result {
36 | match &self.kind {
37 | ParseIntErrorKind::Overflow => f.write_str("number too large to fit in target type"),
38 | ParseIntErrorKind::Underflow => f.write_str("number too small to fit in target type"),
39 | ParseIntErrorKind::Unknown(e) => write!(f, "{}", e),
40 | }
41 | }
42 | }
43 |
44 | #[cfg(any(feature = "rust_1.81", feature = "std"))]
45 | impl Error for ParseIntError {}
46 |
47 | /// The error type returned when a checked integral type conversion fails.
48 | #[derive(Clone)]
49 | pub struct TryFromIntError {
50 | _private: (),
51 | }
52 |
53 | impl TryFromIntError {
54 | pub(crate) fn new() -> Self {
55 | Self { _private: () }
56 | }
57 | }
58 |
59 | impl Display for TryFromIntError {
60 | fn fmt(&self, f: &mut Formatter) -> fmt::Result {
61 | f.write_str("out of range integral type conversion attempted")
62 | }
63 | }
64 |
65 | impl Debug for TryFromIntError {
66 | fn fmt(&self, f: &mut Formatter) -> fmt::Result {
67 | f.write_str("TryFromIntError")
68 | }
69 | }
70 |
71 | #[cfg(any(feature = "rust_1.81", feature = "std"))]
72 | impl Error for TryFromIntError {}
73 |
--------------------------------------------------------------------------------
/tests/uint.rs:
--------------------------------------------------------------------------------
1 | #![cfg(feature = "serde")]
2 |
3 | use crate::test_serializer::{Number, TestSerializer};
4 | use core::convert::TryFrom;
5 | use js_int::{uint, UInt};
6 | use serde_core::{de::IntoDeserializer, Deserialize, Serialize};
7 |
8 | mod test_serializer;
9 |
10 | #[test]
11 | fn serialize() {
12 | assert_serialize(100);
13 | assert_serialize(0);
14 | }
15 |
16 | fn assert_serialize(number: u32) {
17 | let serialized =
18 | UInt::from(number).serialize(TestSerializer).expect("Failed to serialize UInt");
19 |
20 | assert_eq!(Number::U64(number.into()), serialized);
21 | }
22 |
23 | #[test]
24 | fn deserialize() {
25 | assert_eq!(deserialize_from(100).unwrap(), uint!(100));
26 | assert_eq!(deserialize_from(0).unwrap(), uint!(0));
27 | assert_eq!(deserialize_from(9007199254740991i64).unwrap(), UInt::MAX);
28 | assert!(deserialize_from(9007199254740992i64).is_err());
29 | }
30 |
31 | #[test]
32 | fn dont_deserialize_integral_float() {
33 | assert!(deserialize_from(1.0).is_err());
34 | assert!(deserialize_from(9007199254740991.0).is_err());
35 | assert!(deserialize_from(9007199254740992.0).is_err());
36 | }
37 |
38 | #[test]
39 | fn dont_deserialize_fractional_float() {
40 | assert!(deserialize_from(0.5).is_err());
41 | assert!(deserialize_from(42.1337).is_err());
42 | }
43 |
44 | #[test]
45 | fn deserialize_integral_float() {
46 | assert_eq!(deserialize_via_float(1.0).unwrap(), uint!(1));
47 | assert_eq!(deserialize_via_float(9007199254740991.0).unwrap(), UInt::MAX);
48 | assert!(deserialize_via_float(9007199254740992.0).is_err());
49 | // NOTE: This still ends up as integral because the .49 exceeds the representable range of f64
50 | assert_eq!(
51 | deserialize_via_float(9007199254740991.49).unwrap(),
52 | UInt::try_from(9007199254740991i64).unwrap()
53 | );
54 |
55 | assert!(deserialize_via_float(f64::NAN).is_err());
56 | assert!(deserialize_via_float(f64::INFINITY).is_err());
57 | assert!(deserialize_via_float(f64::NEG_INFINITY).is_err());
58 |
59 | fn deserialize_via_float<'de, Value: IntoDeserializer<'de>>(
60 | value: Value,
61 | ) -> Result {
62 | UInt::deserialize_via_float(value.into_deserializer())
63 | }
64 | }
65 |
66 | fn deserialize_from<'de, Value: IntoDeserializer<'de>>(
67 | value: Value,
68 | ) -> Result {
69 | UInt::deserialize(value.into_deserializer())
70 | }
71 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Unreleased
2 |
3 | * Breaking: Allow values larger than 32 bit for `int!` and `uint!` macros
4 | This means that `i32`-suffixed and `u32`-suffixed literals are no longer accepcted
5 | * The old macros can be replaced like follows: `int!(42)` -> `Int::from(42_i32)` etc.
6 | * Breaking: Serialization of `Int` and `UInt` now call the serialization of `i64` and `u64` directly instead of
7 | serializing them as newtype structs, emulating `#[serde(transparent)]`.
8 | This doesn't make a difference for `serde_json` for example, but it could make a difference for other serializers
9 | * Breaking: Remove the `float_deserialize` feature and replace it with the `(U)Int::deserialize_via_float` methods that
10 | can be used with serde's `deserialize_with` attribute.
11 | * The `int!` and `uint!` macros now support arbitrary const expressions, not just literals
12 | * `Int::new` and `UInt::new` are now const
13 | * The minimum supported rust version is raised to 1.60.
14 | * Update to edition 2021
15 |
16 | # 0.2.2
17 |
18 | * Consider negative values in saturating add / sub
19 | * `impl TryFrom for iN` for N = [8, 16, 32]
20 | * `impl TryFrom for uN` for N = [8, 16, 32]
21 | * Fix lax_deserialize accepting NaN
22 | * Support deserializing floats without fractional component
23 | * Add `usize` and `isize` `TryFrom` implementations
24 |
25 | # 0.2.1
26 |
27 | * Update crate metadata
28 |
29 | # 0.2.0
30 |
31 | * Bump MSRV to 1.35
32 | * Drop support for the `rocket_04` Cargo feature (Rocket 0.4 `FromFormValue` / `FromParam`
33 | implementations)
34 |
35 | # 0.1.9
36 |
37 | * Add a new Cargo feature: `lax_deserialize`
38 | * See the crate documentation or [README.md](README.md) for what it does.
39 |
40 | # 0.1.8
41 |
42 | * Update the documentation to use the macros introduced in 0.1.6.
43 |
44 | # 0.1.7
45 |
46 | * Fix building without the `std` feature
47 |
48 | # 0.1.6
49 |
50 | * Introduce `int!` and `uint!` macros as shorthand for `Int::from(Ni32)` and `UInt::from(Nu32)`
51 |
52 | # 0.1.5
53 |
54 | * Introduce `Int::MIN`, `Int::MAX`, `UInt::MIN`, `UInt::MAX` and deprecate `const fn min_value` and
55 | `const fn max_value`s.
56 |
57 | # 0.1.4
58 |
59 | * Allow deserialization of `Int`s and `UInt`s from non-self-describing formats
60 |
61 | # 0.1.3
62 |
63 | * Add conversions to / from 128 bit integer types
64 |
65 | # 0.1.2
66 |
67 | * Implement `std::iter::Sum` and `std::iter::Product` for `Int` and `UInt`
68 | * Mention JavaScript's propsed BigInt type in documentation
69 |
70 | # 0.1.1
71 |
72 | * Add doctests for every inherent method of `Int` and `UInt`
73 | * Fix buggy implementation of `Int::saturating_mul`
74 | * Add (optional) implementations of `rocket::{FromFormValue, FromParam}` (for rocket 0.4)
75 |
76 | # 0.1.0
77 |
78 | Initial release containing the `Int` and `UInt` types, `serde` support and many of the methods that
79 | `std`'s integer types provide.
80 |
--------------------------------------------------------------------------------
/src/lib.rs:
--------------------------------------------------------------------------------
1 | //! Crate `js_int` provides JavaScript-interoperable integer types.
2 | //!
3 | //! JavaScript does not have native integers. Instead it represents all numeric values with a
4 | //! single `Number` type which is represented as an [IEEE 754
5 | //! floating-point](https://en.wikipedia.org/wiki/IEEE_754) value.\* Rust's `i64` and `u64` types
6 | //! can contain values outside the range of what can be represented in a JavaScript `Number`.
7 | //!
8 | //! This crate provides the types `Int` and `UInt` which wrap `i64` and `u64`, respectively. These
9 | //! types add bounds checking to ensure the contained value is within the range representable by a
10 | //! JavaScript `Number`. They provide useful trait implementations to easily convert from Rust's
11 | //! primitive integer types.
12 | //!
13 | //! * In the upcoming ECMAScript 2020, JavaScript will probably gain support for integers.
14 | //! There is a proposal for a [`BigInt`][mdn] type type that is not far from becoming part of the
15 | //! JavaScript specification. It won't make this crate obsolete in any way though, since there will
16 | //! still be lots of JS code using `Number`, and code in other languages that assumes its use.
17 | //!
18 | //!
19 | //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt
20 | //!
21 | //! # `#![no_std]`
22 | //!
23 | //! The `js_int` crate does not use Rust's standard library, and is compatible with `#![no_std]`
24 | //! programs.
25 | //!
26 | //! # Features
27 | //!
28 | //! * `serde`: Serialization and deserialization support via [serde](https://serde.rs). Disabled by
29 | //! default. You can use `js_int` + `serde` in `#![no_std]` contexts if you use
30 | //! `default-features = false` for both.
31 | //! deserialized with the fractional part discarded.
32 | //! Please be aware that `serde_json` doesn't losslessly parse large floats with a fractional part
33 | //! by default (even if the fractional part is `.0`). To fix that, enable its `float_roundtrip`
34 | //! feature.
35 | //! * `std`: Enable `std::error::Error` implementations for `ParseIntError`, `TryFromIntError`.
36 | //! Enabled by default.
37 | //! * `rust_1.81`: Enable `core::error::Error` implementations for `ParseIntError`,
38 | //! `TryFromIntError`. Does nothing if the `std` feature is enabled.
39 |
40 | #![no_std]
41 | #![deny(missing_debug_implementations, missing_docs)]
42 | #![allow(clippy::cast_lossless)] // Not useful in this crate
43 |
44 | #[cfg(feature = "std")]
45 | extern crate std;
46 |
47 | #[macro_use]
48 | mod macros;
49 | mod error;
50 | mod int;
51 | mod uint;
52 |
53 | pub use self::{
54 | error::{ParseIntError, TryFromIntError},
55 | int::{Int, MAX_SAFE_INT, MIN_SAFE_INT},
56 | uint::{UInt, MAX_SAFE_UINT},
57 | };
58 |
59 | #[cfg(feature = "serde")]
60 | #[inline(always)]
61 | pub(crate) fn is_acceptable_float(float: f64) -> bool {
62 | !float.is_nan() && float.fract() == 0.0
63 | }
64 |
--------------------------------------------------------------------------------
/tests/int.rs:
--------------------------------------------------------------------------------
1 | #![cfg(feature = "serde")]
2 |
3 | use crate::test_serializer::{Number, TestSerializer};
4 | use core::convert::TryFrom;
5 | use js_int::{int, Int};
6 | use serde_core::{de::IntoDeserializer, Deserialize, Serialize};
7 |
8 | mod test_serializer;
9 |
10 | #[test]
11 | fn serialize() {
12 | assert_serialize(100);
13 | assert_serialize(0);
14 | assert_serialize(-100);
15 | }
16 |
17 | fn assert_serialize(number: i32) {
18 | let serialized = Int::from(number).serialize(TestSerializer).expect("Failed to serialize UInt");
19 |
20 | assert_eq!(Number::I64(number.into()), serialized);
21 | }
22 |
23 | #[test]
24 | fn deserialize() {
25 | assert_eq!(deserialize_from(100).unwrap(), int!(100));
26 | assert_eq!(deserialize_from(0).unwrap(), int!(0));
27 | assert_eq!(deserialize_from(-100).unwrap(), int!(-100));
28 | assert_eq!(deserialize_from(-9007199254740991i64).unwrap(), Int::MIN);
29 | assert_eq!(deserialize_from(9007199254740991i64).unwrap(), Int::MAX);
30 | assert!(deserialize_from(9007199254740992i64).is_err());
31 | assert!(deserialize_from(-9007199254740992i64).is_err());
32 | }
33 |
34 | #[test]
35 | fn dont_deserialize_integral_float() {
36 | assert!(deserialize_from(-10.0).is_err());
37 | assert!(deserialize_from(-0.0).is_err());
38 | assert!(deserialize_from(1.0).is_err());
39 | assert!(deserialize_from(9007199254740991.0).is_err());
40 | assert!(deserialize_from(9007199254740992.0).is_err());
41 | }
42 |
43 | #[test]
44 | fn dont_deserialize_fractional_float() {
45 | assert!(deserialize_from(0.5).is_err());
46 | assert!(deserialize_from(42.1337).is_err());
47 | assert!(deserialize_from(-42.1337).is_err());
48 | }
49 |
50 | #[test]
51 | fn deserialize_integral_float() {
52 | assert_eq!(deserialize_via_float(-10.0).unwrap(), int!(-10));
53 | assert_eq!(deserialize_via_float(-0.0).unwrap(), int!(0));
54 | assert_eq!(deserialize_via_float(1.0).unwrap(), int!(1));
55 | assert_eq!(deserialize_via_float(9007199254740991.0).unwrap(), Int::MAX);
56 | assert!(deserialize_via_float(9007199254740992.0).is_err());
57 | // NOTE: This still ends up as integral because the .49 exceeds the representable range of f64
58 | assert_eq!(
59 | deserialize_via_float(9007199254740991.49).unwrap(),
60 | Int::try_from(9007199254740991i64).unwrap()
61 | );
62 |
63 | assert!(deserialize_via_float(f64::NAN).is_err());
64 | assert!(deserialize_via_float(f64::INFINITY).is_err());
65 | assert!(deserialize_via_float(f64::NEG_INFINITY).is_err());
66 |
67 | fn deserialize_via_float<'de, Value: IntoDeserializer<'de>>(
68 | value: Value,
69 | ) -> Result {
70 | Int::deserialize_via_float(value.into_deserializer())
71 | }
72 | }
73 |
74 | fn deserialize_from<'de, Value: IntoDeserializer<'de>>(
75 | value: Value,
76 | ) -> Result {
77 | Int::deserialize(value.into_deserializer())
78 | }
79 |
--------------------------------------------------------------------------------
/src/macros.rs:
--------------------------------------------------------------------------------
1 | /// Creates an `Int` from a constant expression.
2 | /// Checks at compile time that the expression is in a valid range.
3 | #[macro_export]
4 | macro_rules! int {
5 | ($n:expr) => {{
6 | const VALUE: $crate::Int = match $crate::Int::new($n) {
7 | Some(int) => int,
8 | None => panic!("Number is outside the range of an Int"),
9 | };
10 | VALUE
11 | }};
12 | }
13 |
14 | /// Creates a `UInt` from a constant expression.
15 | /// Checks at compile time that the expression is in a valid range.
16 | #[macro_export]
17 | macro_rules! uint {
18 | ($n:expr) => {{
19 | const VALUE: $crate::UInt = match $crate::UInt::new($n) {
20 | Some(int) => int,
21 | None => panic!("Number is outside the range of an Int"),
22 | };
23 | VALUE
24 | }};
25 | }
26 |
27 | macro_rules! fmt_impls {
28 | ($type:ident) => {
29 | impl ::core::fmt::Display for $type {
30 | fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
31 | write!(f, "{}", self.0)
32 | }
33 | }
34 |
35 | impl ::core::fmt::Debug for $type {
36 | fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
37 | write!(f, "{:?}", self.0)
38 | }
39 | }
40 | };
41 | }
42 |
43 | macro_rules! convert_impls {
44 | (
45 | $type:ident,
46 | $t8:ident,
47 | $t16:ident,
48 | $t32:ident,
49 | $t64:ident,
50 | $t128:ident,
51 | $tsize:ident,
52 | $ot8:ident,
53 | $ot16:ident,
54 | $ot32:ident,
55 | $otsize:ident
56 | ) => {
57 | impl ::core::convert::From<$t8> for $type {
58 | fn from(val: $t8) -> Self {
59 | Self($t64::from(val))
60 | }
61 | }
62 |
63 | impl ::core::convert::From<$t16> for $type {
64 | fn from(val: $t16) -> Self {
65 | Self($t64::from(val))
66 | }
67 | }
68 |
69 | impl ::core::convert::From<$t32> for $type {
70 | fn from(val: $t32) -> Self {
71 | Self($t64::from(val))
72 | }
73 | }
74 |
75 | impl ::core::convert::TryFrom<$t64> for $type {
76 | type Error = crate::error::TryFromIntError;
77 |
78 | fn try_from(val: $t64) -> Result {
79 | Self::new(val).ok_or_else(crate::error::TryFromIntError::new)
80 | }
81 | }
82 |
83 | impl ::core::convert::TryFrom<$t128> for $type {
84 | type Error = crate::error::TryFromIntError;
85 |
86 | fn try_from(val: $t128) -> Result {
87 | $t64::try_from(val)
88 | .map_err(|_| crate::error::TryFromIntError::new())
89 | .and_then($type::try_from)
90 | }
91 | }
92 |
93 | impl ::core::convert::TryFrom<$tsize> for $type {
94 | type Error = crate::error::TryFromIntError;
95 |
96 | fn try_from(val: $tsize) -> Result {
97 | $t64::try_from(val)
98 | .map_err(|_| crate::error::TryFromIntError::new())
99 | .and_then($type::try_from)
100 | }
101 | }
102 |
103 | impl ::core::convert::TryFrom<$otsize> for $type {
104 | type Error = crate::error::TryFromIntError;
105 |
106 | fn try_from(val: $otsize) -> Result {
107 | $t64::try_from(val)
108 | .map_err(|_| crate::error::TryFromIntError::new())
109 | .and_then($type::try_from)
110 | }
111 | }
112 |
113 | impl ::core::convert::TryFrom<$type> for $t8 {
114 | type Error = ::core::num::TryFromIntError;
115 |
116 | fn try_from(val: $type) -> Result {
117 | Self::try_from(val.0)
118 | }
119 | }
120 |
121 | impl ::core::convert::TryFrom<$type> for $ot8 {
122 | type Error = ::core::num::TryFromIntError;
123 |
124 | fn try_from(val: $type) -> Result {
125 | Self::try_from(val.0)
126 | }
127 | }
128 |
129 | impl ::core::convert::TryFrom<$type> for $t16 {
130 | type Error = ::core::num::TryFromIntError;
131 |
132 | fn try_from(val: $type) -> Result {
133 | Self::try_from(val.0)
134 | }
135 | }
136 |
137 | impl ::core::convert::TryFrom<$type> for $ot16 {
138 | type Error = ::core::num::TryFromIntError;
139 |
140 | fn try_from(val: $type) -> Result {
141 | Self::try_from(val.0)
142 | }
143 | }
144 |
145 | impl ::core::convert::TryFrom<$type> for $t32 {
146 | type Error = ::core::num::TryFromIntError;
147 |
148 | fn try_from(val: $type) -> Result {
149 | Self::try_from(val.0)
150 | }
151 | }
152 |
153 | impl ::core::convert::TryFrom<$type> for $ot32 {
154 | type Error = ::core::num::TryFromIntError;
155 |
156 | fn try_from(val: $type) -> Result {
157 | Self::try_from(val.0)
158 | }
159 | }
160 |
161 | impl ::core::convert::From<$type> for $t64 {
162 | fn from(val: $type) -> Self {
163 | val.0
164 | }
165 | }
166 |
167 | impl ::core::convert::From<$type> for $t128 {
168 | fn from(val: $type) -> Self {
169 | $t128::from(val.0)
170 | }
171 | }
172 |
173 | impl ::core::convert::TryFrom<$type> for $tsize {
174 | type Error = ::core::num::TryFromIntError;
175 |
176 | fn try_from(val: $type) -> Result {
177 | Self::try_from(val.0)
178 | }
179 | }
180 |
181 | impl ::core::convert::TryFrom<$type> for $otsize {
182 | type Error = ::core::num::TryFromIntError;
183 |
184 | fn try_from(val: $type) -> Result {
185 | Self::try_from(val.0)
186 | }
187 | }
188 |
189 | impl ::core::convert::From<$type> for f64 {
190 | fn from(val: $type) -> Self {
191 | val.0 as f64
192 | }
193 | }
194 | };
195 | }
196 |
--------------------------------------------------------------------------------
/tests/test_serializer.rs:
--------------------------------------------------------------------------------
1 | #![cfg(feature = "serde")]
2 | use serde_core::{
3 | ser::{
4 | SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple,
5 | SerializeTupleStruct, SerializeTupleVariant,
6 | },
7 | Serialize, Serializer,
8 | };
9 | use std::fmt::{Display, Formatter};
10 |
11 | pub struct TestSerializer;
12 |
13 | #[derive(PartialEq, Eq, Debug)]
14 | pub enum Number {
15 | U64(u64),
16 | I64(i64),
17 | }
18 |
19 | #[derive(Debug)]
20 | pub struct Error(String);
21 |
22 | impl Display for Error {
23 | fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
24 | formatter.write_str(&self.0)
25 | }
26 | }
27 |
28 | impl std::error::Error for Error {}
29 |
30 | impl From<&'static str> for Error {
31 | fn from(error: &'static str) -> Self {
32 | Self(error.to_owned())
33 | }
34 | }
35 |
36 | impl serde_core::ser::Error for Error {
37 | fn custom(message: T) -> Self
38 | where
39 | T: Display,
40 | {
41 | Self(message.to_string())
42 | }
43 | }
44 |
45 | pub enum Never {}
46 |
47 | impl Serializer for TestSerializer {
48 | type Ok = Number;
49 | type Error = Error;
50 | type SerializeSeq = Never;
51 | type SerializeTuple = Never;
52 | type SerializeTupleStruct = Never;
53 | type SerializeTupleVariant = Never;
54 | type SerializeMap = Never;
55 | type SerializeStruct = Never;
56 | type SerializeStructVariant = Never;
57 |
58 | fn serialize_bool(self, _: bool) -> Result {
59 | Err("serialize_bool".into())
60 | }
61 |
62 | fn serialize_i8(self, _: i8) -> Result {
63 | Err("serialize_i8".into())
64 | }
65 |
66 | fn serialize_i16(self, _: i16) -> Result {
67 | Err("serialize_i16".into())
68 | }
69 |
70 | fn serialize_i32(self, _: i32) -> Result {
71 | Err("serialize_i32".into())
72 | }
73 |
74 | fn serialize_i64(self, number: i64) -> Result {
75 | Ok(Number::I64(number))
76 | }
77 |
78 | fn serialize_u8(self, _: u8) -> Result {
79 | Err("serialize_u8".into())
80 | }
81 |
82 | fn serialize_u16(self, _: u16) -> Result {
83 | Err("serialize_u16".into())
84 | }
85 |
86 | fn serialize_u32(self, _: u32) -> Result {
87 | Err("serialize_u32".into())
88 | }
89 |
90 | fn serialize_u64(self, number: u64) -> Result {
91 | Ok(Number::U64(number))
92 | }
93 |
94 | fn serialize_f32(self, _: f32) -> Result {
95 | Err("serialize_f32".into())
96 | }
97 |
98 | fn serialize_f64(self, _: f64) -> Result {
99 | Err("serialize_f64".into())
100 | }
101 |
102 | fn serialize_char(self, _: char) -> Result {
103 | Err("serialize_char".into())
104 | }
105 |
106 | fn serialize_str(self, _: &str) -> Result {
107 | Err("serialize_str".into())
108 | }
109 |
110 | fn serialize_bytes(self, _: &[u8]) -> Result {
111 | Err("serialize_bytes".into())
112 | }
113 |
114 | fn serialize_none(self) -> Result {
115 | Err("serialize_none".into())
116 | }
117 |
118 | fn serialize_some(self, _: &T) -> Result
119 | where
120 | T: ?Sized + Serialize,
121 | {
122 | Err("serialize_some".into())
123 | }
124 |
125 | fn serialize_unit(self) -> Result {
126 | Err("serialize_unit".into())
127 | }
128 |
129 | fn serialize_unit_struct(self, _: &'static str) -> Result {
130 | Err("serialize_unit_struct".into())
131 | }
132 |
133 | fn serialize_unit_variant(
134 | self,
135 | _: &'static str,
136 | _: u32,
137 | _: &'static str,
138 | ) -> Result {
139 | Err("serialize_unit_variant".into())
140 | }
141 |
142 | fn serialize_newtype_struct(self, _: &'static str, _: &T) -> Result
143 | where
144 | T: ?Sized + Serialize,
145 | {
146 | Err("serialize_newtype_struct".into())
147 | }
148 |
149 | fn serialize_newtype_variant(
150 | self,
151 | _: &'static str,
152 | _: u32,
153 | _: &'static str,
154 | _: &T,
155 | ) -> Result
156 | where
157 | T: ?Sized + Serialize,
158 | {
159 | Err("serialize_newtype_variant".into())
160 | }
161 |
162 | fn serialize_seq(self, _: Option) -> Result {
163 | Err("serialize_seq".into())
164 | }
165 |
166 | fn serialize_tuple(self, _: usize) -> Result {
167 | Err("serialize_tuple".into())
168 | }
169 |
170 | fn serialize_tuple_struct(
171 | self,
172 | _: &'static str,
173 | _: usize,
174 | ) -> Result {
175 | Err("serialize_tuple_struct".into())
176 | }
177 |
178 | fn serialize_tuple_variant(
179 | self,
180 | _: &'static str,
181 | _: u32,
182 | _: &'static str,
183 | _: usize,
184 | ) -> Result {
185 | Err("serialize_tuple_variant".into())
186 | }
187 |
188 | fn serialize_map(self, _: Option) -> Result {
189 | Err("serialize_map".into())
190 | }
191 |
192 | fn serialize_struct(
193 | self,
194 | _: &'static str,
195 | _: usize,
196 | ) -> Result {
197 | Err("serialize_struct".into())
198 | }
199 |
200 | fn serialize_struct_variant(
201 | self,
202 | _: &'static str,
203 | _: u32,
204 | _: &'static str,
205 | _: usize,
206 | ) -> Result {
207 | Err("serialize_struct_variant".into())
208 | }
209 |
210 | fn collect_str(self, _: &T) -> Result
211 | where
212 | T: ?Sized + Display,
213 | {
214 | Err("collect_str".into())
215 | }
216 | }
217 |
218 | impl SerializeSeq for Never {
219 | type Ok = Number;
220 | type Error = Error;
221 |
222 | fn serialize_element(&mut self, _: &T) -> Result<(), Self::Error>
223 | where
224 | T: ?Sized + Serialize,
225 | {
226 | unreachable!()
227 | }
228 |
229 | fn end(self) -> Result {
230 | unreachable!()
231 | }
232 | }
233 |
234 | impl SerializeTuple for Never {
235 | type Ok = Number;
236 | type Error = Error;
237 |
238 | fn serialize_element(&mut self, _: &T) -> Result<(), Self::Error>
239 | where
240 | T: ?Sized + Serialize,
241 | {
242 | unreachable!()
243 | }
244 |
245 | fn end(self) -> Result {
246 | unreachable!()
247 | }
248 | }
249 |
250 | impl SerializeTupleStruct for Never {
251 | type Ok = Number;
252 | type Error = Error;
253 |
254 | fn serialize_field(&mut self, _: &T) -> Result<(), Self::Error>
255 | where
256 | T: ?Sized + Serialize,
257 | {
258 | unreachable!()
259 | }
260 |
261 | fn end(self) -> Result {
262 | unreachable!()
263 | }
264 | }
265 |
266 | impl SerializeTupleVariant for Never {
267 | type Ok = Number;
268 | type Error = Error;
269 |
270 | fn serialize_field(&mut self, _: &T) -> Result<(), Self::Error>
271 | where
272 | T: ?Sized + Serialize,
273 | {
274 | unreachable!()
275 | }
276 |
277 | fn end(self) -> Result {
278 | unreachable!()
279 | }
280 | }
281 |
282 | impl SerializeMap for Never {
283 | type Ok = Number;
284 | type Error = Error;
285 |
286 | fn serialize_key(&mut self, _: &T) -> Result<(), Self::Error>
287 | where
288 | T: ?Sized + Serialize,
289 | {
290 | unreachable!()
291 | }
292 |
293 | fn serialize_value(&mut self, _: &T) -> Result<(), Self::Error>
294 | where
295 | T: ?Sized + Serialize,
296 | {
297 | unreachable!()
298 | }
299 |
300 | fn end(self) -> Result {
301 | unreachable!()
302 | }
303 | }
304 |
305 | impl SerializeStruct for Never {
306 | type Ok = Number;
307 | type Error = Error;
308 |
309 | fn serialize_field(&mut self, _: &'static str, _: &T) -> Result<(), Self::Error>
310 | where
311 | T: ?Sized + Serialize,
312 | {
313 | unreachable!()
314 | }
315 |
316 | fn end(self) -> Result {
317 | unreachable!()
318 | }
319 | }
320 |
321 | impl SerializeStructVariant for Never {
322 | type Ok = Number;
323 | type Error = Error;
324 |
325 | fn serialize_field(&mut self, _: &'static str, _: &T) -> Result<(), Self::Error>
326 | where
327 | T: ?Sized + Serialize,
328 | {
329 | unreachable!()
330 | }
331 |
332 | fn end(self) -> Result {
333 | unreachable!()
334 | }
335 | }
336 |
--------------------------------------------------------------------------------
/src/uint.rs:
--------------------------------------------------------------------------------
1 | use core::{
2 | convert::TryFrom,
3 | iter,
4 | ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign},
5 | str::FromStr,
6 | };
7 |
8 | use crate::{
9 | error::{ParseIntError, ParseIntErrorKind, TryFromIntError},
10 | MAX_SAFE_INT,
11 | };
12 | #[cfg(feature = "serde")]
13 | use serde_core::{
14 | de::{Error as _, Unexpected},
15 | Deserialize, Deserializer, Serialize, Serializer,
16 | };
17 |
18 | /// The same as `MAX_SAFE_INT`, but with `u64` as the type.
19 | pub const MAX_SAFE_UINT: u64 = 0x001F_FFFF_FFFF_FFFF;
20 |
21 | /// An integer limited to the range of non-negative integers that can be represented exactly by an
22 | /// f64.
23 | #[derive(Clone, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
24 | pub struct UInt(u64);
25 |
26 | impl UInt {
27 | /// The smallest value that can be represented by this integer type.
28 | ///
29 | /// # Examples
30 | ///
31 | /// Basic usage:
32 | ///
33 | /// ```
34 | /// # use js_int::{uint, UInt};
35 | /// assert_eq!(UInt::MIN, uint!(0));
36 | /// ```
37 | pub const MIN: Self = Self(0);
38 |
39 | /// The largest value that can be represented by this integer type.
40 | ///
41 | /// # Examples
42 | ///
43 | /// Basic usage:
44 | ///
45 | /// ```
46 | /// # use {core::convert::TryFrom, js_int::UInt};
47 | /// assert_eq!(UInt::MAX, UInt::try_from(9_007_199_254_740_991u64).unwrap());
48 | /// ```
49 | pub const MAX: Self = Self(MAX_SAFE_UINT);
50 |
51 | /// Try to create a `UInt` from the provided `u64`, returning `None` if it is larger than
52 | /// `MAX_SAFE_UINT`.
53 | ///
54 | /// This is the same as the `TryFrom` implementation for `UInt`, except that it returns
55 | /// an `Option` instead of a `Result`.
56 | ///
57 | /// # Examples
58 | ///
59 | /// Basic usage:
60 | ///
61 | /// ```
62 | /// # use js_int::UInt;
63 | /// assert_eq!(UInt::new(js_int::MAX_SAFE_UINT), Some(UInt::MAX));
64 | /// assert_eq!(UInt::new(js_int::MAX_SAFE_UINT + 1), None);
65 | /// ```
66 | #[must_use]
67 | pub const fn new(val: u64) -> Option {
68 | if val <= MAX_SAFE_UINT {
69 | Some(Self(val))
70 | } else {
71 | None
72 | }
73 | }
74 |
75 | /// Create a `UInt` from the provided `u64`, wrapping at `MAX_SAFE_UINT`.
76 | ///
77 | /// # Examples
78 | ///
79 | /// Basic usage:
80 | ///
81 | /// ```
82 | /// # use js_int::{uint, UInt};
83 | /// assert_eq!(UInt::new_wrapping(js_int::MAX_SAFE_UINT), UInt::MAX);
84 | /// assert_eq!(UInt::new_wrapping(js_int::MAX_SAFE_UINT + 1), uint!(0));
85 | /// ```
86 | #[must_use]
87 | pub fn new_wrapping(val: u64) -> Self {
88 | Self(val & MAX_SAFE_UINT)
89 | }
90 |
91 | /// Creates an `UInt` from the given `u64` capped at `MAX_SAFE_UINT`.
92 | ///
93 | /// # Examples
94 | ///
95 | /// Basic usage:
96 | ///
97 | /// ```
98 | /// # use js_int::{uint, UInt};
99 | /// assert_eq!(UInt::new_saturating(0), uint!(0));
100 | /// assert_eq!(UInt::new_saturating(js_int::MAX_SAFE_UINT), UInt::MAX);
101 | /// assert_eq!(UInt::new_saturating(js_int::MAX_SAFE_UINT + 1), UInt::MAX);
102 | /// ```
103 | #[must_use]
104 | pub fn new_saturating(val: u64) -> Self {
105 | if val <= MAX_SAFE_UINT {
106 | Self(val)
107 | } else {
108 | Self::MAX
109 | }
110 | }
111 |
112 | /// The constructor used for arithmetic operations
113 | #[must_use]
114 | fn new_(val: u64) -> Self {
115 | if cfg!(debug_assertions) {
116 | assert!(val <= MAX_SAFE_UINT);
117 | Self(val)
118 | } else {
119 | Self::new_wrapping(val)
120 | }
121 | }
122 |
123 | /// Helper function for mutable arithmetic operations (`+=`, `-=`, …)
124 | fn assign_(&mut self, val: u64) {
125 | if cfg!(debug_assertions) {
126 | assert!(val <= MAX_SAFE_UINT);
127 | *self = Self(val);
128 | } else {
129 | *self = Self::new_wrapping(val);
130 | }
131 | }
132 |
133 | /// Returns the smallest value that can be represented by this integer type.
134 | ///
135 | /// # Examples
136 | ///
137 | /// Basic usage:
138 | ///
139 | /// ```
140 | /// # use js_int::{uint, UInt};
141 | /// assert_eq!(UInt::min_value(), uint!(0));
142 | /// ```
143 | #[must_use]
144 | #[deprecated = "Use `UInt::MIN` instead."]
145 | pub const fn min_value() -> Self {
146 | Self(0)
147 | }
148 |
149 | /// Returns the largest value that can be represented by this integer type.
150 | ///
151 | /// # Examples
152 | ///
153 | /// Basic usage:
154 | ///
155 | /// ```
156 | /// # use {core::convert::TryFrom, js_int::UInt};
157 | /// assert_eq!(UInt::max_value(), UInt::try_from(9_007_199_254_740_991u64).unwrap());
158 | /// ```
159 | #[must_use]
160 | #[deprecated = "Use `UInt::MAX` instead."]
161 | pub const fn max_value() -> Self {
162 | Self(MAX_SAFE_UINT)
163 | }
164 |
165 | /// Returns true if and only if `self == 2^k` for some `k`.
166 | ///
167 | /// # Examples
168 | ///
169 | /// Basic usage:
170 | ///
171 | /// ```
172 | /// # use js_int::uint;
173 | /// assert!(uint!(16).is_power_of_two());
174 | /// assert!(!uint!(10).is_power_of_two());
175 | /// ```
176 | #[must_use]
177 | pub fn is_power_of_two(self) -> bool {
178 | self.0.is_power_of_two()
179 | }
180 |
181 | /// Returns the smallest power of two greater than or equal to `n`. If the next power of two is
182 | /// greater than the type's maximum value, `None` is returned, otherwise the power of two is
183 | /// wrapped in `Some`.
184 | ///
185 | /// # Examples
186 | ///
187 | /// Basic usage:
188 | ///
189 | /// ```
190 | /// # use js_int::{uint, UInt};
191 | /// assert_eq!(uint!(2).checked_next_power_of_two(), Some(uint!(2)));
192 | /// assert_eq!(uint!(3).checked_next_power_of_two(), Some(uint!(4)));
193 | /// assert_eq!(UInt::MAX.checked_next_power_of_two(), None);
194 | /// ```
195 | #[must_use]
196 | pub fn checked_next_power_of_two(self) -> Option {
197 | self.0.checked_next_power_of_two().and_then(Self::new)
198 | }
199 |
200 | /// Converts a string slice in a given base to an integer.
201 | ///
202 | /// The string is expected to be an optional `+` sign followed by digits. Leading and trailing
203 | /// whitespace represent an error. Digits are a subset of these characters, depending on
204 | /// `radix`:
205 | ///
206 | /// * `0-9`
207 | /// * `a-z`
208 | /// * `A-Z`
209 | ///
210 | /// # Panics
211 | ///
212 | /// This function panics if `radix` is not in the range from 2 to 36.
213 | ///
214 | /// # Examples
215 | ///
216 | /// Basic usage:
217 | ///
218 | /// ```
219 | /// # use js_int::{uint, UInt};
220 | /// assert_eq!(UInt::from_str_radix("A", 16), Ok(uint!(10)));
221 | /// ```
222 | pub fn from_str_radix(src: &str, radix: u32) -> Result {
223 | let val = u64::from_str_radix(src, radix)?;
224 | if val > MAX_SAFE_UINT {
225 | Err(ParseIntError { kind: ParseIntErrorKind::Overflow })
226 | } else {
227 | Ok(Self(val))
228 | }
229 | }
230 |
231 | /// Checked integer addition. Computes `self + rhs`, returning `None` if overflow occurred.
232 | ///
233 | /// ```
234 | /// # use js_int::{uint, UInt};
235 | /// assert_eq!(
236 | /// (UInt::MAX - uint!(2)).checked_add(uint!(1)),
237 | /// Some(UInt::MAX - uint!(1))
238 | /// );
239 | /// assert_eq!((UInt::MAX - uint!(2)).checked_add(uint!(3)), None);
240 | /// ```
241 | #[must_use]
242 | pub fn checked_add(self, rhs: Self) -> Option {
243 | self.0.checked_add(rhs.0).and_then(Self::new)
244 | }
245 |
246 | /// Checked integer subtraction. Computes `self - rhs`, returning `None` if overflow occurred.
247 | ///
248 | /// # Examples
249 | ///
250 | /// Basic usage:
251 | ///
252 | /// ```
253 | /// # use js_int::uint;
254 | /// assert_eq!(uint!(1).checked_sub(uint!(1)), Some(uint!(0)));
255 | /// assert_eq!(uint!(0).checked_sub(uint!(1)), None);
256 | /// ```
257 | #[must_use]
258 | pub fn checked_sub(self, rhs: Self) -> Option {
259 | self.0.checked_sub(rhs.0).and_then(Self::new)
260 | }
261 |
262 | /// Checked integer multiplication. Computes `self * rhs`, returning `None` if overflow
263 | /// occurred.
264 | ///
265 | /// # Examples
266 | ///
267 | /// Basic usage:
268 | ///
269 | /// ```
270 | /// # use js_int::{uint, UInt};
271 | /// assert_eq!(uint!(5).checked_mul(uint!(1)), Some(uint!(5)));
272 | /// assert_eq!(UInt::MAX.checked_mul(uint!(2)), None);
273 | /// ```
274 | #[must_use]
275 | pub fn checked_mul(self, rhs: Self) -> Option {
276 | self.0.checked_mul(rhs.0).and_then(Self::new)
277 | }
278 |
279 | /// Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`.
280 | ///
281 | /// # Examples
282 | ///
283 | /// Basic usage:
284 | ///
285 | /// ```
286 | /// # use js_int::uint;
287 | /// assert_eq!(uint!(128).checked_div(uint!(2)), Some(uint!(64)));
288 | /// assert_eq!(uint!(1).checked_div(uint!(0)), None);
289 | /// ```
290 | #[must_use]
291 | pub fn checked_div(self, rhs: Self) -> Option {
292 | self.0.checked_div(rhs.0).map(Self)
293 | }
294 |
295 | /// Checked integer remainder. Computes `self % rhs`, returning `None` if `rhs == 0`.
296 | ///
297 | /// # Examples
298 | ///
299 | /// Basic usage:
300 | ///
301 | /// ```
302 | /// # use js_int::uint;
303 | /// assert_eq!(uint!(5).checked_rem(uint!(2)), Some(uint!(1)));
304 | /// assert_eq!(uint!(5).checked_rem(uint!(0)), None);
305 | /// ```
306 | #[must_use]
307 | pub fn checked_rem(self, rhs: Self) -> Option {
308 | self.0.checked_rem(rhs.0).map(Self)
309 | }
310 |
311 | /// Checked negation. Computes `-self`, returning None unless `self == 0`.
312 | ///
313 | /// Note that negating any positive integer will overflow.
314 | ///
315 | /// # Examples
316 | ///
317 | /// Basic usage:
318 | ///
319 | /// ```
320 | /// # use js_int::uint;
321 | /// assert_eq!(uint!(0).checked_neg(), Some(uint!(0)));
322 | /// assert_eq!(uint!(1).checked_neg(), None);
323 | /// ```
324 | #[must_use]
325 | pub fn checked_neg(self) -> Option {
326 | self.0.checked_neg().map(Self)
327 | }
328 |
329 | /// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if overflow or
330 | /// underflow occurred.
331 | ///
332 | /// # Examples
333 | ///
334 | /// Basic usage:
335 | ///
336 | /// ```
337 | /// # use js_int::{uint, UInt};
338 | /// assert_eq!(uint!(0).checked_pow(2), Some(uint!(0)));
339 | /// assert_eq!(uint!(8).checked_pow(2), Some(uint!(64)));
340 | /// assert_eq!(uint!(1_000_000_000).checked_pow(2), None);
341 | /// assert_eq!(UInt::MAX.checked_pow(2), None);
342 | /// ```
343 | #[must_use]
344 | pub fn checked_pow(self, exp: u32) -> Option {
345 | self.0.checked_pow(exp).and_then(Self::new)
346 | }
347 |
348 | /// Saturating integer addition. Computes `self + rhs`, saturating at the numeric bounds
349 | /// instead of overflowing.
350 | ///
351 | /// # Examples
352 | ///
353 | /// Basic usage:
354 | ///
355 | /// ```
356 | /// # use js_int::{uint, UInt};
357 | /// assert_eq!(uint!(100).saturating_add(uint!(1)), uint!(101));
358 | /// assert_eq!(UInt::MAX.saturating_add(uint!(1)), UInt::MAX);
359 | /// ```
360 | #[must_use]
361 | pub fn saturating_add(self, rhs: Self) -> Self {
362 | self.checked_add(rhs).unwrap_or(Self::MAX)
363 | }
364 |
365 | /// Saturating integer subtraction. Computes `self - rhs`, saturating at the numeric
366 | /// bounds instead of underflowing.
367 | ///
368 | /// # Examples
369 | ///
370 | /// Basic usage:
371 | ///
372 | /// ```
373 | /// # use js_int::uint;
374 | /// assert_eq!(uint!(100).saturating_sub(uint!(1)), uint!(99));
375 | /// assert_eq!(uint!(1).saturating_sub(uint!(2)), uint!(0));
376 | /// ```
377 | #[must_use]
378 | pub fn saturating_sub(self, rhs: Self) -> Self {
379 | self.checked_sub(rhs).unwrap_or(Self::MIN)
380 | }
381 |
382 | /// Saturating integer multiplication. Computes `self * rhs`, saturating at the numeric
383 | /// bounds instead of overflowing.
384 | ///
385 | /// # Examples
386 | ///
387 | /// Basic usage:
388 | ///
389 | /// ```
390 | /// # use js_int::{uint, UInt};
391 | /// assert_eq!(uint!(100).saturating_mul(uint!(2)), uint!(200));
392 | /// assert_eq!(UInt::MAX.saturating_mul(uint!(2)), UInt::MAX);
393 | /// assert_eq!(UInt::MAX.saturating_mul(UInt::MAX), UInt::MAX);
394 | /// ```
395 | #[must_use]
396 | pub fn saturating_mul(self, rhs: Self) -> Self {
397 | self.checked_mul(rhs).unwrap_or(Self::MAX)
398 | }
399 |
400 | /// Saturating integer exponentiation. Computes `self.pow(exp)`, saturating at the
401 | /// numeric bounds instead of overflowing or underflowing.
402 | ///
403 | /// # Examples
404 | ///
405 | /// Basic usage:
406 | ///
407 | /// ```
408 | /// # use js_int::{uint, UInt};
409 | /// assert_eq!(uint!(5).saturating_pow(2), uint!(25));
410 | /// assert_eq!(UInt::MAX.saturating_pow(2), UInt::MAX);
411 | /// ```
412 | #[must_use]
413 | pub fn saturating_pow(self, exp: u32) -> Self {
414 | Self::new_saturating(self.0.saturating_pow(exp))
415 | }
416 |
417 | /// Deserialization function for use with `#[serde(deserialize_with = ...)]` that performs
418 | /// deserialization through `f64` instead of `u64`.
419 | /// This allows deserializing from numbers with a fractional component like `.0`.
420 | ///
421 | /// Note, however, that this will not accept non-zero fractional components like `.1`.
422 | ///
423 | /// # Example
424 | /// ```rs
425 | /// use serde::Deserialize;
426 | /// use js_int::UInt;
427 | ///
428 | /// #[derive(Deserialize)]
429 | /// struct Point {
430 | /// #[serde(deserialize_with = "UInt::deserialize_via_float")]
431 | /// x: UInt;
432 | /// #[serde(deserialize_with = "UInt::deserialize_via_float")]
433 | /// y: UInt;
434 | /// }
435 | /// ```
436 | #[cfg(feature = "serde")]
437 | pub fn deserialize_via_float<'de, D>(deserializer: D) -> Result
438 | where
439 | D: Deserializer<'de>,
440 | {
441 | const EXPECTING: &str = "a number between 0 and 2^53 - 1 without fractional component";
442 |
443 | let val = f64::deserialize(deserializer)?;
444 |
445 | if val < 0.0 || val > MAX_SAFE_UINT as f64 || !super::is_acceptable_float(val) {
446 | Err(D::Error::invalid_value(Unexpected::Float(val), &EXPECTING))
447 | } else {
448 | Ok(Self(val as u64))
449 | }
450 | }
451 |
452 | // TODO: wrapping_* methods, overflowing_* methods
453 | }
454 |
455 | fmt_impls!(UInt);
456 | convert_impls!(UInt, u8, u16, u32, u64, u128, usize, i8, i16, i32, isize);
457 |
458 | impl TryFrom for UInt {
459 | type Error = TryFromIntError;
460 |
461 | fn try_from(val: i8) -> Result {
462 | if val >= 0 {
463 | Ok(Self(val as u64))
464 | } else {
465 | Err(TryFromIntError::new())
466 | }
467 | }
468 | }
469 |
470 | impl TryFrom for UInt {
471 | type Error = TryFromIntError;
472 |
473 | fn try_from(val: i16) -> Result {
474 | if val >= 0 {
475 | Ok(Self(val as u64))
476 | } else {
477 | Err(TryFromIntError::new())
478 | }
479 | }
480 | }
481 |
482 | impl TryFrom for UInt {
483 | type Error = TryFromIntError;
484 |
485 | fn try_from(val: i32) -> Result {
486 | if val >= 0 {
487 | Ok(Self(val as u64))
488 | } else {
489 | Err(TryFromIntError::new())
490 | }
491 | }
492 | }
493 |
494 | impl TryFrom for UInt {
495 | type Error = TryFromIntError;
496 |
497 | fn try_from(val: i64) -> Result {
498 | if (0..=MAX_SAFE_INT).contains(&val) {
499 | Ok(Self(val as u64))
500 | } else {
501 | Err(TryFromIntError::new())
502 | }
503 | }
504 | }
505 |
506 | impl TryFrom for UInt {
507 | type Error = TryFromIntError;
508 |
509 | fn try_from(val: i128) -> Result {
510 | if (0..=MAX_SAFE_INT.into()).contains(&val) {
511 | Ok(Self(val as u64))
512 | } else {
513 | Err(TryFromIntError::new())
514 | }
515 | }
516 | }
517 |
518 | impl From for i64 {
519 | fn from(val: UInt) -> Self {
520 | val.0 as i64
521 | }
522 | }
523 |
524 | impl From for i128 {
525 | fn from(val: UInt) -> Self {
526 | val.0 as i128
527 | }
528 | }
529 |
530 | macro_rules! uint_op_impl {
531 | ($trait:ident, $method:ident, $assign_trait:ident, $assign_method:ident) => {
532 | impl $trait for UInt {
533 | type Output = Self;
534 |
535 | fn $method(self, rhs: Self) -> Self {
536 | Self::new_(::$method(self.0, rhs.0))
537 | }
538 | }
539 |
540 | impl $assign_trait for UInt {
541 | fn $assign_method(&mut self, other: Self) {
542 | self.assign_(::$method(self.0, other.0));
543 | }
544 | }
545 | };
546 | }
547 |
548 | uint_op_impl!(Add, add, AddAssign, add_assign);
549 | uint_op_impl!(Sub, sub, SubAssign, sub_assign);
550 | uint_op_impl!(Mul, mul, MulAssign, mul_assign);
551 | uint_op_impl!(Div, div, DivAssign, div_assign);
552 | uint_op_impl!(Rem, rem, RemAssign, rem_assign);
553 |
554 | impl iter::Sum for UInt {
555 | fn sum(iter: I) -> Self
556 | where
557 | I: Iterator- ,
558 | {
559 | Self::new_(iter.map(|x| x.0).sum())
560 | }
561 | }
562 |
563 | impl<'a> iter::Sum<&'a UInt> for UInt {
564 | fn sum(iter: I) -> Self
565 | where
566 | I: Iterator
- ,
567 | {
568 | Self::new_(iter.map(|x| x.0).sum())
569 | }
570 | }
571 |
572 | impl iter::Product for UInt {
573 | fn product(iter: I) -> Self
574 | where
575 | I: Iterator
- ,
576 | {
577 | Self::new_(iter.map(|x| x.0).product())
578 | }
579 | }
580 |
581 | impl<'a> iter::Product<&'a UInt> for UInt {
582 | fn product(iter: I) -> Self
583 | where
584 | I: Iterator
- ,
585 | {
586 | Self::new_(iter.map(|x| x.0).product())
587 | }
588 | }
589 |
590 | impl FromStr for UInt {
591 | type Err = ParseIntError;
592 |
593 | fn from_str(src: &str) -> Result {
594 | let val = u64::from_str(src)?;
595 | if val > MAX_SAFE_UINT {
596 | Err(ParseIntError { kind: ParseIntErrorKind::Overflow })
597 | } else {
598 | Ok(Self(val))
599 | }
600 | }
601 | }
602 |
603 | #[cfg(feature = "serde")]
604 | impl<'de> Deserialize<'de> for UInt {
605 | fn deserialize(deserializer: D) -> Result
606 | where
607 | D: Deserializer<'de>,
608 | {
609 | let val = u64::deserialize(deserializer)?;
610 |
611 | Self::new(val).ok_or_else(|| {
612 | D::Error::invalid_value(Unexpected::Unsigned(val), &"an integer between 0 and 2^53 - 1")
613 | })
614 | }
615 | }
616 |
617 | #[cfg(feature = "serde")]
618 | impl Serialize for UInt {
619 | fn serialize
(&self, serializer: S) -> Result
620 | where
621 | S: Serializer,
622 | {
623 | self.0.serialize(serializer)
624 | }
625 | }
626 |
627 | #[cfg(test)]
628 | mod tests {
629 | use super::{UInt, MAX_SAFE_UINT};
630 |
631 | #[test]
632 | fn uint_ops() {
633 | assert_eq!(uint!(5) + uint!(3), uint!(8));
634 | assert_eq!(uint!(2) - uint!(1), uint!(1));
635 | assert_eq!(uint!(4) * uint!(2), uint!(8));
636 | assert_eq!(uint!(5) / uint!(2), uint!(2));
637 | assert_eq!(uint!(11) % uint!(4), uint!(3));
638 | }
639 |
640 | #[test]
641 | fn uint_assign_ops() {
642 | let mut uint = uint!(1);
643 |
644 | uint += uint!(3);
645 | assert_eq!(uint, uint!(4));
646 |
647 | uint -= uint!(1);
648 | assert_eq!(uint, uint!(3));
649 |
650 | uint *= uint!(3);
651 | assert_eq!(uint, uint!(9));
652 |
653 | uint /= uint!(3);
654 | assert_eq!(uint, uint!(3));
655 |
656 | uint %= uint!(2);
657 | assert_eq!(uint, uint!(1));
658 | }
659 |
660 | #[test]
661 | fn uint_wrapping_new() {
662 | assert_eq!(UInt::new_wrapping(MAX_SAFE_UINT + 1), uint!(0));
663 | }
664 |
665 | #[test]
666 | #[cfg_attr(debug_assertions, ignore)]
667 | fn uint_underflow_wrap() {
668 | assert_eq!(uint!(0) - uint!(1), UInt::MAX);
669 | }
670 |
671 | #[test]
672 | #[cfg_attr(debug_assertions, ignore)]
673 | fn uint_overflow_wrap() {
674 | assert_eq!(UInt::MAX + uint!(1), uint!(0));
675 | assert_eq!(UInt::MAX + uint!(5), uint!(4));
676 | }
677 |
678 | #[test]
679 | #[should_panic]
680 | #[cfg_attr(not(debug_assertions), ignore)]
681 | fn uint_underflow_panic() {
682 | let _ = uint!(0) - uint!(1);
683 | }
684 |
685 | #[test]
686 | #[should_panic]
687 | #[cfg_attr(not(debug_assertions), ignore)]
688 | fn uint_overflow_panic() {
689 | let _ = UInt::MAX + uint!(1);
690 | }
691 |
692 | #[test]
693 | fn try_from_uint_for_i_n() {
694 | use core::convert::TryFrom;
695 | let i8_max = i8::MAX as u64;
696 | let i16_max = i16::MAX as u64;
697 | let i32_max = i32::MAX as u64;
698 |
699 | assert_eq!(i8::try_from(UInt(0)), Ok(0));
700 | assert_eq!(i8::try_from(UInt(10)), Ok(10));
701 | assert_eq!(i8::try_from(UInt(i8_max)), Ok(i8::MAX));
702 | assert!(i8::try_from(UInt(i8_max + 1)).is_err());
703 |
704 | assert_eq!(i16::try_from(UInt(0)), Ok(0));
705 | assert_eq!(i16::try_from(UInt(10)), Ok(10));
706 | assert_eq!(i16::try_from(UInt(i8_max + 1)), Ok((i8::MAX as i16) + 1));
707 | assert_eq!(i16::try_from(UInt(i16_max)), Ok(i16::MAX));
708 | assert!(i16::try_from(UInt(i16_max + 1)).is_err());
709 |
710 | assert_eq!(i32::try_from(UInt(0)), Ok(0));
711 | assert_eq!(i32::try_from(UInt(10)), Ok(10));
712 | assert_eq!(i32::try_from(UInt(i16_max + 1)), Ok((i16::MAX as i32) + 1));
713 | assert_eq!(i32::try_from(UInt(i32_max)), Ok(i32::MAX));
714 | assert!(i32::try_from(UInt(i32_max + 1)).is_err());
715 | }
716 | }
717 |
--------------------------------------------------------------------------------
/src/int.rs:
--------------------------------------------------------------------------------
1 | use core::{
2 | convert::TryFrom,
3 | iter,
4 | ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign},
5 | str::FromStr,
6 | };
7 |
8 | use crate::{
9 | error::{ParseIntError, ParseIntErrorKind, TryFromIntError},
10 | UInt, MAX_SAFE_UINT,
11 | };
12 | #[cfg(feature = "serde")]
13 | use serde_core::{
14 | de::{Error as _, Unexpected},
15 | Deserialize, Deserializer, Serialize, Serializer,
16 | };
17 |
18 | /// The largest integer value that can be represented exactly by an f64.
19 | pub const MAX_SAFE_INT: i64 = 0x001F_FFFF_FFFF_FFFF;
20 | /// The smallest integer value that can be represented exactly by an f64.
21 | pub const MIN_SAFE_INT: i64 = -MAX_SAFE_INT;
22 |
23 | /// An integer limited to the range of integers that can be represented exactly by an f64.
24 | #[derive(Clone, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
25 | pub struct Int(i64);
26 |
27 | impl Int {
28 | /// The smallest value that can be represented by this integer type.
29 | ///
30 | /// # Examples
31 | ///
32 | /// Basic usage:
33 | ///
34 | /// ```
35 | /// # use {core::convert::TryFrom, js_int::Int};
36 | /// assert_eq!(Int::MIN, Int::try_from(-9_007_199_254_740_991i64).unwrap());
37 | /// ```
38 | pub const MIN: Self = Self(MIN_SAFE_INT);
39 |
40 | /// The largest value that can be represented by this integer type.
41 | ///
42 | /// # Examples
43 | ///
44 | /// Basic usage:
45 | ///
46 | /// ```
47 | /// # use {core::convert::TryFrom, js_int::Int};
48 | /// assert_eq!(Int::MAX, Int::try_from(9_007_199_254_740_991i64).unwrap());
49 | /// ```
50 | pub const MAX: Self = Self(MAX_SAFE_INT);
51 |
52 | /// Try to create an `Int` from the provided `i64`, returning `None` if it is smaller than
53 | /// `MIN_SAFE_INT` or larger than `MAX_SAFE_INT`.
54 | ///
55 | /// This is the same as the `TryFrom` implementation for `Int`, except that it returns
56 | /// an `Option` instead of a `Result`.
57 | ///
58 | /// # Examples
59 | ///
60 | /// Basic usage:
61 | ///
62 | /// ```
63 | /// # use js_int::Int;
64 | /// assert_eq!(Int::new(js_int::MIN_SAFE_INT), Some(Int::MIN));
65 | /// assert_eq!(Int::new(js_int::MAX_SAFE_INT), Some(Int::MAX));
66 | /// assert_eq!(Int::new(js_int::MIN_SAFE_INT - 1), None);
67 | /// assert_eq!(Int::new(js_int::MAX_SAFE_INT + 1), None);
68 | /// ```
69 | #[must_use]
70 | pub const fn new(val: i64) -> Option {
71 | if val >= MIN_SAFE_INT && val <= MAX_SAFE_INT {
72 | Some(Self(val))
73 | } else {
74 | None
75 | }
76 | }
77 |
78 | /// Creates an `Int` from the given `i64` clamped to the safe interval.
79 | ///
80 | /// The given value gets clamped into the closed interval between
81 | /// `MIN_SAFE_INT` and `MAX_SAFE_INT`.
82 | ///
83 | /// # Examples
84 | ///
85 | /// Basic usage:
86 | ///
87 | /// ```
88 | /// # use js_int::{int, Int};
89 | /// assert_eq!(Int::new_saturating(0), int!(0));
90 | /// assert_eq!(Int::new_saturating(js_int::MAX_SAFE_INT), Int::MAX);
91 | /// assert_eq!(Int::new_saturating(js_int::MAX_SAFE_INT + 1), Int::MAX);
92 | /// assert_eq!(Int::new_saturating(js_int::MIN_SAFE_INT), Int::MIN);
93 | /// assert_eq!(Int::new_saturating(js_int::MIN_SAFE_INT - 1), Int::MIN);
94 | /// ```
95 | #[must_use]
96 | pub fn new_saturating(val: i64) -> Self {
97 | if val < MIN_SAFE_INT {
98 | Self::MIN
99 | } else if val > MAX_SAFE_INT {
100 | Self::MAX
101 | } else {
102 | Self(val)
103 | }
104 | }
105 |
106 | /// The constructor used for arithmetic operations
107 | #[must_use]
108 | fn new_(val: i64) -> Self {
109 | assert!(val >= MIN_SAFE_INT);
110 | assert!(val <= MAX_SAFE_INT);
111 |
112 | Self(val)
113 | }
114 |
115 | /// Helper function for mutable arithmetic operations (`+=`, `-=`, …)
116 | fn assign_(&mut self, val: i64) {
117 | assert!(val >= MIN_SAFE_INT);
118 | assert!(val <= MAX_SAFE_INT);
119 |
120 | *self = Self(val);
121 | }
122 |
123 | /// Converts a string slice in a given base to an integer.
124 | ///
125 | /// The string is expected to be an optional `+` or `-` sign followed by digits.
126 | /// Leading and trailing whitespace represent an error. Digits are a subset of these characters,
127 | /// depending on `radix`:
128 | ///
129 | /// * `0-9`
130 | /// * `a-z`
131 | /// * `A-Z`
132 | ///
133 | /// # Panics
134 | ///
135 | /// This function panics if `radix` is not in the range from 2 to 36.
136 | ///
137 | /// # Examples
138 | ///
139 | /// Basic usage:
140 | ///
141 | /// ```
142 | /// # use js_int::{int, Int};
143 | /// assert_eq!(Int::from_str_radix("A", 16), Ok(int!(10)));
144 | /// ```
145 | pub fn from_str_radix(src: &str, radix: u32) -> Result {
146 | let val = i64::from_str_radix(src, radix)?;
147 | if val < MIN_SAFE_INT {
148 | Err(ParseIntError { kind: ParseIntErrorKind::Underflow })
149 | } else if val > MAX_SAFE_INT {
150 | Err(ParseIntError { kind: ParseIntErrorKind::Overflow })
151 | } else {
152 | Ok(Self(val))
153 | }
154 | }
155 |
156 | /// Returns the smallest value that can be represented by this integer type.
157 | ///
158 | /// # Examples
159 | ///
160 | /// Basic usage:
161 | ///
162 | /// ```
163 | /// # use {core::convert::TryFrom, js_int::Int};
164 | /// assert_eq!(Int::min_value(), Int::try_from(-9_007_199_254_740_991i64).unwrap());
165 | /// ```
166 | #[must_use]
167 | #[deprecated = "Use `UInt::MIN` instead."]
168 | pub const fn min_value() -> Self {
169 | Self(MIN_SAFE_INT)
170 | }
171 |
172 | /// Returns the largest value that can be represented by this integer type.
173 | ///
174 | /// # Examples
175 | ///
176 | /// Basic usage:
177 | ///
178 | /// ```
179 | /// # use {core::convert::TryFrom, js_int::Int};
180 | /// assert_eq!(Int::max_value(), Int::try_from(9_007_199_254_740_991i64).unwrap());
181 | /// ```
182 | #[must_use]
183 | #[deprecated = "Use `Int::MAX` instead."]
184 | pub const fn max_value() -> Self {
185 | Self(MAX_SAFE_INT)
186 | }
187 |
188 | /// Computes the absolute value of `self`.
189 | ///
190 | /// # Examples
191 | ///
192 | /// Basic usage:
193 | ///
194 | /// ```
195 | /// # use js_int::{int, Int};
196 | /// assert_eq!(int!(10).abs(), int!(10));
197 | /// assert_eq!(int!(-10).abs(), int!(10));
198 | ///
199 | /// // Differently from i8 / i16 / i32 / i128, Int's min_value is its max_value negated
200 | /// assert_eq!(Int::MIN.abs(), Int::MAX);
201 | /// ```
202 | #[must_use]
203 | pub fn abs(self) -> Self {
204 | Self(self.0.abs())
205 | }
206 |
207 | /// Returns `true` if `self` is positive and `false` if the number is zero or negative.
208 | ///
209 | /// # Examples
210 | ///
211 | /// Basic usage:
212 | ///
213 | /// ```
214 | /// # use js_int::int;
215 | /// assert!(int!(10).is_positive());
216 | /// assert!(!int!(0).is_positive());
217 | /// assert!(!int!(-10).is_positive());
218 | /// ```
219 | #[must_use]
220 | pub const fn is_positive(self) -> bool {
221 | self.0.is_positive()
222 | }
223 |
224 | /// Returns `true` if `self` is negative and `false` if the number is zero or positive.
225 | ///
226 | /// # Examples
227 | ///
228 | /// Basic usage:
229 | ///
230 | /// ```
231 | /// # use js_int::int;
232 | /// assert!(int!(-10).is_negative());
233 | /// assert!(!int!(0).is_negative());
234 | /// assert!(!int!(10).is_negative());
235 | /// ```
236 | #[must_use]
237 | pub const fn is_negative(self) -> bool {
238 | self.0.is_negative()
239 | }
240 |
241 | /// Checked integer addition. Computes `self + rhs`, returning `None` if overflow
242 | /// occurred.
243 | ///
244 | /// # Examples
245 | ///
246 | /// Basic usage:
247 | ///
248 | /// ```
249 | /// # use js_int::{int, Int};
250 | /// assert_eq!(
251 | /// (Int::MAX - int!(1)).checked_add(int!(1)),
252 | /// Some(Int::MAX)
253 | /// );
254 | /// assert_eq!((Int::MAX - int!(1)).checked_add(int!(2)), None);
255 | /// ```
256 | #[must_use]
257 | pub fn checked_add(self, rhs: Self) -> Option {
258 | self.0.checked_add(rhs.0).and_then(Self::new)
259 | }
260 |
261 | /// Checked integer subtraction. Computes `self - rhs`, returning `None` if overflow
262 | /// occurred.
263 | ///
264 | /// # Examples
265 | ///
266 | /// Basic usage:
267 | ///
268 | /// ```
269 | /// # use js_int::{int, Int};
270 | /// assert_eq!(
271 | /// (Int::MIN + int!(2)).checked_sub(int!(1)),
272 | /// Some(Int::MIN + int!(1))
273 | /// );
274 | /// assert_eq!((Int::MIN + int!(2)).checked_sub(int!(3)), None);
275 | /// ```
276 | #[must_use]
277 | pub fn checked_sub(self, rhs: Self) -> Option {
278 | self.0.checked_sub(rhs.0).and_then(Self::new)
279 | }
280 |
281 | /// Checked integer multiplication. Computes `self * rhs`, returning `None` if overflow
282 | /// occurred.
283 | ///
284 | /// # Examples
285 | ///
286 | /// Basic usage:
287 | ///
288 | /// ```
289 | /// # use js_int::{int, Int};
290 | /// assert_eq!(int!(5).checked_mul(int!(1)), Some(int!(5)));
291 | /// assert_eq!(Int::MAX.checked_mul(int!(2)), None);
292 | /// ```
293 | #[must_use]
294 | pub fn checked_mul(self, rhs: Self) -> Option {
295 | self.0.checked_mul(rhs.0).and_then(Self::new)
296 | }
297 |
298 | /// Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`.
299 | ///
300 | /// # Examples
301 | ///
302 | /// Basic usage:
303 | ///
304 | /// ```
305 | /// # use js_int::{int, Int};
306 | /// assert_eq!(Int::MIN.checked_div(int!(-1)), Some(Int::MAX));
307 | /// assert_eq!(int!(1).checked_div(int!(0)), None);
308 | /// ```
309 | #[must_use]
310 | pub fn checked_div(self, rhs: Self) -> Option {
311 | self.0.checked_div(rhs.0).map(Self)
312 | }
313 |
314 | /// Checked integer remainder. Computes `self % rhs`, returning `None` if `rhs == 0`.
315 | ///
316 | /// # Examples
317 | ///
318 | /// Basic usage:
319 | ///
320 | /// ```
321 | /// # use js_int::{int, Int};
322 | /// assert_eq!(int!(5).checked_rem(int!(2)), Some(int!(1)));
323 | /// assert_eq!(int!(5).checked_rem(int!(0)), None);
324 | /// assert_eq!(Int::MIN.checked_rem(int!(-1)), Some(int!(0)));
325 | /// ```
326 | #[must_use]
327 | pub fn checked_rem(self, rhs: Self) -> Option {
328 | self.0.checked_rem(rhs.0).map(Self)
329 | }
330 |
331 | /// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if overflow or
332 | /// underflow occurred.
333 | ///
334 | /// # Examples
335 | ///
336 | /// Basic usage:
337 | ///
338 | /// ```
339 | /// # use js_int::{int, Int};
340 | /// assert_eq!(int!(8).checked_pow(2), Some(int!(64)));
341 | /// assert_eq!(Int::MAX.checked_pow(2), None);
342 | /// assert_eq!(Int::MIN.checked_pow(2), None);
343 | /// assert_eq!(int!(1_000_000_000).checked_pow(2), None);
344 | /// ```
345 | #[must_use]
346 | pub fn checked_pow(self, exp: u32) -> Option {
347 | self.0.checked_pow(exp).and_then(Self::new)
348 | }
349 |
350 | /// Saturating integer addition. Computes `self + rhs`, saturating at the numeric bounds
351 | /// instead of overflowing.
352 | ///
353 | /// # Examples
354 | ///
355 | /// Basic usage:
356 | ///
357 | /// ```
358 | /// # use js_int::{int, Int};
359 | /// assert_eq!(int!(100).saturating_add(int!(1)), int!(101));
360 | /// assert_eq!(Int::MAX.saturating_add(int!(1)), Int::MAX);
361 | /// assert_eq!(Int::MIN.saturating_add(int!(-1)), Int::MIN);
362 | /// ```
363 | #[must_use]
364 | pub fn saturating_add(self, rhs: Self) -> Self {
365 | self.checked_add(rhs).unwrap_or_else(|| {
366 | if self > 0_i32.into() {
367 | Self::MAX
368 | } else {
369 | Self::MIN
370 | }
371 | })
372 | }
373 |
374 | /// Saturating integer subtraction. Computes `self - rhs`, saturating at the numeric
375 | /// bounds instead of underflowing.
376 | ///
377 | /// # Examples
378 | ///
379 | /// Basic usage:
380 | ///
381 | /// ```
382 | /// # use js_int::{int, Int};
383 | /// assert_eq!(int!(100).saturating_sub(int!(1)), int!(99));
384 | /// assert_eq!(Int::MIN.saturating_sub(int!(1)), Int::MIN);
385 | /// assert_eq!(Int::MAX.saturating_sub(int!(-1)), Int::MAX);
386 | /// ```
387 | #[must_use]
388 | pub fn saturating_sub(self, rhs: Self) -> Self {
389 | self.checked_sub(rhs).unwrap_or_else(|| {
390 | if self > 0_i32.into() {
391 | Self::MAX
392 | } else {
393 | Self::MIN
394 | }
395 | })
396 | }
397 |
398 | /// Saturating integer multiplication. Computes `self * rhs`, saturating at the numeric
399 | /// bounds instead of overflowing.
400 | ///
401 | /// # Examples
402 | ///
403 | /// Basic usage:
404 | ///
405 | /// ```
406 | /// # use js_int::{int, Int};
407 | /// assert_eq!(int!(100).saturating_mul(int!(2)), int!(200));
408 | /// assert_eq!(Int::MAX.saturating_mul(int!(2)), Int::MAX);
409 | /// assert_eq!(Int::MAX.saturating_mul(Int::MAX), Int::MAX);
410 | /// assert_eq!(Int::MAX.saturating_mul(Int::MIN), Int::MIN);
411 | /// ```
412 | #[must_use]
413 | pub fn saturating_mul(self, rhs: Self) -> Self {
414 | Self::new_saturating(self.0.saturating_mul(rhs.0))
415 | }
416 |
417 | /// Saturating integer exponentiation. Computes `self.pow(exp)`, saturating at the
418 | /// numeric bounds instead of overflowing or underflowing.
419 | ///
420 | /// # Examples
421 | ///
422 | /// Basic usage:
423 | ///
424 | /// ```
425 | /// # use js_int::{int, Int};
426 | /// assert_eq!(int!(5).saturating_pow(2), int!(25));
427 | /// assert_eq!(int!(-2).saturating_pow(3), int!(-8));
428 | /// assert_eq!(Int::MAX.saturating_pow(2), Int::MAX);
429 | /// assert_eq!(Int::MIN.saturating_pow(2), Int::MAX);
430 | /// ```
431 | #[must_use]
432 | pub fn saturating_pow(self, exp: u32) -> Self {
433 | Self::new_saturating(self.0.saturating_pow(exp))
434 | }
435 |
436 | /// Deserialization function for use with `#[serde(deserialize_with = ...)]` that performs
437 | /// deserialization through `f64` instead of `i64`.
438 | /// This allows deserializing from numbers with a fractional component like `.0`.
439 | ///
440 | /// Note, however, that this will not accept non-zero fractional components like `.1`.
441 | ///
442 | /// # Example
443 | /// ```rs
444 | /// use serde::Deserialize;
445 | /// use js_int::Int;
446 | ///
447 | /// #[derive(Deserialize)]
448 | /// struct Point {
449 | /// #[serde(deserialize_with = "Int::deserialize_via_float")]
450 | /// x: Int;
451 | /// #[serde(deserialize_with = "Int::deserialize_via_float")]
452 | /// y: Int;
453 | /// }
454 | #[cfg(feature = "serde")]
455 | pub fn deserialize_via_float<'de, D>(deserializer: D) -> Result
456 | where
457 | D: Deserializer<'de>,
458 | {
459 | const EXPECTING: &str =
460 | "a number between -2^53 + 1 and 2^53 - 1 without fractional component";
461 |
462 | let val = f64::deserialize(deserializer)?;
463 |
464 | if val > MAX_SAFE_INT as f64
465 | || val < MIN_SAFE_INT as f64
466 | || !super::is_acceptable_float(val)
467 | {
468 | Err(D::Error::invalid_value(Unexpected::Float(val), &EXPECTING))
469 | } else {
470 | Ok(Self(val as i64))
471 | }
472 | }
473 |
474 | // TODO: wrapping_* methods, overflowing_* methods
475 | }
476 |
477 | fmt_impls!(Int);
478 | convert_impls!(Int, i8, i16, i32, i64, i128, isize, u8, u16, u32, usize);
479 |
480 | impl From for Int {
481 | fn from(val: u8) -> Self {
482 | Self(i64::from(val))
483 | }
484 | }
485 |
486 | impl From for Int {
487 | fn from(val: u16) -> Self {
488 | Self(i64::from(val))
489 | }
490 | }
491 |
492 | impl From for Int {
493 | fn from(val: u32) -> Self {
494 | Self(i64::from(val))
495 | }
496 | }
497 |
498 | impl From for Int {
499 | fn from(val: UInt) -> Self {
500 | Self(i64::from(val))
501 | }
502 | }
503 |
504 | impl TryFrom for Int {
505 | type Error = TryFromIntError;
506 |
507 | fn try_from(val: u64) -> Result {
508 | if val <= MAX_SAFE_UINT {
509 | Ok(Self(val as i64))
510 | } else {
511 | Err(TryFromIntError::new())
512 | }
513 | }
514 | }
515 |
516 | impl TryFrom for Int {
517 | type Error = TryFromIntError;
518 |
519 | fn try_from(val: u128) -> Result {
520 | if val <= u128::from(MAX_SAFE_UINT) {
521 | Ok(Self(val as i64))
522 | } else {
523 | Err(TryFromIntError::new())
524 | }
525 | }
526 | }
527 |
528 | macro_rules! int_op_impl {
529 | ($trait:ident, $method:ident, $assign_trait:ident, $assign_method:ident) => {
530 | impl $trait for Int {
531 | type Output = Self;
532 |
533 | fn $method(self, rhs: Self) -> Self {
534 | Self::new_(::$method(self.0, rhs.0))
535 | }
536 | }
537 |
538 | impl $assign_trait for Int {
539 | fn $assign_method(&mut self, other: Self) {
540 | self.assign_(::$method(self.0, other.0));
541 | }
542 | }
543 | };
544 | }
545 |
546 | int_op_impl!(Add, add, AddAssign, add_assign);
547 | int_op_impl!(Sub, sub, SubAssign, sub_assign);
548 | int_op_impl!(Mul, mul, MulAssign, mul_assign);
549 | int_op_impl!(Div, div, DivAssign, div_assign);
550 | int_op_impl!(Rem, rem, RemAssign, rem_assign);
551 |
552 | impl Neg for Int {
553 | type Output = Self;
554 |
555 | fn neg(self) -> Self {
556 | Self(-self.0)
557 | }
558 | }
559 |
560 | impl iter::Sum for Int {
561 | fn sum(iter: I) -> Self
562 | where
563 | I: Iterator- ,
564 | {
565 | Self::new_(iter.map(|x| x.0).sum())
566 | }
567 | }
568 |
569 | impl<'a> iter::Sum<&'a Int> for Int {
570 | fn sum(iter: I) -> Self
571 | where
572 | I: Iterator
- ,
573 | {
574 | Self::new_(iter.map(|x| x.0).sum())
575 | }
576 | }
577 |
578 | impl iter::Product for Int {
579 | fn product(iter: I) -> Self
580 | where
581 | I: Iterator
- ,
582 | {
583 | Self::new_(iter.map(|x| x.0).product())
584 | }
585 | }
586 |
587 | impl<'a> iter::Product<&'a Int> for Int {
588 | fn product(iter: I) -> Self
589 | where
590 | I: Iterator
- ,
591 | {
592 | Self::new_(iter.map(|x| x.0).product())
593 | }
594 | }
595 |
596 | impl FromStr for Int {
597 | type Err = ParseIntError;
598 |
599 | fn from_str(src: &str) -> Result {
600 | let val = i64::from_str(src)?;
601 | if val < MIN_SAFE_INT {
602 | Err(ParseIntError { kind: ParseIntErrorKind::Underflow })
603 | } else if val > MAX_SAFE_INT {
604 | Err(ParseIntError { kind: ParseIntErrorKind::Overflow })
605 | } else {
606 | Ok(Self(val))
607 | }
608 | }
609 | }
610 |
611 | #[cfg(feature = "serde")]
612 | impl<'de> Deserialize<'de> for Int {
613 | fn deserialize(deserializer: D) -> Result
614 | where
615 | D: Deserializer<'de>,
616 | {
617 | let val = i64::deserialize(deserializer)?;
618 |
619 | Self::new(val).ok_or_else(|| {
620 | D::Error::invalid_value(
621 | Unexpected::Signed(val),
622 | &"an integer between -2^53 + 1 and 2^53 - 1",
623 | )
624 | })
625 | }
626 | }
627 |
628 | #[cfg(feature = "serde")]
629 | impl Serialize for Int {
630 | fn serialize
(&self, serializer: S) -> Result
631 | where
632 | S: Serializer,
633 | {
634 | self.0.serialize(serializer)
635 | }
636 | }
637 |
638 | #[cfg(test)]
639 | mod tests {
640 | use super::Int;
641 |
642 | #[test]
643 | fn int_ops() {
644 | assert_eq!(int!(5) + int!(3), int!(8));
645 | assert_eq!(int!(1) - int!(2), int!(-1));
646 | assert_eq!(int!(4) * int!(-7), int!(-28));
647 | assert_eq!(int!(5) / int!(2), int!(2));
648 | assert_eq!(int!(9) % int!(3), int!(0));
649 | }
650 |
651 | #[test]
652 | fn int_assign_ops() {
653 | let mut int = int!(1);
654 |
655 | int += int!(1);
656 | assert_eq!(int, int!(2));
657 |
658 | int -= int!(-1);
659 | assert_eq!(int, int!(3));
660 |
661 | int *= int!(3);
662 | assert_eq!(int, int!(9));
663 |
664 | int /= int!(3);
665 | assert_eq!(int, int!(3));
666 |
667 | int %= int!(2);
668 | assert_eq!(int, int!(1));
669 | }
670 |
671 | #[test]
672 | #[should_panic]
673 | fn int_underflow_panic() {
674 | let _ = Int::MIN - int!(1);
675 | }
676 |
677 | #[test]
678 | #[should_panic]
679 | fn int_overflow_panic() {
680 | let _ = Int::MAX + int!(1);
681 | }
682 |
683 | #[test]
684 | fn try_from_int_for_u_n() {
685 | use core::convert::TryFrom;
686 | let u8_max = u8::MAX as i64;
687 | let u16_max = u16::MAX as i64;
688 | let u32_max = u32::MAX as i64;
689 |
690 | assert_eq!(u8::try_from(Int(0)), Ok(0));
691 | assert_eq!(u8::try_from(Int(10)), Ok(10));
692 | assert_eq!(u8::try_from(Int(u8_max)), Ok(u8::MAX));
693 | assert!(u8::try_from(Int(u8_max + 1)).is_err());
694 | assert!(u8::try_from(Int(-1)).is_err());
695 | assert!(u8::try_from(Int(-10)).is_err());
696 |
697 | assert_eq!(u16::try_from(Int(0)), Ok(0));
698 | assert_eq!(u16::try_from(Int(1000)), Ok(1000));
699 | assert_eq!(u16::try_from(Int(u8_max + 1)), Ok((u8_max + 1) as u16));
700 | assert_eq!(u16::try_from(Int(u16_max)), Ok(u16::MAX));
701 | assert!(u16::try_from(Int(u16_max + 1)).is_err());
702 | assert!(u16::try_from(Int(-1)).is_err());
703 | assert!(u16::try_from(Int(-10)).is_err());
704 |
705 | assert_eq!(u32::try_from(Int(0)), Ok(0));
706 | assert_eq!(u32::try_from(Int(1000)), Ok(1000));
707 | assert_eq!(u32::try_from(Int(u16_max + 1)), Ok((u16_max + 1) as u32));
708 | assert_eq!(u32::try_from(Int(u32_max)), Ok(u32::MAX));
709 | assert!(u32::try_from(Int(u32_max + 1)).is_err());
710 | assert!(u32::try_from(Int(-1)).is_err());
711 | assert!(u32::try_from(Int(-10)).is_err());
712 | }
713 | }
714 |
--------------------------------------------------------------------------------