#[cfg(feature = "floats")]
use libm::pow;
#[cfg(feature = "wasm")]
use equanetwork_macros::wasm_expose;
use super::consts::Q64_ONE;
use super::error::{CoreError, AMOUNT_EXCEEDS_MAX_U64, ARITHMETIC_OVERFLOW, DIVISION_BY_ZERO};
use super::U128;
#[cfg(feature = "floats")]
#[cfg_attr(feature = "wasm", wasm_expose)]
pub fn amount_to_ui_amount(amount: u64, decimals: u8) -> f64 {
let power = pow(10f64, decimals as f64);
amount as f64 / power
}
#[cfg(feature = "floats")]
#[cfg_attr(feature = "wasm", wasm_expose)]
pub fn ui_amount_to_amount(amount: f64, decimals: u8) -> u64 {
let power = pow(10f64, decimals as f64);
(amount * power) as u64
}
#[cfg_attr(feature = "wasm", wasm_expose)]
pub fn mul_q64(amount: u64, price: U128, round_up: bool) -> Result<u64, CoreError> {
let price: u128 = price.into();
let product = (amount as u128)
.checked_mul(price)
.ok_or(ARITHMETIC_OVERFLOW)?;
let quotient = product >> 64;
let remainder = product as u64;
let result = if round_up && remainder > 0 {
quotient + 1
} else {
quotient
};
result.try_into().map_err(|_| AMOUNT_EXCEEDS_MAX_U64)
}
#[cfg_attr(feature = "wasm", wasm_expose)]
pub fn div_q64(amount: u64, price: U128, round_up: bool) -> Result<u64, CoreError> {
let price: u128 = price.into();
if price == 0 {
return Err(DIVISION_BY_ZERO);
}
let numerator = (amount as u128)
.checked_shl(64)
.ok_or(ARITHMETIC_OVERFLOW)?;
let quotient = numerator.checked_div(price).ok_or(ARITHMETIC_OVERFLOW)?;
let remainder = numerator.checked_rem(price).ok_or(ARITHMETIC_OVERFLOW)?;
let result = if round_up && remainder > 0 {
quotient + 1
} else {
quotient
};
result.try_into().map_err(|_| AMOUNT_EXCEEDS_MAX_U64)
}
#[cfg_attr(feature = "wasm", wasm_expose)]
pub fn one_q64() -> U128 {
U128::from(Q64_ONE)
}
#[cfg(test)]
mod tests {
use super::*;
use rstest::rstest;
#[rstest]
#[case(100, Q64_ONE, false, 100)]
#[case(100, Q64_ONE * 2, false, 200)]
fn test_mul_q64(
#[case] amount: u64,
#[case] price: u128,
#[case] round_up: bool,
#[case] expected: u64,
) {
assert_eq!(
mul_q64(amount, U128::from(price), round_up).unwrap(),
expected
);
}
}