multiversx_sc/types/managed/wrapped/managed_decimal/
managed_decimal_signed.rs

1use crate::{
2    abi::{TypeAbi, TypeAbiFrom, TypeName},
3    api::{
4        const_handles, use_raw_handle, BigFloatApiImpl, BigIntApiImpl, HandleConstraints,
5        ManagedBufferApiImpl, ManagedTypeApi,
6    },
7    err_msg,
8    formatter::{FormatBuffer, FormatByteReceiver, SCDisplay},
9    typenum::{Unsigned, U4, U8},
10    types::{
11        managed_vec_item_read_from_payload_index, managed_vec_item_save_to_payload_index, BigFloat,
12        BigInt, BigUint, ManagedVecItem, ManagedVecItemPayloadBuffer, ManagedVecRef, Sign,
13    },
14};
15
16use alloc::string::ToString;
17use multiversx_sc_codec::{
18    DecodeError, DecodeErrorHandler, EncodeErrorHandler, NestedDecode, NestedDecodeInput,
19    NestedEncode, NestedEncodeOutput, TopDecode, TopDecodeInput, TopEncode, TopEncodeOutput,
20};
21
22use core::{cmp::Ordering, ops::Deref};
23
24use super::{
25    decimals::{ConstDecimals, Decimals, NumDecimals},
26    ManagedDecimal,
27};
28use super::{ManagedBufferCachedBuilder, ManagedRef};
29
30/// Fixed-point decimal numbers that accept either a constant or variable number of decimals.
31///
32/// Unlike for `ManagedDecimal`, ngative numbers are also allowed.
33#[derive(Clone)]
34pub struct ManagedDecimalSigned<M: ManagedTypeApi, D: Decimals> {
35    pub(crate) data: BigInt<M>,
36    pub(crate) decimals: D,
37}
38
39impl<M: ManagedTypeApi, D: Decimals> ManagedDecimalSigned<M, D> {
40    pub fn trunc(&self) -> BigInt<M> {
41        &self.data / self.decimals.scaling_factor().deref()
42    }
43
44    pub fn into_raw_units(&self) -> &BigInt<M> {
45        &self.data
46    }
47
48    pub fn from_raw_units(data: BigInt<M>, decimals: D) -> Self {
49        ManagedDecimalSigned { data, decimals }
50    }
51
52    pub fn scale(&self) -> usize {
53        self.decimals.num_decimals()
54    }
55
56    pub fn scaling_factor(&self) -> ManagedRef<'static, M, BigUint<M>> {
57        self.decimals.scaling_factor()
58    }
59
60    pub(crate) fn rescale_data(&self, scale_to_num_decimals: NumDecimals) -> BigInt<M> {
61        let from_num_decimals = self.decimals.num_decimals();
62
63        match from_num_decimals.cmp(&scale_to_num_decimals) {
64            Ordering::Less => {
65                let delta_decimals = scale_to_num_decimals - from_num_decimals;
66                let scaling_factor: &BigUint<M> = &delta_decimals.scaling_factor();
67                &self.data * &scaling_factor.value
68            }
69            Ordering::Equal => self.data.clone(),
70            Ordering::Greater => {
71                let delta_decimals = from_num_decimals - scale_to_num_decimals;
72                let scaling_factor: &BigUint<M> = &delta_decimals.scaling_factor();
73                &self.data / &scaling_factor.value
74            }
75        }
76    }
77
78    pub fn rescale<T: Decimals>(&self, scale_to: T) -> ManagedDecimalSigned<M, T> {
79        let scale_to_num_decimals = scale_to.num_decimals();
80        ManagedDecimalSigned::from_raw_units(self.rescale_data(scale_to_num_decimals), scale_to)
81    }
82
83    pub fn into_unsigned_or_fail(self) -> ManagedDecimal<M, D> {
84        ManagedDecimal {
85            data: self
86                .data
87                .into_big_uint()
88                .unwrap_or_sc_panic(err_msg::UNSIGNED_NEGATIVE),
89            decimals: self.decimals,
90        }
91    }
92
93    pub fn sign(&self) -> Sign {
94        self.data.sign()
95    }
96}
97
98impl<M: ManagedTypeApi, DECIMALS: Unsigned> ManagedDecimalSigned<M, ConstDecimals<DECIMALS>> {
99    pub fn const_decimals_from_raw(data: BigInt<M>) -> Self {
100        ManagedDecimalSigned {
101            data,
102            decimals: ConstDecimals::new(),
103        }
104    }
105
106    /// Converts from constant (compile-time) number of decimals to a variable number of decimals.
107    pub fn into_var_decimals(self) -> ManagedDecimalSigned<M, NumDecimals> {
108        ManagedDecimalSigned {
109            data: self.data,
110            decimals: DECIMALS::to_usize(),
111        }
112    }
113}
114
115impl<M: ManagedTypeApi, DECIMALS: Unsigned> From<BigInt<M>>
116    for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
117{
118    fn from(mut value: BigInt<M>) -> Self {
119        let decimals = ConstDecimals::new();
120        value *= decimals.scaling_factor().as_big_int();
121        ManagedDecimalSigned {
122            data: value,
123            decimals,
124        }
125    }
126}
127
128impl<M: ManagedTypeApi, DECIMALS: Unsigned> From<i64>
129    for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
130{
131    fn from(value: i64) -> Self {
132        Self::from(BigInt::from(value))
133    }
134}
135
136impl<M: ManagedTypeApi, D: Decimals> ManagedDecimalSigned<M, D> {
137    pub fn to_big_float(&self) -> BigFloat<M> {
138        let result = BigFloat::from_big_int(&self.data);
139        let temp_handle: M::BigFloatHandle = use_raw_handle(const_handles::BIG_FLOAT_TEMPORARY);
140        let denominator = self.decimals.scaling_factor::<M>();
141        M::managed_type_impl().bf_set_bi(temp_handle.clone(), denominator.handle);
142        M::managed_type_impl().bf_div(result.handle.clone(), result.handle.clone(), temp_handle);
143        result
144    }
145
146    pub fn from_big_float<T: Decimals>(
147        big_float: &BigFloat<M>,
148        num_decimals: T,
149    ) -> ManagedDecimalSigned<M, T> {
150        let scaling_factor: &BigUint<M> = &num_decimals.scaling_factor();
151
152        let scaled = &BigFloat::from(scaling_factor) * big_float;
153        let fixed_big_int = scaled.trunc();
154
155        ManagedDecimalSigned::from_raw_units(fixed_big_int, num_decimals)
156    }
157}
158
159impl<M: ManagedTypeApi, DECIMALS: Unsigned> From<&BigFloat<M>>
160    for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
161{
162    fn from(value: &BigFloat<M>) -> Self {
163        Self::from_big_float(value, ConstDecimals::new())
164    }
165}
166
167impl<M: ManagedTypeApi, DECIMALS: Unsigned> From<BigFloat<M>>
168    for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
169{
170    #[inline]
171    fn from(value: BigFloat<M>) -> Self {
172        Self::from(&value)
173    }
174}
175
176impl<M: ManagedTypeApi, DECIMALS: Unsigned> From<f64>
177    for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
178{
179    fn from(x: f64) -> Self {
180        Self::from(BigFloat::from(x))
181    }
182}
183
184impl<M: ManagedTypeApi, DECIMALS: Unsigned> From<f32>
185    for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
186{
187    fn from(x: f32) -> Self {
188        Self::from(x as f64)
189    }
190}
191
192impl<M: ManagedTypeApi> ManagedVecItem for ManagedDecimalSigned<M, NumDecimals> {
193    type PAYLOAD = ManagedVecItemPayloadBuffer<U8>; // 4 bigInt + 4 usize
194
195    const SKIPS_RESERIALIZATION: bool = false;
196
197    type Ref<'a> = ManagedVecRef<'a, Self>;
198
199    fn read_from_payload(payload: &Self::PAYLOAD) -> Self {
200        let mut index = 0;
201        unsafe {
202            Self {
203                data: managed_vec_item_read_from_payload_index(payload, &mut index),
204                decimals: managed_vec_item_read_from_payload_index(payload, &mut index),
205            }
206        }
207    }
208
209    unsafe fn borrow_from_payload<'a>(payload: &Self::PAYLOAD) -> Self::Ref<'a> {
210        ManagedVecRef::new(Self::read_from_payload(payload))
211    }
212
213    fn save_to_payload(self, payload: &mut Self::PAYLOAD) {
214        let mut index = 0;
215        unsafe {
216            managed_vec_item_save_to_payload_index(self.data, payload, &mut index);
217            managed_vec_item_save_to_payload_index(self.decimals, payload, &mut index);
218        }
219    }
220}
221
222impl<M: ManagedTypeApi, DECIMALS: Unsigned> ManagedVecItem
223    for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
224{
225    type PAYLOAD = ManagedVecItemPayloadBuffer<U4>; // data only
226
227    const SKIPS_RESERIALIZATION: bool = false;
228
229    type Ref<'a> = ManagedVecRef<'a, Self>;
230
231    fn read_from_payload(payload: &Self::PAYLOAD) -> Self {
232        Self::const_decimals_from_raw(BigInt::read_from_payload(payload))
233    }
234
235    unsafe fn borrow_from_payload<'a>(payload: &Self::PAYLOAD) -> Self::Ref<'a> {
236        ManagedVecRef::new(Self::read_from_payload(payload))
237    }
238
239    fn save_to_payload(self, payload: &mut Self::PAYLOAD) {
240        self.data.save_to_payload(payload);
241    }
242}
243
244impl<M: ManagedTypeApi, DECIMALS: Unsigned> TopEncode
245    for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
246{
247    #[inline]
248    fn top_encode_or_handle_err<O, H>(&self, output: O, h: H) -> Result<(), H::HandledErr>
249    where
250        O: TopEncodeOutput,
251        H: EncodeErrorHandler,
252    {
253        self.data.top_encode_or_handle_err(output, h)
254    }
255}
256
257impl<M: ManagedTypeApi, DECIMALS: Unsigned> TopDecode
258    for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
259{
260    fn top_decode_or_handle_err<I, H>(input: I, h: H) -> Result<Self, H::HandledErr>
261    where
262        I: TopDecodeInput,
263        H: DecodeErrorHandler,
264    {
265        Ok(ManagedDecimalSigned::const_decimals_from_raw(
266            BigInt::top_decode_or_handle_err(input, h)?,
267        ))
268    }
269}
270
271impl<M: ManagedTypeApi, DECIMALS: Unsigned> NestedEncode
272    for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
273{
274    fn dep_encode_or_handle_err<O, H>(&self, dest: &mut O, h: H) -> Result<(), H::HandledErr>
275    where
276        O: NestedEncodeOutput,
277        H: EncodeErrorHandler,
278    {
279        NestedEncode::dep_encode_or_handle_err(&self.data, dest, h)?;
280
281        Result::Ok(())
282    }
283}
284
285impl<M: ManagedTypeApi, DECIMALS: Unsigned> NestedDecode
286    for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
287{
288    fn dep_decode_or_handle_err<I, H>(input: &mut I, h: H) -> Result<Self, H::HandledErr>
289    where
290        I: NestedDecodeInput,
291        H: DecodeErrorHandler,
292    {
293        Result::Ok(ManagedDecimalSigned::const_decimals_from_raw(
294            <BigInt<M> as NestedDecode>::dep_decode_or_handle_err(input, h)?,
295        ))
296    }
297}
298
299impl<M: ManagedTypeApi> NestedEncode for ManagedDecimalSigned<M, NumDecimals> {
300    fn dep_encode_or_handle_err<O, H>(&self, dest: &mut O, h: H) -> Result<(), H::HandledErr>
301    where
302        O: NestedEncodeOutput,
303        H: EncodeErrorHandler,
304    {
305        NestedEncode::dep_encode_or_handle_err(&self.data, dest, h)?;
306        NestedEncode::dep_encode_or_handle_err(&self.decimals, dest, h)?;
307
308        Result::Ok(())
309    }
310}
311
312impl<M: ManagedTypeApi> TopEncode for ManagedDecimalSigned<M, NumDecimals> {
313    fn top_encode_or_handle_err<O, H>(&self, output: O, h: H) -> Result<(), H::HandledErr>
314    where
315        O: TopEncodeOutput,
316        H: EncodeErrorHandler,
317    {
318        let mut buffer = output.start_nested_encode();
319        let dest = &mut buffer;
320        NestedEncode::dep_encode_or_handle_err(&self.data, dest, h)?;
321        NestedEncode::dep_encode_or_handle_err(&self.decimals, dest, h)?;
322
323        output.finalize_nested_encode(buffer);
324        Result::Ok(())
325    }
326}
327
328impl<M: ManagedTypeApi> NestedDecode for ManagedDecimalSigned<M, NumDecimals> {
329    fn dep_decode_or_handle_err<I, H>(input: &mut I, h: H) -> Result<Self, H::HandledErr>
330    where
331        I: NestedDecodeInput,
332        H: DecodeErrorHandler,
333    {
334        Result::Ok(ManagedDecimalSigned::from_raw_units(
335            <BigInt<M> as NestedDecode>::dep_decode_or_handle_err(input, h)?,
336            <NumDecimals as NestedDecode>::dep_decode_or_handle_err(input, h)?,
337        ))
338    }
339}
340
341impl<M: ManagedTypeApi> TopDecode for ManagedDecimalSigned<M, NumDecimals> {
342    fn top_decode_or_handle_err<I, H>(top_input: I, h: H) -> Result<Self, H::HandledErr>
343    where
344        I: TopDecodeInput,
345        H: DecodeErrorHandler,
346    {
347        let mut nested_buffer = top_input.into_nested_buffer();
348        let result = ManagedDecimalSigned::from_raw_units(
349            <BigInt<M> as NestedDecode>::dep_decode_or_handle_err(&mut nested_buffer, h)?,
350            <NumDecimals as NestedDecode>::dep_decode_or_handle_err(&mut nested_buffer, h)?,
351        );
352        if !NestedDecodeInput::is_depleted(&nested_buffer) {
353            return Result::Err(h.handle_error(DecodeError::INPUT_TOO_LONG));
354        }
355        Result::Ok(result)
356    }
357}
358
359impl<M: ManagedTypeApi> TypeAbiFrom<Self> for ManagedDecimalSigned<M, NumDecimals> {}
360
361impl<M: ManagedTypeApi> TypeAbi for ManagedDecimalSigned<M, NumDecimals> {
362    type Unmanaged = Self;
363
364    fn type_name() -> TypeName {
365        TypeName::from("ManagedDecimalSigned<usize>")
366    }
367
368    fn is_variadic() -> bool {
369        false
370    }
371}
372
373impl<M: ManagedTypeApi, DECIMALS: Unsigned> TypeAbiFrom<Self>
374    for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
375{
376}
377
378impl<M: ManagedTypeApi, DECIMALS: Unsigned> TypeAbi
379    for ManagedDecimalSigned<M, ConstDecimals<DECIMALS>>
380{
381    type Unmanaged = Self;
382
383    fn type_name() -> TypeName {
384        TypeName::from(alloc::format!(
385            "ManagedDecimalSigned<{}>",
386            DECIMALS::to_usize()
387        ))
388    }
389
390    fn type_name_rust() -> TypeName {
391        TypeName::from(alloc::format!(
392            "ManagedDecimalSigned<$API, ConstDecimals<{}>>",
393            DECIMALS::to_usize()
394        ))
395    }
396
397    fn is_variadic() -> bool {
398        false
399    }
400}
401
402pub(super) fn managed_decimal_fmt<M: ManagedTypeApi, F: FormatByteReceiver>(
403    value: &BigInt<M>,
404    num_dec: NumDecimals,
405    f: &mut F,
406) {
407    let full_str_handle: M::ManagedBufferHandle = use_raw_handle(const_handles::MBUF_TEMPORARY_1);
408    M::managed_type_impl().bi_to_string(value.handle.clone(), full_str_handle.clone());
409    let len = M::managed_type_impl().mb_len(full_str_handle.clone());
410
411    if len > num_dec {
412        let temp_str_handle: M::ManagedBufferHandle =
413            use_raw_handle(const_handles::MBUF_TEMPORARY_2);
414        let cast_handle = temp_str_handle.clone().cast_or_signal_error::<M, _>();
415        let temp_str_ref = unsafe { ManagedRef::wrap_handle(cast_handle) };
416        let _ = M::managed_type_impl().mb_copy_slice(
417            full_str_handle.clone(),
418            0,
419            len - num_dec,
420            temp_str_handle.clone(),
421        );
422        f.append_managed_buffer(&temp_str_ref);
423        f.append_bytes(b".");
424        let _ = M::managed_type_impl().mb_copy_slice(
425            full_str_handle.clone(),
426            len - num_dec,
427            num_dec,
428            temp_str_handle.clone(),
429        );
430        f.append_managed_buffer(&temp_str_ref);
431    } else {
432        f.append_bytes(b"0.");
433        for _ in len..num_dec {
434            f.append_bytes(b"0");
435        }
436        let cast_handle = full_str_handle.clone().cast_or_signal_error::<M, _>();
437        let full_str_ref = unsafe { ManagedRef::wrap_handle(cast_handle) };
438        f.append_managed_buffer(&full_str_ref);
439    }
440}
441
442impl<M: ManagedTypeApi, D: Decimals> SCDisplay for ManagedDecimalSigned<M, D> {
443    fn fmt<F: FormatByteReceiver>(&self, f: &mut F) {
444        managed_decimal_fmt(&self.data, self.decimals.num_decimals(), f);
445    }
446}
447
448impl<M: ManagedTypeApi, D: Decimals> core::fmt::Display for ManagedDecimalSigned<M, D> {
449    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
450        let mut result = ManagedBufferCachedBuilder::<M>::new_from_slice(&[]);
451        result.append_display(self);
452        core::fmt::Display::fmt(&result.into_managed_buffer(), f)
453    }
454}
455
456impl<M: ManagedTypeApi, D: Decimals> core::fmt::Debug for ManagedDecimalSigned<M, D> {
457    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
458        f.debug_struct("ManagedDecimalSigned")
459            .field("handle", &self.data.handle.clone())
460            .field("number", &self.to_string())
461            .finish()
462    }
463}