crypto_pay_api/utils/
types.rs

1pub 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}