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())
+}