substrate_fixed/
cast.rs

1// Copyright © 2018–2019 Trevor Spiteri
2
3// This library is free software: you can redistribute it and/or
4// modify it under the terms of either
5//
6//   * the Apache License, Version 2.0 or
7//   * the MIT License
8//
9// at your option.
10//
11// You should have recieved copies of the Apache License and the MIT
12// License along with the library. If not, see
13// <https://www.apache.org/licenses/LICENSE-2.0> and
14// <https://opensource.org/licenses/MIT>.
15
16use crate::{
17    types::extra::{LeEqU128, LeEqU16, LeEqU32, LeEqU64, LeEqU8},
18    FixedI128, FixedI16, FixedI32, FixedI64, FixedI8, FixedU128, FixedU16, FixedU32, FixedU64,
19    FixedU8,
20};
21use az::{Cast, CheckedCast, OverflowingCast, SaturatingCast, StaticCast, WrappingCast};
22use core::mem;
23#[cfg(feature = "f16")]
24use half::{bf16, f16};
25
26macro_rules! run_time {
27    ($Src:ident($LeEqUSrc:ident); $Dst:ident($LeEqUDst:ident)) => {
28        impl<FracSrc: $LeEqUSrc, FracDst: $LeEqUDst> Cast<$Dst<FracDst>> for $Src<FracSrc> {
29            #[inline]
30            fn cast(self) -> $Dst<FracDst> {
31                self.to_num()
32            }
33        }
34
35        impl<FracSrc: $LeEqUSrc, FracDst: $LeEqUDst> CheckedCast<$Dst<FracDst>> for $Src<FracSrc> {
36            #[inline]
37            fn checked_cast(self) -> Option<$Dst<FracDst>> {
38                self.checked_to_num()
39            }
40        }
41
42        impl<FracSrc: $LeEqUSrc, FracDst: $LeEqUDst> SaturatingCast<$Dst<FracDst>>
43            for $Src<FracSrc>
44        {
45            #[inline]
46            fn saturating_cast(self) -> $Dst<FracDst> {
47                self.saturating_to_num()
48            }
49        }
50
51        impl<FracSrc: $LeEqUSrc, FracDst: $LeEqUDst> WrappingCast<$Dst<FracDst>> for $Src<FracSrc> {
52            #[inline]
53            fn wrapping_cast(self) -> $Dst<FracDst> {
54                self.wrapping_to_num()
55            }
56        }
57
58        impl<FracSrc: $LeEqUSrc, FracDst: $LeEqUDst> OverflowingCast<$Dst<FracDst>>
59            for $Src<FracSrc>
60        {
61            #[inline]
62            fn overflowing_cast(self) -> ($Dst<FracDst>, bool) {
63                self.overflowing_to_num()
64            }
65        }
66    };
67
68    ($Fixed:ident($LeEqU:ident); $Dst:ident) => {
69        impl<Frac: $LeEqU> Cast<$Dst> for $Fixed<Frac> {
70            #[inline]
71            fn cast(self) -> $Dst {
72                self.to_num()
73            }
74        }
75
76        impl<Frac: $LeEqU> CheckedCast<$Dst> for $Fixed<Frac> {
77            #[inline]
78            fn checked_cast(self) -> Option<$Dst> {
79                self.checked_to_num()
80            }
81        }
82
83        impl<Frac: $LeEqU> SaturatingCast<$Dst> for $Fixed<Frac> {
84            #[inline]
85            fn saturating_cast(self) -> $Dst {
86                self.saturating_to_num()
87            }
88        }
89
90        impl<Frac: $LeEqU> WrappingCast<$Dst> for $Fixed<Frac> {
91            #[inline]
92            fn wrapping_cast(self) -> $Dst {
93                self.wrapping_to_num()
94            }
95        }
96
97        impl<Frac: $LeEqU> OverflowingCast<$Dst> for $Fixed<Frac> {
98            #[inline]
99            fn overflowing_cast(self) -> ($Dst, bool) {
100                self.overflowing_to_num()
101            }
102        }
103    };
104
105    ($Src:ident; $Fixed:ident($LeEqU:ident)) => {
106        impl<Frac: $LeEqU> Cast<$Fixed<Frac>> for $Src {
107            #[inline]
108            fn cast(self) -> $Fixed<Frac> {
109                <$Fixed<Frac>>::from_num(self)
110            }
111        }
112
113        impl<Frac: $LeEqU> CheckedCast<$Fixed<Frac>> for $Src {
114            #[inline]
115            fn checked_cast(self) -> Option<$Fixed<Frac>> {
116                <$Fixed<Frac>>::checked_from_num(self)
117            }
118        }
119
120        impl<Frac: $LeEqU> SaturatingCast<$Fixed<Frac>> for $Src {
121            #[inline]
122            fn saturating_cast(self) -> $Fixed<Frac> {
123                <$Fixed<Frac>>::saturating_from_num(self)
124            }
125        }
126
127        impl<Frac: $LeEqU> WrappingCast<$Fixed<Frac>> for $Src {
128            #[inline]
129            fn wrapping_cast(self) -> $Fixed<Frac> {
130                <$Fixed<Frac>>::wrapping_from_num(self)
131            }
132        }
133
134        impl<Frac: $LeEqU> OverflowingCast<$Fixed<Frac>> for $Src {
135            #[inline]
136            fn overflowing_cast(self) -> ($Fixed<Frac>, bool) {
137                <$Fixed<Frac>>::overflowing_from_num(self)
138            }
139        }
140    };
141}
142
143macro_rules! compile_time {
144    (
145        impl<$FracSrc:ident: $LeEqUSrc:ident, $FracDst:ident: $LeEqUDst:ident> StaticCast<$Dst:ty>
146            for $Src:ty
147        {
148            $cond:expr
149        }
150    ) => {
151        impl<$FracSrc: $LeEqUSrc, $FracDst: $LeEqUDst> StaticCast<$Dst> for $Src {
152            #[inline]
153            fn static_cast(self) -> Option<$Dst> {
154                if $cond {
155                    Some(az::cast(self))
156                } else {
157                    None
158                }
159            }
160        }
161    };
162
163    (impl<$Frac:ident: $LeEqU:ident> StaticCast<$Dst:ty> for $Src:ty { $cond:expr }) => {
164        impl<$Frac: $LeEqU> StaticCast<$Dst> for $Src {
165            #[inline]
166            fn static_cast(self) -> Option<$Dst> {
167                if $cond {
168                    Some(az::cast(self))
169                } else {
170                    None
171                }
172            }
173        }
174    };
175
176    ($SrcI:ident, $SrcU:ident($LeEqUSrc:ident); $DstI:ident, $DstU:ident($LeEqUDst:ident)) => {
177        compile_time! {
178            impl<FracSrc: $LeEqUSrc, FracDst: $LeEqUDst> StaticCast<$DstI<FracDst>>
179                for $SrcI<FracSrc>
180            {
181                <$DstI<FracDst>>::INT_NBITS >= <$SrcI<FracSrc>>::INT_NBITS
182            }
183        }
184
185        compile_time! {
186            impl<FracSrc: $LeEqUSrc, FracDst: $LeEqUDst> StaticCast<$DstU<FracDst>>
187                for $SrcI<FracSrc>
188            {
189                false
190            }
191        }
192
193        compile_time! {
194            impl<FracSrc: $LeEqUSrc, FracDst: $LeEqUDst> StaticCast<$DstI<FracDst>>
195                for $SrcU<FracSrc>
196            {
197                <$DstI<FracDst>>::INT_NBITS > <$SrcU<FracSrc>>::INT_NBITS
198            }
199        }
200
201        compile_time! {
202            impl<FracSrc: $LeEqUSrc, FracDst: $LeEqUDst> StaticCast<$DstU<FracDst>>
203                for $SrcU<FracSrc>
204            {
205                <$DstU<FracDst>>::INT_NBITS >= <$SrcU<FracSrc>>::INT_NBITS
206            }
207        }
208    };
209
210    ($FixedI:ident, $FixedU:ident($LeEqU:ident); int $DstI:ident, $DstU:ident) => {
211        compile_time! {
212            impl<Frac: $LeEqU> StaticCast<$DstI> for $FixedI<Frac> {
213                8 * mem::size_of::<$DstI>() as u32 >= <$FixedI<Frac>>::INT_NBITS
214            }
215        }
216
217        compile_time! {
218            impl<Frac: $LeEqU> StaticCast<$DstI> for $FixedU<Frac> {
219                8 * mem::size_of::<$DstI>() as u32 > <$FixedU<Frac>>::INT_NBITS
220            }
221        }
222
223        compile_time! {
224            impl<Frac: $LeEqU> StaticCast<$DstU> for $FixedI<Frac> {
225                false
226            }
227        }
228
229        compile_time! {
230            impl<Frac: $LeEqU> StaticCast<$DstU> for $FixedU<Frac> {
231                8 * mem::size_of::<$DstU>() as u32 >= <$FixedU<Frac>>::INT_NBITS
232            }
233        }
234    };
235
236    (int $SrcI:ident, $SrcU:ident; $FixedI:ident, $FixedU:ident($LeEqU:ident)) => {
237        compile_time! {
238            impl<Frac: $LeEqU> StaticCast<$FixedI<Frac>> for $SrcI {
239                <$FixedI<Frac>>::INT_NBITS >= 8 * mem::size_of::<$SrcI>() as u32
240            }
241        }
242
243        compile_time! {
244            impl<Frac: $LeEqU> StaticCast<$FixedU<Frac>> for $SrcI {
245                false
246            }
247        }
248
249        compile_time! {
250            impl<Frac: $LeEqU> StaticCast<$FixedI<Frac>> for $SrcU {
251                <$FixedI<Frac>>::INT_NBITS > 8 * mem::size_of::<$SrcU>() as u32
252            }
253        }
254
255        compile_time! {
256            impl<Frac: $LeEqU> StaticCast<$FixedU<Frac>> for $SrcU {
257                <$FixedU<Frac>>::INT_NBITS >= 8 * mem::size_of::<$SrcU>() as u32
258            }
259        }
260    };
261
262    ($Fixed:ident($LeEqU:ident); float $Dst:ident) => {
263        compile_time! {
264            impl<Frac: $LeEqU> StaticCast<$Dst> for $Fixed<Frac> {
265                true
266            }
267        }
268    };
269
270    (float $Src:ident; $Fixed:ident($LeEqU:ident)) => {
271        compile_time! {
272            impl<Frac: $LeEqU> StaticCast<$Fixed<Frac>> for $Src {
273                false
274            }
275        }
276    };
277}
278
279macro_rules! run_time_num {
280    ($Src:ident($LeEqUSrc:ident); $($Dst:ident($LeEqUDst:ident),)*) => { $(
281        run_time! { $Src($LeEqUSrc); $Dst($LeEqUDst) }
282    )* };
283    ($Fixed:ident($LeEqU:ident); $($Num:ident,)*) => { $(
284        run_time! { $Fixed($LeEqU); $Num }
285        run_time! { $Num; $Fixed($LeEqU) }
286    )* };
287    ($($Fixed:ident($LeEqU:ident),)*) => { $(
288        run_time_num! {
289            $Fixed($LeEqU);
290            FixedI8(LeEqU8), FixedI16(LeEqU16), FixedI32(LeEqU32), FixedI64(LeEqU64),
291            FixedI128(LeEqU128),
292            FixedU8(LeEqU8), FixedU16(LeEqU16), FixedU32(LeEqU32), FixedU64(LeEqU64),
293            FixedU128(LeEqU128),
294        }
295        run_time! { bool; $Fixed($LeEqU) }
296        run_time_num! {
297            $Fixed($LeEqU);
298            i8, i16, i32, i64, i128, isize,
299            u8, u16, u32, u64, u128, usize,
300            f32, f64,
301        }
302        #[cfg(feature = "f16")]
303        run_time_num! {
304            $Fixed($LeEqU);
305            f16, bf16,
306        }
307    )* };
308}
309
310run_time_num! {
311    FixedI8(LeEqU8), FixedI16(LeEqU16), FixedI32(LeEqU32), FixedI64(LeEqU64), FixedI128(LeEqU128),
312    FixedU8(LeEqU8), FixedU16(LeEqU16), FixedU32(LeEqU32), FixedU64(LeEqU64), FixedU128(LeEqU128),
313}
314
315macro_rules! compile_time_fixed {
316    (
317        $SrcI:ident, $SrcU:ident($LeEqUSrc:ident); $(($DstI:ident, $DstU:ident($LeEqUDst:ident)),)*
318    ) => { $(
319        compile_time! { $SrcI, $SrcU($LeEqUSrc); $DstI, $DstU($LeEqUDst) }
320    )* };
321    ($($FixedI:ident, $FixedU:ident($LeEqU:ident),)*) => { $(
322        compile_time_fixed! {
323            $FixedI, $FixedU($LeEqU);
324            (FixedI8, FixedU8(LeEqU8)),
325            (FixedI16, FixedU16(LeEqU16)),
326            (FixedI32, FixedU32(LeEqU32)),
327            (FixedI64, FixedU64(LeEqU64)),
328            (FixedI128, FixedU128(LeEqU128)),
329        }
330    )* };
331}
332
333compile_time_fixed! {
334    FixedI8, FixedU8(LeEqU8),
335    FixedI16, FixedU16(LeEqU16),
336    FixedI32, FixedU32(LeEqU32),
337    FixedI64, FixedU64(LeEqU64),
338    FixedI128, FixedU128(LeEqU128),
339}
340
341macro_rules! compile_time_int {
342    ($FixedI:ident, $FixedU:ident($LeEqU:ident); $(($IntI:ident, $IntU:ident),)*) => { $(
343        compile_time! { $FixedI, $FixedU($LeEqU); int $IntI, $IntU }
344        compile_time! { int $IntI, $IntU; $FixedI, $FixedU($LeEqU) }
345    )* };
346    ($($FixedI:ident, $FixedU:ident($LeEqU:ident),)*) => { $(
347        compile_time! {
348            impl<Frac: $LeEqU> StaticCast<$FixedI<Frac>> for bool {
349                <$FixedI<Frac>>::INT_NBITS > 1
350            }
351        }
352
353        compile_time! {
354            impl<Frac: $LeEqU> StaticCast<$FixedU<Frac>> for bool {
355                <$FixedU<Frac>>::INT_NBITS >= 1
356            }
357        }
358
359        compile_time_int! {
360            $FixedI, $FixedU($LeEqU);
361            (i8, u8),
362            (i16, u16),
363            (i32, u32),
364            (i64, u64),
365            (i128, u128),
366            (isize, usize),
367        }
368    )* };
369}
370
371compile_time_int! {
372    FixedI8, FixedU8(LeEqU8),
373    FixedI16, FixedU16(LeEqU16),
374    FixedI32, FixedU32(LeEqU32),
375    FixedI64, FixedU64(LeEqU64),
376    FixedI128, FixedU128(LeEqU128),
377}
378
379macro_rules! compile_time_float {
380    ($Fixed:ident($LeEqU:ident); $($Float:ident,)*) => { $(
381        compile_time! { $Fixed($LeEqU); float $Float }
382        compile_time! { float $Float; $Fixed($LeEqU) }
383    )* };
384    ($($Fixed:ident($LeEqU:ident),)*) => { $(
385        compile_time_float! {
386            $Fixed($LeEqU);
387            f32, f64,
388        }
389        #[cfg(feature = "f16")]
390        compile_time_float! {
391            $Fixed($LeEqU);
392            f16, bf16,
393        }
394    )* };
395}
396
397compile_time_float! {
398    FixedI8(LeEqU8), FixedI16(LeEqU16), FixedI32(LeEqU32), FixedI64(LeEqU64), FixedI128(LeEqU128),
399    FixedU8(LeEqU8), FixedU16(LeEqU16), FixedU32(LeEqU32), FixedU64(LeEqU64), FixedU128(LeEqU128),
400}