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
//! Defines data types combining collateral and USD.
//!
//! The purpose of this is to avoid accidentally updating one field in a data
//! structure without updating the other.

use crate::prelude::*;

/// Collateral and USD which will always be non-negative.
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, PartialEq, Eq, Copy, Default)]
pub struct CollateralAndUsd {
    collateral: Collateral,
    usd: Usd,
}

impl CollateralAndUsd {
    /// Create a new value from the given collateral
    pub fn new(collateral: Collateral, price_point: &PricePoint) -> Self {
        CollateralAndUsd {
            collateral,
            usd: price_point.collateral_to_usd(collateral),
        }
    }

    /// Creates a new value from the raw collateral and USD values.
    pub fn from_pair(collateral: Collateral, usd: Usd) -> Self {
        CollateralAndUsd { collateral, usd }
    }

    /// Get the collateral component
    pub fn collateral(&self) -> Collateral {
        self.collateral
    }

    /// Get the USD component
    pub fn usd(&self) -> Usd {
        self.usd
    }

    /// Add a new value
    pub fn checked_add_assign(
        &mut self,
        collateral: Collateral,
        price_point: &PricePoint,
    ) -> Result<()> {
        self.collateral = self.collateral.checked_add(collateral)?;
        self.usd = self
            .usd
            .checked_add(price_point.collateral_to_usd(collateral))?;
        Ok(())
    }
}

/// Collateral and USD which can become negative
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, PartialEq, Eq, Copy, Default)]
pub struct SignedCollateralAndUsd {
    collateral: Signed<Collateral>,
    usd: Signed<Usd>,
}

impl SignedCollateralAndUsd {
    /// Create a new value from the given collateral
    pub fn new(collateral: Signed<Collateral>, price_point: &PricePoint) -> Self {
        SignedCollateralAndUsd {
            collateral,
            usd: collateral.map(|x| price_point.collateral_to_usd(x)),
        }
    }

    /// Get the collateral component
    pub fn collateral(&self) -> Signed<Collateral> {
        self.collateral
    }

    /// Get the USD component
    pub fn usd(&self) -> Signed<Usd> {
        self.usd
    }

    /// Add a new value
    pub fn checked_add_assign(
        &mut self,
        collateral: Signed<Collateral>,
        price_point: &PricePoint,
    ) -> Result<()> {
        self.collateral = self.collateral.checked_add(collateral)?;
        self.usd = self
            .usd
            .checked_add(collateral.map(|x| price_point.collateral_to_usd(x)))?;
        Ok(())
    }
}