js_int-0.2.2/.cargo_vcs_info.json0000644000000001360000000000100123230ustar { "git": { "sha1": "cc8e1a077b46f880e5bb0ed775d662532e118e05" }, "path_in_vcs": "" }js_int-0.2.2/.github/workflows/msrv.yml000064400000000000000000000016770072674642500162650ustar 00000000000000name: Rust 1.35 on: push: branches: [main] pull_request: branches: [main] jobs: check: name: Check runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: toolchain: '1.35' profile: minimal override: true - name: Check (no default features) uses: actions-rs/cargo@v1 with: command: check args: --no-default-features - name: Check (default features) uses: actions-rs/cargo@v1 with: command: check - name: Check (serde) uses: actions-rs/cargo@v1 with: command: check args: --features serde - name: Check (float_deserialize) uses: actions-rs/cargo@v1 with: command: check args: --features float_deserialize - name: Check (all features) uses: actions-rs/cargo@v1 with: command: check args: --all-features js_int-0.2.2/.github/workflows/nightly.yml000064400000000000000000000011660072674642500167450ustar 00000000000000name: Rust Nightly on: push: branches: [main] pull_request: branches: [main] jobs: check: name: Check runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: toolchain: nightly profile: minimal override: true components: rustfmt, clippy - name: Check formatting uses: actions-rs/cargo@v1 with: command: fmt args: -- --check - name: Catch common mistakes uses: actions-rs/cargo@v1 with: command: clippy args: --all-features --all-targets -- -D warnings js_int-0.2.2/.github/workflows/stable.yml000064400000000000000000000021220072674642500165320ustar 00000000000000name: Rust Stable on: push: branches: [main] pull_request: branches: [main] jobs: check: name: Check runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: toolchain: stable profile: minimal override: true - name: Run tests (no default features) uses: actions-rs/cargo@v1 with: command: test args: --no-default-features - name: Run tests (default features) uses: actions-rs/cargo@v1 with: command: test - name: Run tests (serde) uses: actions-rs/cargo@v1 with: command: test args: --features serde - name: Run tests (float_deserialize) uses: actions-rs/cargo@v1 with: command: test args: --features float_deserialize - name: Run tests (all features) uses: actions-rs/cargo@v1 with: command: test args: --all-features - name: Run tests (release build) uses: actions-rs/cargo@v1 with: command: test args: --release js_int-0.2.2/.gitignore000064400000000000000000000000360072674642500131320ustar 00000000000000/target **/*.rs.bk Cargo.lock js_int-0.2.2/.rustfmt.toml000064400000000000000000000001320072674642500136160ustar 00000000000000edition = "2018" merge_imports = true newline_style = "Unix" use_small_heuristics = "Max" js_int-0.2.2/CHANGELOG.md000064400000000000000000000031340072674642500127550ustar 00000000000000# 0.2.2 * Consider negative values in saturating add / sub * `impl TryFrom for iN` for N = [8, 16, 32] * `impl TryFrom for uN` for N = [8, 16, 32] * Fix lax_deserialize accepting NaN * Support deserializing floats without fractional component * Add `usize` and `isize` `TryFrom` implementations # 0.2.1 * Update crate metadata # 0.2.0 * Bump MSRV to 1.35 * Drop support for the `rocket_04` Cargo feature (Rocket 0.4 `FromFormValue` / `FromParam` implementations) # 0.1.9 * Add a new Cargo feature: `lax_deserialize` * See the crate documentation or [README.md](README.md) for what it does. # 0.1.8 * Update the documentation to use the macros introduced in 0.1.6. # 0.1.7 * Fix building without the `std` feature # 0.1.6 * Introduce `int!` and `uint!` macros as shorthand for `Int::from(Ni32)` and `UInt::from(Nu32)` # 0.1.5 * Introduce `Int::MIN`, `Int::MAX`, `UInt::MIN`, `UInt::MAX` and deprecate `const fn min_value` and `const fn max_value`s. # 0.1.4 * Allow deserialization of `Int`s and `UInt`s from non-self-describing formats # 0.1.3 * Add conversions to / from 128 bit integer types # 0.1.2 * Implement `std::iter::Sum` and `std::iter::Product` for `Int` and `UInt` * Mention JavaScript's propsed BigInt type in documentation # 0.1.1 * Add doctests for every inherent method of `Int` and `UInt` * Fix buggy implementation of `Int::saturating_mul` * Add (optional) implementations of `rocket::{FromFormValue, FromParam}` (for rocket 0.4) # 0.1.0 Initial release containing the `Int` and `UInt` types, `serde` support and many of the methods that `std`'s integer types provide. js_int-0.2.2/Cargo.toml0000644000000020050000000000100103160ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "js_int" version = "0.2.2" authors = ["Jonas Platte "] description = "JavaScript-interoperable integer types" readme = "README.md" keywords = ["integer", "no_std"] categories = ["no-std"] license = "MIT" repository = "https://github.com/ruma/js_int" [dependencies.serde] version = "1.0" features = ["derive"] optional = true default-features = false [dev-dependencies.serde_test] version = "1.0" [features] default = ["std"] float_deserialize = ["serde"] lax_deserialize = ["float_deserialize"] std = [] js_int-0.2.2/Cargo.toml.orig000064400000000000000000000010540072674642500140320ustar 00000000000000[package] name = "js_int" description = "JavaScript-interoperable integer types" version = "0.2.2" authors = ["Jonas Platte "] edition = "2018" license = "MIT" readme = "README.md" repository = "https://github.com/ruma/js_int" keywords = ["integer", "no_std"] categories = ["no-std"] [dependencies.serde] version = "1.0" optional = true default-features = false features = ["derive"] [features] float_deserialize = ["serde"] lax_deserialize = ["float_deserialize"] default = ["std"] std = [] [dev-dependencies] serde_test = "1.0" js_int-0.2.2/LICENSE000064400000000000000000000020560072674642500121530ustar 00000000000000Copyright (c) 2019 Jonas Platte, Jimmy Cuadra Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. js_int-0.2.2/README.md000064400000000000000000000044050072674642500124250ustar 00000000000000# js_int [![Latest Version](https://img.shields.io/crates/v/js_int.svg)][crates-io] [![Docs](https://docs.rs/js_int/badge.svg)][docs-rs] Crate `js_int` provides JavaScript-interoperable integer types. JavaScript does not have native integers. Instead it represents all numeric values with a single `Number` type which is represented as an [IEEE 754 floating-point](https://en.wikipedia.org/wiki/IEEE_754) value.\* Rust's `i64` and `u64` types can contain values outside the range of what can be represented in a JavaScript `Number`. This crate provides the types `Int` and `UInt` which wrap `i64` and `u64`, respectively. These types add bounds checking to ensure the contained value is within the range representable by a JavaScript `Number`. They provide useful trait implementations to easily convert from Rust's primitive integer types. * In the upcoming ECMAScript 2020, JavaScript will probably gain support for integers. There is a proposal for a [`BigInt`][mdn] type type that is not far from becoming part of the JavaScript specification. It won't make this crate obsolete in any way though, since there will still be lots of JS code using `Number`, and code in other languages that assumes its use. This crate requires rustc >= 1.35. This crate is `no_std`-compatible with `default-features = false`. This will disable the `std` feature, which at the time of writing will only omit the implementations of `std::error::Error` for `ParseIntError` and `TryFromIntError`. (De-)Serialization via `serde` is supported via the `serde` feature, even without the `std` feature. Deserialization can be routed through `f64` instead of `u64` with the `float_deserialize` feature. This will still not deserialize numbers with a non-zero fractional component. Enabling the `lax_deserialize` feature will discard the fractional part instead of declining to deserialize. Please be aware that `serde_json` doesn't losslessly parse large floats with a fractional part by default (even if the fractional part is `.0`). To fix that, enable its `float_roundtrip` feature. [travis]: https://travis-ci.org/jplatte/js_int [crates-io]: https://crates.io/crates/js_int [docs-rs]: https://docs.rs/js_int [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt js_int-0.2.2/src/error.rs000064400000000000000000000035210072674642500134320ustar 00000000000000use core::{ fmt::{self, Debug, Display, Formatter}, num::ParseIntError as StdParseIntError, }; /// The error type returned when when parsing an integer fails. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ParseIntError { pub(crate) kind: ParseIntErrorKind, } // When https://github.com/rust-lang/rust/issues/22639 is resolved, the error kind can be provided // publicly as well. For now, distinguishing between overflow / underflow and anything else doesn't // seem very useful. #[derive(Debug, Clone, PartialEq, Eq)] pub(crate) enum ParseIntErrorKind { Overflow, Underflow, Unknown(StdParseIntError), } impl From for ParseIntError { fn from(e: StdParseIntError) -> Self { ParseIntError { kind: ParseIntErrorKind::Unknown(e) } } } impl Display for ParseIntError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match &self.kind { ParseIntErrorKind::Overflow => f.write_str("number too large to fit in target type"), ParseIntErrorKind::Underflow => f.write_str("number too small to fit in target type"), ParseIntErrorKind::Unknown(e) => write!(f, "{}", e), } } } #[cfg(feature = "std")] impl std::error::Error for ParseIntError {} /// The error type returned when a checked integral type conversion fails. #[derive(Clone)] pub struct TryFromIntError { _private: (), } impl TryFromIntError { pub(crate) fn new() -> Self { Self { _private: () } } } impl Display for TryFromIntError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.write_str("out of range integral type conversion attempted") } } impl Debug for TryFromIntError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.write_str("TryFromIntError") } } #[cfg(feature = "std")] impl std::error::Error for TryFromIntError {} js_int-0.2.2/src/int.rs000064400000000000000000000455320072674642500131030ustar 00000000000000use core::{ convert::TryFrom, iter, ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign}, str::FromStr, }; #[cfg(feature = "serde")] use serde::{ de::{Error as _, Unexpected}, Deserialize, Deserializer, Serialize, }; use crate::{ error::{ParseIntError, ParseIntErrorKind, TryFromIntError}, UInt, MAX_SAFE_UINT, }; /// The largest integer value that can be represented exactly by an f64. pub const MAX_SAFE_INT: i64 = 0x001F_FFFF_FFFF_FFFF; /// The smallest integer value that can be represented exactly by an f64. pub const MIN_SAFE_INT: i64 = -MAX_SAFE_INT; /// An integer limited to the range of integers that can be represented exactly by an f64. #[derive(Clone, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "serde", derive(Serialize))] pub struct Int(i64); impl Int { /// The smallest value that can be represented by this integer type. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use {core::convert::TryFrom, js_int::Int}; /// assert_eq!(Int::MIN, Int::try_from(-9_007_199_254_740_991i64).unwrap()); /// ``` pub const MIN: Self = Self(MIN_SAFE_INT); /// The largest value that can be represented by this integer type. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use {core::convert::TryFrom, js_int::Int}; /// assert_eq!(Int::MAX, Int::try_from(9_007_199_254_740_991i64).unwrap()); /// ``` pub const MAX: Self = Self(MAX_SAFE_INT); /// Try to create an `Int` from the provided `i64`, returning `None` if it is smaller than /// `MIN_SAFE_INT` or larger than `MAX_SAFE_INT`. /// /// This is the same as the `TryFrom` implementation for `Int`, except that it returns /// an `Option` instead of a `Result`. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::Int; /// assert_eq!(Int::new(js_int::MIN_SAFE_INT), Some(Int::MIN)); /// assert_eq!(Int::new(js_int::MAX_SAFE_INT), Some(Int::MAX)); /// assert_eq!(Int::new(js_int::MIN_SAFE_INT - 1), None); /// assert_eq!(Int::new(js_int::MAX_SAFE_INT + 1), None); /// ``` #[must_use] pub fn new(val: i64) -> Option { if (MIN_SAFE_INT..=MAX_SAFE_INT).contains(&val) { Some(Self(val)) } else { None } } /// Creates an `Int` from the given `i64` clamped to the safe interval. /// /// The given value gets clamped into the closed interval between /// `MIN_SAFE_INT` and `MAX_SAFE_INT`. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{int, Int}; /// assert_eq!(Int::new_saturating(0), int!(0)); /// assert_eq!(Int::new_saturating(js_int::MAX_SAFE_INT), Int::MAX); /// assert_eq!(Int::new_saturating(js_int::MAX_SAFE_INT + 1), Int::MAX); /// assert_eq!(Int::new_saturating(js_int::MIN_SAFE_INT), Int::MIN); /// assert_eq!(Int::new_saturating(js_int::MIN_SAFE_INT - 1), Int::MIN); /// ``` #[must_use] pub fn new_saturating(val: i64) -> Self { if val < MIN_SAFE_INT { Self::MIN } else if val > MAX_SAFE_INT { Self::MAX } else { Self(val) } } /// The constructor used for arithmetic operations #[must_use] fn new_(val: i64) -> Self { assert!(val >= MIN_SAFE_INT); assert!(val <= MAX_SAFE_INT); Self(val) } /// Helper function for mutable arithmetic operations (`+=`, `-=`, …) fn assign_(&mut self, val: i64) { assert!(val >= MIN_SAFE_INT); assert!(val <= MAX_SAFE_INT); *self = Self(val); } /// Converts a string slice in a given base to an integer. /// /// The string is expected to be an optional `+` or `-` sign followed by digits. /// Leading and trailing whitespace represent an error. Digits are a subset of these characters, /// depending on `radix`: /// /// * `0-9` /// * `a-z` /// * `A-Z` /// /// # Panics /// /// This function panics if `radix` is not in the range from 2 to 36. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{int, Int}; /// assert_eq!(Int::from_str_radix("A", 16), Ok(int!(10))); /// ``` pub fn from_str_radix(src: &str, radix: u32) -> Result { let val = i64::from_str_radix(src, radix)?; if val < MIN_SAFE_INT { Err(ParseIntError { kind: ParseIntErrorKind::Underflow }) } else if val > MAX_SAFE_INT { Err(ParseIntError { kind: ParseIntErrorKind::Overflow }) } else { Ok(Self(val)) } } /// Returns the smallest value that can be represented by this integer type. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use {core::convert::TryFrom, js_int::Int}; /// assert_eq!(Int::min_value(), Int::try_from(-9_007_199_254_740_991i64).unwrap()); /// ``` #[must_use] #[deprecated = "Use `UInt::MIN` instead."] pub const fn min_value() -> Self { Self(MIN_SAFE_INT) } /// Returns the largest value that can be represented by this integer type. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use {core::convert::TryFrom, js_int::Int}; /// assert_eq!(Int::max_value(), Int::try_from(9_007_199_254_740_991i64).unwrap()); /// ``` #[must_use] #[deprecated = "Use `Int::MAX` instead."] pub const fn max_value() -> Self { Self(MAX_SAFE_INT) } /// Computes the absolute value of `self`. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{int, Int}; /// assert_eq!(int!(10).abs(), int!(10)); /// assert_eq!(int!(-10).abs(), int!(10)); /// /// // Differently from i8 / i16 / i32 / i128, Int's min_value is its max_value negated /// assert_eq!(Int::MIN.abs(), Int::MAX); /// ``` #[must_use] pub fn abs(self) -> Self { Self(self.0.abs()) } /// Returns `true` if `self` is positive and `false` if the number is zero or negative. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::int; /// assert!(int!(10).is_positive()); /// assert!(!int!(0).is_positive()); /// assert!(!int!(-10).is_positive()); /// ``` #[must_use] pub const fn is_positive(self) -> bool { self.0.is_positive() } /// Returns `true` if `self` is negative and `false` if the number is zero or positive. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::int; /// assert!(int!(-10).is_negative()); /// assert!(!int!(0).is_negative()); /// assert!(!int!(10).is_negative()); /// ``` #[must_use] pub const fn is_negative(self) -> bool { self.0.is_negative() } /// Checked integer addition. Computes `self + rhs`, returning `None` if overflow /// occurred. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{int, Int}; /// assert_eq!( /// (Int::MAX - int!(1)).checked_add(int!(1)), /// Some(Int::MAX) /// ); /// assert_eq!((Int::MAX - int!(1)).checked_add(int!(2)), None); /// ``` #[must_use] pub fn checked_add(self, rhs: Self) -> Option { self.0.checked_add(rhs.0).and_then(Self::new) } /// Checked integer subtraction. Computes `self - rhs`, returning `None` if overflow /// occurred. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{int, Int}; /// assert_eq!( /// (Int::MIN + int!(2)).checked_sub(int!(1)), /// Some(Int::MIN + int!(1)) /// ); /// assert_eq!((Int::MIN + int!(2)).checked_sub(int!(3)), None); /// ``` #[must_use] pub fn checked_sub(self, rhs: Self) -> Option { self.0.checked_sub(rhs.0).and_then(Self::new) } /// Checked integer multiplication. Computes `self * rhs`, returning `None` if overflow /// occurred. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{int, Int}; /// assert_eq!(int!(5).checked_mul(int!(1)), Some(int!(5))); /// assert_eq!(Int::MAX.checked_mul(int!(2)), None); /// ``` #[must_use] pub fn checked_mul(self, rhs: Self) -> Option { self.0.checked_mul(rhs.0).and_then(Self::new) } /// Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{int, Int}; /// assert_eq!(Int::MIN.checked_div(int!(-1)), Some(Int::MAX)); /// assert_eq!(int!(1).checked_div(int!(0)), None); /// ``` #[must_use] pub fn checked_div(self, rhs: Self) -> Option { self.0.checked_div(rhs.0).map(Self) } /// Checked integer remainder. Computes `self % rhs`, returning `None` if `rhs == 0`. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{int, Int}; /// assert_eq!(int!(5).checked_rem(int!(2)), Some(int!(1))); /// assert_eq!(int!(5).checked_rem(int!(0)), None); /// assert_eq!(Int::MIN.checked_rem(int!(-1)), Some(int!(0))); /// ``` #[must_use] pub fn checked_rem(self, rhs: Self) -> Option { self.0.checked_rem(rhs.0).map(Self) } /// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if overflow or /// underflow occurred. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{int, Int}; /// assert_eq!(int!(8).checked_pow(2), Some(int!(64))); /// assert_eq!(Int::MAX.checked_pow(2), None); /// assert_eq!(Int::MIN.checked_pow(2), None); /// assert_eq!(int!(1_000_000_000).checked_pow(2), None); /// ``` #[must_use] pub fn checked_pow(self, exp: u32) -> Option { self.0.checked_pow(exp).and_then(Self::new) } /// Saturating integer addition. Computes `self + rhs`, saturating at the numeric bounds /// instead of overflowing. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{int, Int}; /// assert_eq!(int!(100).saturating_add(int!(1)), int!(101)); /// assert_eq!(Int::MAX.saturating_add(int!(1)), Int::MAX); /// assert_eq!(Int::MIN.saturating_add(int!(-1)), Int::MIN); /// ``` #[must_use] pub fn saturating_add(self, rhs: Self) -> Self { self.checked_add(rhs).unwrap_or_else(|| if self > int!(0) { Self::MAX } else { Self::MIN }) } /// Saturating integer subtraction. Computes `self - rhs`, saturating at the numeric /// bounds instead of underflowing. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{int, Int}; /// assert_eq!(int!(100).saturating_sub(int!(1)), int!(99)); /// assert_eq!(Int::MIN.saturating_sub(int!(1)), Int::MIN); /// assert_eq!(Int::MAX.saturating_sub(int!(-1)), Int::MAX); /// ``` #[must_use] pub fn saturating_sub(self, rhs: Self) -> Self { self.checked_sub(rhs).unwrap_or_else(|| if self > int!(0) { Self::MAX } else { Self::MIN }) } /// Saturating integer multiplication. Computes `self * rhs`, saturating at the numeric /// bounds instead of overflowing. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{int, Int}; /// assert_eq!(int!(100).saturating_mul(int!(2)), int!(200)); /// assert_eq!(Int::MAX.saturating_mul(int!(2)), Int::MAX); /// assert_eq!(Int::MAX.saturating_mul(Int::MAX), Int::MAX); /// assert_eq!(Int::MAX.saturating_mul(Int::MIN), Int::MIN); /// ``` #[must_use] pub fn saturating_mul(self, rhs: Self) -> Self { Self::new_saturating(self.0.saturating_mul(rhs.0)) } /// Saturating integer exponentiation. Computes `self.pow(exp)`, saturating at the /// numeric bounds instead of overflowing or underflowing. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{int, Int}; /// assert_eq!(int!(5).saturating_pow(2), int!(25)); /// assert_eq!(int!(-2).saturating_pow(3), int!(-8)); /// assert_eq!(Int::MAX.saturating_pow(2), Int::MAX); /// assert_eq!(Int::MIN.saturating_pow(2), Int::MAX); /// ``` #[must_use] pub fn saturating_pow(self, exp: u32) -> Self { Self::new_saturating(self.0.saturating_pow(exp)) } // TODO: wrapping_* methods, overflowing_* methods } fmt_impls!(Int); convert_impls!(Int, i8, i16, i32, i64, i128, isize, u8, u16, u32, usize); impl From for Int { fn from(val: u8) -> Self { Self(i64::from(val)) } } impl From for Int { fn from(val: u16) -> Self { Self(i64::from(val)) } } impl From for Int { fn from(val: u32) -> Self { Self(i64::from(val)) } } impl From for Int { fn from(val: UInt) -> Self { Self(i64::from(val)) } } impl TryFrom for Int { type Error = TryFromIntError; fn try_from(val: u64) -> Result { if val <= MAX_SAFE_UINT { Ok(Self(val as i64)) } else { Err(TryFromIntError::new()) } } } impl TryFrom for Int { type Error = TryFromIntError; fn try_from(val: u128) -> Result { if val <= u128::from(MAX_SAFE_UINT) { Ok(Self(val as i64)) } else { Err(TryFromIntError::new()) } } } macro_rules! int_op_impl { ($trait:ident, $method:ident, $assign_trait:ident, $assign_method:ident) => { impl $trait for Int { type Output = Self; fn $method(self, rhs: Self) -> Self { Self::new_(::$method(self.0, rhs.0)) } } impl $assign_trait for Int { fn $assign_method(&mut self, other: Self) { self.assign_(::$method(self.0, other.0)); } } }; } int_op_impl!(Add, add, AddAssign, add_assign); int_op_impl!(Sub, sub, SubAssign, sub_assign); int_op_impl!(Mul, mul, MulAssign, mul_assign); int_op_impl!(Div, div, DivAssign, div_assign); int_op_impl!(Rem, rem, RemAssign, rem_assign); impl Neg for Int { type Output = Self; fn neg(self) -> Self { Self(-self.0) } } impl iter::Sum for Int { fn sum(iter: I) -> Self where I: Iterator, { Self::new_(iter.map(|x| x.0).sum()) } } impl<'a> iter::Sum<&'a Int> for Int { fn sum(iter: I) -> Self where I: Iterator, { Self::new_(iter.map(|x| x.0).sum()) } } impl iter::Product for Int { fn product(iter: I) -> Self where I: Iterator, { Self::new_(iter.map(|x| x.0).product()) } } impl<'a> iter::Product<&'a Int> for Int { fn product(iter: I) -> Self where I: Iterator, { Self::new_(iter.map(|x| x.0).product()) } } impl FromStr for Int { type Err = ParseIntError; fn from_str(src: &str) -> Result { let val = i64::from_str(src)?; if val < MIN_SAFE_INT { Err(ParseIntError { kind: ParseIntErrorKind::Underflow }) } else if val > MAX_SAFE_INT { Err(ParseIntError { kind: ParseIntErrorKind::Overflow }) } else { Ok(Self(val)) } } } #[cfg(feature = "serde")] impl<'de> Deserialize<'de> for Int { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { #[cfg(not(feature = "float_deserialize"))] { let val = i64::deserialize(deserializer)?; Self::new(val).ok_or_else(|| { D::Error::invalid_value( Unexpected::Signed(val), &"an integer between -2^53 + 1 and 2^53 - 1", ) }) } #[cfg(feature = "float_deserialize")] { #[cfg(not(feature = "lax_deserialize"))] const EXPECTING: &str = "a number between -2^53 + 1 and 2^53 - 1 without fractional component"; #[cfg(feature = "lax_deserialize")] const EXPECTING: &str = "a number between -2^53 + 1 and 2^53 - 1"; let val = f64::deserialize(deserializer)?; if val > MAX_SAFE_INT as f64 || val < MIN_SAFE_INT as f64 || !super::is_acceptable_float(val) { Err(D::Error::invalid_value(Unexpected::Float(val), &EXPECTING)) } else { Ok(Self(val as i64)) } } } } #[cfg(test)] mod tests { use super::Int; #[test] fn int_ops() { assert_eq!(int!(5) + int!(3), int!(8)); assert_eq!(int!(1) - int!(2), int!(-1)); assert_eq!(int!(4) * int!(-7), int!(-28)); assert_eq!(int!(5) / int!(2), int!(2)); assert_eq!(int!(9) % int!(3), int!(0)); } #[test] fn int_assign_ops() { let mut int = int!(1); int += int!(1); assert_eq!(int, int!(2)); int -= int!(-1); assert_eq!(int, int!(3)); int *= int!(3); assert_eq!(int, int!(9)); int /= int!(3); assert_eq!(int, int!(3)); int %= int!(2); assert_eq!(int, int!(1)); } #[test] #[should_panic] fn int_underflow_panic() { let _ = Int::MIN - int!(1); } #[test] #[should_panic] fn int_overflow_panic() { let _ = Int::MAX + int!(1); } #[test] fn try_from_int_for_u_n() { use core::convert::TryFrom; let u8_max = u8::MAX as i64; let u16_max = u16::MAX as i64; let u32_max = u32::MAX as i64; assert_eq!(u8::try_from(Int(0)), Ok(0)); assert_eq!(u8::try_from(Int(10)), Ok(10)); assert_eq!(u8::try_from(Int(u8_max)), Ok(u8::MAX)); assert!(u8::try_from(Int(u8_max + 1)).is_err()); assert!(u8::try_from(Int(-1)).is_err()); assert!(u8::try_from(Int(-10)).is_err()); assert_eq!(u16::try_from(Int(0)), Ok(0)); assert_eq!(u16::try_from(Int(1000)), Ok(1000)); assert_eq!(u16::try_from(Int(u8_max + 1)), Ok((u8_max + 1) as u16)); assert_eq!(u16::try_from(Int(u16_max)), Ok(u16::MAX)); assert!(u16::try_from(Int(u16_max + 1)).is_err()); assert!(u16::try_from(Int(-1)).is_err()); assert!(u16::try_from(Int(-10)).is_err()); assert_eq!(u32::try_from(Int(0)), Ok(0)); assert_eq!(u32::try_from(Int(1000)), Ok(1000)); assert_eq!(u32::try_from(Int(u16_max + 1)), Ok((u16_max + 1) as u32)); assert_eq!(u32::try_from(Int(u32_max)), Ok(u32::MAX)); assert!(u32::try_from(Int(u32_max + 1)).is_err()); assert!(u32::try_from(Int(-1)).is_err()); assert!(u32::try_from(Int(-10)).is_err()); } } js_int-0.2.2/src/lib.rs000064400000000000000000000054710072674642500130550ustar 00000000000000//! Crate `js_int` provides JavaScript-interoperable integer types. //! //! JavaScript does not have native integers. Instead it represents all numeric values with a //! single `Number` type which is represented as an [IEEE 754 //! floating-point](https://en.wikipedia.org/wiki/IEEE_754) value.\* Rust's `i64` and `u64` types //! can contain values outside the range of what can be represented in a JavaScript `Number`. //! //! This crate provides the types `Int` and `UInt` which wrap `i64` and `u64`, respectively. These //! types add bounds checking to ensure the contained value is within the range representable by a //! JavaScript `Number`. They provide useful trait implementations to easily convert from Rust's //! primitive integer types. //! //! * In the upcoming ECMAScript 2020, JavaScript will probably gain support for integers. //! There is a proposal for a [`BigInt`][mdn] type type that is not far from becoming part of the //! JavaScript specification. It won't make this crate obsolete in any way though, since there will //! still be lots of JS code using `Number`, and code in other languages that assumes its use. //! //! //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt //! //! # `#![no_std]` //! //! The `js_int` crate does not use Rust's standard library, and is compatible with `#![no_std]` //! programs. //! //! # Features //! //! * `serde`: Serialization and deserialization support via [serde](https://serde.rs). Disabled by //! default. You can use `js_int` + `serde` in `#![no_std]` contexts if you use //! `default-features = false` for both. //! * `float_deserialize`: Deserialize via `f64`, not via `u64`. If the input has a fraction, //! deserialization will fail. //! * `lax_deserialize`: Like `float_deserialize`, but if the input has a fraction, it is //! deserialized with the fractional part discarded. //! Please be aware that `serde_json` doesn't losslessly parse large floats with a fractional part //! by default (even if the fractional part is `.0`). To fix that, enable its `float_roundtrip` //! feature. //! * `std`: Enable `std::error::Error` implementations for `ParseIntError`, `TryFromIntError`. //! Enabled by default. #![deny(missing_debug_implementations, missing_docs)] #![allow(clippy::cast_lossless)] // Not useful in this crate #![cfg_attr(not(feature = "std"), no_std)] #[macro_use] mod macros; mod error; mod int; mod uint; pub use self::{ error::{ParseIntError, TryFromIntError}, int::{Int, MAX_SAFE_INT, MIN_SAFE_INT}, uint::{UInt, MAX_SAFE_UINT}, }; #[cfg(feature = "float_deserialize")] #[inline(always)] pub(crate) fn is_acceptable_float(float: f64) -> bool { #[cfg(not(feature = "lax_deserialize"))] { if float.fract() != 0.0 { return false; } } !float.is_nan() } js_int-0.2.2/src/macros.rs000064400000000000000000000126050072674642500135700ustar 00000000000000/// Creates an `Int` from a numeric literal. #[macro_export] macro_rules! int { ($n:literal) => { <$crate::Int as ::core::convert::From>::from($n) }; } /// Creates a `UInt` from a numeric literal. #[macro_export] macro_rules! uint { ($n:literal) => { <$crate::UInt as ::core::convert::From>::from($n) }; } macro_rules! fmt_impls { ($type:ident) => { impl ::core::fmt::Display for $type { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{}", self.0) } } impl ::core::fmt::Debug for $type { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "{:?}", self.0) } } }; } macro_rules! convert_impls { ( $type:ident, $t8:ident, $t16:ident, $t32:ident, $t64:ident, $t128:ident, $tsize:ident, $ot8:ident, $ot16:ident, $ot32:ident, $otsize:ident ) => { impl ::core::convert::From<$t8> for $type { fn from(val: $t8) -> Self { Self($t64::from(val)) } } impl ::core::convert::From<$t16> for $type { fn from(val: $t16) -> Self { Self($t64::from(val)) } } impl ::core::convert::From<$t32> for $type { fn from(val: $t32) -> Self { Self($t64::from(val)) } } impl ::core::convert::TryFrom<$t64> for $type { type Error = crate::error::TryFromIntError; fn try_from(val: $t64) -> Result { Self::new(val).ok_or_else(crate::error::TryFromIntError::new) } } impl ::core::convert::TryFrom<$t128> for $type { type Error = crate::error::TryFromIntError; fn try_from(val: $t128) -> Result { $t64::try_from(val) .map_err(|_| crate::error::TryFromIntError::new()) .and_then($type::try_from) } } impl ::core::convert::TryFrom<$tsize> for $type { type Error = crate::error::TryFromIntError; fn try_from(val: $tsize) -> Result { $t64::try_from(val) .map_err(|_| crate::error::TryFromIntError::new()) .and_then($type::try_from) } } impl ::core::convert::TryFrom<$otsize> for $type { type Error = crate::error::TryFromIntError; fn try_from(val: $otsize) -> Result { $t64::try_from(val) .map_err(|_| crate::error::TryFromIntError::new()) .and_then($type::try_from) } } impl ::core::convert::TryFrom<$type> for $t8 { type Error = ::core::num::TryFromIntError; fn try_from(val: $type) -> Result { Self::try_from(val.0) } } impl ::core::convert::TryFrom<$type> for $ot8 { type Error = ::core::num::TryFromIntError; fn try_from(val: $type) -> Result { Self::try_from(val.0) } } impl ::core::convert::TryFrom<$type> for $t16 { type Error = ::core::num::TryFromIntError; fn try_from(val: $type) -> Result { Self::try_from(val.0) } } impl ::core::convert::TryFrom<$type> for $ot16 { type Error = ::core::num::TryFromIntError; fn try_from(val: $type) -> Result { Self::try_from(val.0) } } impl ::core::convert::TryFrom<$type> for $t32 { type Error = ::core::num::TryFromIntError; fn try_from(val: $type) -> Result { Self::try_from(val.0) } } impl ::core::convert::TryFrom<$type> for $ot32 { type Error = ::core::num::TryFromIntError; fn try_from(val: $type) -> Result { Self::try_from(val.0) } } impl ::core::convert::From<$type> for $t64 { fn from(val: $type) -> Self { val.0 } } impl ::core::convert::From<$type> for $t128 { fn from(val: $type) -> Self { $t128::from(val.0) } } impl ::core::convert::TryFrom<$type> for $tsize { type Error = ::core::num::TryFromIntError; fn try_from(val: $type) -> Result { Self::try_from(val.0) } } impl ::core::convert::TryFrom<$type> for $otsize { type Error = ::core::num::TryFromIntError; fn try_from(val: $type) -> Result { Self::try_from(val.0) } } impl ::core::convert::From<$type> for f64 { fn from(val: $type) -> Self { val.0 as f64 } } }; } js_int-0.2.2/src/uint.rs000064400000000000000000000455530072674642500132730ustar 00000000000000use core::{ convert::TryFrom, iter, ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign}, str::FromStr, }; #[cfg(feature = "serde")] use serde::{ de::{Error as _, Unexpected}, Deserialize, Deserializer, Serialize, }; use crate::{ error::{ParseIntError, ParseIntErrorKind, TryFromIntError}, MAX_SAFE_INT, }; /// The same as `MAX_SAFE_INT`, but with `u64` as the type. pub const MAX_SAFE_UINT: u64 = 0x001F_FFFF_FFFF_FFFF; /// An integer limited to the range of non-negative integers that can be represented exactly by an /// f64. #[derive(Clone, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "serde", derive(Serialize))] pub struct UInt(u64); impl UInt { /// The smallest value that can be represented by this integer type. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{uint, UInt}; /// assert_eq!(UInt::MIN, uint!(0)); /// ``` pub const MIN: Self = Self(0); /// The largest value that can be represented by this integer type. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use {core::convert::TryFrom, js_int::UInt}; /// assert_eq!(UInt::MAX, UInt::try_from(9_007_199_254_740_991u64).unwrap()); /// ``` pub const MAX: Self = Self(MAX_SAFE_UINT); /// Try to create a `UInt` from the provided `u64`, returning `None` if it is larger than /// `MAX_SAFE_UINT`. /// /// This is the same as the `TryFrom` implementation for `UInt`, except that it returns /// an `Option` instead of a `Result`. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::UInt; /// assert_eq!(UInt::new(js_int::MAX_SAFE_UINT), Some(UInt::MAX)); /// assert_eq!(UInt::new(js_int::MAX_SAFE_UINT + 1), None); /// ``` #[must_use] pub fn new(val: u64) -> Option { if val <= MAX_SAFE_UINT { Some(Self(val)) } else { None } } /// Create a `UInt` from the provided `u64`, wrapping at `MAX_SAFE_UINT`. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{uint, UInt}; /// assert_eq!(UInt::new_wrapping(js_int::MAX_SAFE_UINT), UInt::MAX); /// assert_eq!(UInt::new_wrapping(js_int::MAX_SAFE_UINT + 1), uint!(0)); /// ``` #[must_use] pub fn new_wrapping(val: u64) -> Self { Self(val & MAX_SAFE_UINT) } /// Creates an `UInt` from the given `u64` capped at `MAX_SAFE_UINT`. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{uint, UInt}; /// assert_eq!(UInt::new_saturating(0), uint!(0)); /// assert_eq!(UInt::new_saturating(js_int::MAX_SAFE_UINT), UInt::MAX); /// assert_eq!(UInt::new_saturating(js_int::MAX_SAFE_UINT + 1), UInt::MAX); /// ``` #[must_use] pub fn new_saturating(val: u64) -> Self { if val <= MAX_SAFE_UINT { Self(val) } else { Self::MAX } } /// The constructor used for arithmetic operations #[must_use] fn new_(val: u64) -> Self { if cfg!(debug_assertions) { assert!(val <= MAX_SAFE_UINT); Self(val) } else { Self::new_wrapping(val) } } /// Helper function for mutable arithmetic operations (`+=`, `-=`, …) fn assign_(&mut self, val: u64) { if cfg!(debug_assertions) { assert!(val <= MAX_SAFE_UINT); *self = Self(val); } else { *self = Self::new_wrapping(val); } } /// Returns the smallest value that can be represented by this integer type. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{uint, UInt}; /// assert_eq!(UInt::min_value(), uint!(0)); /// ``` #[must_use] #[deprecated = "Use `UInt::MIN` instead."] pub const fn min_value() -> Self { Self(0) } /// Returns the largest value that can be represented by this integer type. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use {core::convert::TryFrom, js_int::UInt}; /// assert_eq!(UInt::max_value(), UInt::try_from(9_007_199_254_740_991u64).unwrap()); /// ``` #[must_use] #[deprecated = "Use `UInt::MAX` instead."] pub const fn max_value() -> Self { Self(MAX_SAFE_UINT) } /// Returns true if and only if `self == 2^k` for some `k`. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::uint; /// assert!(uint!(16).is_power_of_two()); /// assert!(!uint!(10).is_power_of_two()); /// ``` #[must_use] pub fn is_power_of_two(self) -> bool { self.0.is_power_of_two() } /// Returns the smallest power of two greater than or equal to `n`. If the next power of two is /// greater than the type's maximum value, `None` is returned, otherwise the power of two is /// wrapped in `Some`. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{uint, UInt}; /// assert_eq!(uint!(2).checked_next_power_of_two(), Some(uint!(2))); /// assert_eq!(uint!(3).checked_next_power_of_two(), Some(uint!(4))); /// assert_eq!(UInt::MAX.checked_next_power_of_two(), None); /// ``` #[must_use] pub fn checked_next_power_of_two(self) -> Option { self.0.checked_next_power_of_two().and_then(Self::new) } /// Converts a string slice in a given base to an integer. /// /// The string is expected to be an optional `+` sign followed by digits. Leading and trailing /// whitespace represent an error. Digits are a subset of these characters, depending on /// `radix`: /// /// * `0-9` /// * `a-z` /// * `A-Z` /// /// # Panics /// /// This function panics if `radix` is not in the range from 2 to 36. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{uint, UInt}; /// assert_eq!(UInt::from_str_radix("A", 16), Ok(uint!(10))); /// ``` pub fn from_str_radix(src: &str, radix: u32) -> Result { let val = u64::from_str_radix(src, radix)?; if val > MAX_SAFE_UINT { Err(ParseIntError { kind: ParseIntErrorKind::Overflow }) } else { Ok(Self(val)) } } /// Checked integer addition. Computes `self + rhs`, returning `None` if overflow occurred. /// /// ``` /// # use js_int::{uint, UInt}; /// assert_eq!( /// (UInt::MAX - uint!(2)).checked_add(uint!(1)), /// Some(UInt::MAX - uint!(1)) /// ); /// assert_eq!((UInt::MAX - uint!(2)).checked_add(uint!(3)), None); /// ``` #[must_use] pub fn checked_add(self, rhs: Self) -> Option { self.0.checked_add(rhs.0).and_then(Self::new) } /// Checked integer subtraction. Computes `self - rhs`, returning `None` if overflow occurred. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::uint; /// assert_eq!(uint!(1).checked_sub(uint!(1)), Some(uint!(0))); /// assert_eq!(uint!(0).checked_sub(uint!(1)), None); /// ``` #[must_use] pub fn checked_sub(self, rhs: Self) -> Option { self.0.checked_sub(rhs.0).and_then(Self::new) } /// Checked integer multiplication. Computes `self * rhs`, returning `None` if overflow /// occurred. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{uint, UInt}; /// assert_eq!(uint!(5).checked_mul(uint!(1)), Some(uint!(5))); /// assert_eq!(UInt::MAX.checked_mul(uint!(2)), None); /// ``` #[must_use] pub fn checked_mul(self, rhs: Self) -> Option { self.0.checked_mul(rhs.0).and_then(Self::new) } /// Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::uint; /// assert_eq!(uint!(128).checked_div(uint!(2)), Some(uint!(64))); /// assert_eq!(uint!(1).checked_div(uint!(0)), None); /// ``` #[must_use] pub fn checked_div(self, rhs: Self) -> Option { self.0.checked_div(rhs.0).map(Self) } /// Checked integer remainder. Computes `self % rhs`, returning `None` if `rhs == 0`. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::uint; /// assert_eq!(uint!(5).checked_rem(uint!(2)), Some(uint!(1))); /// assert_eq!(uint!(5).checked_rem(uint!(0)), None); /// ``` #[must_use] pub fn checked_rem(self, rhs: Self) -> Option { self.0.checked_rem(rhs.0).map(Self) } /// Checked negation. Computes `-self`, returning None unless `self == 0`. /// /// Note that negating any positive integer will overflow. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::uint; /// assert_eq!(uint!(0).checked_neg(), Some(uint!(0))); /// assert_eq!(uint!(1).checked_neg(), None); /// ``` #[must_use] pub fn checked_neg(self) -> Option { self.0.checked_neg().map(Self) } /// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if overflow or /// underflow occurred. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{uint, UInt}; /// assert_eq!(uint!(0).checked_pow(2), Some(uint!(0))); /// assert_eq!(uint!(8).checked_pow(2), Some(uint!(64))); /// assert_eq!(uint!(1_000_000_000u32).checked_pow(2), None); /// assert_eq!(UInt::MAX.checked_pow(2), None); /// ``` #[must_use] pub fn checked_pow(self, exp: u32) -> Option { self.0.checked_pow(exp).and_then(Self::new) } /// Saturating integer addition. Computes `self + rhs`, saturating at the numeric bounds /// instead of overflowing. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{uint, UInt}; /// assert_eq!(uint!(100).saturating_add(uint!(1)), uint!(101)); /// assert_eq!(UInt::MAX.saturating_add(uint!(1)), UInt::MAX); /// ``` #[must_use] pub fn saturating_add(self, rhs: Self) -> Self { self.checked_add(rhs).unwrap_or(Self::MAX) } /// Saturating integer subtraction. Computes `self - rhs`, saturating at the numeric /// bounds instead of underflowing. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::uint; /// assert_eq!(uint!(100).saturating_sub(uint!(1)), uint!(99)); /// assert_eq!(uint!(1).saturating_sub(uint!(2)), uint!(0)); /// ``` #[must_use] pub fn saturating_sub(self, rhs: Self) -> Self { self.checked_sub(rhs).unwrap_or(Self::MIN) } /// Saturating integer multiplication. Computes `self * rhs`, saturating at the numeric /// bounds instead of overflowing. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{uint, UInt}; /// assert_eq!(uint!(100).saturating_mul(uint!(2)), uint!(200)); /// assert_eq!(UInt::MAX.saturating_mul(uint!(2)), UInt::MAX); /// assert_eq!(UInt::MAX.saturating_mul(UInt::MAX), UInt::MAX); /// ``` #[must_use] pub fn saturating_mul(self, rhs: Self) -> Self { self.checked_mul(rhs).unwrap_or(Self::MAX) } /// Saturating integer exponentiation. Computes `self.pow(exp)`, saturating at the /// numeric bounds instead of overflowing or underflowing. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use js_int::{uint, UInt}; /// assert_eq!(uint!(5).saturating_pow(2), uint!(25)); /// assert_eq!(UInt::MAX.saturating_pow(2), UInt::MAX); /// ``` #[must_use] pub fn saturating_pow(self, exp: u32) -> Self { Self::new_saturating(self.0.saturating_pow(exp)) } // TODO: wrapping_* methods, overflowing_* methods } fmt_impls!(UInt); convert_impls!(UInt, u8, u16, u32, u64, u128, usize, i8, i16, i32, isize); impl TryFrom for UInt { type Error = TryFromIntError; fn try_from(val: i8) -> Result { if val >= 0 { Ok(Self(val as u64)) } else { Err(TryFromIntError::new()) } } } impl TryFrom for UInt { type Error = TryFromIntError; fn try_from(val: i16) -> Result { if val >= 0 { Ok(Self(val as u64)) } else { Err(TryFromIntError::new()) } } } impl TryFrom for UInt { type Error = TryFromIntError; fn try_from(val: i32) -> Result { if val >= 0 { Ok(Self(val as u64)) } else { Err(TryFromIntError::new()) } } } impl TryFrom for UInt { type Error = TryFromIntError; fn try_from(val: i64) -> Result { if (0..=MAX_SAFE_INT).contains(&val) { Ok(Self(val as u64)) } else { Err(TryFromIntError::new()) } } } impl TryFrom for UInt { type Error = TryFromIntError; fn try_from(val: i128) -> Result { if (0..=MAX_SAFE_INT.into()).contains(&val) { Ok(Self(val as u64)) } else { Err(TryFromIntError::new()) } } } impl From for i64 { fn from(val: UInt) -> Self { val.0 as i64 } } impl From for i128 { fn from(val: UInt) -> Self { val.0 as i128 } } macro_rules! uint_op_impl { ($trait:ident, $method:ident, $assign_trait:ident, $assign_method:ident) => { impl $trait for UInt { type Output = Self; fn $method(self, rhs: Self) -> Self { Self::new_(::$method(self.0, rhs.0)) } } impl $assign_trait for UInt { fn $assign_method(&mut self, other: Self) { self.assign_(::$method(self.0, other.0)); } } }; } uint_op_impl!(Add, add, AddAssign, add_assign); uint_op_impl!(Sub, sub, SubAssign, sub_assign); uint_op_impl!(Mul, mul, MulAssign, mul_assign); uint_op_impl!(Div, div, DivAssign, div_assign); uint_op_impl!(Rem, rem, RemAssign, rem_assign); impl iter::Sum for UInt { fn sum(iter: I) -> Self where I: Iterator, { Self::new_(iter.map(|x| x.0).sum()) } } impl<'a> iter::Sum<&'a UInt> for UInt { fn sum(iter: I) -> Self where I: Iterator, { Self::new_(iter.map(|x| x.0).sum()) } } impl iter::Product for UInt { fn product(iter: I) -> Self where I: Iterator, { Self::new_(iter.map(|x| x.0).product()) } } impl<'a> iter::Product<&'a UInt> for UInt { fn product(iter: I) -> Self where I: Iterator, { Self::new_(iter.map(|x| x.0).product()) } } impl FromStr for UInt { type Err = ParseIntError; fn from_str(src: &str) -> Result { let val = u64::from_str(src)?; if val > MAX_SAFE_UINT { Err(ParseIntError { kind: ParseIntErrorKind::Overflow }) } else { Ok(Self(val)) } } } #[cfg(feature = "serde")] impl<'de> Deserialize<'de> for UInt { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { #[cfg(not(feature = "float_deserialize"))] { let val = u64::deserialize(deserializer)?; Self::new(val).ok_or_else(|| { D::Error::invalid_value( Unexpected::Unsigned(val), &"an integer between 0 and 2^53 - 1", ) }) } #[cfg(feature = "float_deserialize")] { #[cfg(not(feature = "lax_deserialize"))] const EXPECTING: &str = "a number between 0 and 2^53 - 1 without fractional component"; #[cfg(feature = "lax_deserialize")] const EXPECTING: &str = "a number between 0 and 2^53 - 1"; let val = f64::deserialize(deserializer)?; if val < 0.0 || val > MAX_SAFE_UINT as f64 || !super::is_acceptable_float(val) { Err(D::Error::invalid_value(Unexpected::Float(val), &EXPECTING)) } else { Ok(Self(val as u64)) } } } } #[cfg(test)] mod tests { use super::{UInt, MAX_SAFE_UINT}; #[test] fn uint_ops() { assert_eq!(uint!(5) + uint!(3), uint!(8)); assert_eq!(uint!(2) - uint!(1), uint!(1)); assert_eq!(uint!(4) * uint!(2), uint!(8)); assert_eq!(uint!(5) / uint!(2), uint!(2)); assert_eq!(uint!(11) % uint!(4), uint!(3)); } #[test] fn uint_assign_ops() { let mut uint = uint!(1); uint += uint!(3); assert_eq!(uint, uint!(4)); uint -= uint!(1); assert_eq!(uint, uint!(3)); uint *= uint!(3); assert_eq!(uint, uint!(9)); uint /= uint!(3); assert_eq!(uint, uint!(3)); uint %= uint!(2); assert_eq!(uint, uint!(1)); } #[test] fn uint_wrapping_new() { assert_eq!(UInt::new_wrapping(MAX_SAFE_UINT + 1), uint!(0)); } #[test] #[cfg_attr(debug_assertions, ignore)] fn uint_underflow_wrap() { assert_eq!(uint!(0) - uint!(1), UInt::MAX); } #[test] #[cfg_attr(debug_assertions, ignore)] fn uint_overflow_wrap() { assert_eq!(UInt::MAX + uint!(1), uint!(0)); assert_eq!(UInt::MAX + uint!(5), uint!(4)); } #[test] #[should_panic] #[cfg_attr(not(debug_assertions), ignore)] fn uint_underflow_panic() { let _ = uint!(0) - uint!(1); } #[test] #[should_panic] #[cfg_attr(not(debug_assertions), ignore)] fn uint_overflow_panic() { let _ = UInt::MAX + uint!(1); } #[test] fn try_from_uint_for_i_n() { use core::convert::TryFrom; let i8_max = i8::MAX as u64; let i16_max = i16::MAX as u64; let i32_max = i32::MAX as u64; assert_eq!(i8::try_from(UInt(0)), Ok(0)); assert_eq!(i8::try_from(UInt(10)), Ok(10)); assert_eq!(i8::try_from(UInt(i8_max)), Ok(i8::MAX)); assert!(i8::try_from(UInt(i8_max + 1)).is_err()); assert_eq!(i16::try_from(UInt(0)), Ok(0)); assert_eq!(i16::try_from(UInt(10)), Ok(10)); assert_eq!(i16::try_from(UInt(i8_max + 1)), Ok((i8::MAX as i16) + 1)); assert_eq!(i16::try_from(UInt(i16_max)), Ok(i16::MAX)); assert!(i16::try_from(UInt(i16_max + 1)).is_err()); assert_eq!(i32::try_from(UInt(0)), Ok(0)); assert_eq!(i32::try_from(UInt(10)), Ok(10)); assert_eq!(i32::try_from(UInt(i16_max + 1)), Ok((i16::MAX as i32) + 1)); assert_eq!(i32::try_from(UInt(i32_max)), Ok(i32::MAX)); assert!(i32::try_from(UInt(i32_max + 1)).is_err()); } } js_int-0.2.2/tests/int.rs000064400000000000000000000053440072674642500134530ustar 00000000000000#![cfg(feature = "serde")] use core::convert::TryFrom; use js_int::{int, Int}; use serde::{de::IntoDeserializer, Deserialize}; use serde_test::{assert_ser_tokens, Token}; #[test] fn serialize() { assert_serialize(100); assert_serialize(0); assert_serialize(-100); } fn assert_serialize(number: i32) { assert_ser_tokens( &Int::from(number), &[Token::NewtypeStruct { name: "Int" }, Token::I64(number as _)], ) } #[test] fn deserialize() { assert_eq!(deserialize_from(100).unwrap(), int!(100)); assert_eq!(deserialize_from(0).unwrap(), int!(0)); assert_eq!(deserialize_from(-100).unwrap(), int!(-100)); assert_eq!(deserialize_from(-9007199254740991i64).unwrap(), Int::MIN); assert_eq!(deserialize_from(9007199254740991i64).unwrap(), Int::MAX); assert!(deserialize_from(9007199254740992i64).is_err()); assert!(deserialize_from(-9007199254740992i64).is_err()); } #[test] #[cfg_attr(feature = "float_deserialize", ignore)] fn dont_deserialize_integral_float() { assert!(deserialize_from(-10.0).is_err()); assert!(deserialize_from(-0.0).is_err()); assert!(deserialize_from(1.0).is_err()); assert!(deserialize_from(9007199254740991.0).is_err()); assert!(deserialize_from(9007199254740992.0).is_err()); } #[test] #[cfg_attr(feature = "lax_deserialize", ignore)] fn dont_deserialize_fractional_float() { assert!(deserialize_from(0.5).is_err()); assert!(deserialize_from(42.1337).is_err()); assert!(deserialize_from(-42.1337).is_err()); } #[test] #[cfg_attr(not(feature = "float_deserialize"), ignore)] fn deserialize_integral_float() { assert_eq!(deserialize_from(-10.0).unwrap(), int!(-10)); assert_eq!(deserialize_from(-0.0).unwrap(), int!(0)); assert_eq!(deserialize_from(1.0).unwrap(), int!(1)); assert_eq!(deserialize_from(9007199254740991.0).unwrap(), Int::MAX); assert!(deserialize_from(9007199254740992.0).is_err()); // NOTE: This still ends up as integral because the .49 exceeds the representable range of f64 assert_eq!( deserialize_from(9007199254740991.49).unwrap(), Int::try_from(9007199254740991i64).unwrap() ); assert!(deserialize_from(f64::NAN).is_err()); assert!(deserialize_from(f64::INFINITY).is_err()); assert!(deserialize_from(f64::NEG_INFINITY).is_err()); } #[test] #[cfg_attr(not(feature = "lax_deserialize"), ignore)] fn deserialize_fractional_float() { assert_eq!(deserialize_from(0.5).unwrap(), int!(0)); assert_eq!(deserialize_from(42.1337).unwrap(), int!(42)); assert_eq!(deserialize_from(-42.1337).unwrap(), int!(-42)); } fn deserialize_from<'de, Value: IntoDeserializer<'de>>( value: Value, ) -> Result { Int::deserialize(value.into_deserializer()) } js_int-0.2.2/tests/uint.rs000064400000000000000000000043120072674642500136320ustar 00000000000000#![cfg(feature = "serde")] use core::convert::TryFrom; use js_int::{uint, UInt}; use serde::{de::IntoDeserializer, Deserialize}; use serde_test::{assert_ser_tokens, Token}; #[test] fn serialize() { assert_serialize(100); assert_serialize(0); } fn assert_serialize(number: u32) { assert_ser_tokens( &UInt::from(number), &[Token::NewtypeStruct { name: "UInt" }, Token::U64(number as _)], ) } #[test] fn deserialize() { assert_eq!(deserialize_from(100).unwrap(), uint!(100)); assert_eq!(deserialize_from(0).unwrap(), uint!(0)); assert_eq!(deserialize_from(9007199254740991i64).unwrap(), UInt::MAX); assert!(deserialize_from(9007199254740992i64).is_err()); } #[test] #[cfg_attr(feature = "float_deserialize", ignore)] fn dont_deserialize_integral_float() { assert!(deserialize_from(1.0).is_err()); assert!(deserialize_from(9007199254740991.0).is_err()); assert!(deserialize_from(9007199254740992.0).is_err()); } #[test] #[cfg_attr(feature = "lax_deserialize", ignore)] fn dont_deserialize_fractional_float() { assert!(deserialize_from(0.5).is_err()); assert!(deserialize_from(42.1337).is_err()); } #[test] #[cfg_attr(not(feature = "float_deserialize"), ignore)] fn deserialize_integral_float() { assert_eq!(deserialize_from(1.0).unwrap(), uint!(1)); assert_eq!(deserialize_from(9007199254740991.0).unwrap(), UInt::MAX); assert!(deserialize_from(9007199254740992.0).is_err()); // NOTE: This still ends up as integral because the .49 exceeds the representable range of f64 assert_eq!( deserialize_from(9007199254740991.49).unwrap(), UInt::try_from(9007199254740991i64).unwrap() ); assert!(deserialize_from(f64::NAN).is_err()); assert!(deserialize_from(f64::INFINITY).is_err()); assert!(deserialize_from(f64::NEG_INFINITY).is_err()); } #[test] #[cfg_attr(not(feature = "lax_deserialize"), ignore)] fn deserialize_fractional_float() { assert_eq!(deserialize_from(0.5).unwrap(), uint!(0)); assert_eq!(deserialize_from(42.1337).unwrap(), uint!(42)); } fn deserialize_from<'de, Value: IntoDeserializer<'de>>( value: Value, ) -> Result { UInt::deserialize(value.into_deserializer()) }