1use super::*;
9
10impl Conv<f32> for f64 {
11 fn try_conv(x: f32) -> Result<Self> {
12 match x.is_nan() {
13 false => Ok(x as f64),
14 true => Err(Error::Range),
15 }
16 }
17
18 #[inline]
19 fn conv(x: f32) -> f64 {
20 fn trap_nan(x: f32) {
21 if x.is_nan() {
22 panic!("cast float-to-float: NaN")
23 }
24 }
25
26 if cfg!(any(debug_assertions, feature = "assert_float")) {
27 trap_nan(x)
28 }
29
30 x as f64
31 }
32}
33
34#[allow(clippy::manual_range_contains)]
35impl ConvApprox<f64> for f32 {
36 fn try_conv_approx(x: f64) -> Result<f32> {
37 match x.is_nan() {
38 false => Ok(x as f32),
39 true => Err(Error::Range),
40 }
41 }
42
43 #[inline]
44 fn conv_approx(x: f64) -> f32 {
45 fn trap_nan(x: f64) {
46 if x.is_nan() {
47 panic!("cast float-to-float: NaN")
48 }
49 }
50
51 if cfg!(any(debug_assertions, feature = "assert_float")) {
52 trap_nan(x)
53 }
54
55 x as f32
56 }
57}
58
59#[cfg(all(not(feature = "std"), feature = "libm"))]
60trait FloatRound {
61 fn round(self) -> Self;
62 fn floor(self) -> Self;
63 fn ceil(self) -> Self;
64}
65#[cfg(all(not(feature = "std"), feature = "libm"))]
66impl FloatRound for f32 {
67 fn round(self) -> Self {
68 libm::roundf(self)
69 }
70 fn floor(self) -> Self {
71 libm::floorf(self)
72 }
73 fn ceil(self) -> Self {
74 libm::ceilf(self)
75 }
76}
77#[cfg(all(not(feature = "std"), feature = "libm"))]
78impl FloatRound for f64 {
79 fn round(self) -> Self {
80 libm::round(self)
81 }
82 fn floor(self) -> Self {
83 libm::floor(self)
84 }
85 fn ceil(self) -> Self {
86 libm::ceil(self)
87 }
88}
89
90#[cfg(any(feature = "std", feature = "libm"))]
91macro_rules! impl_float {
92 ($x:ty: $y:tt) => {
93 impl ConvFloat<$x> for $y {
94 #[inline]
95 fn conv_trunc(x: $x) -> $y {
96 if cfg!(any(debug_assertions, feature = "assert_float")) {
97 Self::try_conv_trunc(x).unwrap_or_else(|_| {
98 panic!(
99 "cast x: {} to {} (trunc): range error for x = {}",
100 stringify!($x), stringify!($y), x
101 )
102 })
103 } else {
104 x as $y
105 }
106 }
107 #[inline]
108 fn conv_nearest(x: $x) -> $y {
109 if cfg!(any(debug_assertions, feature = "assert_float")) {
110 Self::try_conv_nearest(x).unwrap_or_else(|_| {
111 panic!(
112 "cast x: {} to {} (nearest): range error for x = {}",
113 stringify!($x), stringify!($y), x
114 )
115 })
116 } else {
117 x.round() as $y
118 }
119 }
120 #[inline]
121 fn conv_floor(x: $x) -> $y {
122 if cfg!(any(debug_assertions, feature = "assert_float")) {
123 Self::try_conv_floor(x).unwrap_or_else(|_| {
124 panic!(
125 "cast x: {} to {} (floor): range error for x = {}",
126 stringify!($x), stringify!($y), x
127 )
128 })
129 } else {
130 x.floor() as $y
131 }
132 }
133 #[inline]
134 fn conv_ceil(x: $x) -> $y {
135 if cfg!(any(debug_assertions, feature = "assert_float")) {
136 Self::try_conv_ceil(x).unwrap_or_else(|_| {
137 panic!(
138 "cast x: {} to {} (ceil): range error for x = {}",
139 stringify!($x), stringify!($y), x
140 )
141 })
142 } else {
143 x.ceil() as $y
144 }
145 }
146
147 #[inline]
148 fn try_conv_trunc(x: $x) -> Result<Self> {
149 const LBOUND: $x = $y::MIN as $x - 1.0;
151 const UBOUND: $x = $y::MAX as $x + 1.0;
152 if x > LBOUND && x < UBOUND {
153 Ok(x as $y)
154 } else {
155 Err(Error::Range)
156 }
157 }
158 #[inline]
159 fn try_conv_nearest(x: $x) -> Result<Self> {
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(Error::Range)
168 }
169 }
170 #[inline]
171 fn try_conv_floor(x: $x) -> Result<Self> {
172 const LBOUND: $x = $y::MIN as $x;
174 const UBOUND: $x = $y::MAX as $x + 1.0;
175 let x = x.floor();
176 if (LBOUND..UBOUND).contains(&x) {
177 Ok(x as $y)
178 } else {
179 Err(Error::Range)
180 }
181 }
182 #[inline]
183 fn try_conv_ceil(x: $x) -> Result<Self> {
184 const LBOUND: $x = $y::MIN as $x;
186 const UBOUND: $x = $y::MAX as $x + 1.0;
187 let x = x.ceil();
188 if (LBOUND..UBOUND).contains(&x) {
189 Ok(x as $y)
190 } else {
191 Err(Error::Range)
192 }
193 }
194 }
195
196 impl ConvApprox<$x> for $y {
197 #[inline]
198 fn try_conv_approx(x: $x) -> Result<Self> {
199 ConvFloat::<$x>::try_conv_trunc(x)
200 }
201 #[inline]
202 fn conv_approx(x: $x) -> Self {
203 ConvFloat::<$x>::conv_trunc(x)
204 }
205 }
206 };
207 ($x:ty: $y:tt, $($yy:tt),+) => {
208 impl_float!($x: $y);
209 impl_float!($x: $($yy),+);
210 };
211}
212
213#[cfg(any(feature = "std", feature = "libm"))]
215impl_float!(f32: i8, i16, i32, i64, i128, isize);
216#[cfg(any(feature = "std", feature = "libm"))]
217impl_float!(f32: u8, u16, u32, u64, usize);
218#[cfg(any(feature = "std", feature = "libm"))]
219impl_float!(f64: i8, i16, i32, i64, i128, isize);
220#[cfg(any(feature = "std", feature = "libm"))]
221impl_float!(f64: u8, u16, u32, u64, u128, usize);
222
223#[cfg(any(feature = "std", feature = "libm"))]
224impl ConvFloat<f32> for u128 {
225 #[inline]
226 fn conv_trunc(x: f32) -> u128 {
227 if cfg!(any(debug_assertions, feature = "assert_float")) {
228 Self::try_conv_trunc(x).unwrap_or_else(|_| {
229 panic!(
230 "cast x: f32 to u128 (trunc/floor): range error for x = {}",
231 x
232 )
233 })
234 } else {
235 x as u128
236 }
237 }
238 #[inline]
239 fn conv_nearest(x: f32) -> u128 {
240 if cfg!(any(debug_assertions, feature = "assert_float")) {
241 Self::try_conv_nearest(x).unwrap_or_else(|_| {
242 panic!("cast x: f32 to u128 (nearest): range error for x = {}", x)
243 })
244 } else {
245 x.round() as u128
246 }
247 }
248 #[inline]
249 fn conv_floor(x: f32) -> u128 {
250 ConvFloat::conv_trunc(x)
251 }
252 #[inline]
253 fn conv_ceil(x: f32) -> u128 {
254 if cfg!(any(debug_assertions, feature = "assert_float")) {
255 Self::try_conv_ceil(x)
256 .unwrap_or_else(|_| panic!("cast x: f32 to u128 (ceil): range error for x = {}", x))
257 } else {
258 x.ceil() as u128
259 }
260 }
261
262 #[inline]
263 fn try_conv_trunc(x: f32) -> Result<Self> {
264 if x >= 0.0 && x.is_finite() {
266 Ok(x as u128)
267 } else {
268 Err(Error::Range)
269 }
270 }
271 #[inline]
272 fn try_conv_nearest(x: f32) -> Result<Self> {
273 let x = x.round();
274 if x >= 0.0 && x.is_finite() {
275 Ok(x as u128)
276 } else {
277 Err(Error::Range)
278 }
279 }
280 #[inline]
281 fn try_conv_floor(x: f32) -> Result<Self> {
282 Self::try_conv_trunc(x)
283 }
284 #[inline]
285 fn try_conv_ceil(x: f32) -> Result<Self> {
286 let x = x.ceil();
287 if x >= 0.0 && x.is_finite() {
288 Ok(x as u128)
289 } else {
290 Err(Error::Range)
291 }
292 }
293}
294
295#[cfg(any(feature = "std", feature = "libm"))]
296impl ConvApprox<f32> for u128 {
297 #[inline]
298 fn try_conv_approx(x: f32) -> Result<Self> {
299 ConvFloat::<f32>::try_conv_trunc(x)
300 }
301 #[inline]
302 fn conv_approx(x: f32) -> Self {
303 ConvFloat::<f32>::conv_trunc(x)
304 }
305}