1use crate::{Approx, ConvExact, ConvTo, Error, Exact, RangeError, Trunc};
9#[cfg(any(feature = "std", feature = "libm"))]
10use crate::{Ceil, Floor, Nearest};
11
12impl ConvExact<f32> for f64 {
13 type Error = RangeError;
14
15 fn try_conv_exact(x: f32) -> Result<Self, RangeError> {
16 match x.is_nan() {
17 false => Ok(x as f64),
18 true => Err(RangeError),
19 }
20 }
21
22 #[inline]
23 fn conv_exact(x: f32) -> f64 {
24 fn trap_nan(x: f32) {
25 if x.is_nan() {
26 panic!("cast float-to-float: NaN")
27 }
28 }
29
30 if cfg!(any(debug_assertions, feature = "assert_float")) {
31 trap_nan(x)
32 }
33
34 x as f64
35 }
36}
37
38impl ConvTo<f64, Approx> for f32 {
39 type Error = RangeError;
40
41 fn try_conv_to(_: Approx, x: f64) -> Result<f32, Self::Error> {
42 match x.is_nan() {
43 false => Ok(x as f32),
44 true => Err(RangeError),
45 }
46 }
47
48 #[inline]
49 fn conv_to(_: Approx, x: f64) -> f32 {
50 fn trap_nan(x: f64) {
51 if x.is_nan() {
52 panic!("cast float-to-float: NaN")
53 }
54 }
55
56 if cfg!(any(debug_assertions, feature = "assert_float")) {
57 trap_nan(x)
58 }
59
60 x as f32
61 }
62}
63
64impl ConvTo<f64, Exact> for f32 {
65 type Error = Error;
66
67 fn try_conv_to(_: Exact, x: f64) -> Result<f32, Self::Error> {
68 match x.is_nan() {
69 false => {
70 let y = x as f32;
71 if <f64 as ConvExact<f32>>::try_conv_exact(y) == Ok(x) {
72 Ok(y)
73 } else {
74 Err(Error::Inexact)
75 }
76 }
77 true => Err(Error::Range),
78 }
79 }
80
81 #[inline]
82 fn conv_to(_: Exact, x: f64) -> f32 {
83 if cfg!(any(debug_assertions, feature = "assert_float")) {
84 f32::try_conv_to(Exact, x).unwrap_or_else(|e| panic!("cast float-to-float: {e}"))
85 } else {
86 x as f32
87 }
88 }
89}
90
91#[cfg(all(not(feature = "std"), feature = "libm"))]
92trait FloatRound {
93 fn round(self) -> Self;
94 fn floor(self) -> Self;
95 fn ceil(self) -> Self;
96}
97#[cfg(all(not(feature = "std"), feature = "libm"))]
98impl FloatRound for f32 {
99 fn round(self) -> Self {
100 libm::roundf(self)
101 }
102 fn floor(self) -> Self {
103 libm::floorf(self)
104 }
105 fn ceil(self) -> Self {
106 libm::ceilf(self)
107 }
108}
109#[cfg(all(not(feature = "std"), feature = "libm"))]
110impl FloatRound for f64 {
111 fn round(self) -> Self {
112 libm::round(self)
113 }
114 fn floor(self) -> Self {
115 libm::floor(self)
116 }
117 fn ceil(self) -> Self {
118 libm::ceil(self)
119 }
120}
121
122macro_rules! impl_float {
123 ($x:ty: $y:tt) => {
124 impl ConvTo<$x, Trunc> for $y {
125 type Error = RangeError;
126
127 #[inline]
128 fn try_conv_to(_: Trunc, x: $x) -> Result<Self, RangeError> {
129 const LBOUND: $x = $y::MIN as $x - 1.0;
131 const UBOUND: $x = $y::MAX as $x + 1.0;
132 if x > LBOUND && x < UBOUND {
133 Ok(x as $y)
134 } else {
135 Err(RangeError)
136 }
137 }
138
139 #[inline]
140 fn conv_to(_: Trunc, x: $x) -> Self {
141 if cfg!(any(debug_assertions, feature = "assert_float")) {
142 <$y>::try_conv_to(Trunc, x).unwrap_or_else(|_| {
143 panic!(
144 "cast x: {} to {} (trunc): range error for x = {}",
145 stringify!($x), stringify!($y), x
146 )
147 })
148 } else {
149 x as $y
150 }
151 }
152 }
153
154 #[cfg(any(feature = "std", feature = "libm"))]
155 impl ConvTo<$x, Nearest> for $y {
156 type Error = RangeError;
157
158 #[inline]
159 fn try_conv_to(_: Nearest, x: $x) -> Result<Self, RangeError> {
160 const LBOUND: $x = $y::MIN as $x;
162 const UBOUND: $x = $y::MAX as $x + 1.0;
163 let x = x.round();
164 if (LBOUND..UBOUND).contains(&x) {
165 Ok(x as $y)
166 } else {
167 Err(RangeError)
168 }
169 }
170
171 #[inline]
172 fn conv_to(_: Nearest, x: $x) -> Self {
173 if cfg!(any(debug_assertions, feature = "assert_float")) {
174 <$y>::try_conv_to(Nearest, x).unwrap_or_else(|_| {
175 panic!(
176 "cast x: {} to {} (nearest): range error for x = {}",
177 stringify!($x), stringify!($y), x
178 )
179 })
180 } else {
181 x.round() as $y
182 }
183 }
184 }
185
186 #[cfg(any(feature = "std", feature = "libm"))]
187 impl ConvTo<$x, Floor> for $y {
188 type Error = RangeError;
189
190 #[inline]
191 fn try_conv_to(_: Floor, x: $x) -> Result<Self, RangeError> {
192 const LBOUND: $x = $y::MIN as $x;
194 const UBOUND: $x = $y::MAX as $x + 1.0;
195 let x = x.floor();
196 if (LBOUND..UBOUND).contains(&x) {
197 Ok(x as $y)
198 } else {
199 Err(RangeError)
200 }
201 }
202
203 #[inline]
204 fn conv_to(_: Floor, x: $x) -> Self {
205 if cfg!(any(debug_assertions, feature = "assert_float")) {
206 <$y>::try_conv_to(Floor, x).unwrap_or_else(|_| {
207 panic!(
208 "cast x: {} to {} (floor): range error for x = {}",
209 stringify!($x), stringify!($y), x
210 )
211 })
212 } else {
213 x.floor() as $y
214 }
215 }
216 }
217
218 #[cfg(any(feature = "std", feature = "libm"))]
219 impl ConvTo<$x, Ceil> for $y {
220 type Error = RangeError;
221
222 #[inline]
223 fn try_conv_to(_: Ceil, x: $x) -> Result<Self, RangeError> {
224 const LBOUND: $x = $y::MIN as $x;
226 const UBOUND: $x = $y::MAX as $x + 1.0;
227 let x = x.ceil();
228 if (LBOUND..UBOUND).contains(&x) {
229 Ok(x as $y)
230 } else {
231 Err(RangeError)
232 }
233 }
234
235 #[inline]
236 fn conv_to(_: Ceil, x: $x) -> Self {
237 if cfg!(any(debug_assertions, feature = "assert_float")) {
238 <$y>::try_conv_to(Ceil, x).unwrap_or_else(|_| {
239 panic!(
240 "cast x: {} to {} (ceil): range error for x = {}",
241 stringify!($x), stringify!($y), x
242 )
243 })
244 } else {
245 x.ceil() as $y
246 }
247 }
248 }
249
250 impl ConvTo<$x, Approx> for $y {
251 type Error = RangeError;
252
253 #[inline]
254 fn try_conv_to(_: Approx, x: $x) -> Result<Self, Self::Error> {
255 Self::try_conv_to(Trunc, x)
256 }
257 #[inline]
258 fn conv_to(_: Approx, x: $x) -> Self {
259 Self::conv_to(Trunc, x)
260 }
261 }
262 };
263 ($x:ty: $y:tt, $($yy:tt),+) => {
264 impl_float!($x: $y);
265 impl_float!($x: $($yy),+);
266 };
267}
268
269impl_float!(f32: i8, i16, i32, i64, i128, isize);
271impl_float!(f32: u8, u16, u32, u64, usize);
272impl_float!(f64: i8, i16, i32, i64, i128, isize);
273impl_float!(f64: u8, u16, u32, u64, u128, usize);
274
275impl ConvTo<f32, Trunc> for u128 {
276 type Error = RangeError;
277
278 #[inline]
279 fn try_conv_to(_: Trunc, x: f32) -> Result<Self, RangeError> {
280 if x >= 0.0 && x.is_finite() {
282 Ok(x as u128)
283 } else {
284 Err(RangeError)
285 }
286 }
287
288 #[inline]
289 fn conv_to(_: Trunc, x: f32) -> u128 {
290 if cfg!(any(debug_assertions, feature = "assert_float")) {
291 <u128>::try_conv_to(Trunc, x).unwrap_or_else(|_| {
292 panic!(
293 "cast x: f32 to u128 (trunc/floor): range error for x = {}",
294 x
295 )
296 })
297 } else {
298 x as u128
299 }
300 }
301}
302
303#[cfg(any(feature = "std", feature = "libm"))]
304impl ConvTo<f32, Nearest> for u128 {
305 type Error = RangeError;
306
307 #[inline]
308 fn try_conv_to(_: Nearest, x: f32) -> Result<Self, RangeError> {
309 let x = x.round();
310 if x >= 0.0 && x.is_finite() {
311 Ok(x as u128)
312 } else {
313 Err(RangeError)
314 }
315 }
316
317 #[inline]
318 fn conv_to(_: Nearest, x: f32) -> u128 {
319 if cfg!(any(debug_assertions, feature = "assert_float")) {
320 <u128>::try_conv_to(Nearest, x).unwrap_or_else(|_| {
321 panic!("cast x: f32 to u128 (nearest): range error for x = {}", x)
322 })
323 } else {
324 x.round() as u128
325 }
326 }
327}
328
329#[cfg(any(feature = "std", feature = "libm"))]
330impl ConvTo<f32, Floor> for u128 {
331 type Error = RangeError;
332
333 #[inline]
334 fn try_conv_to(_: Floor, x: f32) -> Result<Self, RangeError> {
335 Self::try_conv_to(Trunc, x)
336 }
337
338 #[inline]
339 fn conv_to(_: Floor, x: f32) -> u128 {
340 Self::conv_to(Trunc, x)
341 }
342}
343
344#[cfg(any(feature = "std", feature = "libm"))]
345impl ConvTo<f32, Ceil> for u128 {
346 type Error = RangeError;
347
348 #[inline]
349 fn try_conv_to(_: Ceil, x: f32) -> Result<Self, RangeError> {
350 let x = x.ceil();
351 if x >= 0.0 && x.is_finite() {
352 Ok(x as u128)
353 } else {
354 Err(RangeError)
355 }
356 }
357
358 #[inline]
359 fn conv_to(_: Ceil, x: f32) -> u128 {
360 if cfg!(any(debug_assertions, feature = "assert_float")) {
361 u128::try_conv_to(Ceil, x)
362 .unwrap_or_else(|_| panic!("cast x: f32 to u128 (ceil): range error for x = {}", x))
363 } else {
364 x.ceil() as u128
365 }
366 }
367}
368
369impl ConvTo<f32, Approx> for u128 {
370 type Error = RangeError;
371
372 #[inline]
373 fn try_conv_to(_: Approx, x: f32) -> Result<Self, Self::Error> {
374 Self::try_conv_to(Trunc, x)
375 }
376 #[inline]
377 fn conv_to(_: Approx, x: f32) -> Self {
378 Self::conv_to(Trunc, x)
379 }
380}