use crate::{
abi::{TypeAbi, TypeAbiFrom, TypeName},
api::{
const_handles, use_raw_handle, BigFloatApiImpl, BigIntApiImpl, HandleConstraints,
ManagedBufferApiImpl, ManagedTypeApi,
},
err_msg,
formatter::{FormatBuffer, FormatByteReceiver, SCDisplay},
types::{BigFloat, BigInt, BigUint, ManagedBuffer, ManagedType, Sign},
};
use alloc::string::ToString;
use multiversx_sc_codec::{
DecodeError, DecodeErrorHandler, EncodeErrorHandler, NestedDecode, NestedDecodeInput,
NestedEncode, NestedEncodeOutput, TopDecode, TopDecodeInput, TopEncode, TopEncodeOutput,
};
use core::{cmp::Ordering, ops::Deref};
use super::{
decimals::{ConstDecimals, Decimals, NumDecimals},
ManagedDecimal,
};
use super::{ManagedBufferCachedBuilder, ManagedRef};
#[derive(Clone)]
pub struct ManagedDecimalSigned<M: ManagedTypeApi, D: Decimals> {
pub(crate) data: BigInt<M>,
pub(crate) decimals: D,
}
impl<M: ManagedTypeApi, D: Decimals> ManagedDecimalSigned<M, D> {
pub fn trunc(&self) -> BigInt<M> {
&self.data / self.decimals.scaling_factor().deref()
}
pub fn into_raw_units(&self) -> &BigInt<M> {
&self.data
}
pub fn from_raw_units(data: BigInt<M>, decimals: D) -> Self {
ManagedDecimalSigned { data, decimals }
}
pub fn scale(&self) -> usize {
self.decimals.num_decimals()
}
pub fn scaling_factor(&self) -> ManagedRef<'static, M, BigUint<M>> {
self.decimals.scaling_factor()
}
pub(crate) fn rescale_data(&self, scale_to_num_decimals: NumDecimals) -> BigInt<M> {
let from_num_decimals = self.decimals.num_decimals();
match from_num_decimals.cmp(&scale_to_num_decimals) {
Ordering::Less => {
let delta_decimals = scale_to_num_decimals - from_num_decimals;
let scaling_factor: &BigUint<M> = &delta_decimals.scaling_factor();
&self.data * &scaling_factor.value
},
Ordering::Equal => self.data.clone(),
Ordering::Greater => {
let delta_decimals = from_num_decimals - scale_to_num_decimals;
let scaling_factor: &BigUint<M> = &delta_decimals.scaling_factor();
&self.data * &scaling_factor.value
},
}
}
pub fn rescale<T: Decimals>(&self, scale_to: T) -> ManagedDecimalSigned<M, T> {
let scale_to_num_decimals = scale_to.num_decimals();
ManagedDecimalSigned::from_raw_units(self.rescale_data(scale_to_num_decimals), scale_to)
}
pub fn into_unsigned_or_fail(self) -> ManagedDecimal<M, D> {
ManagedDecimal {
data: self
.data
.into_big_uint()
.unwrap_or_sc_panic(err_msg::UNSIGNED_NEGATIVE),
decimals: self.decimals,
}
}
pub fn sign(&self) -> Sign {
self.data.sign()
}
}
impl<M: ManagedTypeApi, const DECIMALS: NumDecimals>
ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
{
pub fn const_decimals_from_raw(data: BigInt<M>) -> Self {
ManagedDecimalSigned {
data,
decimals: ConstDecimals,
}
}
pub fn into_var_decimals(self) -> ManagedDecimalSigned<M, NumDecimals> {
ManagedDecimalSigned {
data: self.data,
decimals: DECIMALS,
}
}
}
impl<M: ManagedTypeApi, const DECIMALS: NumDecimals> From<BigInt<M>>
for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
{
fn from(mut value: BigInt<M>) -> Self {
let decimals = ConstDecimals;
value *= decimals.scaling_factor().as_big_int();
ManagedDecimalSigned {
data: value,
decimals,
}
}
}
impl<M: ManagedTypeApi, const DECIMALS: NumDecimals> From<i64>
for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
{
fn from(value: i64) -> Self {
Self::from(BigInt::from(value))
}
}
impl<M: ManagedTypeApi, D: Decimals> ManagedDecimalSigned<M, D> {
pub fn to_big_float(&self) -> BigFloat<M> {
let result = BigFloat::from_big_int(&self.data);
let temp_handle: M::BigFloatHandle = use_raw_handle(const_handles::BIG_FLOAT_TEMPORARY);
let denominator = self.decimals.scaling_factor::<M>();
M::managed_type_impl().bf_set_bi(temp_handle.clone(), denominator.handle);
M::managed_type_impl().bf_div(result.handle.clone(), result.handle.clone(), temp_handle);
result
}
pub fn from_big_float<T: Decimals>(
big_float: &BigFloat<M>,
num_decimals: T,
) -> ManagedDecimalSigned<M, T> {
let scaling_factor: &BigUint<M> = &num_decimals.scaling_factor();
let scaled = &BigFloat::from(scaling_factor) * big_float;
let fixed_big_int = scaled.trunc();
ManagedDecimalSigned::from_raw_units(fixed_big_int, num_decimals)
}
}
impl<M: ManagedTypeApi, const DECIMALS: NumDecimals> From<&BigFloat<M>>
for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
{
fn from(value: &BigFloat<M>) -> Self {
Self::from_big_float(value, ConstDecimals)
}
}
impl<M: ManagedTypeApi, const DECIMALS: NumDecimals> From<BigFloat<M>>
for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
{
#[inline]
fn from(value: BigFloat<M>) -> Self {
Self::from(&value)
}
}
impl<M: ManagedTypeApi, const DECIMALS: NumDecimals> From<f64>
for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
{
fn from(x: f64) -> Self {
Self::from(BigFloat::from(x))
}
}
impl<M: ManagedTypeApi, const DECIMALS: NumDecimals> From<f32>
for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
{
fn from(x: f32) -> Self {
Self::from(x as f64)
}
}
impl<M: ManagedTypeApi, const DECIMALS: NumDecimals> TopEncode
for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
{
#[inline]
fn top_encode_or_handle_err<O, H>(&self, output: O, h: H) -> Result<(), H::HandledErr>
where
O: TopEncodeOutput,
H: EncodeErrorHandler,
{
self.data.top_encode_or_handle_err(output, h)
}
}
impl<M: ManagedTypeApi, const DECIMALS: NumDecimals> TopDecode
for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
{
fn top_decode_or_handle_err<I, H>(input: I, h: H) -> Result<Self, H::HandledErr>
where
I: TopDecodeInput,
H: DecodeErrorHandler,
{
Ok(ManagedDecimalSigned::const_decimals_from_raw(
BigInt::top_decode_or_handle_err(input, h)?,
))
}
}
impl<M: ManagedTypeApi, const DECIMALS: NumDecimals> NestedEncode
for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
{
fn dep_encode_or_handle_err<O, H>(&self, dest: &mut O, h: H) -> Result<(), H::HandledErr>
where
O: NestedEncodeOutput,
H: EncodeErrorHandler,
{
NestedEncode::dep_encode_or_handle_err(&self.data, dest, h)?;
Result::Ok(())
}
}
impl<M: ManagedTypeApi, const DECIMALS: NumDecimals> NestedDecode
for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
{
fn dep_decode_or_handle_err<I, H>(input: &mut I, h: H) -> Result<Self, H::HandledErr>
where
I: NestedDecodeInput,
H: DecodeErrorHandler,
{
Result::Ok(ManagedDecimalSigned::const_decimals_from_raw(
<BigInt<M> as NestedDecode>::dep_decode_or_handle_err(input, h)?,
))
}
}
impl<M: ManagedTypeApi> NestedEncode for ManagedDecimalSigned<M, NumDecimals> {
fn dep_encode_or_handle_err<O, H>(&self, dest: &mut O, h: H) -> Result<(), H::HandledErr>
where
O: NestedEncodeOutput,
H: EncodeErrorHandler,
{
NestedEncode::dep_encode_or_handle_err(&self.data, dest, h)?;
NestedEncode::dep_encode_or_handle_err(&self.decimals, dest, h)?;
Result::Ok(())
}
}
impl<M: ManagedTypeApi> TopEncode for ManagedDecimalSigned<M, NumDecimals> {
fn top_encode_or_handle_err<O, H>(&self, output: O, h: H) -> Result<(), H::HandledErr>
where
O: TopEncodeOutput,
H: EncodeErrorHandler,
{
let mut buffer = output.start_nested_encode();
let dest = &mut buffer;
NestedEncode::dep_encode_or_handle_err(&self.data, dest, h)?;
NestedEncode::dep_encode_or_handle_err(&self.decimals, dest, h)?;
output.finalize_nested_encode(buffer);
Result::Ok(())
}
}
impl<M: ManagedTypeApi> NestedDecode for ManagedDecimalSigned<M, NumDecimals> {
fn dep_decode_or_handle_err<I, H>(input: &mut I, h: H) -> Result<Self, H::HandledErr>
where
I: NestedDecodeInput,
H: DecodeErrorHandler,
{
Result::Ok(ManagedDecimalSigned::from_raw_units(
<BigInt<M> as NestedDecode>::dep_decode_or_handle_err(input, h)?,
<NumDecimals as NestedDecode>::dep_decode_or_handle_err(input, h)?,
))
}
}
impl<M: ManagedTypeApi> TopDecode for ManagedDecimalSigned<M, NumDecimals> {
fn top_decode_or_handle_err<I, H>(top_input: I, h: H) -> Result<Self, H::HandledErr>
where
I: TopDecodeInput,
H: DecodeErrorHandler,
{
let mut nested_buffer = top_input.into_nested_buffer();
let result = ManagedDecimalSigned::from_raw_units(
<BigInt<M> as NestedDecode>::dep_decode_or_handle_err(&mut nested_buffer, h)?,
<NumDecimals as NestedDecode>::dep_decode_or_handle_err(&mut nested_buffer, h)?,
);
if !NestedDecodeInput::is_depleted(&nested_buffer) {
return Result::Err(h.handle_error(DecodeError::INPUT_TOO_LONG));
}
Result::Ok(result)
}
}
impl<M: ManagedTypeApi> TypeAbiFrom<Self> for ManagedDecimalSigned<M, NumDecimals> {}
impl<M: ManagedTypeApi> TypeAbi for ManagedDecimalSigned<M, NumDecimals> {
type Unmanaged = Self;
fn type_name() -> TypeName {
TypeName::from("ManagedDecimalSigned<usize>")
}
fn is_variadic() -> bool {
false
}
}
impl<M: ManagedTypeApi, const DECIMALS: NumDecimals> TypeAbiFrom<Self>
for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
{
}
impl<M: ManagedTypeApi, const DECIMALS: NumDecimals> TypeAbi
for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
{
type Unmanaged = Self;
fn type_name() -> TypeName {
TypeName::from(alloc::format!("ManagedDecimalSigned<{}>", DECIMALS))
}
fn type_name_rust() -> TypeName {
TypeName::from(alloc::format!(
"ManagedDecimalSigned<$API, ConstDecimals<{}>>",
DECIMALS
))
}
fn is_variadic() -> bool {
false
}
}
pub(super) fn managed_decimal_fmt<M: ManagedTypeApi, F: FormatByteReceiver>(
value: &BigInt<M>,
num_dec: NumDecimals,
f: &mut F,
) {
let full_str_handle: M::ManagedBufferHandle = use_raw_handle(const_handles::MBUF_TEMPORARY_1);
M::managed_type_impl().bi_to_string(value.handle.clone(), full_str_handle.clone());
let len = M::managed_type_impl().mb_len(full_str_handle.clone());
if len > num_dec {
let temp_str_handle: M::ManagedBufferHandle =
use_raw_handle(const_handles::MBUF_TEMPORARY_2);
let _ = M::managed_type_impl().mb_copy_slice(
full_str_handle.clone(),
0,
len - num_dec,
temp_str_handle.clone(),
);
f.append_managed_buffer(&ManagedBuffer::from_raw_handle(
temp_str_handle.get_raw_handle(),
));
f.append_bytes(b".");
let _ = M::managed_type_impl().mb_copy_slice(
full_str_handle.clone(),
len - num_dec,
num_dec,
temp_str_handle.clone(),
);
f.append_managed_buffer(&ManagedBuffer::from_raw_handle(
temp_str_handle.get_raw_handle(),
));
} else {
f.append_bytes(b"0.");
for _ in len..num_dec {
f.append_bytes(b"0");
}
f.append_managed_buffer(&ManagedBuffer::from_raw_handle(
full_str_handle.get_raw_handle(),
));
}
}
impl<M: ManagedTypeApi, D: Decimals> SCDisplay for ManagedDecimalSigned<M, D> {
fn fmt<F: FormatByteReceiver>(&self, f: &mut F) {
managed_decimal_fmt(&self.data, self.decimals.num_decimals(), f);
}
}
impl<M: ManagedTypeApi, D: Decimals> core::fmt::Display for ManagedDecimalSigned<M, D> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let mut result = ManagedBufferCachedBuilder::<M>::new_from_slice(&[]);
result.append_display(self);
core::fmt::Display::fmt(&result.into_managed_buffer(), f)
}
}
impl<M: ManagedTypeApi, D: Decimals> core::fmt::Debug for ManagedDecimalSigned<M, D> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ManagedDecimalSigned")
.field("handle", &self.data.handle.clone())
.field("number", &self.to_string())
.finish()
}
}