use crate::utils::dec::{Dec, Round};
pub const COLLATERAL_DECIMALS: u32 = 6;
pub const LIT_DECIMALS: u32 = 8;
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum BadUnits {
#[error("{0} is not a positive amount")]
NotPositive(Dec),
#[error("{value} has more than {places} decimal places")]
TooFine { value: Dec, places: u32 },
#[error("{value} is more than {most} units at {places} places")]
TooLarge { value: Dec, places: u32, most: u64 },
}
pub fn exact_units(value: Dec, places: u32, most: u64) -> Result<u64, BadUnits> {
if value.places() > places {
return Err(BadUnits::TooFine { value, places });
}
cut_units(value, places, most)
}
pub fn cut_units(value: Dec, places: u32, most: u64) -> Result<u64, BadUnits> {
if !value.is_positive() {
return Err(BadUnits::NotPositive(value));
}
let too_large = || BadUnits::TooLarge { value, places, most };
let units = value.units_at(places, Round::Down).ok_or_else(too_large)?;
match u64::try_from(units) {
Ok(0) => Err(BadUnits::NotPositive(value)),
Ok(units) if units <= most => Ok(units),
_ => Err(too_large()),
}
}
#[must_use]
pub fn from_units(units: i128, places: u32) -> Option<Dec> {
Dec::new(units, places).map(|value| value.round(places, Round::Down))
}
#[cfg(test)]
#[path = "tests/units.rs"]
mod tests;