df_hyperliquid_core/utils/dec/
round.rs1use std::cmp::Ordering;
5
6use crate::utils::dec::{Dec, ten};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum Round {
11 Down,
13 Up,
15 Nearest,
17}
18
19impl Dec {
20 #[must_use]
23 pub fn units_at(self, places: u32, round: Round) -> Option<i128> {
24 match places.cmp(&self.scale) {
25 Ordering::Equal => Some(self.units),
26 Ordering::Greater => self.units.checked_mul(ten(places - self.scale)?),
27 Ordering::Less => Some(divide(self.units, ten(self.scale - places)?, round)),
28 }
29 }
30
31 #[must_use]
33 pub fn round(self, places: u32, round: Round) -> Dec {
34 if places >= self.scale {
35 return self.normal();
36 }
37 self.units_at(places, round).map_or(self, |units| Dec { units, scale: places }.normal())
38 }
39
40 #[must_use]
44 pub fn sig_places(self, figures: u32) -> u32 {
45 let places = i64::from(figures) - i64::from(digits(self.units)) + i64::from(self.scale);
46 u32::try_from(places.max(0)).unwrap_or(0)
47 }
48
49 #[must_use]
52 pub fn round_sig(self, figures: u32, round: Round) -> Dec {
53 let digits = digits(self.units);
54 if figures == 0 || digits <= figures {
55 return self.normal();
56 }
57 let dropped = digits - figures;
58 let Some(step) = ten(dropped) else {
59 return self;
60 };
61 let kept = divide(self.units, step, round);
62 match kept.checked_mul(step) {
63 Some(units) => Dec { units, scale: self.scale }.normal(),
64 None => self,
65 }
66 }
67}
68
69fn digits(units: i128) -> u32 {
70 let mut left = units.unsigned_abs();
71 let mut count = 0;
72 while left > 0 {
73 left /= 10;
74 count += 1;
75 }
76 count
77}
78
79pub(super) fn divide(value: i128, by: i128, round: Round) -> i128 {
81 let quotient = value / by;
82 let rest = value % by;
83 if rest == 0 {
84 return quotient;
85 }
86 let away = if value < 0 { -1 } else { 1 };
87 match round {
88 Round::Down => quotient,
89 Round::Up => quotient + away,
90 Round::Nearest => match (rest.unsigned_abs() * 2).cmp(&by.unsigned_abs()) {
91 Ordering::Less => quotient,
92 _ => quotient + away,
93 },
94 }
95}
96
97#[cfg(test)]
98#[path = "tests/round.rs"]
99mod tests;