use crate::utils::dec::{Dec, Round};
use crate::utils::ids::WIDTH_48;
use crate::utils::units::{BadUnits, exact_units};
pub const MAX_PRICE_UNITS: u64 = u32::MAX as u64;
pub const MAX_SIZE_UNITS: u64 = WIDTH_48;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Grid {
size_decimals: u32,
price_decimals: u32,
}
impl Grid {
#[must_use]
pub const fn new(size_decimals: u32, price_decimals: u32) -> Grid {
Grid { size_decimals, price_decimals }
}
#[must_use]
pub const fn size_decimals(&self) -> u32 {
self.size_decimals
}
#[must_use]
pub const fn price_decimals(&self) -> u32 {
self.price_decimals
}
#[must_use]
pub fn size_step(&self) -> Dec {
Dec::new(1, self.size_decimals).unwrap_or(Dec::ONE)
}
#[must_use]
pub fn tick(&self) -> Dec {
Dec::new(1, self.price_decimals).unwrap_or(Dec::ONE)
}
#[must_use]
pub fn size(&self, size: Dec) -> Option<Dec> {
let cut = size.round(self.size_decimals, Round::Down);
cut.is_positive().then_some(cut)
}
#[must_use]
pub fn price(&self, price: Dec, round: Round) -> Option<Dec> {
let placed = price.round(self.price_decimals, round);
placed.is_positive().then_some(placed)
}
pub fn base_amount(&self, size: Dec) -> Result<u64, BadUnits> {
exact_units(size, self.size_decimals, MAX_SIZE_UNITS)
}
pub fn price_units(&self, price: Dec) -> Result<u32, BadUnits> {
let units = exact_units(price, self.price_decimals, MAX_PRICE_UNITS)?;
u32::try_from(units).map_err(|_| BadUnits::TooLarge {
value: price,
places: self.price_decimals,
most: MAX_PRICE_UNITS,
})
}
#[must_use]
pub fn size_of(&self, base_amount: u64) -> Dec {
Dec::new(i128::from(base_amount), self.size_decimals).unwrap_or(Dec::ZERO)
}
#[must_use]
pub fn price_of(&self, units: u32) -> Dec {
Dec::new(i128::from(units), self.price_decimals).unwrap_or(Dec::ZERO)
}
}
#[cfg(test)]
#[path = "tests/grid.rs"]
mod tests;