xrpl/models/currency/
mod.rs1pub mod issued_currency;
2pub mod mpt_currency;
3pub mod xrp;
4
5use crate::models::Model;
6use alloc::borrow::Cow;
7pub use issued_currency::*;
8pub use mpt_currency::*;
9use serde::{Deserialize, Deserializer, Serialize};
10use strum_macros::Display;
11pub use xrp::*;
12
13use super::{IssuedCurrencyAmount, MPTAmount, XRPAmount};
14
15pub trait ToAmount<'a, A> {
16 fn to_amount(&self, value: Cow<'a, str>) -> A;
17}
18
19#[derive(Debug, PartialEq, Eq, Clone, Serialize, Display)]
20#[serde(untagged)]
21pub enum Currency<'a> {
22 MPTCurrency(MPTCurrency<'a>),
24 IssuedCurrency(IssuedCurrency<'a>),
26 XRP(XRP<'a>),
28}
29
30impl<'de, 'a> Deserialize<'de> for Currency<'a> {
31 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
32 where
33 D: Deserializer<'de>,
34 {
35 let value = serde_json::Value::deserialize(deserializer)?;
36
37 if let Some(obj) = value.as_object() {
39 let has_currency = obj.contains_key("currency");
40 let has_issuer = obj.contains_key("issuer");
41
42 if obj.contains_key("mpt_issuance_id")
45 && !obj.contains_key("currency")
46 && !obj.contains_key("issuer")
47 {
48 if let Ok(mpt) = serde_json::from_value::<MPTCurrency>(value.clone()) {
49 return Ok(Currency::MPTCurrency(mpt));
50 }
51 }
52
53 if has_issuer {
55 if let Ok(ic) = serde_json::from_value::<IssuedCurrency>(value.clone()) {
56 return Ok(Currency::IssuedCurrency(ic));
57 }
58 }
59
60 if has_currency {
62 if let Ok(xrp) = serde_json::from_value::<XRP>(value.clone()) {
63 if xrp.currency == "XRP" {
65 return Ok(Currency::XRP(xrp));
66 }
67 }
68 }
69
70 return Err(serde::de::Error::custom(
72 "Invalid Currency object: must have 'mpt_issuance_id' for MPTCurrency, 'issuer' for IssuedCurrency, or 'currency'='XRP' for XRP"
73 ));
74 }
75
76 Err(serde::de::Error::custom("Currency must be a JSON object"))
77 }
78}
79
80impl<'a> Model for Currency<'a> {
81 fn get_errors(&self) -> crate::models::XRPLModelResult<()> {
82 match self {
83 Currency::MPTCurrency(mpt) => mpt.get_errors(),
84 Currency::IssuedCurrency(issued_currency) => issued_currency.get_errors(),
85 Currency::XRP(xrp) => xrp.get_errors(),
86 }
87 }
88}
89
90impl<'a> Default for Currency<'a> {
91 fn default() -> Self {
92 Self::XRP(XRP::new())
93 }
94}
95
96impl<'a> From<MPTCurrency<'a>> for Currency<'a> {
97 fn from(value: MPTCurrency<'a>) -> Self {
98 Self::MPTCurrency(value)
99 }
100}
101
102impl<'a> From<IssuedCurrency<'a>> for Currency<'a> {
103 fn from(value: IssuedCurrency<'a>) -> Self {
104 Self::IssuedCurrency(value)
105 }
106}
107
108impl<'a> From<XRP<'a>> for Currency<'a> {
109 fn from(value: XRP<'a>) -> Self {
110 Self::XRP(value)
111 }
112}
113
114impl<'a> From<IssuedCurrencyAmount<'a>> for Currency<'a> {
115 fn from(value: IssuedCurrencyAmount<'a>) -> Self {
116 IssuedCurrency::new(value.currency, value.issuer).into()
117 }
118}
119
120impl<'a> From<XRPAmount<'a>> for Currency<'a> {
121 fn from(_value: XRPAmount<'a>) -> Self {
122 XRP::new().into()
123 }
124}
125
126impl<'a> From<&MPTAmount<'a>> for Currency<'a> {
127 fn from(value: &MPTAmount<'a>) -> Self {
128 MPTCurrency::new(value.mpt_issuance_id.clone()).into()
129 }
130}
131
132impl<'a> From<&IssuedCurrencyAmount<'a>> for Currency<'a> {
133 fn from(value: &IssuedCurrencyAmount<'a>) -> Self {
134 IssuedCurrency::new(value.currency.clone(), value.issuer.clone()).into()
135 }
136}
137
138impl<'a> From<&XRPAmount<'a>> for Currency<'a> {
139 fn from(_value: &XRPAmount<'a>) -> Self {
140 XRP::new().into()
141 }
142}
143
144#[cfg(test)]
145mod tests_currency_enum {
146 use crate::models::Model;
147
148 use super::*;
149
150 const VALID_ID: &str = "00000001A407AF5856CEFBF81F3D4A0000000000A407AF58";
151
152 #[test]
153 fn test_currency_deserialize_mpt() {
154 let json = alloc::format!(r#"{{"mpt_issuance_id":"{VALID_ID}"}}"#);
155 let cur: Currency = serde_json::from_str(&json).unwrap();
156 assert!(matches!(cur, Currency::MPTCurrency(_)));
157 }
158
159 #[test]
160 fn test_currency_mpt_json_round_trip() {
161 let original = Currency::MPTCurrency(MPTCurrency::new(VALID_ID.into()));
162 let json = serde_json::to_string(&original).unwrap();
163 let decoded: Currency = serde_json::from_str(&json).unwrap();
164 assert_eq!(original, decoded);
165 }
166
167 #[test]
168 fn test_currency_deserialize_issued_not_mpt() {
169 let json = r#"{"currency":"USD","issuer":"rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd"}"#;
170 let cur: Currency = serde_json::from_str(json).unwrap();
171 assert!(matches!(cur, Currency::IssuedCurrency(_)));
172 }
173
174 #[test]
175 fn test_currency_mpt_get_errors_valid() {
176 let cur = Currency::MPTCurrency(MPTCurrency::new(VALID_ID.into()));
177 assert!(cur.get_errors().is_ok());
178 }
179
180 #[test]
181 fn test_currency_mpt_get_errors_bad_id() {
182 let cur = Currency::MPTCurrency(MPTCurrency::new("TOOSHORT".into()));
183 assert!(cur.get_errors().is_err());
184 }
185}