crypto_pay_api/utils/
types.rs1pub use reqwest::header::{HeaderName, HeaderValue};
2pub use reqwest::Client;
3pub use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
4pub use rust_decimal::Decimal;
5pub use rust_decimal_macros::dec;
6pub use serde::{Deserialize, Serialize};
7use std::str::FromStr;
8
9pub trait IntoDecimal {
10 fn into_decimal(self) -> Decimal;
11 fn try_into_decimal(self) -> Result<Decimal, String>;
12}
13
14impl IntoDecimal for Decimal {
15 fn into_decimal(self) -> Decimal {
16 self
17 }
18
19 fn try_into_decimal(self) -> Result<Decimal, String> {
20 Ok(self)
21 }
22}
23
24impl IntoDecimal for &Decimal {
25 fn into_decimal(self) -> Decimal {
26 *self
27 }
28
29 fn try_into_decimal(self) -> Result<Decimal, String> {
30 Ok(*self)
31 }
32}
33
34macro_rules! impl_into_decimal_int {
35 ($($t:ty),*) => {
36 $(
37 impl IntoDecimal for $t {
38 fn into_decimal(self) -> Decimal {
39 Decimal::from(self)
40 }
41
42 fn try_into_decimal(self) -> Result<Decimal, String> {
43 Ok(Decimal::from(self))
44 }
45 }
46 )*
47 };
48}
49
50impl_into_decimal_int!(u8, i8, u16, i16, u32, i32, u64, i64, isize, usize);
51
52impl IntoDecimal for f32 {
53 fn into_decimal(self) -> Decimal {
54 self.try_into_decimal().unwrap_or(Decimal::ZERO)
55 }
56
57 fn try_into_decimal(self) -> Result<Decimal, String> {
58 Decimal::from_f32(self).ok_or_else(|| format!("Invalid float value: {}", self))
59 }
60}
61
62impl IntoDecimal for f64 {
63 fn into_decimal(self) -> Decimal {
64 self.try_into_decimal().unwrap_or(Decimal::ZERO)
65 }
66
67 fn try_into_decimal(self) -> Result<Decimal, String> {
68 Decimal::from_f64(self).ok_or_else(|| format!("Invalid float value: {}", self))
69 }
70}
71
72impl IntoDecimal for &str {
73 fn into_decimal(self) -> Decimal {
74 self.try_into_decimal().unwrap_or(Decimal::ZERO)
75 }
76
77 fn try_into_decimal(self) -> Result<Decimal, String> {
78 Decimal::from_str(self).map_err(|e| format!("Invalid decimal string '{}': {}", self, e))
79 }
80}
81
82impl IntoDecimal for String {
83 fn into_decimal(self) -> Decimal {
84 self.try_into_decimal().unwrap_or(Decimal::ZERO)
85 }
86
87 fn try_into_decimal(self) -> Result<Decimal, String> {
88 Decimal::from_str(&self).map_err(|e| format!("Invalid decimal string '{}': {}", self, e))
89 }
90}
91
92impl IntoDecimal for &String {
93 fn into_decimal(self) -> Decimal {
94 self.try_into_decimal().unwrap_or(Decimal::ZERO)
95 }
96
97 fn try_into_decimal(self) -> Result<Decimal, String> {
98 Decimal::from_str(self).map_err(|e| format!("Invalid decimal string '{}': {}", self, e))
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 #[test]
107 fn test_decimal_conversions() {
108 let decimal = dec!(123.45);
109 assert_eq!(decimal.into_decimal(), dec!(123.45));
110 assert!(decimal.try_into_decimal().is_ok());
111 }
112
113 #[test]
114 fn test_decimal_ref_conversions() {
115 let decimal = dec!(123.45);
116 assert_eq!((&decimal).into_decimal(), dec!(123.45));
117 assert!((&decimal).try_into_decimal().is_ok());
118 }
119
120 #[test]
121 fn test_integer_conversions() {
122 assert_eq!(42u8.into_decimal(), dec!(42));
123 assert_eq!((-100i32).into_decimal(), dec!(-100));
124 assert_eq!(999u64.into_decimal(), dec!(999));
125
126 assert!(42u8.try_into_decimal().is_ok());
127 assert!((-100i32).try_into_decimal().is_ok());
128 assert!(999u64.try_into_decimal().is_ok());
129 }
130
131 #[test]
132 fn test_float_conversions() {
133 assert_eq!(3.14f32.into_decimal(), dec!(3.14));
134 assert!(3.14f32.try_into_decimal().is_ok());
135
136 assert_eq!(2.718281828f64.into_decimal(), dec!(2.718281828));
137 assert!(2.718281828f64.try_into_decimal().is_ok());
138
139 assert!(f32::NAN.try_into_decimal().is_err());
140 assert!(f32::INFINITY.try_into_decimal().is_err());
141 assert!(f64::NAN.try_into_decimal().is_err());
142 assert!(f64::INFINITY.try_into_decimal().is_err());
143
144 assert_eq!(f32::NAN.into_decimal(), Decimal::ZERO);
145 assert_eq!(f64::INFINITY.into_decimal(), Decimal::ZERO);
146 }
147
148 #[test]
149 fn test_string_conversions() {
150 let valid_str = "123.45";
151 let valid_string = String::from("678.90");
152 let valid_string_ref = &String::from("42.0");
153
154 assert_eq!(valid_str.into_decimal(), dec!(123.45));
155 assert_eq!(valid_string.clone().into_decimal(), dec!(678.90));
156 assert_eq!(valid_string_ref.into_decimal(), dec!(42.0));
157
158 assert!(valid_str.try_into_decimal().is_ok());
159 assert!(valid_string.try_into_decimal().is_ok());
160 assert!(valid_string_ref.try_into_decimal().is_ok());
161
162 let invalid_str = "not_a_number";
163 let invalid_string = String::from("abc123");
164 let invalid_string_ref = &String::from("invalid");
165
166 assert!(invalid_str.try_into_decimal().is_err());
167 assert!(invalid_string.clone().try_into_decimal().is_err());
168 assert!(invalid_string_ref.try_into_decimal().is_err());
169
170 assert_eq!(invalid_str.into_decimal(), Decimal::ZERO);
171 assert_eq!(invalid_string.into_decimal(), Decimal::ZERO);
172 assert_eq!(invalid_string_ref.into_decimal(), Decimal::ZERO);
173 }
174
175 #[test]
176 fn test_empty_string_conversion() {
177 let empty_str = "";
178 let empty_string = String::new();
179 let empty_string_ref = &String::new();
180
181 assert!(empty_str.try_into_decimal().is_err());
182 assert!(empty_string.clone().try_into_decimal().is_err());
183 assert!(empty_string_ref.try_into_decimal().is_err());
184
185 assert_eq!(empty_str.into_decimal(), Decimal::ZERO);
186 assert_eq!(empty_string.into_decimal(), Decimal::ZERO);
187 assert_eq!(empty_string_ref.into_decimal(), Decimal::ZERO);
188 }
189
190 #[test]
191 fn test_edge_case_numbers() {
192 assert_eq!(0.into_decimal(), Decimal::ZERO);
193 assert_eq!(0.0f32.into_decimal(), Decimal::ZERO);
194 assert_eq!("0".into_decimal(), Decimal::ZERO);
195
196 assert_eq!((-42i32).into_decimal(), dec!(-42));
197 assert_eq!((-3.14f64).into_decimal(), dec!(-3.14));
198 assert_eq!("-123.45".into_decimal(), dec!(-123.45));
199
200 assert_eq!(0.000001f32.into_decimal(), dec!(0.000001));
201 assert_eq!(999999999.0f64.into_decimal(), dec!(999999999.0));
202 }
203
204 #[test]
205 fn test_error_messages() {
206 let error = "invalid".try_into_decimal().unwrap_err();
207 assert!(error.contains("Invalid decimal string 'invalid'"));
208
209 let error = f32::NAN.try_into_decimal().unwrap_err();
210 assert!(error.contains("Invalid float value"));
211
212 let error = f64::INFINITY.try_into_decimal().unwrap_err();
213 assert!(error.contains("Invalid float value"));
214 }
215}