use sim_kernel::{Error, Result};
pub const DEFAULT_MAX_ARBITRARY_MAGNITUDE_BITS: u64 = 262_144;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct MagnitudeLimit {
max_bits: u64,
}
impl MagnitudeLimit {
pub const fn new(max_bits: u64) -> Self {
Self { max_bits }
}
pub const fn default_arbitrary_precision() -> Self {
Self::new(DEFAULT_MAX_ARBITRARY_MAGNITUDE_BITS)
}
pub const fn max_bits(self) -> u64 {
self.max_bits
}
pub fn check_bits(self, context: &str, estimated_bits: u64) -> Result<()> {
if estimated_bits > self.max_bits {
return Err(Error::Eval(format!(
"{context} magnitude too large: estimated {estimated_bits} bits exceeds limit {}",
self.max_bits
)));
}
Ok(())
}
pub fn check_decimal_digits(self, context: &str, digits: usize) -> Result<u64> {
let estimated_bits = decimal_digits_to_bits_ceil(digits);
self.check_bits(context, estimated_bits)?;
Ok(estimated_bits)
}
pub fn max_decimal_digits(self) -> usize {
self.max_bits
.saturating_mul(1000)
.checked_div(3322)
.unwrap_or(0)
.try_into()
.unwrap_or(usize::MAX)
}
}
impl Default for MagnitudeLimit {
fn default() -> Self {
Self::default_arbitrary_precision()
}
}
pub fn decimal_digits_to_bits_ceil(digits: usize) -> u64 {
let digits = u64::try_from(digits).unwrap_or(u64::MAX);
if digits == 0 {
return 0;
}
digits.saturating_mul(3322).saturating_add(999) / 1000
}