use core::fmt;
#[cfg(test)]
mod tests;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum MeasurementRatioError {
ZeroDenominator,
Overflow,
}
impl fmt::Display for MeasurementRatioError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(match self {
Self::ZeroDenominator => "measurement ratio denominator is zero",
Self::Overflow => "scaled measurement ratio exceeds u128",
})
}
}
impl core::error::Error for MeasurementRatioError {}
pub const fn checked_scaled_ratio(
numerator: u128,
denominator: u64,
scale: u64,
) -> Result<u128, MeasurementRatioError> {
if denominator == 0 {
return Err(MeasurementRatioError::ZeroDenominator);
}
let denominator = denominator as u128;
let scale = scale as u128;
let Some(whole) = (numerator / denominator).checked_mul(scale) else {
return Err(MeasurementRatioError::Overflow);
};
let fraction = (numerator % denominator) * scale / denominator;
match whole.checked_add(fraction) {
Some(value) => Ok(value),
None => Err(MeasurementRatioError::Overflow),
}
}