1pub trait NumTo<T> {
5 fn fits(&self) -> bool;
10
11 fn to(&self) -> T;
16}
17
18#[derive(Clone, Copy)]
21pub enum Num {
22 F32(f32),
24
25 F64(f64),
27
28 Signed(i64),
30
31 Unsigned(u64),
33}
34
35impl core::fmt::Debug for Num {
36 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
37 match self {
38 Num::F32(n) => n.fmt(f),
39 Num::F64(n) => n.fmt(f),
40 Num::Signed(n) => n.fmt(f),
41 Num::Unsigned(n) => n.fmt(f),
42 }
43 }
44}
45
46impl core::fmt::Display for Num {
47 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
48 match self {
49 Num::F32(n) => n.fmt(f),
50 Num::F64(n) => n.fmt(f),
51 Num::Signed(n) => n.fmt(f),
52 Num::Unsigned(n) => n.fmt(f),
53 }
54 }
55}
56
57impl PartialEq for Num {
58 fn eq(&self, oth: &Num) -> bool {
59 match self {
60 Num::F32(f) => oth.eq(f),
61 Num::F64(f) => oth.eq(f),
62 Num::Signed(i) => oth.eq(i),
63 Num::Unsigned(u) => oth.eq(u),
64 }
65 }
66}
67
68macro_rules! p_eq {
69 ($($t:ty)*) => {$(
70 impl PartialEq<$t> for Num {
71 fn eq(&self, oth: &$t) -> bool {
72 match self {
73 Num::F32(f) => *oth as f32 == *f && *oth as f32 as $t == *oth,
74 Num::F64(f) => *oth as f64 == *f && *oth as f64 as $t == *oth,
75 Num::Signed(i) => *oth as i64 == *i && *oth as i64 as $t == *oth,
76 Num::Unsigned(u) => *oth as u64 == *u && *oth as u64 as $t == *oth,
77 }
78 }
79 }
80 )*};
81}
82
83p_eq!( u8 u16 u32 u64 i128 usize i8 i16 i32 i64 u128 isize f32 f64 );
84
85impl Num {
86 pub fn fits<T>(&self) -> bool
91 where
92 Self: NumTo<T>,
93 {
94 NumTo::fits(self)
95 }
96
97 pub fn to<T>(&self) -> T
102 where
103 Self: NumTo<T>,
104 {
105 NumTo::to(self)
106 }
107}
108
109impl From<f32> for Num {
110 fn from(t: f32) -> Self {
111 if t >= 0.0 && t as u64 as f32 == t {
112 Num::Unsigned(t as u64)
113 } else if t as i64 as f32 == t {
114 Num::Signed(t as i64)
115 } else {
116 Num::F32(t)
117 }
118 }
119}
120
121impl From<f64> for Num {
122 fn from(t: f64) -> Self {
123 if t >= 0.0 && t as u64 as f64 == t {
124 Num::Unsigned(t as u64)
125 } else if t as i64 as f64 == t {
126 Num::Signed(t as i64)
127 } else if t as f32 as f64 == t {
128 Num::F32(t as f32)
129 } else {
130 Num::F64(t)
131 }
132 }
133}
134
135macro_rules! into_num {
136 ($i:ident:$e:expr => $($t:ty)*) => {$(
137 impl From<$t> for Num {
138 fn from($i: $t) -> Self {
139 $e
140 }
141 }
142 )*};
143}
144
145into_num!(t:Num::Signed(t as i64) => i8 i16 i32 i64 isize); into_num!(t:Num::Unsigned(t as u64) => u8 u16 u32 u64 usize); macro_rules! num_to {
149 ($($t:ty)*) => {$(
150 impl NumTo<$t> for Num {
151 fn fits(&self) -> bool {
152 match self {
153 Num::F32(f) => *f as $t as f32 == *f,
154 Num::F64(f) => *f as $t as f64 == *f,
155 Num::Signed(i) => *i as $t as i64 == *i,
156 Num::Unsigned(u) => *u as $t as u64 == *u,
157 }
158 }
159
160 fn to(&self) -> $t {
161 match &self {
162 Num::F32(f) => (*f) as $t,
163 Num::F64(f) => (*f) as $t,
164 Num::Signed(i) => (*i as i128).clamp(
165 <$t>::MIN as i128,
166 <$t>::MAX as i128,
167 ) as $t,
168 Num::Unsigned(u) => (*u as i128).clamp(
169 <$t>::MIN as i128,
170 <$t>::MAX as i128,
171 ) as $t,
172 }
173 }
174 }
175 )*};
176}
177
178num_to!(u8 u16 u32 u64 usize i8 i16 i32 i64 i128 isize f32 f64);
179
180impl NumTo<u128> for Num {
182 fn fits(&self) -> bool {
183 match self {
184 Num::F32(f) => *f as u128 as f32 == *f,
185 Num::F64(f) => *f as u128 as f64 == *f,
186 Num::Signed(i) => *i as u128 as i64 == *i,
187 Num::Unsigned(u) => *u as u128 as u64 == *u,
188 }
189 }
190
191 fn to(&self) -> u128 {
192 match &self {
193 Num::F32(f) => (*f) as u128,
194 Num::F64(f) => (*f) as u128,
195 Num::Signed(i) => (*i).clamp(0, i64::MAX) as u128,
196 Num::Unsigned(u) => (*u) as u128,
197 }
198 }
199}
200
201#[cfg(test)]
202mod num_tests {
203 use super::*;
204
205 #[test]
206 fn test_to() {
207 macro_rules! test_to_from {
208 ($tt:ty:$($tf:ty)*) => {$({
209 let _n: $tt = Num::from(<$tf>::MIN).to();
210 let _n: $tt = Num::from(<$tf>::MAX).to();
211 })*};
212 }
213
214 macro_rules! test_to {
215 ($($t:ty)*) => {$(
216 test_to_from!($t: u8 u16 u32 u64 usize i8 i16 i32 i64 isize f32 f64);
217 )*};
218 }
219
220 test_to!(u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize f32 f64);
221 }
222}