├── .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 | [![Latest Version](https://img.shields.io/crates/v/js_int.svg)][crates-io] 4 | [![Docs](https://docs.rs/js_int/badge.svg)][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 | --------------------------------------------------------------------------------