diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:47:55 +0000 |
commit | 2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4 (patch) | |
tree | 033cc839730fda84ff08db877037977be94e5e3a /vendor/deranged | |
parent | Initial commit. (diff) | |
download | cargo-2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4.tar.xz cargo-2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4.zip |
Adding upstream version 0.70.1+ds1.upstream/0.70.1+ds1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/deranged')
-rw-r--r-- | vendor/deranged/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | vendor/deranged/Cargo.toml | 83 | ||||
-rw-r--r-- | vendor/deranged/LICENSE-Apache | 202 | ||||
-rw-r--r-- | vendor/deranged/LICENSE-MIT | 19 | ||||
-rw-r--r-- | vendor/deranged/README.md | 3 | ||||
-rw-r--r-- | vendor/deranged/src/lib.rs | 1388 | ||||
-rw-r--r-- | vendor/deranged/src/tests.rs | 643 | ||||
-rw-r--r-- | vendor/deranged/src/traits.rs | 117 |
8 files changed, 2456 insertions, 0 deletions
diff --git a/vendor/deranged/.cargo-checksum.json b/vendor/deranged/.cargo-checksum.json new file mode 100644 index 0000000..7fcdffb --- /dev/null +++ b/vendor/deranged/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3"}
\ No newline at end of file diff --git a/vendor/deranged/Cargo.toml b/vendor/deranged/Cargo.toml new file mode 100644 index 0000000..81d8ddd --- /dev/null +++ b/vendor/deranged/Cargo.toml @@ -0,0 +1,83 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.65.0" +name = "deranged" +version = "0.3.9" +authors = ["Jacob Pratt <jacob@jhpratt.dev>"] +include = [ + "src/**/*", + "LICENSE-*", + "README.md", +] +description = "Ranged integers" +readme = "README.md" +keywords = [ + "integer", + "int", + "range", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/jhpratt/deranged" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docs_rs", +] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies.num-traits] +version = "0.2.15" +optional = true +default-features = false + +[dependencies.powerfmt] +version = "0.2.0" +optional = true +default-features = false + +[dependencies.quickcheck] +version = "1.0.3" +optional = true +default-features = false + +[dependencies.rand] +version = "0.8.4" +optional = true +default-features = false + +[dependencies.serde] +version = "1.0.126" +optional = true +default-features = false + +[dev-dependencies.rand] +version = "0.8.4" + +[dev-dependencies.serde_json] +version = "1.0.86" + +[features] +alloc = [] +default = ["std"] +num = ["dep:num-traits"] +powerfmt = ["dep:powerfmt"] +quickcheck = [ + "dep:quickcheck", + "alloc", +] +rand = ["dep:rand"] +serde = ["dep:serde"] +std = ["alloc"] diff --git a/vendor/deranged/LICENSE-Apache b/vendor/deranged/LICENSE-Apache new file mode 100644 index 0000000..7646f21 --- /dev/null +++ b/vendor/deranged/LICENSE-Apache @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2022 Jacob Pratt et al. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/deranged/LICENSE-MIT b/vendor/deranged/LICENSE-MIT new file mode 100644 index 0000000..a11a755 --- /dev/null +++ b/vendor/deranged/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) 2022 Jacob Pratt et al. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/deranged/README.md b/vendor/deranged/README.md new file mode 100644 index 0000000..eddc4b9 --- /dev/null +++ b/vendor/deranged/README.md @@ -0,0 +1,3 @@ +# Deranged + +This crate is a proof-of-concept implementation of ranged integers. diff --git a/vendor/deranged/src/lib.rs b/vendor/deranged/src/lib.rs new file mode 100644 index 0000000..441dacb --- /dev/null +++ b/vendor/deranged/src/lib.rs @@ -0,0 +1,1388 @@ +#![cfg_attr(docs_rs, feature(doc_auto_cfg))] +#![cfg_attr(not(feature = "std"), no_std)] +#![deny( + anonymous_parameters, + clippy::all, + clippy::missing_safety_doc, + clippy::missing_safety_doc, + clippy::undocumented_unsafe_blocks, + illegal_floating_point_literal_pattern, + late_bound_lifetime_arguments, + patterns_in_fns_without_body, + rust_2018_idioms, + trivial_casts, + trivial_numeric_casts, + unreachable_pub, + unsafe_op_in_unsafe_fn, + unused_extern_crates +)] +#![warn( + clippy::dbg_macro, + clippy::decimal_literal_representation, + clippy::get_unwrap, + clippy::nursery, + clippy::pedantic, + clippy::todo, + clippy::unimplemented, + clippy::unwrap_used, + clippy::use_debug, + missing_copy_implementations, + missing_debug_implementations, + unused_qualifications, + variant_size_differences +)] +#![allow( + path_statements, // used for static assertions + clippy::inline_always, + clippy::missing_errors_doc, + clippy::must_use_candidate, + clippy::redundant_pub_crate, +)] +#![doc(test(attr(deny(warnings))))] + +#[cfg(test)] +mod tests; +mod traits; + +#[cfg(feature = "alloc")] +#[allow(unused_extern_crates)] +extern crate alloc; + +use core::borrow::Borrow; +use core::cmp::Ordering; +use core::fmt; +use core::num::IntErrorKind; +use core::str::FromStr; +#[cfg(feature = "std")] +use std::error::Error; + +#[cfg(feature = "powerfmt")] +use powerfmt::smart_display; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct TryFromIntError; + +impl fmt::Display for TryFromIntError { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("out of range integral type conversion attempted") + } +} +#[cfg(feature = "std")] +impl Error for TryFromIntError {} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ParseIntError { + kind: IntErrorKind, +} + +impl ParseIntError { + /// Outputs the detailed cause of parsing an integer failing. + // This function is not const because the counterpart of stdlib isn't + #[allow(clippy::missing_const_for_fn)] + #[inline(always)] + pub fn kind(&self) -> &IntErrorKind { + &self.kind + } +} + +impl fmt::Display for ParseIntError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.kind { + IntErrorKind::Empty => "cannot parse integer from empty string", + IntErrorKind::InvalidDigit => "invalid digit found in string", + IntErrorKind::PosOverflow => "number too large to fit in target type", + IntErrorKind::NegOverflow => "number too small to fit in target type", + IntErrorKind::Zero => "number would be zero for non-zero type", + _ => "Unknown Int error kind", + } + .fmt(f) + } +} + +#[cfg(feature = "std")] +impl Error for ParseIntError {} + +macro_rules! const_try_opt { + ($e:expr) => { + match $e { + Some(value) => value, + None => return None, + } + }; +} + +macro_rules! if_signed { + (true $($x:tt)*) => { $($x)*}; + (false $($x:tt)*) => {}; +} + +macro_rules! article { + (true) => { + "An" + }; + (false) => { + "A" + }; +} + +macro_rules! unsafe_unwrap_unchecked { + ($e:expr) => {{ + let opt = $e; + debug_assert!(opt.is_some()); + match $e { + Some(value) => value, + None => core::hint::unreachable_unchecked(), + } + }}; +} + +/// Informs the optimizer that a condition is always true. If the condition is false, the behavior +/// is undefined. +/// +/// # Safety +/// +/// `b` must be `true`. +#[inline] +const unsafe fn assume(b: bool) { + debug_assert!(b); + if !b { + // Safety: The caller must ensure that `b` is true. + unsafe { core::hint::unreachable_unchecked() } + } +} + +macro_rules! impl_ranged { + ($( + $type:ident { + mod_name: $mod_name:ident + internal: $internal:ident + signed: $is_signed:ident + unsigned: $unsigned_type:ident + optional: $optional_type:ident + } + )*) => {$( + pub use $mod_name::{$type, $optional_type}; + + // Introduce the type in a module. This ensures that all accesses and mutations of the field + // have the necessary checks. + mod $mod_name { + #[doc = concat!( + article!($is_signed), + " `", + stringify!($internal), + "` that is known to be in the range `MIN..=MAX`.", + )] + #[repr(transparent)] + #[derive(Clone, Copy, Eq, Ord, Hash)] + pub struct $type<const MIN: $internal, const MAX: $internal>( + $internal, + ); + + #[doc = concat!( + "A `", + stringify!($type), + "` that is optional. Equivalent to [`Option<", + stringify!($type), + ">`] with niche value optimization.", + )] + /// + #[doc = concat!( + "If `MIN` is [`", + stringify!($internal), + "::MIN`] _and_ `MAX` is [`", + stringify!($internal) + ,"::MAX`] then compilation will fail. This is because there is no way to represent \ + the niche value.", + )] + /// + /// This type is useful when you need to store an optional ranged value in a struct, but + /// do not want the overhead of an `Option` type. This reduces the size of the struct + /// overall, and is particularly useful when you have a large number of optional fields. + /// Note that most operations must still be performed on the [`Option`] type, which is + #[doc = concat!("obtained with [`", stringify!($optional_type), "::get`].")] + #[repr(transparent)] + #[derive(Clone, Copy, Eq, Hash)] + pub struct $optional_type<const MIN: $internal, const MAX: $internal>( + $internal, + ); + + impl<const MIN: $internal, const MAX: $internal> $type<MIN, MAX> { + /// Creates a ranged integer without checking the value. + /// + /// # Safety + /// + /// The value must be within the range `MIN..=MAX`. + #[inline(always)] + pub const unsafe fn new_unchecked(value: $internal) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + // Safety: The caller must ensure that the value is in range. + unsafe { $crate::assume(MIN <= value && value <= MAX) }; + Self(value) + } + + /// Creates a ranged integer if the given value is in the range + /// `MIN..=MAX`. + #[inline(always)] + pub const fn new(value: $internal) -> Option<Self> { + <Self as $crate::traits::RangeIsValid>::ASSERT; + if value < MIN || value > MAX { + None + } else { + Some(Self(value)) + } + } + + /// Returns the value as a primitive type. + #[inline(always)] + pub const fn get(self) -> $internal { + <Self as $crate::traits::RangeIsValid>::ASSERT; + // Safety: A stored value is always in range. + unsafe { $crate::assume(MIN <= self.0 && self.0 <= MAX) }; + self.0 + } + + #[inline(always)] + pub(crate) const fn get_ref(&self) -> &$internal { + <Self as $crate::traits::RangeIsValid>::ASSERT; + // Safety: A stored value is always in range. + unsafe { $crate::assume(MIN <= self.0 && self.0 <= MAX) }; + &self.0 + } + } + + impl<const MIN: $internal, const MAX: $internal> $optional_type<MIN, MAX> { + /// The value used as the niche. Must not be in the range `MIN..=MAX`. + const NICHE: $internal = match (MIN, MAX) { + ($internal::MIN, $internal::MAX) => panic!("type has no niche"), + ($internal::MIN, _) => $internal::MAX, + (_, _) => $internal::MIN, + }; + + /// An optional ranged value that is not present. + #[allow(non_upper_case_globals)] + pub const None: Self = Self(Self::NICHE); + + /// Creates an optional ranged value that is present. + #[allow(non_snake_case)] + #[inline(always)] + pub const fn Some(value: $type<MIN, MAX>) -> Self { + <$type<MIN, MAX> as $crate::traits::RangeIsValid>::ASSERT; + Self(value.get()) + } + + /// Returns the value as the standard library's [`Option`] type. + #[inline(always)] + pub const fn get(self) -> Option<$type<MIN, MAX>> { + <$type<MIN, MAX> as $crate::traits::RangeIsValid>::ASSERT; + if self.0 == Self::NICHE { + None + } else { + // Safety: A stored value that is not the niche is always in range. + Some(unsafe { $type::new_unchecked(self.0) }) + } + } + + /// Creates an optional ranged integer without checking the value. + /// + /// # Safety + /// + /// The value must be within the range `MIN..=MAX`. As the value used for niche + /// value optimization is unspecified, the provided value must not be the niche + /// value. + #[inline(always)] + pub const unsafe fn some_unchecked(value: $internal) -> Self { + <$type<MIN, MAX> as $crate::traits::RangeIsValid>::ASSERT; + // Safety: The caller must ensure that the value is in range. + unsafe { $crate::assume(MIN <= value && value <= MAX) }; + Self(value) + } + + /// Obtain the inner value of the struct. This is useful for comparisons. + #[inline(always)] + pub(crate) const fn inner(self) -> $internal { + <$type<MIN, MAX> as $crate::traits::RangeIsValid>::ASSERT; + self.0 + } + } + } + + impl<const MIN: $internal, const MAX: $internal> $type<MIN, MAX> { + /// The smallest value that can be represented by this type. + // Safety: `MIN` is in range by definition. + pub const MIN: Self = unsafe { Self::new_unchecked(MIN) }; + + /// The largest value that can be represented by this type. + // Safety: `MAX` is in range by definition. + pub const MAX: Self = unsafe { Self::new_unchecked(MAX) }; + + /// Expand the range that the value may be in. **Fails to compile** if the new range is + /// not a superset of the current range. + pub const fn expand<const NEW_MIN: $internal, const NEW_MAX: $internal>( + self, + ) -> $type<NEW_MIN, NEW_MAX> { + <$type<MIN, MAX> as $crate::traits::RangeIsValid>::ASSERT; + <$type<NEW_MIN, NEW_MAX> as $crate::traits::RangeIsValid>::ASSERT; + <($type<MIN, MAX>, $type<NEW_MIN, NEW_MAX>) as $crate::traits::ExpandIsValid> + ::ASSERT; + // Safety: The range is widened. + unsafe { $type::new_unchecked(self.get()) } + } + + /// Attempt to narrow the range that the value may be in. Returns `None` if the value + /// is outside the new range. **Fails to compile** if the new range is not a subset of + /// the current range. + pub const fn narrow< + const NEW_MIN: $internal, + const NEW_MAX: $internal, + >(self) -> Option<$type<NEW_MIN, NEW_MAX>> { + <$type<MIN, MAX> as $crate::traits::RangeIsValid>::ASSERT; + <$type<NEW_MIN, NEW_MAX> as $crate::traits::RangeIsValid>::ASSERT; + <($type<MIN, MAX>, $type<NEW_MIN, NEW_MAX>) as $crate::traits::NarrowIsValid> + ::ASSERT; + $type::<NEW_MIN, NEW_MAX>::new(self.get()) + } + + + /// Creates a ranged integer with a statically known value. **Fails to compile** if the + /// value is not in range. + #[inline(always)] + pub const fn new_static<const VALUE: $internal>() -> Self { + <($type<MIN, VALUE>, $type<VALUE, MAX>) as $crate::traits::StaticIsValid>::ASSERT; + // Safety: The value is in range. + unsafe { Self::new_unchecked(VALUE) } + } + + #[inline] + const fn new_saturating(value: $internal) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + // Safety: The value is clamped to the range. + unsafe { + Self::new_unchecked(if value < MIN { + MIN + } else if value > MAX { + MAX + } else { + value + }) + } + } + + + /// 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 + /// + /// Panics if `radix` is not in the range `2..=36`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ```rust + #[doc = concat!("# use deranged::", stringify!($type), ";")] + #[doc = concat!( + "assert_eq!(", + stringify!($type), + "::<5, 10>::from_str_radix(\"A\", 16), Ok(", + stringify!($type), + "::new_static::<10>()));", + )] + /// ``` + #[inline] + pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> { + <Self as $crate::traits::RangeIsValid>::ASSERT; + match $internal::from_str_radix(src, radix) { + Ok(value) if value > MAX => { + Err(ParseIntError { kind: IntErrorKind::PosOverflow }) + } + Ok(value) if value < MIN => { + Err(ParseIntError { kind: IntErrorKind::NegOverflow }) + } + // Safety: If the value was out of range, it would have been caught in a + // previous arm. + Ok(value) => Ok(unsafe { Self::new_unchecked(value) }), + Err(e) => Err(ParseIntError { kind: e.kind().clone() }), + } + } + + /// Checked integer addition. Computes `self + rhs`, returning `None` if the resulting + /// value is out of range. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn checked_add(self, rhs: $internal) -> Option<Self> { + <Self as $crate::traits::RangeIsValid>::ASSERT; + Self::new(const_try_opt!(self.get().checked_add(rhs))) + } + + /// Unchecked integer addition. Computes `self + rhs`, assuming that the result is in + /// range. + /// + /// # Safety + /// + /// The result of `self + rhs` must be in the range `MIN..=MAX`. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline(always)] + pub const unsafe fn unchecked_add(self, rhs: $internal) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + // Safety: The caller must ensure that the result is in range. + unsafe { + Self::new_unchecked(unsafe_unwrap_unchecked!(self.get().checked_add(rhs))) + } + } + + /// Checked integer addition. Computes `self - rhs`, returning `None` if the resulting + /// value is out of range. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn checked_sub(self, rhs: $internal) -> Option<Self> { + <Self as $crate::traits::RangeIsValid>::ASSERT; + Self::new(const_try_opt!(self.get().checked_sub(rhs))) + } + + /// Unchecked integer subtraction. Computes `self - rhs`, assuming that the result is in + /// range. + /// + /// # Safety + /// + /// The result of `self - rhs` must be in the range `MIN..=MAX`. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline(always)] + pub const unsafe fn unchecked_sub(self, rhs: $internal) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + // Safety: The caller must ensure that the result is in range. + unsafe { + Self::new_unchecked(unsafe_unwrap_unchecked!(self.get().checked_sub(rhs))) + } + } + + /// Checked integer addition. Computes `self * rhs`, returning `None` if the resulting + /// value is out of range. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn checked_mul(self, rhs: $internal) -> Option<Self> { + <Self as $crate::traits::RangeIsValid>::ASSERT; + Self::new(const_try_opt!(self.get().checked_mul(rhs))) + } + + /// Unchecked integer multiplication. Computes `self * rhs`, assuming that the result is + /// in range. + /// + /// # Safety + /// + /// The result of `self * rhs` must be in the range `MIN..=MAX`. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline(always)] + pub const unsafe fn unchecked_mul(self, rhs: $internal) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + // Safety: The caller must ensure that the result is in range. + unsafe { + Self::new_unchecked(unsafe_unwrap_unchecked!(self.get().checked_mul(rhs))) + } + } + + /// Checked integer addition. Computes `self / rhs`, returning `None` if `rhs == 0` or + /// if the resulting value is out of range. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn checked_div(self, rhs: $internal) -> Option<Self> { + <Self as $crate::traits::RangeIsValid>::ASSERT; + Self::new(const_try_opt!(self.get().checked_div(rhs))) + } + + /// Unchecked integer division. Computes `self / rhs`, assuming that `rhs != 0` and that + /// the result is in range. + /// + /// # Safety + /// + /// `self` must not be zero and the result of `self / rhs` must be in the range + /// `MIN..=MAX`. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline(always)] + pub const unsafe fn unchecked_div(self, rhs: $internal) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + // Safety: The caller must ensure that the result is in range and that `rhs` is not + // zero. + unsafe { + Self::new_unchecked(unsafe_unwrap_unchecked!(self.get().checked_div(rhs))) + } + } + + /// Checked Euclidean division. Computes `self.div_euclid(rhs)`, returning `None` if + /// `rhs == 0` or if the resulting value is out of range. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn checked_div_euclid(self, rhs: $internal) -> Option<Self> { + <Self as $crate::traits::RangeIsValid>::ASSERT; + Self::new(const_try_opt!(self.get().checked_div_euclid(rhs))) + } + + /// Unchecked Euclidean division. Computes `self.div_euclid(rhs)`, assuming that + /// `rhs != 0` and that the result is in range. + /// + /// # Safety + /// + /// `self` must not be zero and the result of `self.div_euclid(rhs)` must be in the + /// range `MIN..=MAX`. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline(always)] + pub const unsafe fn unchecked_div_euclid(self, rhs: $internal) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + // Safety: The caller must ensure that the result is in range and that `rhs` is not + // zero. + unsafe { + Self::new_unchecked( + unsafe_unwrap_unchecked!(self.get().checked_div_euclid(rhs)) + ) + } + } + + /// Checked integer remainder. Computes `self % rhs`, returning `None` if `rhs == 0` or + /// if the resulting value is out of range. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn checked_rem(self, rhs: $internal) -> Option<Self> { + <Self as $crate::traits::RangeIsValid>::ASSERT; + Self::new(const_try_opt!(self.get().checked_rem(rhs))) + } + + /// Unchecked remainder. Computes `self % rhs`, assuming that `rhs != 0` and that the + /// result is in range. + /// + /// # Safety + /// + /// `self` must not be zero and the result of `self % rhs` must be in the range + /// `MIN..=MAX`. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline(always)] + pub const unsafe fn unchecked_rem(self, rhs: $internal) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + // Safety: The caller must ensure that the result is in range and that `rhs` is not + // zero. + unsafe { + Self::new_unchecked(unsafe_unwrap_unchecked!(self.get().checked_rem(rhs))) + } + } + + /// Checked Euclidean remainder. Computes `self.rem_euclid(rhs)`, returning `None` if + /// `rhs == 0` or if the resulting value is out of range. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn checked_rem_euclid(self, rhs: $internal) -> Option<Self> { + <Self as $crate::traits::RangeIsValid>::ASSERT; + Self::new(const_try_opt!(self.get().checked_rem_euclid(rhs))) + } + + /// Unchecked Euclidean remainder. Computes `self.rem_euclid(rhs)`, assuming that + /// `rhs != 0` and that the result is in range. + /// + /// # Safety + /// + /// `self` must not be zero and the result of `self.rem_euclid(rhs)` must be in the + /// range `MIN..=MAX`. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline(always)] + pub const unsafe fn unchecked_rem_euclid(self, rhs: $internal) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + // Safety: The caller must ensure that the result is in range and that `rhs` is not + // zero. + unsafe { + Self::new_unchecked( + unsafe_unwrap_unchecked!(self.get().checked_rem_euclid(rhs)) + ) + } + } + + /// Checked negation. Computes `-self`, returning `None` if the resulting value is out + /// of range. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn checked_neg(self) -> Option<Self> { + <Self as $crate::traits::RangeIsValid>::ASSERT; + Self::new(const_try_opt!(self.get().checked_neg())) + } + + /// Unchecked negation. Computes `-self`, assuming that `-self` is in range. + /// + /// # Safety + /// + /// The result of `-self` must be in the range `MIN..=MAX`. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline(always)] + pub const unsafe fn unchecked_neg(self) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + // Safety: The caller must ensure that the result is in range. + unsafe { Self::new_unchecked(unsafe_unwrap_unchecked!(self.get().checked_neg())) } + } + + /// Absolute value. Computes `self.neg()`, **failing to compile** if the result is not + /// guaranteed to be in range. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline(always)] + pub const fn neg(self) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + <Self as $crate::traits::NegIsSafe>::ASSERT; + // Safety: The compiler asserts that the result is in range. + unsafe { self.unchecked_neg() } + } + + /// Checked shift left. Computes `self << rhs`, returning `None` if the resulting value + /// is out of range. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn checked_shl(self, rhs: u32) -> Option<Self> { + <Self as $crate::traits::RangeIsValid>::ASSERT; + Self::new(const_try_opt!(self.get().checked_shl(rhs))) + } + + /// Unchecked shift left. Computes `self << rhs`, assuming that the result is in range. + /// + /// # Safety + /// + /// The result of `self << rhs` must be in the range `MIN..=MAX`. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline(always)] + pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + // Safety: The caller must ensure that the result is in range. + unsafe { + Self::new_unchecked(unsafe_unwrap_unchecked!(self.get().checked_shl(rhs))) + } + } + + /// Checked shift right. Computes `self >> rhs`, returning `None` if + /// the resulting value is out of range. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn checked_shr(self, rhs: u32) -> Option<Self> { + <Self as $crate::traits::RangeIsValid>::ASSERT; + Self::new(const_try_opt!(self.get().checked_shr(rhs))) + } + + /// Unchecked shift right. Computes `self >> rhs`, assuming that the result is in range. + /// + /// # Safety + /// + /// The result of `self >> rhs` must be in the range `MIN..=MAX`. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline(always)] + pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + // Safety: The caller must ensure that the result is in range. + unsafe { + Self::new_unchecked(unsafe_unwrap_unchecked!(self.get().checked_shr(rhs))) + } + } + + if_signed!($is_signed + /// Checked absolute value. Computes `self.abs()`, returning `None` if the resulting + /// value is out of range. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn checked_abs(self) -> Option<Self> { + <Self as $crate::traits::RangeIsValid>::ASSERT; + Self::new(const_try_opt!(self.get().checked_abs())) + } + + /// Unchecked absolute value. Computes `self.abs()`, assuming that the result is in + /// range. + /// + /// # Safety + /// + /// The result of `self.abs()` must be in the range `MIN..=MAX`. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline(always)] + pub const unsafe fn unchecked_abs(self) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + // Safety: The caller must ensure that the result is in range. + unsafe { Self::new_unchecked(unsafe_unwrap_unchecked!(self.get().checked_abs())) } + } + + /// Absolute value. Computes `self.abs()`, **failing to compile** if the result is not + /// guaranteed to be in range. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline(always)] + pub const fn abs(self) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + <Self as $crate::traits::AbsIsSafe>::ASSERT; + // Safety: The compiler asserts that the result is in range. + unsafe { self.unchecked_abs() } + }); + + /// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if the resulting + /// value is out of range. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn checked_pow(self, exp: u32) -> Option<Self> { + <Self as $crate::traits::RangeIsValid>::ASSERT; + Self::new(const_try_opt!(self.get().checked_pow(exp))) + } + + /// Unchecked exponentiation. Computes `self.pow(exp)`, assuming that the result is in + /// range. + /// + /// # Safety + /// + /// The result of `self.pow(exp)` must be in the range `MIN..=MAX`. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline(always)] + pub const unsafe fn unchecked_pow(self, exp: u32) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + // Safety: The caller must ensure that the result is in range. + unsafe { + Self::new_unchecked(unsafe_unwrap_unchecked!(self.get().checked_pow(exp))) + } + } + + /// Saturating integer addition. Computes `self + rhs`, saturating at the numeric + /// bounds. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn saturating_add(self, rhs: $internal) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + Self::new_saturating(self.get().saturating_add(rhs)) + } + + /// Saturating integer subtraction. Computes `self - rhs`, saturating at the numeric + /// bounds. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn saturating_sub(self, rhs: $internal) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + Self::new_saturating(self.get().saturating_sub(rhs)) + } + + if_signed!($is_signed + /// Saturating integer negation. Computes `self - rhs`, saturating at the numeric + /// bounds. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn saturating_neg(self) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + Self::new_saturating(self.get().saturating_neg()) + }); + + if_signed!($is_signed + /// Saturating absolute value. Computes `self.abs()`, saturating at the numeric bounds. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn saturating_abs(self) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + Self::new_saturating(self.get().saturating_abs()) + }); + + /// Saturating integer multiplication. Computes `self * rhs`, saturating at the numeric + /// bounds. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn saturating_mul(self, rhs: $internal) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + Self::new_saturating(self.get().saturating_mul(rhs)) + } + + /// Saturating integer exponentiation. Computes `self.pow(exp)`, saturating at the + /// numeric bounds. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn saturating_pow(self, exp: u32) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + Self::new_saturating(self.get().saturating_pow(exp)) + } + + /// Wrapping integer addition. Computes `self + rhs`, wrapping around the numeric + /// bounds. + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + #[allow(trivial_casts, trivial_numeric_casts)] // needed since some casts have to send unsigned -> unsigned to handle signed -> unsigned + pub const fn wrapping_add(self, rhs: $internal) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + // Forward to internal type's impl if same as type. + if MIN == $internal::MIN && MAX == $internal::MAX { + // Safety: std's wrapping methods match ranged arithmetic when the range is the internal datatype's range. + return unsafe { Self::new_unchecked(self.get().wrapping_add(rhs)) } + } + + let inner = self.get(); + // Won't overflow because of std impl forwarding. + let range_len = MAX.abs_diff(MIN) + 1; + // Calculate the offset with proper handling for negative rhs + #[allow(unused_comparisons)] + // equivalent to `rem_euclid_unsigned()` if that method existed + let offset = if rhs >= 0 { + (rhs as $unsigned_type) % range_len + } else { + // Let ux refer to an n bit unsigned and ix refer to an n bit signed integer. + // Can't write -ux or ux::abs() method. This gets around compilation error. + // `wrapping_sub` is to handle rhs = ix::MIN since ix::MIN = -ix::MAX-1 + let rhs_abs = ($internal::wrapping_sub(0, rhs)) as $unsigned_type; + // Largest multiple of range_len <= type::MAX is lowest if range_len * 2 > ux::MAX -> range_len >= ux::MAX / 2 + 1 + // Also = 0 in mod range_len arithmetic. + // Sub from this large number rhs_abs (same as sub -rhs = -(-rhs) = add rhs) to get rhs % range_len + // ix::MIN = -2^(n-1) so 0 <= rhs_abs <= 2^(n-1) + // ux::MAX / 2 + 1 = 2^(n-1) so this subtraction will always be a >= 0 after subtraction + // Thus converting rhs signed negative to equivalent positive value in mod range_len arithmetic + ((($unsigned_type::MAX / range_len) * range_len) - (rhs_abs)) % range_len + }; + + let greater_vals = MAX.abs_diff(inner); + // No wrap + if offset <= greater_vals { + // Safety: + // if inner >= 0 -> No overflow beyond range (offset <= greater_vals) + // if inner < 0: Same as >=0 with caveat: + // `(signed as unsigned).wrapping_add(unsigned) as signed` is the same as + // `signed::checked_add_unsigned(unsigned).unwrap()` or `wrapping_add_unsigned` + // (the difference doesn't matter since it won't overflow the signed type), + // but unsigned integers don't have either method so it won't compile that way. + unsafe { Self::new_unchecked( + ((inner as $unsigned_type).wrapping_add(offset)) as $internal + ) } + } + // Wrap + else { + // Safety: + // - offset < range_len by rem_euclid (MIN + ... safe) + // - offset > greater_values from if statement (offset - (greater_values + 1) safe) + // + // again using `(signed as unsigned).wrapping_add(unsigned) as signed` = `checked_add_unsigned` trick + unsafe { Self::new_unchecked( + ((MIN as $unsigned_type).wrapping_add( + offset - ((greater_vals + 1)) + )) as $internal + ) } + } + } + } + + impl<const MIN: $internal, const MAX: $internal> $optional_type<MIN, MAX> { + #[inline(always)] + pub const fn get_primitive(self) -> Option<$internal> { + <$type<MIN, MAX> as $crate::traits::RangeIsValid>::ASSERT; + Some(const_try_opt!(self.get()).get()) + } + + /// Returns `true` if the value is the niche value. + #[inline(always)] + pub const fn is_none(self) -> bool { + <$type<MIN, MAX> as $crate::traits::RangeIsValid>::ASSERT; + self.get().is_none() + } + + /// Returns `true` if the value is not the niche value. + #[inline(always)] + pub const fn is_some(self) -> bool { + <$type<MIN, MAX> as $crate::traits::RangeIsValid>::ASSERT; + self.get().is_some() + } + } + + impl<const MIN: $internal, const MAX: $internal> fmt::Debug for $type<MIN, MAX> { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + <Self as $crate::traits::RangeIsValid>::ASSERT; + self.get().fmt(f) + } + } + + impl<const MIN: $internal, const MAX: $internal> fmt::Debug for $optional_type<MIN, MAX> { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + <$type<MIN, MAX> as $crate::traits::RangeIsValid>::ASSERT; + self.get().fmt(f) + } + } + + impl<const MIN: $internal, const MAX: $internal> fmt::Display for $type<MIN, MAX> { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + <Self as $crate::traits::RangeIsValid>::ASSERT; + self.get().fmt(f) + } + } + + #[cfg(feature = "powerfmt")] + impl< + const MIN: $internal, + const MAX: $internal, + > smart_display::SmartDisplay for $type<MIN, MAX> { + type Metadata = <$internal as smart_display::SmartDisplay>::Metadata; + + #[inline(always)] + fn metadata( + &self, + f: smart_display::FormatterOptions, + ) -> smart_display::Metadata<'_, Self> { + <Self as $crate::traits::RangeIsValid>::ASSERT; + self.get_ref().metadata(f).reuse() + } + + #[inline(always)] + fn fmt_with_metadata( + &self, + f: &mut fmt::Formatter<'_>, + metadata: smart_display::Metadata<'_, Self>, + ) -> fmt::Result { + <Self as $crate::traits::RangeIsValid>::ASSERT; + self.get().fmt_with_metadata(f, metadata.reuse()) + } + } + + impl<const MIN: $internal, const MAX: $internal> Default for $optional_type<MIN, MAX> { + #[inline(always)] + fn default() -> Self { + <$type<MIN, MAX> as $crate::traits::RangeIsValid>::ASSERT; + Self::None + } + } + + impl<const MIN: $internal, const MAX: $internal> AsRef<$internal> for $type<MIN, MAX> { + #[inline(always)] + fn as_ref(&self) -> &$internal { + <Self as $crate::traits::RangeIsValid>::ASSERT; + &self.get_ref() + } + } + + impl<const MIN: $internal, const MAX: $internal> Borrow<$internal> for $type<MIN, MAX> { + #[inline(always)] + fn borrow(&self) -> &$internal { + <Self as $crate::traits::RangeIsValid>::ASSERT; + &self.get_ref() + } + } + + impl< + const MIN_A: $internal, + const MAX_A: $internal, + const MIN_B: $internal, + const MAX_B: $internal, + > PartialEq<$type<MIN_B, MAX_B>> for $type<MIN_A, MAX_A> { + #[inline(always)] + fn eq(&self, other: &$type<MIN_B, MAX_B>) -> bool { + <Self as $crate::traits::RangeIsValid>::ASSERT; + <$type<MIN_B, MAX_B> as $crate::traits::RangeIsValid>::ASSERT; + self.get() == other.get() + } + } + + impl< + const MIN_A: $internal, + const MAX_A: $internal, + const MIN_B: $internal, + const MAX_B: $internal, + > PartialEq<$optional_type<MIN_B, MAX_B>> for $optional_type<MIN_A, MAX_A> { + #[inline(always)] + fn eq(&self, other: &$optional_type<MIN_B, MAX_B>) -> bool { + <$type<MIN_A, MAX_A> as $crate::traits::RangeIsValid>::ASSERT; + <$type<MIN_B, MAX_B> as $crate::traits::RangeIsValid>::ASSERT; + self.inner() == other.inner() + } + } + + impl< + const MIN_A: $internal, + const MAX_A: $internal, + const MIN_B: $internal, + const MAX_B: $internal, + > PartialOrd<$type<MIN_B, MAX_B>> for $type<MIN_A, MAX_A> { + #[inline(always)] + fn partial_cmp(&self, other: &$type<MIN_B, MAX_B>) -> Option<Ordering> { + <Self as $crate::traits::RangeIsValid>::ASSERT; + <$type<MIN_B, MAX_B> as $crate::traits::RangeIsValid>::ASSERT; + self.get().partial_cmp(&other.get()) + } + } + + impl< + const MIN_A: $internal, + const MAX_A: $internal, + const MIN_B: $internal, + const MAX_B: $internal, + > PartialOrd<$optional_type<MIN_B, MAX_B>> for $optional_type<MIN_A, MAX_A> { + #[inline] + fn partial_cmp(&self, other: &$optional_type<MIN_B, MAX_B>) -> Option<Ordering> { + <$type<MIN_A, MAX_A> as $crate::traits::RangeIsValid>::ASSERT; + <$type<MIN_B, MAX_B> as $crate::traits::RangeIsValid>::ASSERT; + if self.is_none() && other.is_none() { + Some(Ordering::Equal) + } else if self.is_none() { + Some(Ordering::Less) + } else if other.is_none() { + Some(Ordering::Greater) + } else { + self.inner().partial_cmp(&other.inner()) + } + } + } + + impl< + const MIN: $internal, + const MAX: $internal, + > Ord for $optional_type<MIN, MAX> { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + <$type<MIN, MAX> as $crate::traits::RangeIsValid>::ASSERT; + if self.is_none() && other.is_none() { + Ordering::Equal + } else if self.is_none() { + Ordering::Less + } else if other.is_none() { + Ordering::Greater + } else { + self.inner().cmp(&other.inner()) + } + } + } + + impl<const MIN: $internal, const MAX: $internal> fmt::Binary for $type<MIN, MAX> { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + <Self as $crate::traits::RangeIsValid>::ASSERT; + self.get().fmt(f) + } + } + + impl<const MIN: $internal, const MAX: $internal> fmt::LowerHex for $type<MIN, MAX> { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + <Self as $crate::traits::RangeIsValid>::ASSERT; + self.get().fmt(f) + } + } + + impl<const MIN: $internal, const MAX: $internal> fmt::UpperHex for $type<MIN, MAX> { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + <Self as $crate::traits::RangeIsValid>::ASSERT; + self.get().fmt(f) + } + } + + impl<const MIN: $internal, const MAX: $internal> fmt::LowerExp for $type<MIN, MAX> { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + <Self as $crate::traits::RangeIsValid>::ASSERT; + self.get().fmt(f) + } + } + + impl<const MIN: $internal, const MAX: $internal> fmt::UpperExp for $type<MIN, MAX> { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + <Self as $crate::traits::RangeIsValid>::ASSERT; + self.get().fmt(f) + } + } + + impl<const MIN: $internal, const MAX: $internal> fmt::Octal for $type<MIN, MAX> { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + <Self as $crate::traits::RangeIsValid>::ASSERT; + self.get().fmt(f) + } + } + + impl<const MIN: $internal, const MAX: $internal> From<$type<MIN, MAX>> for $internal { + #[inline(always)] + fn from(value: $type<MIN, MAX>) -> Self { + <$type<MIN, MAX> as $crate::traits::RangeIsValid>::ASSERT; + value.get() + } + } + + impl< + const MIN: $internal, + const MAX: $internal, + > From<$type<MIN, MAX>> for $optional_type<MIN, MAX> { + #[inline(always)] + fn from(value: $type<MIN, MAX>) -> Self { + <$type<MIN, MAX> as $crate::traits::RangeIsValid>::ASSERT; + Self::Some(value) + } + } + + impl< + const MIN: $internal, + const MAX: $internal, + > From<Option<$type<MIN, MAX>>> for $optional_type<MIN, MAX> { + #[inline(always)] + fn from(value: Option<$type<MIN, MAX>>) -> Self { + <$type<MIN, MAX> as $crate::traits::RangeIsValid>::ASSERT; + match value { + Some(value) => Self::Some(value), + None => Self::None, + } + } + } + + impl< + const MIN: $internal, + const MAX: $internal, + > From<$optional_type<MIN, MAX>> for Option<$type<MIN, MAX>> { + #[inline(always)] + fn from(value: $optional_type<MIN, MAX>) -> Self { + <$type<MIN, MAX> as $crate::traits::RangeIsValid>::ASSERT; + value.get() + } + } + + impl<const MIN: $internal, const MAX: $internal> TryFrom<$internal> for $type<MIN, MAX> { + type Error = TryFromIntError; + + #[inline] + fn try_from(value: $internal) -> Result<Self, Self::Error> { + <Self as $crate::traits::RangeIsValid>::ASSERT; + Self::new(value).ok_or(TryFromIntError) + } + } + + impl<const MIN: $internal, const MAX: $internal> FromStr for $type<MIN, MAX> { + type Err = ParseIntError; + + #[inline] + fn from_str(s: &str) -> Result<Self, Self::Err> { + <Self as $crate::traits::RangeIsValid>::ASSERT; + let value = s.parse::<$internal>().map_err(|e| ParseIntError { + kind: e.kind().clone() + })?; + if value < MIN { + Err(ParseIntError { kind: IntErrorKind::NegOverflow }) + } else if value > MAX { + Err(ParseIntError { kind: IntErrorKind::PosOverflow }) + } else { + // Safety: The value was previously checked for validity. + Ok(unsafe { Self::new_unchecked(value) }) + } + } + } + + #[cfg(feature = "serde")] + impl<const MIN: $internal, const MAX: $internal> serde::Serialize for $type<MIN, MAX> { + #[inline(always)] + fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { + <Self as $crate::traits::RangeIsValid>::ASSERT; + self.get().serialize(serializer) + } + } + + #[cfg(feature = "serde")] + impl< + const MIN: $internal, + const MAX: $internal, + > serde::Serialize for $optional_type<MIN, MAX> { + #[inline(always)] + fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { + <$type<MIN, MAX> as $crate::traits::RangeIsValid>::ASSERT; + self.get().serialize(serializer) + } + } + + #[cfg(feature = "serde")] + impl< + 'de, + const MIN: $internal, + const MAX: $internal, + > serde::Deserialize<'de> for $type<MIN, MAX> { + #[inline] + fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { + <Self as $crate::traits::RangeIsValid>::ASSERT; + let internal = <$internal>::deserialize(deserializer)?; + Self::new(internal).ok_or_else(|| <D::Error as serde::de::Error>::invalid_value( + serde::de::Unexpected::Other("integer"), + #[cfg(feature = "std")] { + &format!("an integer in the range {}..={}", MIN, MAX).as_ref() + }, + #[cfg(not(feature = "std"))] { + &"an integer in the valid range" + } + )) + } + } + + #[cfg(feature = "serde")] + impl< + 'de, + const MIN: $internal, + const MAX: $internal, + > serde::Deserialize<'de> for $optional_type<MIN, MAX> { + #[inline] + fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { + <$type<MIN, MAX> as $crate::traits::RangeIsValid>::ASSERT; + Ok(Self::Some($type::<MIN, MAX>::deserialize(deserializer)?)) + } + } + + #[cfg(feature = "rand")] + impl< + const MIN: $internal, + const MAX: $internal, + > rand::distributions::Distribution<$type<MIN, MAX>> for rand::distributions::Standard { + #[inline] + fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> $type<MIN, MAX> { + <$type<MIN, MAX> as $crate::traits::RangeIsValid>::ASSERT; + $type::new(rng.gen_range(MIN..=MAX)).expect("rand failed to generate a valid value") + } + } + + #[cfg(feature = "rand")] + impl< + const MIN: $internal, + const MAX: $internal, + > rand::distributions::Distribution<$optional_type<MIN, MAX>> + for rand::distributions::Standard { + #[inline] + fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> $optional_type<MIN, MAX> { + <$type<MIN, MAX> as $crate::traits::RangeIsValid>::ASSERT; + rng.gen::<Option<$type<MIN, MAX>>>().into() + } + } + + #[cfg(feature = "num")] + impl<const MIN: $internal, const MAX: $internal> num_traits::Bounded for $type<MIN, MAX> { + #[inline(always)] + fn min_value() -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + Self::MIN + } + + #[inline(always)] + fn max_value() -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + Self::MAX + } + } + + #[cfg(feature = "quickcheck")] + impl<const MIN: $internal, const MAX: $internal> quickcheck::Arbitrary for $type<MIN, MAX> { + #[inline] + fn arbitrary(g: &mut quickcheck::Gen) -> Self { + <Self as $crate::traits::RangeIsValid>::ASSERT; + // Safety: The `rem_euclid` call and addition ensure that the value is in range. + unsafe { + Self::new_unchecked($internal::arbitrary(g).rem_euclid(MAX - MIN + 1) + MIN) + } + } + + #[inline] + fn shrink(&self) -> ::alloc::boxed::Box<dyn Iterator<Item = Self>> { + ::alloc::boxed::Box::new( + self.get() + .shrink() + .filter_map(Self::new) + ) + } + } + + #[cfg(feature = "quickcheck")] + impl< + const MIN: $internal, + const MAX: $internal, + > quickcheck::Arbitrary for $optional_type<MIN, MAX> { + #[inline] + fn arbitrary(g: &mut quickcheck::Gen) -> Self { + <$type<MIN, MAX> as $crate::traits::RangeIsValid>::ASSERT; + Option::<$type<MIN, MAX>>::arbitrary(g).into() + } + + #[inline] + fn shrink(&self) -> ::alloc::boxed::Box<dyn Iterator<Item = Self>> { + ::alloc::boxed::Box::new(self.get().shrink().map(Self::from)) + } + } + )*}; +} + +impl_ranged! { + RangedU8 { + mod_name: ranged_u8 + internal: u8 + signed: false + unsigned: u8 + optional: OptionRangedU8 + } + RangedU16 { + mod_name: ranged_u16 + internal: u16 + signed: false + unsigned: u16 + optional: OptionRangedU16 + } + RangedU32 { + mod_name: ranged_u32 + internal: u32 + signed: false + unsigned: u32 + optional: OptionRangedU32 + } + RangedU64 { + mod_name: ranged_u64 + internal: u64 + signed: false + unsigned: u64 + optional: OptionRangedU64 + } + RangedU128 { + mod_name: ranged_u128 + internal: u128 + signed: false + unsigned: u128 + optional: OptionRangedU128 + } + RangedUsize { + mod_name: ranged_usize + internal: usize + signed: false + unsigned: usize + optional: OptionRangedUsize + } + RangedI8 { + mod_name: ranged_i8 + internal: i8 + signed: true + unsigned: u8 + optional: OptionRangedI8 + } + RangedI16 { + mod_name: ranged_i16 + internal: i16 + signed: true + unsigned: u16 + optional: OptionRangedI16 + } + RangedI32 { + mod_name: ranged_i32 + internal: i32 + signed: true + unsigned: u32 + optional: OptionRangedI32 + } + RangedI64 { + mod_name: ranged_i64 + internal: i64 + signed: true + unsigned: u64 + optional: OptionRangedI64 + } + RangedI128 { + mod_name: ranged_i128 + internal: i128 + signed: true + unsigned: u128 + optional: OptionRangedI128 + } + RangedIsize { + mod_name: ranged_isize + internal: isize + signed: true + unsigned: usize + optional: OptionRangedIsize + } +} diff --git a/vendor/deranged/src/tests.rs b/vendor/deranged/src/tests.rs new file mode 100644 index 0000000..b48615f --- /dev/null +++ b/vendor/deranged/src/tests.rs @@ -0,0 +1,643 @@ +use std::hash::Hash; + +use crate::{ + IntErrorKind, OptionRangedI128, OptionRangedI16, OptionRangedI32, OptionRangedI64, + OptionRangedI8, OptionRangedIsize, OptionRangedU128, OptionRangedU16, OptionRangedU32, + OptionRangedU64, OptionRangedU8, OptionRangedUsize, ParseIntError, RangedI128, RangedI16, + RangedI32, RangedI64, RangedI8, RangedIsize, RangedU128, RangedU16, RangedU32, RangedU64, + RangedU8, RangedUsize, TryFromIntError, +}; + +macro_rules! if_signed { + (signed $($x:tt)*) => { $($x)*}; + (unsigned $($x:tt)*) => {}; +} + +#[test] +fn errors() { + assert_eq!( + TryFromIntError.to_string(), + "out of range integral type conversion attempted" + ); + assert_eq!(TryFromIntError.clone(), TryFromIntError); + assert_eq!(format!("{TryFromIntError:?}"), "TryFromIntError"); + + assert_eq!( + ParseIntError { + kind: IntErrorKind::Empty, + } + .to_string(), + "cannot parse integer from empty string" + ); + assert_eq!( + ParseIntError { + kind: IntErrorKind::InvalidDigit, + } + .to_string(), + "invalid digit found in string" + ); + assert_eq!( + ParseIntError { + kind: IntErrorKind::PosOverflow, + } + .to_string(), + "number too large to fit in target type" + ); + assert_eq!( + ParseIntError { + kind: IntErrorKind::NegOverflow, + } + .to_string(), + "number too small to fit in target type" + ); + assert_eq!( + ParseIntError { + kind: IntErrorKind::Zero, + } + .to_string(), + "number would be zero for non-zero type" + ); + assert_eq!( + format!( + "{:?}", + ParseIntError { + kind: IntErrorKind::Empty + } + ), + "ParseIntError { kind: Empty }" + ); + assert_eq!( + ParseIntError { + kind: IntErrorKind::Empty + } + .clone(), + ParseIntError { + kind: IntErrorKind::Empty + } + ); + assert_eq!( + ParseIntError { + kind: IntErrorKind::Empty + } + .kind(), + &IntErrorKind::Empty + ); +} + +macro_rules! tests { + ($($signed:ident $opt:ident $t:ident $inner:ident),* $(,)?) => { + #[test] + fn derives() {$( + assert_eq!($t::<5, 10>::MIN.clone(), $t::<5, 10>::MIN); + let mut hasher = std::collections::hash_map::DefaultHasher::new(); + $t::<5, 10>::MIN.hash(&mut hasher); + assert_eq!( + $t::<5, 10>::MIN.cmp(&$t::<5, 10>::MAX), + std::cmp::Ordering::Less + ); + + assert_eq!($opt::<5, 10>::None.clone(), $opt::<5, 10>::None); + $opt::<5, 10>::None.hash(&mut hasher); + )*} + + #[test] + fn expand() {$( + let expanded: $t::<0, 20> = $t::<5, 10>::MAX.expand(); + assert_eq!(expanded, $t::<0, 20>::new_static::<10>()); + )*} + + #[test] + fn narrow() {$( + let narrowed: Option<$t::<10, 20>> = $t::<0, 20>::new_static::<10>().narrow(); + assert_eq!(narrowed, Some($t::<10, 20>::MIN)); + )*} + + #[test] + fn new() {$( + assert!($t::<5, 10>::new(10).is_some()); + assert!($t::<5, 10>::new(11).is_none()); + )*} + + #[test] + fn new_static() {$( + let six: $t::<5, 10> = $t::<5, 10>::new_static::<6>(); + assert_eq!(Some(six), $t::<5, 10>::new(6)); + )*} + + #[test] + fn some_unchecked() {$( + // Safety: The value is in range. + unsafe { + assert_eq!($opt::<5, 10>::some_unchecked(10), $opt::Some($t::<5, 10>::MAX)); + } + )*} + + #[test] + fn is_some() {$( + assert!($opt::<5, 10>::Some($t::<5, 10>::MAX).is_some()); + )*} + + #[test] + fn is_none() {$( + assert!($opt::<5, 10>::None.is_none()); + )*} + + #[test] + fn default() {$( + assert_eq!($opt::<5, 10>::default(), $opt::<5, 10>::None); + )*} + + #[test] + fn get() {$( + assert_eq!($t::<5, 10>::MAX.get(), 10); + assert_eq!($opt::<5, 10>::None.get(), None); + assert_eq!($opt::Some($t::<5, 10>::MAX).get(), Some($t::<5, 10>::MAX)); + )*} + + #[test] + fn get_primitive() {$( + assert_eq!($opt::Some($t::<5, 10>::MAX).get_primitive(), Some(10)); + assert_eq!($opt::<5, 10>::None.get_primitive(), None); + )*} + + #[test] + fn get_ref() {$( + assert_eq!($t::<5, 10>::MAX.get_ref(), &10); + )*} + + #[test] + fn new_saturating() {$( + assert_eq!($t::<5, 10>::new_saturating(11), $t::<5, 10>::MAX); + assert_eq!($t::<5, 10>::new_saturating(0), $t::<5, 10>::MIN); + assert_eq!($t::<5, 10>::new_saturating(9), $t::<5, 10>::new_static::<9>()); + )*} + + #[test] + fn from_str_radix() {$( + assert_eq!($t::<5, 10>::from_str_radix("10", 10), Ok($t::<5, 10>::MAX)); + assert_eq!($t::<5, 10>::from_str_radix("5", 10), Ok($t::<5, 10>::MIN)); + assert_eq!( + $t::<5, 10>::from_str_radix("4", 10), + Err(ParseIntError { kind: IntErrorKind::NegOverflow }), + ); + assert_eq!( + $t::<5, 10>::from_str_radix("11", 10), + Err(ParseIntError { kind: IntErrorKind::PosOverflow }), + ); + assert_eq!( + $t::<5, 10>::from_str_radix("", 10), + Err(ParseIntError { kind: IntErrorKind::Empty }), + ); + )*} + + #[test] + fn checked_add() {$( + assert_eq!($t::<5, 10>::MAX.checked_add(1), None); + assert_eq!($t::<5, 10>::MAX.checked_add(0), Some($t::<5, 10>::MAX)); + )*} + + #[test] + fn unchecked_add() {$( + // Safety: The result is in range. + unsafe { + assert_eq!($t::<5, 10>::MIN.unchecked_add(5), $t::<5, 10>::MAX); + } + )*} + + #[test] + fn checked_sub() {$( + assert_eq!($t::<5, 10>::MIN.checked_sub(1), None); + assert_eq!($t::<5, 10>::MIN.checked_sub(0), Some($t::<5, 10>::MIN)); + )*} + + #[test] + fn unchecked_sub() {$( + // Safety: The result is in range. + unsafe { + assert_eq!($t::<5, 10>::MAX.unchecked_sub(5), $t::<5, 10>::MIN); + } + )*} + + #[test] + fn checked_mul() {$( + assert_eq!($t::<5, 10>::MAX.checked_mul(2), None); + assert_eq!($t::<5, 10>::MAX.checked_mul(1), Some($t::<5, 10>::MAX)); + )*} + + #[test] + fn unchecked_mul() {$( + // Safety: The result is in range. + unsafe { + assert_eq!($t::<5, 10>::MAX.unchecked_mul(1), $t::<5, 10>::MAX); + } + )*} + + #[test] + fn checked_div() {$( + assert_eq!($t::<5, 10>::MAX.checked_div(3), None); + assert_eq!($t::<5, 10>::MAX.checked_div(2), $t::<5, 10>::new(5)); + assert_eq!($t::<5, 10>::MAX.checked_div(1), Some($t::<5, 10>::MAX)); + assert_eq!($t::<5, 10>::MAX.checked_div(0), None); + )*} + + #[test] + fn unchecked_div() {$( + // Safety: The result is in range. + unsafe { + assert_eq!($t::<5, 10>::MAX.unchecked_div(1), $t::<5, 10>::MAX); + } + )*} + + #[test] + fn checked_div_euclid() {$( + assert_eq!($t::<5, 10>::MAX.checked_div_euclid(3), None); + assert_eq!($t::<5, 10>::MAX.checked_div_euclid(2), $t::<5, 10>::new(5)); + assert_eq!($t::<5, 10>::MAX.checked_div_euclid(1), Some($t::<5, 10>::MAX)); + assert_eq!($t::<5, 10>::MAX.checked_div_euclid(0), None); + )*} + + #[test] + fn unchecked_div_euclid() {$( + // Safety: The result is in range. + unsafe { + assert_eq!($t::<5, 10>::MAX.unchecked_div_euclid(1), $t::<5, 10>::MAX); + } + )*} + + #[test] + fn checked_rem() {$( + assert_eq!($t::<5, 10>::MAX.checked_rem(11), Some($t::<5, 10>::MAX)); + assert_eq!($t::<5, 10>::MAX.checked_rem(5), None); + )*} + + #[test] + fn unchecked_rem() {$( + // Safety: The result is in range. + unsafe { + assert_eq!($t::<5, 10>::MAX.unchecked_rem(11), $t::<5, 10>::MAX); + } + )*} + + #[test] + fn checked_rem_euclid() {$( + assert_eq!($t::<5, 10>::MAX.checked_rem_euclid(11), Some($t::<5, 10>::MAX)); + assert_eq!($t::<5, 10>::MAX.checked_rem_euclid(5), None); + )*} + + #[test] + fn unchecked_rem_euclid() {$( + // Safety: The result is in range. + unsafe { + assert_eq!($t::<5, 10>::MAX.unchecked_rem_euclid(11), $t::<5, 10>::MAX); + } + )*} + + #[test] + fn checked_neg() {$( + assert_eq!($t::<5, 10>::MIN.checked_neg(), None); + assert_eq!($t::<0, 10>::MIN.checked_neg(), Some($t::<0, 10>::MIN)); + )*} + + #[test] + fn unchecked_neg() {$( + // Safety: The result is in range. + unsafe { + assert_eq!($t::<0, 10>::MIN.unchecked_neg(), $t::<0, 10>::MIN); + } + )*} + + #[test] + fn neg() {$( if_signed! { $signed + assert_eq!($t::<-10, 10>::MIN.neg(), $t::<-10, 10>::MAX); + })*} + + #[test] + fn checked_shl() {$( + assert_eq!($t::<5, 10>::MAX.checked_shl(1), None); + assert_eq!($t::<5, 10>::MAX.checked_shl(0), Some($t::<5, 10>::MAX)); + assert_eq!($t::<5, 10>::MIN.checked_shl(1), Some($t::<5, 10>::MAX)); + )*} + + #[test] + fn unchecked_shl() {$( + // Safety: The result is in range. + unsafe { + assert_eq!($t::<5, 10>::MAX.unchecked_shl(0), $t::<5, 10>::MAX); + assert_eq!($t::<5, 10>::MIN.unchecked_shl(1), $t::<5, 10>::MAX); + } + )*} + + #[test] + fn checked_shr() {$( + assert_eq!($t::<5, 10>::MAX.checked_shr(2), None); + assert_eq!($t::<5, 10>::MAX.checked_shr(1), Some($t::<5, 10>::MIN)); + assert_eq!($t::<5, 10>::MAX.checked_shr(0), Some($t::<5, 10>::MAX)); + )*} + + #[test] + fn unchecked_shr() {$( + // Safety: The result is in range. + unsafe { + assert_eq!($t::<5, 10>::MAX.unchecked_shr(1), $t::<5, 10>::MIN); + assert_eq!($t::<5, 10>::MAX.unchecked_shr(0), $t::<5, 10>::MAX); + } + )*} + + #[test] + fn checked_abs() {$( if_signed! { $signed + assert_eq!($t::<5, 10>::MAX.checked_abs(), Some($t::<5, 10>::MAX)); + assert_eq!($t::<-10, 10>::MIN.checked_abs(), Some($t::<-10, 10>::MAX)); + assert_eq!($t::<-10, 0>::MIN.checked_abs(), None); + })*} + + #[test] + fn unchecked_abs() { $(if_signed! { $signed + // Safety: The result is in range. + unsafe { + assert_eq!($t::<5, 10>::MAX.unchecked_abs(), $t::<5, 10>::MAX); + assert_eq!($t::<-10, 10>::MIN.unchecked_abs(), $t::<-10, 10>::MAX); + } + })*} + + #[test] + fn abs() { $(if_signed! { $signed + assert_eq!($t::<-5, 10>::MIN.abs().get(), 5); + })*} + + #[test] + fn checked_pow() {$( + assert_eq!($t::<5, 10>::MAX.checked_pow(0), None); + assert_eq!($t::<5, 10>::MAX.checked_pow(1), Some($t::<5, 10>::MAX)); + assert_eq!($t::<5, 10>::MAX.checked_pow(2), None); + )*} + + #[test] + fn unchecked_pow() {$( + // Safety: The result is in range. + unsafe { + assert_eq!($t::<5, 10>::MAX.unchecked_pow(1), $t::<5, 10>::MAX); + } + )*} + + #[test] + fn saturating_add() {$( + assert_eq!($t::<5, 10>::MAX.saturating_add(0), $t::<5, 10>::MAX); + assert_eq!($t::<5, 10>::MAX.saturating_add(1), $t::<5, 10>::MAX); + )*} + + #[test] + fn wrapping_add() { + $( + assert_eq!($t::<5, 10>::MAX.wrapping_add(0), $t::<5, 10>::MAX); + assert_eq!($t::<5, 10>::MAX.wrapping_add(1), $t::<5, 10>::MIN); + assert_eq!($t::<{ $inner::MIN }, { $inner::MAX }>::MAX.wrapping_add(1), + $t::<{ $inner::MIN }, { $inner::MAX }>::MIN); + for i in 1..127 { + assert_eq!($t::<{ $inner::MIN}, { $inner::MAX - 1 }>::MAX.wrapping_add(i), + $t::<{ $inner::MIN}, { $inner::MAX - 1 }>::new($inner::MIN + i - 1).unwrap_or_else(|| panic!("adding {i}+{} does not yield {}", $inner::MIN, $inner::MAX + i ))); + } + )* + $(if_signed! { $signed + for i in 1..=127 { + assert_eq!($t::<-5, 126>::MIN.wrapping_add(-i), $t::<-5,126>::new(126-i+1).unwrap_or_else(|| panic!("adding {i}+{} does not yield {}", $inner::MIN, 126-i+1))); + assert_eq!($t::<-5, 126>::MIN.wrapping_add(i), $t::<-5,126>::new(-5+i).unwrap_or_else(|| panic!("adding {i}+{} does not yield {}", $inner::MIN, 126-i+1))); + } + for i in -127..=-1 { + assert_eq!($t::<-5, 126>::MIN.wrapping_add(i), $t::<-5,126>::new(126+i+1).unwrap_or_else(|| panic!("adding {i}+{} does not yield {}", $inner::MIN, 126-i+1))); + assert_eq!($t::<-5, 126>::MIN.wrapping_add(-i), $t::<-5,126>::new(-5-i).unwrap_or_else(|| panic!("adding {i}+{} does not yield {}", $inner::MIN, 126-i+1))); + } + assert_eq!($t::<-5, 126>::MIN.wrapping_add(-128), $t::<-5,126>::new(-1).unwrap_or_else(|| panic!("adding 128+{} does not yield -1", $inner::MIN))); + assert_eq!($t::<-5, 10>::MAX.wrapping_add(0), $t::<-5, 10>::MAX); + assert_eq!($t::<-5, -3>::MIN.wrapping_add(-1-3), $t::<-5, -3>::MAX); + assert_eq!($t::<-5, -3>::MIN.wrapping_add(-1-30), $t::<-5, -3>::MAX); + assert_eq!($t::<-5, -3>::MIN.wrapping_add(30), $t::<-5, -3>::MIN); + assert_eq!($t::<-5, -3>::MIN.wrapping_add(-30), $t::<-5, -3>::MIN); + assert_eq!($t::<-5, 10>::MAX.wrapping_add(25), $t::<-5, 10>::MIN.wrapping_add(24)); + assert_eq!($t::<-5, 10>::MIN.wrapping_add(24), $t::<-5, 10>::MIN.wrapping_add(8)); + assert_eq!($t::<-5, 10>::MAX.wrapping_add(1), $t::<-5, 10>::MIN); + assert_eq!($t::<-5, 10>::MIN.wrapping_add(-1), $t::<-5, 10>::MAX); + assert_eq!($t::<-5, 127>::MIN.wrapping_add(-1), $t::<-5, 127>::MAX); + assert_eq!($t::<-127, 126>::MIN.wrapping_add(-1), $t::<-127, 126>::MAX); + assert_eq!($t::<{ $inner::MIN }, { $inner::MAX }>::MIN.wrapping_add(-1), + $t::<{ $inner::MIN }, { $inner::MAX }>::MAX); + })* + } + + #[test] + fn saturating_sub() {$( + assert_eq!($t::<5, 10>::MIN.saturating_sub(0), $t::<5, 10>::MIN); + assert_eq!($t::<5, 10>::MIN.saturating_sub(1), $t::<5, 10>::MIN); + )*} + + #[test] + fn saturating_neg() {$(if_signed! { $signed + assert_eq!($t::<5, 10>::MIN.saturating_neg(), $t::<5, 10>::MIN); + assert_eq!($t::<5, 10>::MAX.saturating_neg(), $t::<5, 10>::MIN); + assert_eq!($t::<-10, 0>::MIN.saturating_neg(), $t::<-10, 0>::MAX); + assert_eq!($t::<-10, 0>::MAX.saturating_neg(), $t::<-10, 0>::MAX); + })*} + + #[test] + fn saturating_abs() {$(if_signed! { $signed + assert_eq!($t::<5, 10>::MIN.saturating_abs(), $t::<5, 10>::MIN); + assert_eq!($t::<5, 10>::MAX.saturating_abs(), $t::<5, 10>::MAX); + assert_eq!($t::<-10, 0>::MIN.saturating_abs(), $t::<-10, 0>::MAX); + assert_eq!($t::<-10, 0>::MAX.saturating_abs(), $t::<-10, 0>::MAX); + })*} + + #[test] + fn saturating_mul() {$( + assert_eq!($t::<5, 10>::MIN.saturating_mul(0), $t::<5, 10>::MIN); + assert_eq!($t::<5, 10>::MIN.saturating_mul(1), $t::<5, 10>::MIN); + assert_eq!($t::<5, 10>::MIN.saturating_mul(2), $t::<5, 10>::MAX); + assert_eq!($t::<5, 10>::MIN.saturating_mul(3), $t::<5, 10>::MAX); + )*} + + #[test] + fn saturating_pow() {$( + assert_eq!($t::<5, 10>::MIN.saturating_pow(0), $t::<5, 10>::MIN); + assert_eq!($t::<5, 10>::MIN.saturating_pow(1), $t::<5, 10>::MIN); + assert_eq!($t::<5, 10>::MIN.saturating_pow(2), $t::<5, 10>::MAX); + assert_eq!($t::<5, 10>::MIN.saturating_pow(3), $t::<5, 10>::MAX); + )*} + + #[test] + fn as_ref() {$( + assert_eq!($t::<5, 10>::MIN.as_ref(), &5); + assert_eq!($t::<5, 10>::MAX.as_ref(), &10); + )*} + + #[test] + fn borrow() { + use std::borrow::Borrow; + $( + assert_eq!(Borrow::<$inner>::borrow(&$t::<5, 10>::MIN), &5); + assert_eq!(Borrow::<$inner>::borrow(&$t::<5, 10>::MAX), &10); + )* + } + + #[test] + fn formatting() {$( + let val = $t::<5, 10>::MAX; + assert_eq!(format!("{}", val), "10"); + assert_eq!(format!("{:?}", val), "10"); + assert_eq!(format!("{:b}", val), "1010"); + assert_eq!(format!("{:o}", val), "12"); + assert_eq!(format!("{:x}", val), "a"); + assert_eq!(format!("{:X}", val), "A"); + assert_eq!(format!("{:e}", val), "1e1"); + assert_eq!(format!("{:E}", val), "1E1"); + + assert_eq!(format!("{:?}", $opt::Some($t::<5, 10>::MAX)), "Some(10)"); + assert_eq!(format!("{:?}", $opt::<5, 10>::None), "None"); + )*} + + #[test] + fn ord() {$( + assert!($t::<5, 10>::MIN < $t::<5, 10>::MAX); + assert!($t::<5, 10>::MIN <= $t::<5, 10>::MAX); + assert!($t::<5, 10>::MAX > $t::<5, 10>::MIN); + assert!($t::<5, 10>::MAX >= $t::<5, 10>::MIN); + + let none = $opt::<5, 10>::None; + let five = $opt::Some($t::<5, 10>::MIN); + let ten = $opt::Some($t::<5, 10>::MAX); + + assert_eq!(none.cmp(&none), std::cmp::Ordering::Equal); + assert_eq!(five.cmp(&five), std::cmp::Ordering::Equal); + assert_eq!(ten.cmp(&ten), std::cmp::Ordering::Equal); + assert_eq!(none.cmp(&five), std::cmp::Ordering::Less); + assert_eq!(five.cmp(&ten), std::cmp::Ordering::Less); + assert_eq!(none.cmp(&ten), std::cmp::Ordering::Less); + assert_eq!(ten.cmp(&none), std::cmp::Ordering::Greater); + + let none = $opt::<0, 10>::None; + let zero = $opt::Some($t::<0, 10>::MIN); + let ten = $opt::Some($t::<0, 10>::MAX); + + assert_eq!(none.partial_cmp(&none), Some(std::cmp::Ordering::Equal)); + assert_eq!(none.partial_cmp(&zero), Some(std::cmp::Ordering::Less)); + assert_eq!(zero.partial_cmp(&ten), Some(std::cmp::Ordering::Less)); + assert_eq!(none.partial_cmp(&ten), Some(std::cmp::Ordering::Less)); + assert_eq!(ten.partial_cmp(&none), Some(std::cmp::Ordering::Greater)); + )*} + + #[test] + fn from() {$( + assert_eq!($inner::from($t::<5, 10>::MAX), 10); + assert_eq!($inner::from($t::<5, 10>::MIN), 5); + + assert_eq!($opt::from($t::<5, 10>::MAX), $opt::Some($t::<5, 10>::MAX)); + assert_eq!($opt::from(Some($t::<5, 10>::MAX)), $opt::Some($t::<5, 10>::MAX)); + assert_eq!($opt::<5, 10>::from(None), $opt::<5, 10>::None); + assert_eq!(Option::from($opt::Some($t::<5, 10>::MAX)), Some($t::<5, 10>::MAX)); + assert_eq!(Option::<$t<5, 10>>::from($opt::<5, 10>::None), None); + )*} + + #[test] + fn try_from() {$( + assert_eq!($t::<5, 10>::try_from(10), Ok($t::<5, 10>::MAX)); + assert_eq!($t::<5, 10>::try_from(5), Ok($t::<5, 10>::MIN)); + assert_eq!($t::<5, 10>::try_from(4), Err(TryFromIntError)); + assert_eq!($t::<5, 10>::try_from(11), Err(TryFromIntError)); + )*} + + #[test] + fn from_str() {$( + assert_eq!("10".parse::<$t<5, 10>>(), Ok($t::<5, 10>::MAX)); + assert_eq!("5".parse::<$t<5, 10>>(), Ok($t::<5, 10>::MIN)); + assert_eq!("4".parse::<$t<5, 10>>(), Err(ParseIntError { kind: IntErrorKind::NegOverflow })); + assert_eq!("11".parse::<$t<5, 10>>(), Err(ParseIntError { kind: IntErrorKind::PosOverflow })); + assert_eq!("".parse::<$t<5, 10>>(), Err(ParseIntError { kind: IntErrorKind::Empty })); + )*} + + #[cfg(feature = "serde")] + #[test] + fn serde() -> serde_json::Result<()> { + $( + let val = $t::<5, 10>::MAX; + let serialized = serde_json::to_string(&val)?; + assert_eq!(serialized, "10"); + let deserialized: $t<5, 10> = serde_json::from_str(&serialized)?; + assert_eq!(deserialized, val); + + assert!(serde_json::from_str::<$t<5, 10>>("").is_err()); + assert!(serde_json::from_str::<$t<5, 10>>("4").is_err()); + assert!(serde_json::from_str::<$t<5, 10>>("11").is_err()); + + let val = $opt::<5, 10>::Some($t::<5, 10>::MAX); + let serialized = serde_json::to_string(&val)?; + assert_eq!(serialized, "10"); + let deserialized: $opt<5, 10> = serde_json::from_str(&serialized)?; + assert_eq!(deserialized, val); + + assert!(serde_json::from_str::<$opt<5, 10>>("").is_err()); + assert!(serde_json::from_str::<$opt<5, 10>>("4").is_err()); + assert!(serde_json::from_str::<$opt<5, 10>>("11").is_err()); + + let val = $opt::<5, 10>::None; + let serialized = serde_json::to_string(&val)?; + assert_eq!(serialized, "null"); + + assert!(serde_json::from_str::<$opt<5, 10>>("").is_err()); + assert!(serde_json::from_str::<$opt<5, 10>>("4").is_err()); + assert!(serde_json::from_str::<$opt<5, 10>>("11").is_err()); + )* + Ok(()) + } + + #[cfg(feature = "rand")] + #[test] + fn rand() {$( + let rand_val: $t<5, 10> = rand::random(); + assert!(rand_val >= $t::<5, 10>::MIN); + assert!(rand_val <= $t::<5, 10>::MAX); + + let rand: $opt<5, 10> = rand::random(); + if let Some(rand) = rand.get() { + assert!(rand >= $t::<5, 10>::MIN); + assert!(rand <= $t::<5, 10>::MAX); + } + )*} + + #[cfg(feature = "num")] + #[test] + fn num() {$( + assert_eq!(<$t<5, 10> as num_traits::Bounded>::min_value(), $t::<5, 10>::MIN); + assert_eq!(<$t<5, 10> as num_traits::Bounded>::max_value(), $t::<5, 10>::MAX); + )*} + + #[cfg(feature = "quickcheck")] + #[test] + fn quickcheck() {$( + #[allow(trivial_casts)] + quickcheck::quickcheck((|val| { + val >= $t::<5, 10>::MIN && val <= $t::<5, 10>::MAX + }) as fn($t<5, 10>) -> bool); + + #[allow(trivial_casts)] + quickcheck::quickcheck((|val| { + if let Some(val) = val.get() { + val >= $t::<5, 10>::MIN && val <= $t::<5, 10>::MAX + } else { + true + } + }) as fn($opt<5, 10>) -> bool); + )*} + }; +} + +tests![ + signed OptionRangedI8 RangedI8 i8, + signed OptionRangedI16 RangedI16 i16, + signed OptionRangedI32 RangedI32 i32, + signed OptionRangedI64 RangedI64 i64, + signed OptionRangedI128 RangedI128 i128, + signed OptionRangedIsize RangedIsize isize, + unsigned OptionRangedU8 RangedU8 u8, + unsigned OptionRangedU16 RangedU16 u16, + unsigned OptionRangedU32 RangedU32 u32, + unsigned OptionRangedU64 RangedU64 u64, + unsigned OptionRangedU128 RangedU128 u128, + unsigned OptionRangedUsize RangedUsize usize, +]; diff --git a/vendor/deranged/src/traits.rs b/vendor/deranged/src/traits.rs new file mode 100644 index 0000000..d1b69ac --- /dev/null +++ b/vendor/deranged/src/traits.rs @@ -0,0 +1,117 @@ +use crate::{ + RangedI128, RangedI16, RangedI32, RangedI64, RangedI8, RangedIsize, RangedU128, RangedU16, + RangedU32, RangedU64, RangedU8, RangedUsize, +}; + +macro_rules! declare_traits { + ($($trait_name:ident),* $(,)?) => {$( + pub(crate) trait $trait_name { + const ASSERT: (); + } + )*}; +} + +macro_rules! impl_traits_for_all { + ($($ranged_ty:ident $inner_ty:ident),* $(,)?) => {$( + impl<const MIN: $inner_ty, const MAX: $inner_ty> RangeIsValid for $ranged_ty<MIN, MAX> { + const ASSERT: () = assert!(MIN <= MAX); + } + + impl< + const CURRENT_MIN: $inner_ty, + const CURRENT_MAX: $inner_ty, + const NEW_MIN: $inner_ty, + const NEW_MAX: $inner_ty, + > ExpandIsValid for ($ranged_ty<CURRENT_MIN, CURRENT_MAX>, $ranged_ty<NEW_MIN, NEW_MAX>) { + const ASSERT: () = { + assert!(NEW_MIN <= CURRENT_MIN); + assert!(NEW_MAX >= CURRENT_MAX); + }; + } + + impl< + const CURRENT_MIN: $inner_ty, + const CURRENT_MAX: $inner_ty, + const NEW_MIN: $inner_ty, + const NEW_MAX: $inner_ty, + > NarrowIsValid for ($ranged_ty<CURRENT_MIN, CURRENT_MAX>, $ranged_ty<NEW_MIN, NEW_MAX>) { + const ASSERT: () = { + assert!(NEW_MIN >= CURRENT_MIN); + assert!(NEW_MAX <= CURRENT_MAX); + }; + } + + impl< + const VALUE: $inner_ty, + const MIN: $inner_ty, + const MAX: $inner_ty, + > StaticIsValid for ($ranged_ty<MIN, VALUE>, $ranged_ty<VALUE, MAX>) { + const ASSERT: () = { + assert!(VALUE >= MIN); + assert!(VALUE <= MAX); + }; + } + )*}; +} + +macro_rules! impl_traits_for_signed { + ($($ranged_ty:ident $inner_ty:ident),* $(,)?) => {$( + impl<const MIN: $inner_ty, const MAX: $inner_ty> AbsIsSafe for $ranged_ty<MIN, MAX> { + const ASSERT: () = { + assert!(MIN != <$inner_ty>::MIN); + assert!(-MIN <= MAX); + }; + } + + impl<const MIN: $inner_ty, const MAX: $inner_ty> NegIsSafe for $ranged_ty<MIN, MAX> { + const ASSERT: () = { + assert!(MIN != <$inner_ty>::MIN); + assert!(-MIN <= MAX); + assert!(-MAX >= MIN); + }; + } + + impl_traits_for_all!($ranged_ty $inner_ty); + )*}; +} + +macro_rules! impl_traits_for_unsigned { + ($($ranged_ty:ident $inner_ty:ident),* $(,)?) => {$( + impl<const MIN: $inner_ty, const MAX: $inner_ty> AbsIsSafe for $ranged_ty<MIN, MAX> { + const ASSERT: () = (); + } + + impl<const MIN: $inner_ty, const MAX: $inner_ty> NegIsSafe for $ranged_ty<MIN, MAX> { + const ASSERT: () = assert!(MAX == 0); + } + + impl_traits_for_all!($ranged_ty $inner_ty); + )*}; +} + +declare_traits![ + RangeIsValid, + AbsIsSafe, + NegIsSafe, + ExpandIsValid, + NarrowIsValid, + StaticIsValid, +]; + +impl_traits_for_signed! { + RangedI8 i8, + RangedI16 i16, + RangedI32 i32, + RangedI64 i64, + RangedI128 i128, + RangedIsize isize, +} + +impl_traits_for_unsigned! { + RangedU8 u8, + RangedU16 u16, + RangedU32 u32, + RangedU64 u64, + RangedU128 u128, + RangedUsize usize, +} |