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
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use super::{amount::Amount, asset::AssetIdentifier};
use serde::{de, Deserialize, Deserializer};

/// A path resource contains information about a payment path. A path can be used by code to
/// populate necessary fields on path payment operation, such as path and sendMax.  The
/// also describes assets this path hops through.
#[derive(Debug, Clone)]
pub struct PaymentPath {
    path: Vec<AssetIdentifier>,
    source_amount: Amount,
    destination_amount: Amount,
    destination_asset: AssetIdentifier,
    source_asset: AssetIdentifier,
}

impl PaymentPath {
    /// Returns a new Payment Path.
    pub fn new(
        path: Vec<AssetIdentifier>,
        source_amount: Amount,
        destination_amount: Amount,
        destination_asset: AssetIdentifier,
        source_asset: AssetIdentifier,
    ) -> Result<PaymentPath, String> {
        Ok(PaymentPath {
            path,
            source_amount,
            destination_amount,
            destination_asset,
            source_asset,
        })
    }

    /// An array of assets that represents the intermediary assets this path hops through
    pub fn path(&self) -> &Vec<AssetIdentifier> {
        &self.path
    }

    /// Destination amount
    pub fn destination_amount(&self) -> &Amount {
        &self.destination_amount
    }

    /// Source amount
    pub fn source_amount(&self) -> &Amount {
        &self.source_amount
    }

    /// Destination asset specified in the search that found this path
    pub fn destination_asset(&self) -> &AssetIdentifier {
        &self.destination_asset
    }

    /// Source asset specified in the search that found this path
    pub fn source_asset(&self) -> &AssetIdentifier {
        &self.source_asset
    }
}

#[derive(Deserialize, Debug)]
struct IntermediatePaymentPath {
    path: Vec<AssetIdentifier>,
    destination_amount: Amount,
    destination_asset_type: String,
    destination_asset_code: Option<String>,
    destination_asset_issuer: Option<String>,
    source_amount: Amount,
    source_asset_type: String,
    source_asset_code: Option<String>,
    source_asset_issuer: Option<String>,
}

impl<'de> Deserialize<'de> for PaymentPath {
    fn deserialize<D>(d: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let rep: IntermediatePaymentPath = IntermediatePaymentPath::deserialize(d)?;
        let destination_asset = AssetIdentifier::new(
            rep.destination_asset_type.as_str(),
            rep.destination_asset_code,
            rep.destination_asset_issuer,
        ).map_err(de::Error::custom)?;
        let source_asset = AssetIdentifier::new(
            rep.source_asset_type.as_str(),
            rep.source_asset_code,
            rep.source_asset_issuer,
        ).map_err(de::Error::custom)?;
        PaymentPath::new(
            rep.path,
            rep.source_amount,
            rep.destination_amount,
            destination_asset,
            source_asset,
        ).map_err(de::Error::custom)
    }
}

#[cfg(test)]
mod payment_path_tests {
    use super::*;
    use serde_json;

    fn payment_path_json() -> &'static str {
        include_str!("../../fixtures/payment_path.json")
    }

    #[test]
    fn it_deserializes_payment_paths_from_json() {
        let payment_path: PaymentPath = serde_json::from_str(&payment_path_json()).unwrap();
        assert_eq!(payment_path.path().first().unwrap().code(), "1");
        assert_eq!(payment_path.source_amount(), &Amount::new(200_000_000));
        assert_eq!(payment_path.destination_amount(), &Amount::new(200_000_000));
        assert_eq!(payment_path.destination_asset().code(), "EUR");
        assert_eq!(payment_path.source_asset().code(), "USD");
    }
}