use std::str::FromStr;
use bigdecimal::BigDecimal;
use num_bigint::BigInt;
use serde::Deserialize;
use serde::Serialize;
use crate::wire::is_valid_big_decimal_scale;
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub(in crate::wire) struct BigDecimalPayload {
pub(in crate::wire) coefficient: String,
pub(in crate::wire) scale: i64,
}
impl TryFrom<&BigDecimal> for BigDecimalPayload {
type Error = &'static str;
#[inline]
fn try_from(value: &BigDecimal) -> Result<Self, Self::Error> {
let (coefficient, scale) = value.as_bigint_and_scale();
if !is_valid_big_decimal_scale(scale) {
return Err("decimal scale exceeds the V1 maximum absolute scale");
}
Ok(Self {
coefficient: coefficient.to_string(),
scale,
})
}
}
impl TryFrom<BigDecimalPayload> for BigDecimal {
type Error = &'static str;
fn try_from(value: BigDecimalPayload) -> Result<Self, Self::Error> {
if !is_valid_big_decimal_scale(value.scale) {
return Err("decimal scale exceeds the V1 maximum absolute scale");
}
let coefficient = BigInt::from_str(&value.coefficient).map_err(|_| "invalid decimal coefficient")?;
if coefficient.to_string() != value.coefficient {
return Err("non-canonical decimal coefficient");
}
Ok(Self::new(coefficient, value.scale))
}
}