Skip to content

Commit

Permalink
Merge pull request #13 from invariant-labs/add-checked-from-big-decimal
Browse files Browse the repository at this point in the history
Add checked from big decimal
  • Loading branch information
wojciech-cichocki authored Sep 18, 2023
2 parents 6c74676 + 9de2e5e commit a01ae1d
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 0 deletions.
41 changes: 41 additions & 0 deletions decimal_core/src/factories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub fn generate_factories(characteristics: DecimalCharacteristics) -> proc_macro
struct_name,
underlying_type,
scale,
big_type,
..
} = characteristics;

Expand Down Expand Up @@ -108,6 +109,46 @@ pub fn generate_factories(characteristics: DecimalCharacteristics) -> proc_macro
}
}

impl<T> FactoriesToValue<T, #big_type> for #struct_name
where
T: TryInto<#underlying_type>,
{

fn checked_from_scale_to_value(val: T, scale: u8) -> std::result::Result<#big_type, String> {
Ok(
if #scale > scale {
let base: #big_type = #big_type::try_from(
val.try_into().map_err(|_| "checked_from_scale_to_value: can't convert val to base")?)
.map_err(|_| "checked_from_scale_to_value: can't convert val to big_type"
)?;
let multiplier: u128 = 10u128.checked_pow((#scale - scale) as u32).ok_or_else(|| "checked_from_scale_to_value: multiplier overflow")?;

base.checked_mul(multiplier.try_into().map_err(|_| "checked_from_scale_to_value: can't convert multiplier to big_type")?)
.ok_or_else(|| "checked_from_scale_to_value: (multiplier * base) overflow")?
} else {
let denominator: u128 = 10u128.checked_pow((scale - #scale) as u32).ok_or_else(|| "checked_from_scale_to_value: denominator overflow")?;
let base: #big_type = #big_type::try_from(
val.try_into().map_err(|_| "checked_from_scale_to_value: can't convert val to base")?)
.map_err(|_| "checked_from_scale_to_value: can't convert val to big_type"
)?;

base.checked_div(
denominator.try_into().map_err(|_| "checked_from_scale_to_value: can't convert denominator to big_type")?
).ok_or_else(|| "checked_from_scale_to_value: (base / denominator) overflow")?
.try_into().map_err(|_| "checked_from_scale_to_value: can't convert to result")?
})
}
}

impl<T: Decimal, #big_type> BetweenDecimalsToValue<T, #big_type> for #struct_name
where
Self: FactoriesToValue<T::U, #big_type>,
{
fn checked_from_decimal_to_value(other: T) -> std::result::Result<#big_type, String> {
Self::checked_from_scale_to_value(other.get(), T::scale())
}
}


#[cfg(test)]
pub mod #module_name {
Expand Down
9 changes: 9 additions & 0 deletions src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub trait Factories<T>: Sized {
fn from_scale_up(integer: T, scale: u8) -> Self;
}


pub trait BetweenDecimals<T>: Sized {
fn from_decimal(other: T) -> Self;
fn checked_from_decimal(other: T) -> std::result::Result<Self, String>;
Expand All @@ -50,6 +51,14 @@ pub trait ToValue<T, B> {
fn big_mul_to_value_up(self, value: T) -> B;
}

pub trait FactoriesToValue<T, B> {
fn checked_from_scale_to_value(integer: T, scale: u8) -> std::result::Result<B, String>;
}

pub trait BetweenDecimalsToValue<T, B> {
fn checked_from_decimal_to_value(other: T) -> std::result::Result<B, String>;
}

pub trait ByNumber<B>: Sized {
fn big_div_by_number(self, number: B) -> Self;
fn big_div_by_number_up(self, number: B) -> Self;
Expand Down
13 changes: 13 additions & 0 deletions src/walkthrough.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,14 @@ mod walkthrough {
Price::new(34028236692093846346337460743176821145u128)
);
}
// checked_from_scale_to_value
{
let result = Price::checked_from_scale_to_value(max_price_value, price_scale - 1).unwrap();
assert_eq!(
result,
U256::from_dec_str("3402823669209384634633746074317682114550").unwrap()
);
}
// checked_from_decimal
{
let price = Price::checked_from_decimal(Percentage::from_integer(1)).unwrap();
Expand All @@ -110,6 +118,11 @@ mod walkthrough {
let convert_err = Percentage::checked_from_decimal(Price::max_instance()).unwrap_err();
assert_eq!(convert_err, "checked_from_scale: can't convert to result");
}
// checked_from_decimal_to_value
{
let result = Price::checked_from_decimal_to_value(Price::max_instance()).unwrap();
assert_eq!(result, U256::from(Price::max_value()));
}
// checked_big_div_by_number & checked_big_div_by_number_up
{
let three = U256::from(Price::from_integer(3).get());
Expand Down

0 comments on commit a01ae1d

Please sign in to comment.