defituna_client/math/
fixed_128.rs1use 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}