Skip to main content

fixed/
helpers.rs

1// Copyright © 2018–2026 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::int_helper;
17use crate::types::extra::{LeEqU8, LeEqU16, LeEqU32, LeEqU64, LeEqU128};
18use crate::{
19    FixedI8, FixedI16, FixedI32, FixedI64, FixedI128, FixedU8, FixedU16, FixedU32, FixedU64,
20    FixedU128,
21};
22use core::cmp::Ordering;
23
24// Unsigned can have 0 ≤ x < 2^128, that is its msb can be 0 or 1.
25// Negative can have -2^127 ≤ x < 0, that is its msb must be 1.
26pub enum Widest {
27    Unsigned(u128),
28    Negative(i128),
29}
30
31pub struct ToFixedHelper {
32    pub(crate) bits: Widest,
33    pub(crate) dir: Ordering,
34    pub(crate) overflow: bool,
35}
36
37pub struct ToFloatHelper {
38    pub(crate) neg: bool,
39    pub(crate) abs: u128,
40}
41
42pub struct FromFloatHelper {
43    pub(crate) kind: FloatKind,
44}
45pub enum FloatKind {
46    NaN,
47    Infinite { neg: bool },
48    Finite { neg: bool, conv: ToFixedHelper },
49}
50
51pub struct Private;
52
53pub trait Sealed: Copy {
54    fn to_fixed_helper(self, _: Private, dst_frac_nbits: u32, dst_int_nbits: u32) -> ToFixedHelper;
55    fn to_float_helper(self, _: Private) -> ToFloatHelper;
56    fn saturating_from_float_helper(_: Private, src: FromFloatHelper) -> Self;
57    fn overflowing_from_float_helper(_: Private, src: FromFloatHelper) -> (Self, bool);
58}
59macro_rules! impl_sealed {
60    ($Fixed:ident($LeEqU:ident, $Signedness:ident, $Inner:ident)) => {
61        impl<Frac: $LeEqU> Sealed for $Fixed<Frac> {
62            #[inline]
63            fn to_fixed_helper(
64                self,
65                _: Private,
66                dst_frac_nbits: u32,
67                dst_int_nbits: u32,
68            ) -> ToFixedHelper {
69                int_helper::$Inner::to_fixed_helper(
70                    self.to_bits(),
71                    Self::FRAC_NBITS as i32,
72                    dst_frac_nbits,
73                    dst_int_nbits,
74                )
75            }
76            #[inline]
77            fn to_float_helper(self, _: Private) -> ToFloatHelper {
78                let (neg, abs) = int_helper::$Inner::neg_abs(self.to_bits());
79                let abs = abs.into();
80                ToFloatHelper { neg, abs }
81            }
82            #[inline]
83            fn saturating_from_float_helper(_: Private, src: FromFloatHelper) -> Self {
84                let neg = match src.kind {
85                    FloatKind::NaN => panic!("NaN"),
86                    FloatKind::Infinite { neg } => neg,
87                    FloatKind::Finite { neg, .. } => neg,
88                };
89                let saturated = if neg { Self::MIN } else { Self::MAX };
90                let FloatKind::Finite { conv, .. } = src.kind else {
91                    return saturated;
92                };
93                if conv.overflow {
94                    return saturated;
95                }
96                let bits = if_signed_unsigned!(
97                    $Signedness,
98                    match conv.bits {
99                        Widest::Unsigned(bits) => {
100                            let bits = bits as _;
101                            if bits < 0 {
102                                return Self::MAX;
103                            }
104                            bits
105                        }
106                        Widest::Negative(bits) => bits as _,
107                    },
108                    match conv.bits {
109                        Widest::Unsigned(bits) => bits as _,
110                        Widest::Negative(_) => return Self::MIN,
111                    },
112                );
113                Self::from_bits(bits)
114            }
115            #[inline]
116            #[track_caller]
117            fn overflowing_from_float_helper(_: Private, src: FromFloatHelper) -> (Self, bool) {
118                let conv = match src.kind {
119                    FloatKind::NaN => panic!("NaN"),
120                    FloatKind::Infinite { .. } => panic!("infinite"),
121                    FloatKind::Finite { conv, .. } => conv,
122                };
123                let mut new_overflow = false;
124                let bits = if_signed_unsigned!(
125                    $Signedness,
126                    match conv.bits {
127                        Widest::Unsigned(bits) => {
128                            let bits = bits as _;
129                            if bits < 0 {
130                                new_overflow = true;
131                            }
132                            bits
133                        }
134                        Widest::Negative(bits) => bits as _,
135                    },
136                    match conv.bits {
137                        Widest::Unsigned(bits) => bits as _,
138                        Widest::Negative(bits) => {
139                            new_overflow = true;
140                            bits as _
141                        }
142                    },
143                );
144                (Self::from_bits(bits), conv.overflow || new_overflow)
145            }
146        }
147    };
148}
149
150impl_sealed! { FixedI8(LeEqU8, Signed, i8) }
151impl_sealed! { FixedI16(LeEqU16, Signed, i16) }
152impl_sealed! { FixedI32(LeEqU32, Signed, i32) }
153impl_sealed! { FixedI64(LeEqU64, Signed, i64) }
154impl_sealed! { FixedI128(LeEqU128, Signed, i128) }
155impl_sealed! { FixedU8(LeEqU8, Unsigned, u8) }
156impl_sealed! { FixedU16(LeEqU16, Unsigned, u16) }
157impl_sealed! { FixedU32(LeEqU32, Unsigned, u32) }
158impl_sealed! { FixedU64(LeEqU64, Unsigned, u64) }
159impl_sealed! { FixedU128(LeEqU128, Unsigned, u128) }