1use gmsol_store::constants::MARKET_DECIMALS;
2use rust_decimal::Decimal;
3
4const MAX_REPR: u128 = 0x0000_0000_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF;
5const TARGET_SCALE: u32 = MAX_REPR.ilog10() - 1;
6
7pub fn signed_value_to_decimal(num: i128) -> Decimal {
21 signed_fixed_to_decimal(num, MARKET_DECIMALS).expect("must be `Some`")
22}
23
24pub fn unsigned_value_to_decimal(num: u128) -> Decimal {
38 unsigned_fixed_to_decimal(num, MARKET_DECIMALS).expect("must be `Some`")
39}
40
41pub fn unsigned_amount_to_decimal(mut num: u64, mut decimals: u8) -> Decimal {
55 const MAX_DECIMALS: u8 = 28;
56 const MAX_SCALE_FOR_U64: u8 = 19;
57
58 if decimals > MAX_DECIMALS {
59 let scale_diff = decimals - MAX_DECIMALS;
60 if scale_diff > MAX_SCALE_FOR_U64 {
61 return Decimal::ZERO;
62 }
63 num /= 10u64.pow(scale_diff as u32);
64 decimals = MAX_DECIMALS;
65 }
66
67 unsigned_fixed_to_decimal(num as u128, decimals).expect("must be `Some`")
68}
69
70pub fn signed_amount_to_decimal(num: i64, decimals: u8) -> Decimal {
84 let is_negative = num.is_negative();
85 let d = unsigned_amount_to_decimal(num.unsigned_abs(), decimals);
86 if is_negative {
87 -d
88 } else {
89 d
90 }
91}
92
93pub fn unsigned_fixed_to_decimal(num: u128, decimals: u8) -> Option<Decimal> {
114 fn convert_by_change_the_scale(mut num: u128, scale: u32) -> Option<Decimal> {
115 let digits = num.ilog10();
116 debug_assert!(digits >= TARGET_SCALE);
117 let scale_diff = digits - TARGET_SCALE;
118 if scale < scale_diff {
119 return None;
120 }
121 num /= 10u128.pow(scale_diff);
122 Some(Decimal::from_i128_with_scale(
123 num as i128,
124 scale - scale_diff,
125 ))
126 }
127
128 let scale = decimals as u32;
129 if num > MAX_REPR {
130 convert_by_change_the_scale(num, scale)
131 } else {
132 Decimal::try_from_i128_with_scale(num as i128, scale).ok()
133 }
134}
135
136pub fn signed_fixed_to_decimal(num: i128, decimals: u8) -> Option<Decimal> {
157 let is_negative = num.is_negative();
158 let d = unsigned_fixed_to_decimal(num.unsigned_abs(), decimals)?;
159 if is_negative {
160 Some(-d)
161 } else {
162 Some(d)
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169 use rust_decimal_macros::dec;
170
171 #[test]
172 fn test_convert_value_to_decimal() {
173 assert_eq!(
174 signed_value_to_decimal(2_268_944_690_310_400_000_000_000),
175 dec!(22689.446903104)
176 );
177 assert_eq!(
178 signed_value_to_decimal(i128::MAX),
179 dec!(1701411834604692317.316873037),
180 );
181 assert_eq!(
182 signed_value_to_decimal(i128::MIN),
183 dec!(-1701411834604692317.316873037)
184 );
185 assert_eq!(
186 signed_value_to_decimal(0x0000_0000_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF),
187 dec!(792281625.14264337593543950335),
188 );
189
190 assert_eq!(
191 unsigned_value_to_decimal(u128::MAX),
192 dec!(3402823669209384634.633746074),
193 );
194 assert_eq!(
195 unsigned_value_to_decimal(0x0000_0000_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF),
196 dec!(792281625.14264337593543950335),
197 );
198 }
199
200 #[test]
201 fn test_convert_signed_amount_to_decimal() {
202 assert_eq!(
203 signed_amount_to_decimal(-2_649_941_038_310_943, 6),
204 dec!(-2649941038.310943),
205 );
206
207 assert_eq!(
208 signed_amount_to_decimal(i64::MAX, 0),
209 dec!(9223372036854775807),
210 );
211
212 assert_eq!(
213 signed_amount_to_decimal(i64::MIN, 0),
214 dec!(-9223372036854775808),
215 );
216
217 assert_eq!(
218 signed_amount_to_decimal(1, 28),
219 dec!(0.0000000000000000000000000001),
220 );
221
222 assert_eq!(
223 signed_amount_to_decimal(-1, 28),
224 dec!(-0.0000000000000000000000000001),
225 );
226
227 assert_eq!(
228 signed_amount_to_decimal(i64::MAX, 29),
229 dec!(0.000000000092233720368547758)
230 );
231
232 assert_eq!(
233 signed_amount_to_decimal(i64::MIN, 29),
234 dec!(-0.000000000092233720368547758),
235 );
236
237 assert_eq!(
238 signed_amount_to_decimal(i64::MAX, 46),
239 dec!(0.0000000000000000000000000009),
240 );
241
242 assert_eq!(
243 signed_amount_to_decimal(i64::MIN, 46),
244 dec!(-0.0000000000000000000000000009),
245 );
246
247 assert_eq!(signed_amount_to_decimal(i64::MAX, 47), Decimal::ZERO);
248
249 assert_eq!(signed_amount_to_decimal(i64::MIN, 47), Decimal::ZERO);
250 }
251
252 #[test]
253 fn test_convert_unsigned_amount_to_decimal() {
254 assert_eq!(
255 unsigned_amount_to_decimal(2_649_941_038_310_943, 6),
256 dec!(2649941038.310943),
257 );
258
259 assert_eq!(
260 unsigned_amount_to_decimal(u64::MAX, 0),
261 dec!(18446744073709551615),
262 );
263
264 assert_eq!(
265 unsigned_amount_to_decimal(u64::MAX, 29),
266 dec!(0.0000000001844674407370955161),
267 );
268
269 assert_eq!(
270 unsigned_amount_to_decimal(u64::MAX, 47),
271 dec!(0.0000000000000000000000000001)
272 );
273
274 assert_eq!(unsigned_amount_to_decimal(u64::MAX, 48), Decimal::ZERO);
275 }
276}