diff --git a/Cargo.toml b/Cargo.toml index aa2feff..60c5487 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,3 @@ features = ["derive"] lax_deserialize = ["serde"] default = ["std"] std = [] - -[workspace] -members = ["ext_tests"] diff --git a/expanded.rs b/expanded.rs new file mode 100644 index 0000000..302a7a9 --- /dev/null +++ b/expanded.rs @@ -0,0 +1,1902 @@ +#![feature(prelude_import)] +//! 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. +//! * `lax_deserialize`: Deserialize via `f64`, not via `u64`. If the input has a fraction, it is +//! 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)] +#[prelude_import] +use std::prelude::rust_2018::*; +#[macro_use] +extern crate std; +#[macro_use] +mod macros {} +mod error { + use core::{ + fmt::{self, Debug, Display, Formatter}, + num::ParseIntError as StdParseIntError, + }; + /// The error type returned when when parsing an integer fails. + pub struct ParseIntError { + pub(crate) kind: ParseIntErrorKind, + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::fmt::Debug for ParseIntError { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match *self { + ParseIntError { + kind: ref __self_0_0, + } => { + let debug_trait_builder = + &mut ::core::fmt::Formatter::debug_struct(f, "ParseIntError"); + let _ = ::core::fmt::DebugStruct::field( + debug_trait_builder, + "kind", + &&(*__self_0_0), + ); + ::core::fmt::DebugStruct::finish(debug_trait_builder) + } + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for ParseIntError { + #[inline] + fn clone(&self) -> ParseIntError { + match *self { + ParseIntError { + kind: ref __self_0_0, + } => ParseIntError { + kind: ::core::clone::Clone::clone(&(*__self_0_0)), + }, + } + } + } + impl ::core::marker::StructuralPartialEq for ParseIntError {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for ParseIntError { + #[inline] + fn eq(&self, other: &ParseIntError) -> bool { + match *other { + ParseIntError { + kind: ref __self_1_0, + } => match *self { + ParseIntError { + kind: ref __self_0_0, + } => (*__self_0_0) == (*__self_1_0), + }, + } + } + #[inline] + fn ne(&self, other: &ParseIntError) -> bool { + match *other { + ParseIntError { + kind: ref __self_1_0, + } => match *self { + ParseIntError { + kind: ref __self_0_0, + } => (*__self_0_0) != (*__self_1_0), + }, + } + } + } + impl ::core::marker::StructuralEq for ParseIntError {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for ParseIntError { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + } + } + } + pub(crate) enum ParseIntErrorKind { + Overflow, + Underflow, + Unknown(StdParseIntError), + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::fmt::Debug for ParseIntErrorKind { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match (&*self,) { + (&ParseIntErrorKind::Overflow,) => ::core::fmt::Formatter::write_str(f, "Overflow"), + (&ParseIntErrorKind::Underflow,) => { + ::core::fmt::Formatter::write_str(f, "Underflow") + } + (&ParseIntErrorKind::Unknown(ref __self_0),) => { + let debug_trait_builder = + &mut ::core::fmt::Formatter::debug_tuple(f, "Unknown"); + let _ = ::core::fmt::DebugTuple::field(debug_trait_builder, &&(*__self_0)); + ::core::fmt::DebugTuple::finish(debug_trait_builder) + } + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for ParseIntErrorKind { + #[inline] + fn clone(&self) -> ParseIntErrorKind { + match (&*self,) { + (&ParseIntErrorKind::Overflow,) => ParseIntErrorKind::Overflow, + (&ParseIntErrorKind::Underflow,) => ParseIntErrorKind::Underflow, + (&ParseIntErrorKind::Unknown(ref __self_0),) => { + ParseIntErrorKind::Unknown(::core::clone::Clone::clone(&(*__self_0))) + } + } + } + } + impl ::core::marker::StructuralPartialEq for ParseIntErrorKind {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for ParseIntErrorKind { + #[inline] + fn eq(&self, other: &ParseIntErrorKind) -> bool { + { + let __self_vi = ::core::intrinsics::discriminant_value(&*self); + let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other); + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + ( + &ParseIntErrorKind::Unknown(ref __self_0), + &ParseIntErrorKind::Unknown(ref __arg_1_0), + ) => (*__self_0) == (*__arg_1_0), + _ => true, + } + } else { + false + } + } + } + #[inline] + fn ne(&self, other: &ParseIntErrorKind) -> bool { + { + let __self_vi = ::core::intrinsics::discriminant_value(&*self); + let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other); + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + ( + &ParseIntErrorKind::Unknown(ref __self_0), + &ParseIntErrorKind::Unknown(ref __arg_1_0), + ) => (*__self_0) != (*__arg_1_0), + _ => false, + } + } else { + true + } + } + } + } + impl ::core::marker::StructuralEq for ParseIntErrorKind {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for ParseIntErrorKind { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + } + } + } + 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) => f.write_fmt(::core::fmt::Arguments::new_v1( + &[""], + &match (&e,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )), + } + } + } + #[cfg(feature = "std")] + impl std::error::Error for ParseIntError {} + /// The error type returned when a checked integral type conversion fails. + pub struct TryFromIntError { + _private: (), + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for TryFromIntError { + #[inline] + fn clone(&self) -> TryFromIntError { + match *self { + TryFromIntError { + _private: ref __self_0_0, + } => TryFromIntError { + _private: ::core::clone::Clone::clone(&(*__self_0_0)), + }, + } + } + } + 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 {} +} +mod int { + use 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. + pub struct Int(i64); + #[doc(hidden)] + #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] + const _: () = { + #[allow(unused_extern_crates, clippy::useless_attribute)] + extern crate serde as _serde; + #[automatically_derived] + impl _serde::Serialize for Int { + fn serialize<__S>( + &self, + __serializer: __S, + ) -> _serde::__private::Result<__S::Ok, __S::Error> + where + __S: _serde::Serializer, + { + _serde::Serializer::serialize_newtype_struct(__serializer, "Int", &self.0) + } + } + }; + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for Int { + #[inline] + fn clone(&self) -> Int { + { + let _: ::core::clone::AssertParamIsClone; + *self + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::marker::Copy for Int {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::default::Default for Int { + #[inline] + fn default() -> Int { + Int(::core::default::Default::default()) + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::hash::Hash for Int { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + match *self { + Int(ref __self_0_0) => ::core::hash::Hash::hash(&(*__self_0_0), state), + } + } + } + impl ::core::marker::StructuralPartialEq for Int {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for Int { + #[inline] + fn eq(&self, other: &Int) -> bool { + match *other { + Int(ref __self_1_0) => match *self { + Int(ref __self_0_0) => (*__self_0_0) == (*__self_1_0), + }, + } + } + #[inline] + fn ne(&self, other: &Int) -> bool { + match *other { + Int(ref __self_1_0) => match *self { + Int(ref __self_0_0) => (*__self_0_0) != (*__self_1_0), + }, + } + } + } + impl ::core::marker::StructuralEq for Int {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for Int { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialOrd for Int { + #[inline] + fn partial_cmp(&self, other: &Int) -> ::core::option::Option<::core::cmp::Ordering> { + match *other { + Int(ref __self_1_0) => match *self { + Int(ref __self_0_0) => { + match ::core::cmp::PartialOrd::partial_cmp(&(*__self_0_0), &(*__self_1_0)) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) => { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + } + cmp => cmp, + } + } + }, + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Ord for Int { + #[inline] + fn cmp(&self, other: &Int) -> ::core::cmp::Ordering { + match *other { + Int(ref __self_1_0) => match *self { + Int(ref __self_0_0) => { + match ::core::cmp::Ord::cmp(&(*__self_0_0), &(*__self_1_0)) { + ::core::cmp::Ordering::Equal => ::core::cmp::Ordering::Equal, + cmp => cmp, + } + } + }, + } + } + } + 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 { + if !(val >= MIN_SAFE_INT) { + ::core::panicking::panic("assertion failed: val >= MIN_SAFE_INT") + }; + if !(val <= MAX_SAFE_INT) { + ::core::panicking::panic("assertion failed: val <= MAX_SAFE_INT") + }; + Self(val) + } + /// Helper function for mutable arithmetic operations (`+=`, `-=`, …) + fn assign_(&mut self, val: i64) { + if !(val >= MIN_SAFE_INT) { + ::core::panicking::panic("assertion failed: val >= MIN_SAFE_INT") + }; + if !(val <= MAX_SAFE_INT) { + ::core::panicking::panic("assertion failed: 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 > >::from(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 > >::from(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)) + } + } + impl ::core::fmt::Display for Int { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + f.write_fmt(::core::fmt::Arguments::new_v1( + &[""], + &match (&self.0,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )) + } + } + impl ::core::fmt::Debug for Int { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + f.write_fmt(::core::fmt::Arguments::new_v1( + &[""], + &match (&self.0,) { + (arg0,) => [::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Debug::fmt)], + }, + )) + } + } + impl ::core::convert::From for Int { + fn from(val: i8) -> Self { + Self(i64::from(val)) + } + } + impl ::core::convert::From for Int { + fn from(val: i16) -> Self { + Self(i64::from(val)) + } + } + impl ::core::convert::From for Int { + fn from(val: i32) -> Self { + Self(i64::from(val)) + } + } + impl ::core::convert::TryFrom for Int { + type Error = crate::error::TryFromIntError; + fn try_from(val: i64) -> Result { + Self::new(val).ok_or_else(crate::error::TryFromIntError::new) + } + } + impl ::core::convert::TryFrom for Int { + type Error = crate::error::TryFromIntError; + fn try_from(val: i128) -> Result { + i64::try_from(val) + .map_err(|_| crate::error::TryFromIntError::new()) + .and_then(Int::try_from) + } + } + impl ::core::convert::TryFrom for i8 { + type Error = ::core::num::TryFromIntError; + fn try_from(val: Int) -> Result { + Self::try_from(val.0) + } + } + impl ::core::convert::TryFrom for u8 { + type Error = ::core::num::TryFromIntError; + fn try_from(val: Int) -> Result { + Self::try_from(val.0) + } + } + impl ::core::convert::TryFrom for i16 { + type Error = ::core::num::TryFromIntError; + fn try_from(val: Int) -> Result { + Self::try_from(val.0) + } + } + impl ::core::convert::TryFrom for u16 { + type Error = ::core::num::TryFromIntError; + fn try_from(val: Int) -> Result { + Self::try_from(val.0) + } + } + impl ::core::convert::TryFrom for i32 { + type Error = ::core::num::TryFromIntError; + fn try_from(val: Int) -> Result { + Self::try_from(val.0) + } + } + impl ::core::convert::TryFrom for u32 { + type Error = ::core::num::TryFromIntError; + fn try_from(val: Int) -> Result { + Self::try_from(val.0) + } + } + impl ::core::convert::From for i64 { + fn from(val: Int) -> Self { + val.0 + } + } + impl ::core::convert::From for i128 { + fn from(val: Int) -> Self { + i128::from(val.0) + } + } + impl ::core::convert::From for f64 { + fn from(val: Int) -> Self { + val.0 as f64 + } + } + 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()) + } + } + } + impl Add for Int { + type Output = Self; + fn add(self, rhs: Self) -> Self { + Self::new_(::add(self.0, rhs.0)) + } + } + impl AddAssign for Int { + fn add_assign(&mut self, other: Self) { + self.assign_(::add(self.0, other.0)); + } + } + impl Sub for Int { + type Output = Self; + fn sub(self, rhs: Self) -> Self { + Self::new_(::sub(self.0, rhs.0)) + } + } + impl SubAssign for Int { + fn sub_assign(&mut self, other: Self) { + self.assign_(::sub(self.0, other.0)); + } + } + impl Mul for Int { + type Output = Self; + fn mul(self, rhs: Self) -> Self { + Self::new_(::mul(self.0, rhs.0)) + } + } + impl MulAssign for Int { + fn mul_assign(&mut self, other: Self) { + self.assign_(::mul(self.0, other.0)); + } + } + impl Div for Int { + type Output = Self; + fn div(self, rhs: Self) -> Self { + Self::new_(::div(self.0, rhs.0)) + } + } + impl DivAssign for Int { + fn div_assign(&mut self, other: Self) { + self.assign_(::div(self.0, other.0)); + } + } + impl Rem for Int { + type Output = Self; + fn rem(self, rhs: Self) -> Self { + Self::new_(::rem(self.0, rhs.0)) + } + } + impl RemAssign for Int { + fn rem_assign(&mut self, other: Self) { + self.assign_(::rem(self.0, other.0)); + } + } + 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 = "lax_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", + ) + }) + } + } + } +} +mod uint { + use 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. + pub struct UInt(u64); + #[doc(hidden)] + #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] + const _: () = { + #[allow(unused_extern_crates, clippy::useless_attribute)] + extern crate serde as _serde; + #[automatically_derived] + impl _serde::Serialize for UInt { + fn serialize<__S>( + &self, + __serializer: __S, + ) -> _serde::__private::Result<__S::Ok, __S::Error> + where + __S: _serde::Serializer, + { + _serde::Serializer::serialize_newtype_struct(__serializer, "UInt", &self.0) + } + } + }; + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for UInt { + #[inline] + fn clone(&self) -> UInt { + { + let _: ::core::clone::AssertParamIsClone; + *self + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::marker::Copy for UInt {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::default::Default for UInt { + #[inline] + fn default() -> UInt { + UInt(::core::default::Default::default()) + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::hash::Hash for UInt { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + match *self { + UInt(ref __self_0_0) => ::core::hash::Hash::hash(&(*__self_0_0), state), + } + } + } + impl ::core::marker::StructuralPartialEq for UInt {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for UInt { + #[inline] + fn eq(&self, other: &UInt) -> bool { + match *other { + UInt(ref __self_1_0) => match *self { + UInt(ref __self_0_0) => (*__self_0_0) == (*__self_1_0), + }, + } + } + #[inline] + fn ne(&self, other: &UInt) -> bool { + match *other { + UInt(ref __self_1_0) => match *self { + UInt(ref __self_0_0) => (*__self_0_0) != (*__self_1_0), + }, + } + } + } + impl ::core::marker::StructuralEq for UInt {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for UInt { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialOrd for UInt { + #[inline] + fn partial_cmp(&self, other: &UInt) -> ::core::option::Option<::core::cmp::Ordering> { + match *other { + UInt(ref __self_1_0) => match *self { + UInt(ref __self_0_0) => { + match ::core::cmp::PartialOrd::partial_cmp(&(*__self_0_0), &(*__self_1_0)) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) => { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + } + cmp => cmp, + } + } + }, + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Ord for UInt { + #[inline] + fn cmp(&self, other: &UInt) -> ::core::cmp::Ordering { + match *other { + UInt(ref __self_1_0) => match *self { + UInt(ref __self_0_0) => { + match ::core::cmp::Ord::cmp(&(*__self_0_0), &(*__self_1_0)) { + ::core::cmp::Ordering::Equal => ::core::cmp::Ordering::Equal, + cmp => cmp, + } + } + }, + } + } + } + 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 true { + if !(val <= MAX_SAFE_UINT) { + ::core::panicking::panic("assertion failed: val <= MAX_SAFE_UINT") + }; + Self(val) + } else { + Self::new_wrapping(val) + } + } + /// Helper function for mutable arithmetic operations (`+=`, `-=`, …) + fn assign_(&mut self, val: u64) { + if true { + if !(val <= MAX_SAFE_UINT) { + ::core::panicking::panic("assertion failed: 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)) + } + } + impl ::core::fmt::Display for UInt { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + f.write_fmt(::core::fmt::Arguments::new_v1( + &[""], + &match (&self.0,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )) + } + } + impl ::core::fmt::Debug for UInt { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + f.write_fmt(::core::fmt::Arguments::new_v1( + &[""], + &match (&self.0,) { + (arg0,) => [::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Debug::fmt)], + }, + )) + } + } + impl ::core::convert::From for UInt { + fn from(val: u8) -> Self { + Self(u64::from(val)) + } + } + impl ::core::convert::From for UInt { + fn from(val: u16) -> Self { + Self(u64::from(val)) + } + } + impl ::core::convert::From for UInt { + fn from(val: u32) -> Self { + Self(u64::from(val)) + } + } + impl ::core::convert::TryFrom for UInt { + type Error = crate::error::TryFromIntError; + fn try_from(val: u64) -> Result { + Self::new(val).ok_or_else(crate::error::TryFromIntError::new) + } + } + impl ::core::convert::TryFrom for UInt { + type Error = crate::error::TryFromIntError; + fn try_from(val: u128) -> Result { + u64::try_from(val) + .map_err(|_| crate::error::TryFromIntError::new()) + .and_then(UInt::try_from) + } + } + impl ::core::convert::TryFrom for u8 { + type Error = ::core::num::TryFromIntError; + fn try_from(val: UInt) -> Result { + Self::try_from(val.0) + } + } + impl ::core::convert::TryFrom for i8 { + type Error = ::core::num::TryFromIntError; + fn try_from(val: UInt) -> Result { + Self::try_from(val.0) + } + } + impl ::core::convert::TryFrom for u16 { + type Error = ::core::num::TryFromIntError; + fn try_from(val: UInt) -> Result { + Self::try_from(val.0) + } + } + impl ::core::convert::TryFrom for i16 { + type Error = ::core::num::TryFromIntError; + fn try_from(val: UInt) -> Result { + Self::try_from(val.0) + } + } + impl ::core::convert::TryFrom for u32 { + type Error = ::core::num::TryFromIntError; + fn try_from(val: UInt) -> Result { + Self::try_from(val.0) + } + } + impl ::core::convert::TryFrom for i32 { + type Error = ::core::num::TryFromIntError; + fn try_from(val: UInt) -> Result { + Self::try_from(val.0) + } + } + impl ::core::convert::From for u64 { + fn from(val: UInt) -> Self { + val.0 + } + } + impl ::core::convert::From for u128 { + fn from(val: UInt) -> Self { + u128::from(val.0) + } + } + impl ::core::convert::From for f64 { + fn from(val: UInt) -> Self { + val.0 as f64 + } + } + 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 + } + } + impl Add for UInt { + type Output = Self; + fn add(self, rhs: Self) -> Self { + Self::new_(::add(self.0, rhs.0)) + } + } + impl AddAssign for UInt { + fn add_assign(&mut self, other: Self) { + self.assign_(::add(self.0, other.0)); + } + } + impl Sub for UInt { + type Output = Self; + fn sub(self, rhs: Self) -> Self { + Self::new_(::sub(self.0, rhs.0)) + } + } + impl SubAssign for UInt { + fn sub_assign(&mut self, other: Self) { + self.assign_(::sub(self.0, other.0)); + } + } + impl Mul for UInt { + type Output = Self; + fn mul(self, rhs: Self) -> Self { + Self::new_(::mul(self.0, rhs.0)) + } + } + impl MulAssign for UInt { + fn mul_assign(&mut self, other: Self) { + self.assign_(::mul(self.0, other.0)); + } + } + impl Div for UInt { + type Output = Self; + fn div(self, rhs: Self) -> Self { + Self::new_(::div(self.0, rhs.0)) + } + } + impl DivAssign for UInt { + fn div_assign(&mut self, other: Self) { + self.assign_(::div(self.0, other.0)); + } + } + impl Rem for UInt { + type Output = Self; + fn rem(self, rhs: Self) -> Self { + Self::new_(::rem(self.0, rhs.0)) + } + } + impl RemAssign for UInt { + fn rem_assign(&mut self, other: Self) { + self.assign_(::rem(self.0, other.0)); + } + } + 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 = "lax_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", + ) + }) + } + } + } +} +pub use self::{ + error::{ParseIntError, TryFromIntError}, + int::{Int, MAX_SAFE_INT, MIN_SAFE_INT}, + uint::{UInt, MAX_SAFE_UINT}, +}; diff --git a/ext_tests/Cargo.toml b/ext_tests/Cargo.toml deleted file mode 100644 index e7a9302..0000000 --- a/ext_tests/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "js_int_ext_tests" -version = "0.1.0" -authors = ["Jonas Platte "] -edition = "2018" -publish = false - -[dependencies] -serde = "1.0" - -[dependencies.js_int] -path = "../" -features = ["serde"] - -[features] -lax_deserialize = ["js_int/lax_deserialize"] diff --git a/ext_tests/README.md b/ext_tests/README.md deleted file mode 100644 index 780cdfb..0000000 --- a/ext_tests/README.md +++ /dev/null @@ -1,6 +0,0 @@ -Due to [cargo issue #1796](https://github.com/rust-lang/cargo/issues/1796), we can not depend on -`serde_json` as a `dev-dependency` in `js_int` without breaking `no_std` compatibility, because -`serde_json` isn't `no_std`-compatible (because of that same cargo bug – see -[serde_json PR #516](https://github.com/serde-rs/json/pull/516)). - -Thus, the `serde` tests live in this separate crate. diff --git a/ext_tests/src/lib.rs b/ext_tests/src/lib.rs deleted file mode 100644 index ce1b113..0000000 --- a/ext_tests/src/lib.rs +++ /dev/null @@ -1,105 +0,0 @@ -mod test_serializer; - -#[cfg(test)] -mod tests { - use js_int::{int, uint, Int, UInt}; - use serde::{de::IntoDeserializer, Deserialize, Serialize}; - - use crate::test_serializer::{Serialized, TestSerializer}; - - #[test] - fn serialize_int() { - assert_eq!(int!(100).serialize(TestSerializer).unwrap(), Serialized::Signed(100)); - assert_eq!(int!(0).serialize(TestSerializer).unwrap(), Serialized::Signed(0)); - assert_eq!(int!(-100).serialize(TestSerializer).unwrap(), Serialized::Signed(-100)); - } - - #[test] - fn deserialize_int() { - assert_eq!(deserialize_int_from(100).unwrap(), int!(100)); - assert_eq!(deserialize_int_from(0).unwrap(), int!(0)); - assert_eq!(deserialize_int_from(-100).unwrap(), int!(-100)); - assert_eq!(deserialize_int_from(-9007199254740991i64).unwrap(), Int::MIN); - assert_eq!(deserialize_int_from(9007199254740991i64).unwrap(), Int::MAX); - assert!(deserialize_int_from(9007199254740992i64).is_err()); - assert!(deserialize_int_from(-9007199254740992i64).is_err()); - } - - #[test] - fn serialize_uint() { - assert_eq!(uint!(100).serialize(TestSerializer).unwrap(), Serialized::Unsigned(100)); - assert_eq!(uint!(0).serialize(TestSerializer).unwrap(), Serialized::Unsigned(0)); - } - - #[test] - fn deserialize_uint() { - assert_eq!(deserialize_uint_from(100).unwrap(), uint!(100)); - assert_eq!(deserialize_uint_from(0).unwrap(), uint!(0)); - assert_eq!(deserialize_uint_from(9007199254740991i64).unwrap(), UInt::MAX); - assert!(deserialize_uint_from(9007199254740992i64).is_err()); - } - - #[test] - #[cfg_attr(feature = "lax_deserialize", ignore)] - fn strict_deserialize_int() { - assert!(deserialize_int_from(-10.0).is_err()); - assert!(deserialize_int_from(-0.0).is_err()); - assert!(deserialize_int_from(0.5).is_err()); - assert!(deserialize_int_from(1.0).is_err()); - assert!(deserialize_int_from(9007199254740991.0).is_err()); - assert!(deserialize_int_from(9007199254740991.49).is_err()); - assert!(deserialize_int_from(9007199254740992.0).is_err()); - } - - #[test] - #[cfg_attr(feature = "lax_deserialize", ignore)] - fn strict_deserialize_uint() { - assert!(deserialize_uint_from(0.5).is_err()); - assert!(deserialize_uint_from(1.0).is_err()); - assert!(deserialize_uint_from(9007199254740991.0).is_err()); - assert!(deserialize_uint_from(9007199254740991.49).is_err()); - assert!(deserialize_uint_from(9007199254740992.0).is_err()); - } - - #[test] - #[cfg_attr(not(feature = "lax_deserialize"), ignore)] - fn lax_deserialize_int() { - assert_eq!(deserialize_int_from(-10.0).unwrap(), int!(-10)); - assert_eq!(deserialize_int_from(-0.0).unwrap(), int!(0)); - assert_eq!(deserialize_int_from(0.5).unwrap(), int!(0)); - assert_eq!(deserialize_int_from(1.0).unwrap(), int!(1)); - assert_eq!(deserialize_int_from(9007199254740991.0).unwrap(), Int::MAX); - assert_eq!(deserialize_int_from(9007199254740991.49).unwrap(), Int::MAX); - assert!(deserialize_int_from(9007199254740992.0).is_err()); - - assert!(deserialize_int_from(f64::NAN).is_err()); - assert!(deserialize_int_from(f64::INFINITY).is_err()); - assert!(deserialize_int_from(f64::NEG_INFINITY).is_err()); - } - - #[test] - #[cfg_attr(not(feature = "lax_deserialize"), ignore)] - fn lax_deserialize_uint() { - assert_eq!(deserialize_uint_from(0.5).unwrap(), uint!(0)); - assert_eq!(deserialize_uint_from(1.0).unwrap(), uint!(1)); - assert_eq!(deserialize_uint_from(9007199254740991.0).unwrap(), UInt::MAX); - assert_eq!(deserialize_uint_from(9007199254740991.49).unwrap(), UInt::MAX); - assert!(deserialize_uint_from(9007199254740992.0).is_err()); - - assert!(deserialize_uint_from(f64::NAN).is_err()); - assert!(deserialize_uint_from(f64::INFINITY).is_err()); - assert!(deserialize_uint_from(f64::NEG_INFINITY).is_err()); - } - - fn deserialize_int_from<'de, Value: IntoDeserializer<'de>>( - value: Value, - ) -> Result { - Int::deserialize(value.into_deserializer()) - } - - fn deserialize_uint_from<'de, Value: IntoDeserializer<'de>>( - value: Value, - ) -> Result { - UInt::deserialize(value.into_deserializer()) - } -} diff --git a/tests/int.rs b/tests/int.rs new file mode 100644 index 0000000..cc6f3cd --- /dev/null +++ b/tests/int.rs @@ -0,0 +1,59 @@ +#![cfg(feature = "serde")] +mod test_serializer; + +use js_int::{int, Int}; +use serde::{de::IntoDeserializer, Deserialize, Serialize}; + +use crate::test_serializer::{Serialized, TestSerializer}; + +#[test] +fn serialize_int() { + assert_eq!(int!(100).serialize(TestSerializer).unwrap(), Serialized::Signed(100)); + assert_eq!(int!(0).serialize(TestSerializer).unwrap(), Serialized::Signed(0)); + assert_eq!(int!(-100).serialize(TestSerializer).unwrap(), Serialized::Signed(-100)); +} + +#[test] +fn deserialize_int() { + 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 = "lax_deserialize", ignore)] +fn strict_deserialize_int() { + assert!(deserialize_from(-10.0).is_err()); + assert!(deserialize_from(-0.0).is_err()); + assert!(deserialize_from(0.5).is_err()); + assert!(deserialize_from(1.0).is_err()); + assert!(deserialize_from(9007199254740991.0).is_err()); + assert!(deserialize_from(9007199254740991.49).is_err()); + assert!(deserialize_from(9007199254740992.0).is_err()); +} + +#[test] +#[cfg_attr(not(feature = "lax_deserialize"), ignore)] +fn lax_deserialize_int() { + assert_eq!(deserialize_from(-10.0).unwrap(), int!(-10)); + assert_eq!(deserialize_from(-0.0).unwrap(), int!(0)); + assert_eq!(deserialize_from(0.5).unwrap(), int!(0)); + assert_eq!(deserialize_from(1.0).unwrap(), int!(1)); + assert_eq!(deserialize_from(9007199254740991.0).unwrap(), Int::MAX); + assert_eq!(deserialize_from(9007199254740991.49).unwrap(), Int::MAX); + assert!(deserialize_from(9007199254740992.0).is_err()); + + assert!(deserialize_from(f64::NAN).is_err()); + assert!(deserialize_from(f64::INFINITY).is_err()); + assert!(deserialize_from(f64::NEG_INFINITY).is_err()); +} + +fn deserialize_from<'de, Value: IntoDeserializer<'de>>( + value: Value, +) -> Result { + Int::deserialize(value.into_deserializer()) +} diff --git a/ext_tests/src/test_serializer.rs b/tests/test_serializer.rs similarity index 93% rename from ext_tests/src/test_serializer.rs rename to tests/test_serializer.rs index 46f2653..ab00f5d 100644 --- a/ext_tests/src/test_serializer.rs +++ b/tests/test_serializer.rs @@ -1,5 +1,8 @@ +#![cfg(feature = "serde")] use serde::{ser::Impossible, Serialize, Serializer}; +use std::fmt::Display; +/// serde Serializer for testing that the `Serialize` implementation of `Int` and `UInt` work correctly. pub struct TestSerializer; #[derive(Debug, PartialEq)] @@ -178,4 +181,11 @@ impl Serializer for TestSerializer { ) -> Result { unimplemented!() } + + fn collect_str(self, _: &T) -> Result + where + T: Display, + { + unimplemented!() + } } diff --git a/tests/uint.rs b/tests/uint.rs new file mode 100644 index 0000000..5e4f677 --- /dev/null +++ b/tests/uint.rs @@ -0,0 +1,51 @@ +#![cfg(feature = "serde")] +mod test_serializer; + +use js_int::{uint, UInt}; +use serde::{de::IntoDeserializer, Deserialize, Serialize}; + +use crate::test_serializer::{Serialized, TestSerializer}; + +#[test] +fn serialize_uint() { + assert_eq!(uint!(100).serialize(TestSerializer).unwrap(), Serialized::Unsigned(100)); + assert_eq!(uint!(0).serialize(TestSerializer).unwrap(), Serialized::Unsigned(0)); +} + +#[test] +fn deserialize_uint() { + assert_eq!(deserialize_uint_from(100).unwrap(), uint!(100)); + assert_eq!(deserialize_uint_from(0).unwrap(), uint!(0)); + assert_eq!(deserialize_uint_from(9007199254740991i64).unwrap(), UInt::MAX); + assert!(deserialize_uint_from(9007199254740992i64).is_err()); +} + +#[test] +#[cfg_attr(feature = "lax_deserialize", ignore)] +fn strict_deserialize_uint() { + assert!(deserialize_uint_from(0.5).is_err()); + assert!(deserialize_uint_from(1.0).is_err()); + assert!(deserialize_uint_from(9007199254740991.0).is_err()); + assert!(deserialize_uint_from(9007199254740991.49).is_err()); + assert!(deserialize_uint_from(9007199254740992.0).is_err()); +} + +#[test] +#[cfg_attr(not(feature = "lax_deserialize"), ignore)] +fn lax_deserialize_uint() { + assert_eq!(deserialize_uint_from(0.5).unwrap(), uint!(0)); + assert_eq!(deserialize_uint_from(1.0).unwrap(), uint!(1)); + assert_eq!(deserialize_uint_from(9007199254740991.0).unwrap(), UInt::MAX); + assert_eq!(deserialize_uint_from(9007199254740991.49).unwrap(), UInt::MAX); + assert!(deserialize_uint_from(9007199254740992.0).is_err()); + + assert!(deserialize_uint_from(f64::NAN).is_err()); + assert!(deserialize_uint_from(f64::INFINITY).is_err()); + assert!(deserialize_uint_from(f64::NEG_INFINITY).is_err()); +} + +fn deserialize_uint_from<'de, Value: IntoDeserializer<'de>>( + value: Value, +) -> Result { + UInt::deserialize(value.into_deserializer()) +}