defituna_client/math/
fixed_128.rs

1use fixed::traits::{FromFixed, ToFixed};
2pub use fixed::types::U68F60 as Fixed128;
3use std::fmt::Display;
4
5pub const FRACTION_ONE_SCALED: u128 = Fixed128::ONE.to_bits();
6
7#[inline]
8pub const fn bps_u128_to_fraction(bps: u128) -> Fixed128 {
9    if bps == 1_000_000 {
10        return Fixed128::ONE;
11    }
12    Fixed128::const_from_int(bps).unwrapped_div_int(1_000_000)
13}
14
15pub trait FixedExtra {
16    fn to_bps<Dst: FromFixed>(&self) -> Option<Dst>;
17    fn from_bps<Src: ToFixed>(bps: Src) -> Self;
18
19    fn to_display(&self) -> FixedSingleDisplay;
20}
21
22impl FixedExtra for Fixed128 {
23    #[inline]
24    fn to_bps<Dst: FromFixed>(&self) -> Option<Dst> {
25        (self * 1_000_000).round().checked_to_num()
26    }
27
28    #[inline]
29    fn from_bps<Src: ToFixed>(bps: Src) -> Self {
30        let bps = Fixed128::from_num(bps);
31        bps / 1_000_000
32    }
33
34    #[inline]
35    fn to_display(&self) -> FixedSingleDisplay {
36        FixedSingleDisplay(self)
37    }
38}
39
40pub struct FixedSingleDisplay<'a>(&'a Fixed128);
41
42impl Display for FixedSingleDisplay<'_> {
43    fn fmt(&self, formater: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44        let sf = self.0.to_bits();
45
46        const ROUND_COMP: u128 = (1 << Fixed128::FRAC_NBITS) / (10_000 * 2);
47        let sf = sf + ROUND_COMP;
48
49        let i = sf >> Fixed128::FRAC_NBITS;
50
51        const FRAC_MASK: u128 = (1 << Fixed128::FRAC_NBITS) - 1;
52        let f_p = (sf & FRAC_MASK) as u64;
53        let f_p = ((f_p >> 30) * 10_000) >> 30;
54        write!(formater, "{i}.{f_p:0>4}")
55    }
56}