From 22ce2dcc4b699ff4d89390efc1f71f7dcb9e45b1 Mon Sep 17 00:00:00 2001 From: Andrea Corradi Date: Thu, 29 Aug 2024 18:23:12 +0200 Subject: [PATCH 1/8] Implement Bounded for NonZero* --- src/bounds.rs | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/src/bounds.rs b/src/bounds.rs index acc990ea..d399cb0b 100644 --- a/src/bounds.rs +++ b/src/bounds.rs @@ -1,4 +1,8 @@ use core::num::Wrapping; +use core::num::{ + NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, + NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, +}; use core::{f32, f64}; use core::{i128, i16, i32, i64, i8, isize}; use core::{u128, u16, u32, u64, u8, usize}; @@ -68,6 +72,49 @@ bounded_impl!(i32, i32::MIN, i32::MAX); bounded_impl!(i64, i64::MIN, i64::MAX); bounded_impl!(i128, i128::MIN, i128::MAX); +macro_rules! bounded_impl_nonzero_const { + ($t:ty, $v:expr, $i:ident) => { + const $i: $t = { + let arr = [$v]; + let idx = if $v != 0 { 0 } else { 1 }; + + unsafe { <$t>::new_unchecked(arr[idx]) } + }; + }; +} + +macro_rules! bounded_impl_nonzero { + ($t:ty, $min:expr, $max:expr) => { + impl Bounded for $t { + #[inline] + fn min_value() -> $t { + bounded_impl_nonzero_const!($t, $min, MIN); + MIN + } + + #[inline] + fn max_value() -> $t { + bounded_impl_nonzero_const!($t, $max, MAX); + MAX + } + } + }; +} + +bounded_impl_nonzero!(NonZeroUsize, 1, usize::MAX); +bounded_impl_nonzero!(NonZeroU8, 1, u8::MAX); +bounded_impl_nonzero!(NonZeroU16, 1, u16::MAX); +bounded_impl_nonzero!(NonZeroU32, 1, u32::MAX); +bounded_impl_nonzero!(NonZeroU64, 1, u64::MAX); +bounded_impl_nonzero!(NonZeroU128, 1, u128::MAX); + +bounded_impl_nonzero!(NonZeroIsize, isize::MIN, isize::MAX); +bounded_impl_nonzero!(NonZeroI8, i8::MIN, i8::MAX); +bounded_impl_nonzero!(NonZeroI16, i16::MIN, i16::MAX); +bounded_impl_nonzero!(NonZeroI32, i32::MIN, i32::MAX); +bounded_impl_nonzero!(NonZeroI64, i64::MIN, i64::MAX); +bounded_impl_nonzero!(NonZeroI128, i128::MIN, i128::MAX); + impl Bounded for Wrapping { fn min_value() -> Self { Wrapping(T::min_value()) @@ -146,3 +193,37 @@ fn wrapping_is_bounded() { require_bounded(&Wrapping(42_u32)); require_bounded(&Wrapping(-42)); } + +#[test] +fn bounded_unsigned_nonzero() { + macro_rules! test_bounded_impl_unsigned_nonzero { + ($t:ty, $base_ty:ty) => { + assert_eq!(<$t as Bounded>::min_value().get(), 1); + assert_eq!(<$t as Bounded>::max_value().get(), <$base_ty>::MAX); + }; + } + + test_bounded_impl_unsigned_nonzero!(NonZeroUsize, usize); + test_bounded_impl_unsigned_nonzero!(NonZeroU8, u8); + test_bounded_impl_unsigned_nonzero!(NonZeroU16, u16); + test_bounded_impl_unsigned_nonzero!(NonZeroU32, u32); + test_bounded_impl_unsigned_nonzero!(NonZeroU64, u64); + test_bounded_impl_unsigned_nonzero!(NonZeroU128, u128); +} + +#[test] +fn bounded_signed_nonzero() { + macro_rules! test_bounded_impl_signed_nonzero { + ($t:ty, $base_ty:ty) => { + assert_eq!(<$t as Bounded>::min_value().get(), <$base_ty>::MIN); + assert_eq!(<$t as Bounded>::max_value().get(), <$base_ty>::MAX); + }; + } + + test_bounded_impl_signed_nonzero!(NonZeroIsize, isize); + test_bounded_impl_signed_nonzero!(NonZeroI8, i8); + test_bounded_impl_signed_nonzero!(NonZeroI16, i16); + test_bounded_impl_signed_nonzero!(NonZeroI32, i32); + test_bounded_impl_signed_nonzero!(NonZeroI64, i64); + test_bounded_impl_signed_nonzero!(NonZeroI128, i128); +} From 2b9af3dc383635e4c0f51f6adfdbd1bf9ce569de Mon Sep 17 00:00:00 2001 From: Andrea Corradi Date: Thu, 29 Aug 2024 19:22:21 +0200 Subject: [PATCH 2/8] Implement ToPrimitive for NonZero* --- src/cast.rs | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/cast.rs b/src/cast.rs index a3e4dd8b..7d4ada7f 100644 --- a/src/cast.rs +++ b/src/cast.rs @@ -1,5 +1,9 @@ use core::mem::size_of; use core::num::Wrapping; +use core::num::{ + NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, + NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, +}; use core::{f32, f64}; use core::{i128, i16, i32, i64, i8, isize}; use core::{u128, u16, u32, u64, u8, usize}; @@ -266,6 +270,61 @@ impl_to_primitive_uint!(u32); impl_to_primitive_uint!(u64); impl_to_primitive_uint!(u128); +macro_rules! impl_to_primitive_nonzero_to_method { + ($SrcT:ident : $( $(#[$cfg:meta])* fn $method:ident -> $DstT:ident ; )*) => {$( + #[inline] + $(#[$cfg])* + fn $method(&self) -> Option<$DstT> { + self.get().$method() + } + )*} +} + +macro_rules! impl_to_primitive_nonzero { + ($T:ident) => { + impl ToPrimitive for $T { + impl_to_primitive_nonzero_to_method! { $T: + fn to_isize -> isize; + fn to_i8 -> i8; + fn to_i16 -> i16; + fn to_i32 -> i32; + fn to_i64 -> i64; + fn to_i128 -> i128; + + fn to_usize -> usize; + fn to_u8 -> u8; + fn to_u16 -> u16; + fn to_u32 -> u32; + fn to_u64 -> u64; + fn to_u128 -> u128; + } + + #[inline] + fn to_f32(&self) -> Option { + Some(self.get() as f32) + } + #[inline] + fn to_f64(&self) -> Option { + Some(self.get() as f64) + } + } + }; +} + +impl_to_primitive_nonzero!(NonZeroUsize); +impl_to_primitive_nonzero!(NonZeroU8); +impl_to_primitive_nonzero!(NonZeroU16); +impl_to_primitive_nonzero!(NonZeroU32); +impl_to_primitive_nonzero!(NonZeroU64); +impl_to_primitive_nonzero!(NonZeroU128); + +impl_to_primitive_nonzero!(NonZeroIsize); +impl_to_primitive_nonzero!(NonZeroI8); +impl_to_primitive_nonzero!(NonZeroI16); +impl_to_primitive_nonzero!(NonZeroI32); +impl_to_primitive_nonzero!(NonZeroI64); +impl_to_primitive_nonzero!(NonZeroI128); + macro_rules! impl_to_primitive_float_to_float { ($SrcT:ident : $( fn $method:ident -> $DstT:ident ; )*) => {$( #[inline] From 397037d7c8a5a0ee9fd09dd1839e7ae2e5119c01 Mon Sep 17 00:00:00 2001 From: Andrea Corradi Date: Thu, 29 Aug 2024 19:42:26 +0200 Subject: [PATCH 3/8] Implement NumCast for NonZero* --- src/cast.rs | 28 ++++++ tests/cast.rs | 231 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 259 insertions(+) diff --git a/src/cast.rs b/src/cast.rs index 7d4ada7f..76116bdc 100644 --- a/src/cast.rs +++ b/src/cast.rs @@ -754,6 +754,34 @@ impl_num_cast!(isize, to_isize); impl_num_cast!(f32, to_f32); impl_num_cast!(f64, to_f64); +macro_rules! impl_num_cast_nonzero { + ($T:ty, $conv:ident) => { + impl NumCast for $T { + #[inline] + #[allow(deprecated)] + fn from(n: N) -> Option<$T> { + // `$conv` could be generated using `concat_idents!`, but that + // macro seems to be broken at the moment + n.$conv().and_then(Self::new) + } + } + }; +} + +impl_num_cast_nonzero!(NonZeroUsize, to_usize); +impl_num_cast_nonzero!(NonZeroU8, to_u8); +impl_num_cast_nonzero!(NonZeroU16, to_u16); +impl_num_cast_nonzero!(NonZeroU32, to_u32); +impl_num_cast_nonzero!(NonZeroU64, to_u64); +impl_num_cast_nonzero!(NonZeroU128, to_u128); + +impl_num_cast_nonzero!(NonZeroIsize, to_isize); +impl_num_cast_nonzero!(NonZeroI8, to_i8); +impl_num_cast_nonzero!(NonZeroI16, to_i16); +impl_num_cast_nonzero!(NonZeroI32, to_i32); +impl_num_cast_nonzero!(NonZeroI64, to_i64); +impl_num_cast_nonzero!(NonZeroI128, to_i128); + impl NumCast for Wrapping { fn from(n: U) -> Option { T::from(n).map(Wrapping) diff --git a/tests/cast.rs b/tests/cast.rs index 4f01d749..a8ac546e 100644 --- a/tests/cast.rs +++ b/tests/cast.rs @@ -5,6 +5,10 @@ use num_traits::cast::*; use num_traits::Bounded; +use core::num::{ + NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, + NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, +}; use core::{f32, f64}; use core::{i128, i16, i32, i64, i8, isize}; use core::{u128, u16, u32, u64, u8, usize}; @@ -101,17 +105,50 @@ fn cast_to_int_checks_overflow() { assert_eq!(None, cast::(big_f)); assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(Some(normal_f as isize), cast::(normal_f)); assert_eq!(Some(normal_f as i8), cast::(normal_f)); assert_eq!(Some(normal_f as i16), cast::(normal_f)); assert_eq!(Some(normal_f as i32), cast::(normal_f)); assert_eq!(Some(normal_f as i64), cast::(normal_f)); + assert_eq!( + NonZeroIsize::new(normal_f as isize), + cast::(normal_f) + ); + assert_eq!( + NonZeroI8::new(normal_f as i8), + cast::(normal_f) + ); + assert_eq!( + NonZeroI16::new(normal_f as i16), + cast::(normal_f) + ); + assert_eq!( + NonZeroI32::new(normal_f as i32), + cast::(normal_f) + ); + assert_eq!( + NonZeroI64::new(normal_f as i64), + cast::(normal_f) + ); + assert_eq!(None, cast::(small_f)); assert_eq!(None, cast::(small_f)); assert_eq!(None, cast::(small_f)); assert_eq!(None, cast::(small_f)); assert_eq!(None, cast::(small_f)); + + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); } #[test] @@ -125,17 +162,50 @@ fn cast_to_unsigned_int_checks_overflow() { assert_eq!(None, cast::(big_f)); assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(Some(normal_f as usize), cast::(normal_f)); assert_eq!(Some(normal_f as u8), cast::(normal_f)); assert_eq!(Some(normal_f as u16), cast::(normal_f)); assert_eq!(Some(normal_f as u32), cast::(normal_f)); assert_eq!(Some(normal_f as u64), cast::(normal_f)); + assert_eq!( + NonZeroUsize::new(normal_f as usize), + cast::(normal_f) + ); + assert_eq!( + NonZeroU8::new(normal_f as u8), + cast::(normal_f) + ); + assert_eq!( + NonZeroU16::new(normal_f as u16), + cast::(normal_f) + ); + assert_eq!( + NonZeroU32::new(normal_f as u32), + cast::(normal_f) + ); + assert_eq!( + NonZeroU64::new(normal_f as u64), + cast::(normal_f) + ); + assert_eq!(None, cast::(small_f)); assert_eq!(None, cast::(small_f)); assert_eq!(None, cast::(small_f)); assert_eq!(None, cast::(small_f)); assert_eq!(None, cast::(small_f)); + + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); } #[test] @@ -146,11 +216,26 @@ fn cast_to_i128_checks_overflow() { assert_eq!(None, cast::(big_f)); assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(Some(normal_f as i128), cast::(normal_f)); assert_eq!(Some(normal_f as u128), cast::(normal_f)); + assert_eq!( + NonZeroI128::new(normal_f as i128), + cast::(normal_f) + ); + assert_eq!( + NonZeroU128::new(normal_f as u128), + cast::(normal_f) + ); + assert_eq!(None, cast::(small_f)); assert_eq!(None, cast::(small_f)); + + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); } #[cfg(feature = "std")] @@ -310,6 +395,152 @@ fn cast_int_to_128_edge_cases() { test_edge!(usize u8 u16 u32 u64 u128); } +macro_rules! nonzero_to_int_test_edge { + ($f:ident -> { $($t:ident)+ } with $BigS:ident $BigU:ident ) => { $({ + #[allow(arithmetic_overflow)] // https://github.com/rust-lang/rust/issues/109731 + fn test_edge() { + dbg!("testing cast edge cases for {} -> {}", stringify!($f), stringify!($t)); + + + let from_min = <$f as Bounded>::min_value(); + match (from_min.get() as $BigS).cmp(&($t::MIN as $BigS)) { + Greater => { + assert_eq!(Some(from_min.get() as $t), cast::<$f, $t>(from_min)); + } + Equal => { + assert_eq!(Some($t::MIN), cast::<$f, $t>(from_min)); + } + Less => { + if $t::MIN != 0 { + let min = $f::new($t::MIN.as_()).unwrap(); + assert_eq!(Some($t::MIN), cast::<$f, $t>(min)); + assert_eq!(None, cast::<$f, $t>($f::new(min.get() - 1).unwrap())); + } + } + } + + let from_max = <$f as Bounded>::max_value(); + match (from_max.get() as $BigU).cmp(&($t::MAX as $BigU)) { + Greater => { + let max = $f::new($t::MAX.as_()).unwrap(); + assert_eq!(Some($t::MAX), cast::<$f, $t>(max)); + assert_eq!(None, cast::<$f, $t>($f::new(max.get() + 1).unwrap())); + } + Equal => { + assert_eq!(Some($t::MAX), cast::<$f, $t>(from_max)); + } + Less => { + assert_eq!(Some(from_max.get() as $t), cast::<$f, $t>(from_max)); + } + } + } + test_edge(); + })+} +} + +#[test] +fn cast_nonzero_to_int_edge_cases() { + use core::cmp::Ordering::*; + + macro_rules! test_edge { + ($( $from:ident )+) => { $({ + nonzero_to_int_test_edge!($from -> { isize i8 i16 i32 i64 } with i64 u64); + nonzero_to_int_test_edge!($from -> { usize u8 u16 u32 u64 } with i64 u64); + })+} + } + + test_edge!(NonZeroIsize NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64); + test_edge!(NonZeroUsize NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64); +} + +#[test] +fn cast_nonzero_to_128_edge_cases() { + use core::cmp::Ordering::*; + + macro_rules! test_edge { + ($( $t:ident )+) => { + $( + nonzero_to_int_test_edge!($t -> { i128 u128 } with i128 u128); + )+ + } + } + + test_edge!(NonZeroIsize NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128); + test_edge!(NonZeroUsize NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128); +} + +macro_rules! int_to_nonzero_test_edge { + ($f:ident -> { $($t:ident)+ } with $BigS:ident $BigU:ident ) => { $({ + #[allow(arithmetic_overflow)] // https://github.com/rust-lang/rust/issues/109731 + fn test_edge() { + dbg!("testing cast edge cases for {} -> {}", stringify!($f), stringify!($t)); + + let target_min = <$t as Bounded>::min_value(); + match ($f::MIN as $BigS).cmp(&(target_min.get() as $BigS)) { + Greater => { + assert_eq!($t::new($f::MIN.as_()), cast::<$f, $t>($f::MIN)); + } + Equal => { + assert_eq!(Some(target_min), cast::<$f, $t>($f::MIN)); + } + Less => { + let min = target_min.get() as $f; + assert_eq!(Some(target_min), cast::<$f, $t>(min)); + assert_eq!(None, cast::<$f, $t>(min - 1)); + } + } + + let target_max = <$t as Bounded>::max_value(); + match ($f::MAX as $BigU).cmp(&($t::max_value().get() as $BigU)) { + Greater => { + let max = target_max.get() as $f; + assert_eq!(Some(target_max), cast::<$f, $t>(max)); + assert_eq!(None, cast::<$f, $t>(max + 1)); + } + Equal => { + assert_eq!(Some(target_max), cast::<$f, $t>($f::MAX)); + } + Less => { + assert_eq!($t::new($f::MAX.as_()), cast::<$f, $t>($f::MAX)); + } + } + } + test_edge(); + })+} +} + +#[test] +fn cast_int_to_nonzero_edge_cases() { + use core::cmp::Ordering::*; + + macro_rules! test_edge { + ($( $from:ident )+) => { $({ + int_to_nonzero_test_edge!($from -> { NonZeroIsize NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 } with i64 u64); + int_to_nonzero_test_edge!($from -> { NonZeroUsize NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 } with i64 u64); + })+} + } + + test_edge!(isize i8 i16 i32 i64); + test_edge!(usize u8 u16 u32 u64); +} + +#[test] +fn cast_128_to_nonzero_edge_cases() { + use core::cmp::Ordering::*; + + macro_rules! test_edge { + ($( $t:ident )+) => { + $( + int_to_nonzero_test_edge!($t -> { NonZeroIsize NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 } with i128 u128); + int_to_nonzero_test_edge!($t -> { NonZeroUsize NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 } with i128 u128); + )+ + } + } + + test_edge!(isize i8 i16 i32 i64 i128); + test_edge!(usize u8 u16 u32 u64 u128); +} + #[test] fn newtype_from_primitive() { #[derive(PartialEq, Debug)] From acb1a26ac040a6ae3fbf9e54ca601f294884e18e Mon Sep 17 00:00:00 2001 From: Andrea Corradi Date: Thu, 29 Aug 2024 19:57:50 +0200 Subject: [PATCH 4/8] Implement FromPrimitive for NonZero* --- src/cast.rs | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++ tests/cast.rs | 30 +++++++++++-------- 2 files changed, 97 insertions(+), 12 deletions(-) diff --git a/src/cast.rs b/src/cast.rs index 76116bdc..b1deb843 100644 --- a/src/cast.rs +++ b/src/cast.rs @@ -631,6 +631,85 @@ impl_from_primitive!(u128, to_u128); impl_from_primitive!(f32, to_f32); impl_from_primitive!(f64, to_f64); +macro_rules! impl_from_primitive_nonzero { + ($T:ty, $to_ty:ident) => { + #[allow(deprecated)] + impl FromPrimitive for $T { + #[inline] + fn from_isize(n: isize) -> Option<$T> { + n.$to_ty().and_then(Self::new) + } + #[inline] + fn from_i8(n: i8) -> Option<$T> { + n.$to_ty().and_then(Self::new) + } + #[inline] + fn from_i16(n: i16) -> Option<$T> { + n.$to_ty().and_then(Self::new) + } + #[inline] + fn from_i32(n: i32) -> Option<$T> { + n.$to_ty().and_then(Self::new) + } + #[inline] + fn from_i64(n: i64) -> Option<$T> { + n.$to_ty().and_then(Self::new) + } + #[inline] + fn from_i128(n: i128) -> Option<$T> { + n.$to_ty().and_then(Self::new) + } + + #[inline] + fn from_usize(n: usize) -> Option<$T> { + n.$to_ty().and_then(Self::new) + } + #[inline] + fn from_u8(n: u8) -> Option<$T> { + n.$to_ty().and_then(Self::new) + } + #[inline] + fn from_u16(n: u16) -> Option<$T> { + n.$to_ty().and_then(Self::new) + } + #[inline] + fn from_u32(n: u32) -> Option<$T> { + n.$to_ty().and_then(Self::new) + } + #[inline] + fn from_u64(n: u64) -> Option<$T> { + n.$to_ty().and_then(Self::new) + } + #[inline] + fn from_u128(n: u128) -> Option<$T> { + n.$to_ty().and_then(Self::new) + } + + #[inline] + fn from_f32(n: f32) -> Option<$T> { + n.$to_ty().and_then(Self::new) + } + #[inline] + fn from_f64(n: f64) -> Option<$T> { + n.$to_ty().and_then(Self::new) + } + } + }; +} + +impl_from_primitive_nonzero!(NonZeroIsize, to_isize); +impl_from_primitive_nonzero!(NonZeroI8, to_i8); +impl_from_primitive_nonzero!(NonZeroI16, to_i16); +impl_from_primitive_nonzero!(NonZeroI32, to_i32); +impl_from_primitive_nonzero!(NonZeroI64, to_i64); +impl_from_primitive_nonzero!(NonZeroI128, to_i128); +impl_from_primitive_nonzero!(NonZeroUsize, to_usize); +impl_from_primitive_nonzero!(NonZeroU8, to_u8); +impl_from_primitive_nonzero!(NonZeroU16, to_u16); +impl_from_primitive_nonzero!(NonZeroU32, to_u32); +impl_from_primitive_nonzero!(NonZeroU64, to_u64); +impl_from_primitive_nonzero!(NonZeroU128, to_u128); + macro_rules! impl_to_primitive_wrapping { ($( $(#[$cfg:meta])* fn $method:ident -> $i:ident ; )*) => {$( #[inline] diff --git a/tests/cast.rs b/tests/cast.rs index a8ac546e..785d760e 100644 --- a/tests/cast.rs +++ b/tests/cast.rs @@ -118,23 +118,23 @@ fn cast_to_int_checks_overflow() { assert_eq!(Some(normal_f as i64), cast::(normal_f)); assert_eq!( - NonZeroIsize::new(normal_f as isize), + NonZeroIsize::from_isize(normal_f as isize), cast::(normal_f) ); assert_eq!( - NonZeroI8::new(normal_f as i8), + NonZeroI8::from_i8(normal_f as i8), cast::(normal_f) ); assert_eq!( - NonZeroI16::new(normal_f as i16), + NonZeroI16::from_i16(normal_f as i16), cast::(normal_f) ); assert_eq!( - NonZeroI32::new(normal_f as i32), + NonZeroI32::from_i32(normal_f as i32), cast::(normal_f) ); assert_eq!( - NonZeroI64::new(normal_f as i64), + NonZeroI64::from_i64(normal_f as i64), cast::(normal_f) ); @@ -175,23 +175,23 @@ fn cast_to_unsigned_int_checks_overflow() { assert_eq!(Some(normal_f as u64), cast::(normal_f)); assert_eq!( - NonZeroUsize::new(normal_f as usize), + NonZeroUsize::from_usize(normal_f as usize), cast::(normal_f) ); assert_eq!( - NonZeroU8::new(normal_f as u8), + NonZeroU8::from_u8(normal_f as u8), cast::(normal_f) ); assert_eq!( - NonZeroU16::new(normal_f as u16), + NonZeroU16::from_u16(normal_f as u16), cast::(normal_f) ); assert_eq!( - NonZeroU32::new(normal_f as u32), + NonZeroU32::from_u32(normal_f as u32), cast::(normal_f) ); assert_eq!( - NonZeroU64::new(normal_f as u64), + NonZeroU64::from_u64(normal_f as u64), cast::(normal_f) ); @@ -223,11 +223,11 @@ fn cast_to_i128_checks_overflow() { assert_eq!(Some(normal_f as u128), cast::(normal_f)); assert_eq!( - NonZeroI128::new(normal_f as i128), + NonZeroI128::from_i128(normal_f as i128), cast::(normal_f) ); assert_eq!( - NonZeroU128::new(normal_f as u128), + NonZeroU128::from_u128(normal_f as u128), cast::(normal_f) ); @@ -577,6 +577,9 @@ fn newtype_from_primitive() { } check!(i8 i16 i32 i64 isize); check!(u8 u16 u32 u64 usize); + + check!(NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroIsize); + check!(NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroUsize); } #[test] @@ -615,4 +618,7 @@ fn newtype_to_primitive() { } check!(i8 i16 i32 i64 isize); check!(u8 u16 u32 u64 usize); + + check!(NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroIsize); + check!(NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroUsize); } From 542884d74069bd443fda187efb679162489df6e8 Mon Sep 17 00:00:00 2001 From: Andrea Corradi Date: Mon, 30 Sep 2024 15:00:24 +0200 Subject: [PATCH 5/8] Remove cfg from macros --- src/cast.rs | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/src/cast.rs b/src/cast.rs index b1deb843..2b164e49 100644 --- a/src/cast.rs +++ b/src/cast.rs @@ -130,9 +130,8 @@ pub trait ToPrimitive { } macro_rules! impl_to_primitive_int_to_int { - ($SrcT:ident : $( $(#[$cfg:meta])* fn $method:ident -> $DstT:ident ; )*) => {$( + ($SrcT:ident : $( fn $method:ident -> $DstT:ident ; )*) => {$( #[inline] - $(#[$cfg])* fn $method(&self) -> Option<$DstT> { let min = $DstT::MIN as $SrcT; let max = $DstT::MAX as $SrcT; @@ -146,9 +145,8 @@ macro_rules! impl_to_primitive_int_to_int { } macro_rules! impl_to_primitive_int_to_uint { - ($SrcT:ident : $( $(#[$cfg:meta])* fn $method:ident -> $DstT:ident ; )*) => {$( + ($SrcT:ident : $( fn $method:ident -> $DstT:ident ; )*) => {$( #[inline] - $(#[$cfg])* fn $method(&self) -> Option<$DstT> { let max = $DstT::MAX as $SrcT; if 0 <= *self && (size_of::<$SrcT>() <= size_of::<$DstT>() || *self <= max) { @@ -201,9 +199,8 @@ impl_to_primitive_int!(i64); impl_to_primitive_int!(i128); macro_rules! impl_to_primitive_uint_to_int { - ($SrcT:ident : $( $(#[$cfg:meta])* fn $method:ident -> $DstT:ident ; )*) => {$( + ($SrcT:ident : $( fn $method:ident -> $DstT:ident ; )*) => {$( #[inline] - $(#[$cfg])* fn $method(&self) -> Option<$DstT> { let max = $DstT::MAX as $SrcT; if size_of::<$SrcT>() < size_of::<$DstT>() || *self <= max { @@ -216,9 +213,8 @@ macro_rules! impl_to_primitive_uint_to_int { } macro_rules! impl_to_primitive_uint_to_uint { - ($SrcT:ident : $( $(#[$cfg:meta])* fn $method:ident -> $DstT:ident ; )*) => {$( + ($SrcT:ident : $( fn $method:ident -> $DstT:ident ; )*) => {$( #[inline] - $(#[$cfg])* fn $method(&self) -> Option<$DstT> { let max = $DstT::MAX as $SrcT; if size_of::<$SrcT>() <= size_of::<$DstT>() || *self <= max { @@ -271,9 +267,8 @@ impl_to_primitive_uint!(u64); impl_to_primitive_uint!(u128); macro_rules! impl_to_primitive_nonzero_to_method { - ($SrcT:ident : $( $(#[$cfg:meta])* fn $method:ident -> $DstT:ident ; )*) => {$( + ($SrcT:ident : $( fn $method:ident -> $DstT:ident ; )*) => {$( #[inline] - $(#[$cfg])* fn $method(&self) -> Option<$DstT> { self.get().$method() } @@ -345,9 +340,8 @@ macro_rules! float_to_int_unchecked { } macro_rules! impl_to_primitive_float_to_signed_int { - ($f:ident : $( $(#[$cfg:meta])* fn $method:ident -> $i:ident ; )*) => {$( + ($f:ident : $( fn $method:ident -> $i:ident ; )*) => {$( #[inline] - $(#[$cfg])* fn $method(&self) -> Option<$i> { // Float as int truncates toward zero, so we want to allow values // in the exclusive range `(MIN-1, MAX+1)`. @@ -375,9 +369,8 @@ macro_rules! impl_to_primitive_float_to_signed_int { } macro_rules! impl_to_primitive_float_to_unsigned_int { - ($f:ident : $( $(#[$cfg:meta])* fn $method:ident -> $u:ident ; )*) => {$( + ($f:ident : $( fn $method:ident -> $u:ident ; )*) => {$( #[inline] - $(#[$cfg])* fn $method(&self) -> Option<$u> { // Float as int truncates toward zero, so we want to allow values // in the exclusive range `(-1, MAX+1)`. @@ -711,9 +704,8 @@ impl_from_primitive_nonzero!(NonZeroU64, to_u64); impl_from_primitive_nonzero!(NonZeroU128, to_u128); macro_rules! impl_to_primitive_wrapping { - ($( $(#[$cfg:meta])* fn $method:ident -> $i:ident ; )*) => {$( + ($( fn $method:ident -> $i:ident ; )*) => {$( #[inline] - $(#[$cfg])* fn $method(&self) -> Option<$i> { (self.0).$method() } @@ -742,9 +734,8 @@ impl ToPrimitive for Wrapping { } macro_rules! impl_from_primitive_wrapping { - ($( $(#[$cfg:meta])* fn $method:ident ( $i:ident ); )*) => {$( + ($( fn $method:ident ( $i:ident ); )*) => {$( #[inline] - $(#[$cfg])* fn $method(n: $i) -> Option { T::$method(n).map(Wrapping) } @@ -902,8 +893,7 @@ where } macro_rules! impl_as_primitive { - (@ $T: ty => $(#[$cfg:meta])* impl $U: ty ) => { - $(#[$cfg])* + (@ $T: ty => impl $U: ty ) => { impl AsPrimitive<$U> for $T { #[inline] fn as_(self) -> $U { self as $U } } From d4e5b0aa9d4e74e274649119f28be6115770254d Mon Sep 17 00:00:00 2001 From: Andrea Corradi Date: Mon, 30 Sep 2024 15:07:01 +0200 Subject: [PATCH 6/8] Use to_f* in ToPrimitive impl --- src/cast.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/cast.rs b/src/cast.rs index 2b164e49..ea1f001f 100644 --- a/src/cast.rs +++ b/src/cast.rs @@ -292,15 +292,9 @@ macro_rules! impl_to_primitive_nonzero { fn to_u32 -> u32; fn to_u64 -> u64; fn to_u128 -> u128; - } - #[inline] - fn to_f32(&self) -> Option { - Some(self.get() as f32) - } - #[inline] - fn to_f64(&self) -> Option { - Some(self.get() as f64) + fn to_f32 -> f32; + fn to_f64 -> f64; } } }; From b43a252c29a8663d5a0590d4c7a9d45115a9f664 Mon Sep 17 00:00:00 2001 From: Andrea Corradi Date: Mon, 30 Sep 2024 15:11:53 +0200 Subject: [PATCH 7/8] Remove #[allow(deprecated)] --- src/cast.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/cast.rs b/src/cast.rs index ea1f001f..e1560434 100644 --- a/src/cast.rs +++ b/src/cast.rs @@ -539,7 +539,6 @@ pub trait FromPrimitive: Sized { macro_rules! impl_from_primitive { ($T:ty, $to_ty:ident) => { - #[allow(deprecated)] impl FromPrimitive for $T { #[inline] fn from_isize(n: isize) -> Option<$T> { @@ -620,7 +619,6 @@ impl_from_primitive!(f64, to_f64); macro_rules! impl_from_primitive_nonzero { ($T:ty, $to_ty:ident) => { - #[allow(deprecated)] impl FromPrimitive for $T { #[inline] fn from_isize(n: isize) -> Option<$T> { @@ -793,7 +791,6 @@ macro_rules! impl_num_cast { ($T:ty, $conv:ident) => { impl NumCast for $T { #[inline] - #[allow(deprecated)] fn from(n: N) -> Option<$T> { // `$conv` could be generated using `concat_idents!`, but that // macro seems to be broken at the moment @@ -822,7 +819,6 @@ macro_rules! impl_num_cast_nonzero { ($T:ty, $conv:ident) => { impl NumCast for $T { #[inline] - #[allow(deprecated)] fn from(n: N) -> Option<$T> { // `$conv` could be generated using `concat_idents!`, but that // macro seems to be broken at the moment From 2ce0fb6ea5ed8f4fbf6192bb3f1e3e97b536c94e Mon Sep 17 00:00:00 2001 From: Andrea Corradi Date: Mon, 30 Sep 2024 18:54:13 +0200 Subject: [PATCH 8/8] Remove unsafe from min/max bounds --- src/bounds.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bounds.rs b/src/bounds.rs index d399cb0b..4c918170 100644 --- a/src/bounds.rs +++ b/src/bounds.rs @@ -74,11 +74,9 @@ bounded_impl!(i128, i128::MIN, i128::MAX); macro_rules! bounded_impl_nonzero_const { ($t:ty, $v:expr, $i:ident) => { - const $i: $t = { - let arr = [$v]; - let idx = if $v != 0 { 0 } else { 1 }; - - unsafe { <$t>::new_unchecked(arr[idx]) } + const $i: $t = match <$t>::new($v) { + Some(nz) => nz, + None => panic!("bad nonzero bound!"), }; }; } @@ -88,12 +86,14 @@ macro_rules! bounded_impl_nonzero { impl Bounded for $t { #[inline] fn min_value() -> $t { + // when MSRV is 1.70 we can use $t::MIN bounded_impl_nonzero_const!($t, $min, MIN); MIN } #[inline] fn max_value() -> $t { + // when MSRV is 1.70 we can use $t::MAX bounded_impl_nonzero_const!($t, $max, MAX); MAX }