1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
//! Currency collection stuff.

use crate::cell::*;
use crate::dict::{AugDictSkipValue, Dict};
use crate::num::{Tokens, VarUint248};
use crate::util::{CustomClone, CustomDebug, CustomEq};

/// Amounts collection.
#[derive(CustomDebug, CustomClone, CustomEq, Store, Load)]
pub struct CurrencyCollection<C: CellFamily> {
    /// Amount in native currency.
    pub tokens: Tokens,
    /// Amounts in other currencies.
    pub other: ExtraCurrencyCollection<C>,
}

impl<C: CellFamily> Default for CurrencyCollection<C> {
    #[inline]
    fn default() -> Self {
        Self::ZERO
    }
}

impl<C: CellFamily> CurrencyCollection<C> {
    /// The additive identity for the currency collection
    /// (with empty extra currencies).
    pub const ZERO: Self = Self {
        tokens: Tokens::ZERO,
        other: ExtraCurrencyCollection::new(),
    };

    /// Creates a new currency collection with from the specified tokens amount
    /// and empty extra currency collection.
    pub const fn new(tokens: u128) -> Self {
        Self {
            tokens: Tokens::new(tokens),
            other: ExtraCurrencyCollection::new(),
        }
    }

    /// Returns the number of data bits that this struct occupies.
    pub const fn bit_len(&self) -> u16 {
        self.tokens.unwrap_bit_len() + 1
    }
}

impl<'a, C: CellFamily> AugDictSkipValue<'a, C> for CurrencyCollection<C> {
    #[inline]
    fn skip_value(slice: &mut CellSlice<'a, C>) -> bool {
        Tokens::skip_value(slice) && ExtraCurrencyCollection::<C>::skip_value(slice)
    }
}

/// Dictionary with amounts for multiple currencies.
#[derive(CustomDebug, CustomClone, CustomEq, Store, Load)]
#[repr(transparent)]
pub struct ExtraCurrencyCollection<C: CellFamily>(Dict<C, CellHash, VarUint248>);

impl<C: CellFamily> Default for ExtraCurrencyCollection<C> {
    #[inline]
    fn default() -> Self {
        Self(Dict::new())
    }
}

impl<C: CellFamily> ExtraCurrencyCollection<C> {
    /// Creates an empty extra currency collection.
    pub const fn new() -> Self {
        Self(Dict::new())
    }

    /// Returns `true` if the dictionary contains no elements.
    pub const fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    /// Returns the underlying dictionary.
    pub const fn as_dict(&self) -> &Dict<C, CellHash, VarUint248> {
        &self.0
    }
}

impl<'a, C: CellFamily> AugDictSkipValue<'a, C> for ExtraCurrencyCollection<C> {
    #[inline]
    fn skip_value(slice: &mut CellSlice<'a, C>) -> bool {
        if let Some(has_extra) = slice.load_bit() {
            !has_extra || slice.try_advance(0, 1)
        } else {
            false
        }
    }
}