numera/number/traits/
bound.rs1use core::num::{
30 NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
31 NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
32};
33
34pub trait Bound {
43 fn is_lower_bounded(&self) -> bool;
45
46 fn is_upper_bounded(&self) -> bool;
48
49 fn lower_bound(&self) -> Option<Self>
51 where
52 Self: Sized;
53
54 fn upper_bound(&self) -> Option<Self>
56 where
57 Self: Sized;
58}
59
60pub trait Bounded: LowerBounded + UpperBounded {}
64
65pub trait LowerBounded: Bound {
69 fn new_min() -> Self;
71}
72
73pub trait UpperBounded: Bound {
77 fn new_max() -> Self;
79}
80
81pub trait ConstBounded: ConstLowerBounded + ConstUpperBounded {}
85
86pub trait ConstLowerBounded: Bound {
90 const MIN: Self;
92}
93
94pub trait ConstUpperBounded: Bound {
98 const MAX: Self;
100}
101
102pub trait NonLowerBounded: Bound {}
106
107pub trait NonUpperBounded: Bound {}
111
112pub trait NonBounded: NonLowerBounded + NonUpperBounded {}
116
117macro_rules! impl_bounded {
121 (many_both: $($t:ty),+) => {
122 $( impl_bounded![both: $t]; )+
123 };
124 (both: $t:ty) => {
125 impl Bound for $t {
126 fn is_lower_bounded(&self) -> bool { true }
127 fn is_upper_bounded(&self) -> bool { true }
128 fn lower_bound(&self) -> Option<Self> where Self: Sized { Some(<$t>::MIN) }
129 fn upper_bound(&self) -> Option<Self> where Self: Sized { Some(<$t>::MAX) }
130 }
131 impl ConstLowerBounded for $t { const MIN: Self = <$t>::MIN; }
132 impl LowerBounded for $t { fn new_min() -> Self { <$t>::MIN }}
133 impl ConstUpperBounded for $t { const MAX: Self = <$t>::MAX; }
134 impl UpperBounded for $t { fn new_max() -> Self { <$t>::MAX }}
135 };
136}
137
138macro_rules! impl_bounded_nonzero {
141 (many_both: $($t:ty, $lb:expr, $ub:expr),+) => {
142 $( impl_bounded_nonzero![both: $t, $lb, $ub]; )+
143 };
144
145 (both: $t:ty, $lb:expr, $ub:expr) => {
146 impl Bound for $t {
147 fn is_lower_bounded(&self) -> bool { true }
148 fn is_upper_bounded(&self) -> bool { true }
149 fn lower_bound(&self) -> Option<Self> { Some(<$t as ConstLowerBounded>::MIN) }
150 fn upper_bound(&self) -> Option<Self> { Some(<$t as ConstUpperBounded>::MAX) }
151 }
152 impl ConstLowerBounded for $t {
153 #[cfg(feature = "safe")]
154 const MIN: Self = if let Some(n) = <$t>::new($lb)
155 { n } else { unreachable!() };
156
157 #[cfg(not(feature = "safe"))]
159 const MIN: Self = unsafe { <$t>::new_unchecked($lb) };
160 }
161
162 impl ConstUpperBounded for $t {
163 #[cfg(feature = "safe")]
164 const MAX: Self = if let Some(n) = <$t>::new($ub)
165 { n } else { unreachable!() };
166
167 #[cfg(not(feature = "safe"))]
169 const MAX: Self = unsafe { <$t>::new_unchecked($ub) };
170 }
171 impl LowerBounded for $t {
172 fn new_min() -> Self {
173 #[cfg(feature = "safe")]
174 return <$t>::new($lb).unwrap();
175
176 #[cfg(not(feature = "safe"))]
178 return unsafe { <$t>::new_unchecked($lb) };
179 }
180 }
181 impl UpperBounded for $t {
182 fn new_max() -> Self {
183 #[cfg(feature = "safe")]
184 return <$t>::new($ub).unwrap();
185
186 #[cfg(not(feature = "safe"))]
188 return unsafe { <$t>::new_unchecked($ub) };
189 }
190 }
191 };
192}
193
194#[rustfmt::skip]
198#[allow(unused_macros)]
199macro_rules! impl_nonconst_bounded {
200 (only_lower: $t:ty, $b:expr) => {
202 impl Bound for $t {
203 fn is_lower_bounded(&self) -> bool { true }
204 fn is_upper_bounded(&self) -> bool { false }
205 fn lower_bound(&self) -> Option<Self> { Some($b) }
206 fn upper_bound(&self) -> Option<Self> { None }
207 }
208 impl LowerBounded for $t { fn new_min() -> Self { $b } }
209 impl NonUpperBounded for UBig {}
210 };
211
212 (only_upper: $t:ty, $b:expr) => {
214 impl Bound for $t {
215 fn is_lower_bounded(&self) -> bool { false }
216 fn is_upper_bounded(&self) -> bool { true }
217 fn lower_bound(&self) -> Option<Self> { None }
218 fn upper_bound(&self) -> Option<Self> { Some($b) }
219 }
220 impl UpperBounded for $t { fn new_max() -> Self { $b } }
221 impl NonLowerBounded for UBig {}
222 };
223}
224
225#[allow(unused_macros)]
229macro_rules! impl_nonbounded {
230 ($t:ty) => {
231 impl Bound for $t {
232 fn is_lower_bounded(&self) -> bool {
233 false
234 }
235 fn is_upper_bounded(&self) -> bool {
236 false
237 }
238 fn lower_bound(&self) -> Option<Self> {
239 None
240 }
241 fn upper_bound(&self) -> Option<Self> {
242 None
243 }
244 }
245 impl NonUpperBounded for $t {}
246 impl NonLowerBounded for $t {}
247 };
248}
249
250impl<T: LowerBounded + UpperBounded> Bounded for T {}
254
255impl<T: ConstLowerBounded + ConstUpperBounded> ConstBounded for T {}
257
258impl<T: NonLowerBounded + NonUpperBounded> NonBounded for T {}
260
261#[rustfmt::skip]
262impl_bounded![many_both:
263 f32, f64, i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize];
264
265#[rustfmt::skip]
266impl_bounded_nonzero![many_both:
267 NonZeroU8, 1, u8::MAX, NonZeroU16, 1, u16::MAX, NonZeroU32, 1, u32::MAX,
268 NonZeroU64, 1, u64::MAX, NonZeroU128, 1, u128::MAX, NonZeroUsize, 1, usize::MAX,
269 NonZeroI8, i8::MIN, i8::MAX, NonZeroI16, i16::MIN, i16::MAX,
270 NonZeroI32, i32::MIN, i32::MAX, NonZeroI64, i64::MIN, i64::MAX,
271 NonZeroI128, i128::MIN, i128::MAX, NonZeroIsize, isize::MIN, isize::MAX
272];
273
274#[cfg(feature = "twofloat")]
277impl_bounded![both: twofloat::TwoFloat];
278
279#[cfg(feature = "half")]
280impl_bounded![many_both: half::bf16, half::f16];
281
282#[cfg(feature = "dashu-int")]
283mod impl_big {
284 use super::*;
285 use dashu_int::{IBig, UBig};
286
287 impl_nonconst_bounded![only_lower: UBig, UBig::from(0u8)];
288
289 impl_nonbounded![IBig];
290}