1use num::traits::bounds::UpperBounded;
19use num::Signed;
20use std::error::Error;
21use std::fmt;
22use std::ops::Deref;
23
24pub trait CastFrom<T> {
39 fn cast_from(from: T) -> Self;
41}
42
43macro_rules! cast_from {
44 ($from:ty, $to:ty) => {
45 paste::paste! {
46 impl crate::cast::CastFrom<$from> for $to {
47 #[allow(clippy::as_conversions)]
48 #[allow(unused)]
49 fn cast_from(from: $from) -> $to {
50 from as $to
51 }
52 }
53
54 #[allow(clippy::as_conversions)]
59 #[allow(unused)]
60 pub const fn [< $from _to_ $to >](from: $from) -> $to {
61 from as $to
62 }
63 }
64 };
65}
66
67#[cfg(target_pointer_width = "32")]
68mod target32 {
70 cast_from!(u8, usize);
72 cast_from!(u16, usize);
73 cast_from!(u8, isize);
74 cast_from!(i8, isize);
75 cast_from!(u16, isize);
76 cast_from!(i16, isize);
77
78 cast_from!(usize, u64);
79 cast_from!(usize, i64);
80 cast_from!(usize, u128);
81 cast_from!(usize, i128);
82 cast_from!(isize, i64);
83 cast_from!(isize, i128);
84
85 cast_from!(usize, u32);
87 cast_from!(isize, i32);
88 cast_from!(u32, usize);
89 cast_from!(i32, isize);
90}
91
92#[cfg(target_pointer_width = "64")]
93pub mod target64 {
95 cast_from!(u8, usize);
97 cast_from!(u16, usize);
98 cast_from!(u32, usize);
99 cast_from!(u8, isize);
100 cast_from!(i8, isize);
101 cast_from!(u16, isize);
102 cast_from!(i16, isize);
103 cast_from!(u32, isize);
104 cast_from!(i32, isize);
105
106 cast_from!(usize, u128);
107 cast_from!(usize, i128);
108 cast_from!(isize, i128);
109
110 cast_from!(usize, u64);
112 cast_from!(isize, i64);
113 cast_from!(u64, usize);
114 cast_from!(i64, isize);
115}
116
117cast_from!(u8, u8);
119cast_from!(u8, u16);
120cast_from!(u8, i16);
121cast_from!(u8, u32);
122cast_from!(u8, i32);
123cast_from!(u8, u64);
124cast_from!(u8, i64);
125cast_from!(u8, u128);
126cast_from!(u8, i128);
127cast_from!(u16, u16);
128cast_from!(u16, u32);
129cast_from!(u16, i32);
130cast_from!(u16, u64);
131cast_from!(u16, i64);
132cast_from!(u16, u128);
133cast_from!(u16, i128);
134cast_from!(u32, u32);
135cast_from!(u32, u64);
136cast_from!(u32, i64);
137cast_from!(u32, u128);
138cast_from!(u32, i128);
139cast_from!(u64, u64);
140cast_from!(u64, u128);
141cast_from!(u64, i128);
142cast_from!(i8, i8);
143cast_from!(i8, i16);
144cast_from!(i8, i32);
145cast_from!(i8, i64);
146cast_from!(i8, i128);
147cast_from!(i16, i16);
148cast_from!(i16, i32);
149cast_from!(i16, i64);
150cast_from!(i16, i128);
151cast_from!(i32, i32);
152cast_from!(i32, i64);
153cast_from!(i32, i128);
154cast_from!(i64, i64);
155cast_from!(i64, i128);
156
157pub trait TryCastFrom<T>: Sized {
167 fn try_cast_from(from: T) -> Option<Self>;
169}
170
171macro_rules! try_cast_from {
175 ($from:ty, $to:ty) => {
176 impl crate::cast::TryCastFrom<$from> for $to {
177 #[allow(clippy::as_conversions)]
178 fn try_cast_from(from: $from) -> Option<$to> {
179 let to = from as $to;
180 let inverse = to as $from;
181 if from == inverse {
182 Some(to)
183 } else {
184 None
185 }
186 }
187 }
188 };
189}
190
191try_cast_from!(f64, i64);
192try_cast_from!(i64, f64);
193try_cast_from!(f64, u64);
194try_cast_from!(u64, f64);
195
196#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
198#[repr(transparent)]
199pub struct NonNeg<T>(T)
200where
201 T: Signed + fmt::Display;
202
203impl<T> NonNeg<T>
204where
205 T: Signed + fmt::Display,
206{
207 pub fn min() -> NonNeg<T> {
209 NonNeg(T::zero())
210 }
211
212 pub fn max() -> NonNeg<T>
214 where
215 T: UpperBounded,
216 {
217 NonNeg(T::max_value())
218 }
219
220 pub fn try_from(n: T) -> Result<NonNeg<T>, NonNegError> {
224 match n.is_negative() {
225 false => Ok(NonNeg(n)),
226 true => Err(NonNegError),
227 }
228 }
229}
230
231impl<T> fmt::Display for NonNeg<T>
232where
233 T: Signed + fmt::Display,
234{
235 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
236 self.0.fmt(f)
237 }
238}
239
240impl<T> Deref for NonNeg<T>
241where
242 T: Signed + fmt::Display,
243{
244 type Target = T;
245
246 fn deref(&self) -> &T {
247 &self.0
248 }
249}
250
251impl From<NonNeg<i64>> for u64 {
252 fn from(n: NonNeg<i64>) -> u64 {
253 u64::try_from(*n).expect("non-negative")
254 }
255}
256
257#[cfg(target_pointer_width = "64")]
258impl CastFrom<NonNeg<i64>> for usize {
259 #[allow(clippy::as_conversions)]
260 fn cast_from(from: NonNeg<i64>) -> usize {
261 usize::cast_from(u64::from(from))
262 }
263}
264
265#[derive(Debug, Clone)]
268pub struct NonNegError;
269
270impl fmt::Display for NonNegError {
271 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
272 f.write_str("cannot construct NonNeg from negative number")
273 }
274}
275
276impl Error for NonNegError {}