Skip to content

Commit 9b8d1b2

Browse files
committed
feat: add integer_bounds
1 parent fbdc29a commit 9b8d1b2

File tree

2 files changed

+208
-0
lines changed

2 files changed

+208
-0
lines changed

src/integer_bounds.rs

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
use core::num::Wrapping;
2+
use core::num::{
3+
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
4+
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
5+
};
6+
use core::{f32, f64};
7+
use core::{i128, i16, i32, i64, i8, isize};
8+
use core::{u128, u16, u32, u64, u8, usize};
9+
10+
/// Numbers which have upper and lower bounds
11+
pub trait IntegerBounded : LowerIntegerBounded + UpperIntegerBounded {}
12+
13+
impl<T: LowerIntegerBounded + UpperIntegerBounded> IntegerBounded for T {}
14+
15+
/// Numbers which have lower bounds
16+
pub trait LowerIntegerBounded {
17+
/// Returns the smallest integer number this type can represent
18+
const MIN_INTEGER_VALUE: Self;
19+
}
20+
21+
/// Numbers which have upper bounds
22+
pub trait UpperIntegerBounded {
23+
/// Returns the largest integer number this type can represent
24+
const MAX_INTEGER_VALUE: Self;
25+
}
26+
27+
// FIXME: With a major version bump, this should be a supertrait instead
28+
const fn max_integer_value<T : IntegerBounded>() -> T {
29+
T::MAX_INTEGER_VALUE
30+
}
31+
32+
macro_rules! integer_bounded_impl {
33+
($t:ty, $min:expr, $max:expr) => {
34+
impl LowerIntegerBounded for $t {
35+
const MIN_INTEGER_VALUE: $t = $min;
36+
}
37+
impl UpperIntegerBounded for $t {
38+
const MAX_INTEGER_VALUE: $t = $max;
39+
}
40+
};
41+
}
42+
43+
integer_bounded_impl!(usize, usize::MIN, usize::MAX);
44+
integer_bounded_impl!(u8, u8::MIN, u8::MAX);
45+
integer_bounded_impl!(u16, u16::MIN, u16::MAX);
46+
integer_bounded_impl!(u32, u32::MIN, u32::MAX);
47+
integer_bounded_impl!(u64, u64::MIN, u64::MAX);
48+
integer_bounded_impl!(u128, u128::MIN, u128::MAX);
49+
50+
integer_bounded_impl!(isize, isize::MIN, isize::MAX);
51+
integer_bounded_impl!(i8, i8::MIN, i8::MAX);
52+
integer_bounded_impl!(i16, i16::MIN, i16::MAX);
53+
integer_bounded_impl!(i32, i32::MIN, i32::MAX);
54+
integer_bounded_impl!(i64, i64::MIN, i64::MAX);
55+
integer_bounded_impl!(i128, i128::MIN, i128::MAX);
56+
57+
58+
macro_rules! integer_bounded_impl_nonzero {
59+
($t:ty, $min:expr, $max:expr) => {
60+
impl LowerIntegerBounded for $t {
61+
const MIN_INTEGER_VALUE: $t = match <$t>::new($min) {
62+
Some(nz) => nz,
63+
None => panic!("bad nonzero bound!"),
64+
};
65+
}
66+
impl UpperIntegerBounded for $t {
67+
const MAX_INTEGER_VALUE: $t = match <$t>::new($max) {
68+
Some(nz) => nz,
69+
None => panic!("bad nonzero bound!"),
70+
};
71+
}
72+
};
73+
}
74+
75+
integer_bounded_impl_nonzero!(NonZeroUsize, 1, usize::MAX);
76+
integer_bounded_impl_nonzero!(NonZeroU8, 1, u8::MAX);
77+
integer_bounded_impl_nonzero!(NonZeroU16, 1, u16::MAX);
78+
integer_bounded_impl_nonzero!(NonZeroU32, 1, u32::MAX);
79+
integer_bounded_impl_nonzero!(NonZeroU64, 1, u64::MAX);
80+
integer_bounded_impl_nonzero!(NonZeroU128, 1, u128::MAX);
81+
82+
integer_bounded_impl_nonzero!(NonZeroIsize, isize::MIN, isize::MAX);
83+
integer_bounded_impl_nonzero!(NonZeroI8, i8::MIN, i8::MAX);
84+
integer_bounded_impl_nonzero!(NonZeroI16, i16::MIN, i16::MAX);
85+
integer_bounded_impl_nonzero!(NonZeroI32, i32::MIN, i32::MAX);
86+
integer_bounded_impl_nonzero!(NonZeroI64, i64::MIN, i64::MAX);
87+
integer_bounded_impl_nonzero!(NonZeroI128, i128::MIN, i128::MAX);
88+
89+
impl<T: LowerIntegerBounded> LowerIntegerBounded for Wrapping<T> {
90+
const MIN_INTEGER_VALUE: Self = Wrapping(T::MIN_INTEGER_VALUE);
91+
}
92+
impl<T: UpperIntegerBounded> UpperIntegerBounded for Wrapping<T> {
93+
const MAX_INTEGER_VALUE: Self = Wrapping(T::MAX_INTEGER_VALUE);
94+
}
95+
96+
integer_bounded_impl!(
97+
f32,
98+
-(1 << f32::MANTISSA_DIGITS) as f32,
99+
(1 << f32::MANTISSA_DIGITS) as f32
100+
);
101+
102+
macro_rules! for_each_tuple_ {
103+
( $m:ident !! ) => (
104+
$m! { }
105+
);
106+
( $m:ident !! $h:ident, $($t:ident,)* ) => (
107+
$m! { $h $($t)* }
108+
for_each_tuple_! { $m !! $($t,)* }
109+
);
110+
}
111+
macro_rules! for_each_tuple {
112+
($m:ident) => {
113+
for_each_tuple_! { $m !! A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, }
114+
};
115+
}
116+
117+
macro_rules! integer_bounded_tuple {
118+
( $($name:ident)* ) => (
119+
impl<$($name: LowerIntegerBounded,)*> LowerIntegerBounded for ($($name,)*) {
120+
const MIN_INTEGER_VALUE: Self = ($($name::MIN_INTEGER_VALUE,)*);
121+
}
122+
impl<$($name: UpperIntegerBounded,)*> UpperIntegerBounded for ($($name,)*) {
123+
const MAX_INTEGER_VALUE: Self = ($($name::MAX_INTEGER_VALUE,)*);
124+
}
125+
);
126+
}
127+
128+
for_each_tuple!(integer_bounded_tuple);
129+
integer_bounded_impl!(f64, f64::MIN, f64::MAX);
130+
131+
#[test]
132+
fn wrapping_integer_bounded() {
133+
macro_rules! test_wrapping_integer_bounded {
134+
($($t:ty)+) => {
135+
$(
136+
assert_eq!(<Wrapping<$t> as LowerIntegerBounded>::MIN_INTEGER_VALUE.0, <$t>::MIN_INTEGER_VALUE);
137+
assert_eq!(<Wrapping<$t> as UpperIntegerBounded>::MAX_INTEGER_VALUE.0, <$t>::MAX_INTEGER_VALUE);
138+
)+
139+
};
140+
}
141+
142+
test_wrapping_integer_bounded!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
143+
}
144+
145+
#[test]
146+
fn wrapping_integer_bounded_i128() {
147+
macro_rules! test_wrapping_integer_bounded {
148+
($($t:ty)+) => {
149+
$(
150+
assert_eq!(<Wrapping<$t> as LowerIntegerBounded>::MIN_INTEGER_VALUE.0, <$t>::MIN_INTEGER_VALUE);
151+
assert_eq!(<Wrapping<$t> as UpperIntegerBounded>::MAX_INTEGER_VALUE.0, <$t>::MAX_INTEGER_VALUE);
152+
)+
153+
};
154+
}
155+
156+
test_wrapping_integer_bounded!(u128 i128);
157+
}
158+
159+
#[test]
160+
fn wrapping_is_integer_bounded() {
161+
fn require_integer_bounded<T: IntegerBounded>(_: &T) {}
162+
require_integer_bounded(&Wrapping(42_u32));
163+
require_integer_bounded(&Wrapping(-42));
164+
}
165+
166+
#[test]
167+
fn integer_bounded_unsigned_nonzero() {
168+
macro_rules! test_integer_bounded_impl_unsigned_nonzero {
169+
($t:ty, $base_ty:ty) => {
170+
assert_eq!(<$t as LowerIntegerBounded>::MIN_INTEGER_VALUE.get(), 1);
171+
assert_eq!(
172+
<$t as UpperIntegerBounded>::MAX_INTEGER_VALUE.get(),
173+
<$base_ty>::MAX
174+
);
175+
};
176+
}
177+
178+
test_integer_bounded_impl_unsigned_nonzero!(NonZeroUsize, usize);
179+
test_integer_bounded_impl_unsigned_nonzero!(NonZeroU8, u8);
180+
test_integer_bounded_impl_unsigned_nonzero!(NonZeroU16, u16);
181+
test_integer_bounded_impl_unsigned_nonzero!(NonZeroU32, u32);
182+
test_integer_bounded_impl_unsigned_nonzero!(NonZeroU64, u64);
183+
test_integer_bounded_impl_unsigned_nonzero!(NonZeroU128, u128);
184+
}
185+
186+
#[test]
187+
fn integer_bounded_signed_nonzero() {
188+
macro_rules! test_integer_bounded_impl_signed_nonzero {
189+
($t:ty, $base_ty:ty) => {
190+
assert_eq!(
191+
<$t as LowerIntegerBounded>::MIN_INTEGER_VALUE.get(),
192+
<$base_ty>::MIN
193+
);
194+
assert_eq!(
195+
<$t as UpperIntegerBounded>::MAX_INTEGER_VALUE.get(),
196+
<$base_ty>::MAX
197+
);
198+
};
199+
}
200+
201+
test_integer_bounded_impl_signed_nonzero!(NonZeroIsize, isize);
202+
test_integer_bounded_impl_signed_nonzero!(NonZeroI8, i8);
203+
test_integer_bounded_impl_signed_nonzero!(NonZeroI16, i16);
204+
test_integer_bounded_impl_signed_nonzero!(NonZeroI32, i32);
205+
test_integer_bounded_impl_signed_nonzero!(NonZeroI64, i64);
206+
test_integer_bounded_impl_signed_nonzero!(NonZeroI128, i128);
207+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ pub use crate::sign::{abs, abs_sub, signum, Signed, Unsigned};
5353
mod macros;
5454

5555
pub mod bounds;
56+
pub mod integer_bounds;
5657
pub mod cast;
5758
pub mod float;
5859
pub mod identities;

0 commit comments

Comments
 (0)