crypto-pay-api 0.2.1

A Rust client library for Crypto Pay API provided by Telegram CryptoBot
Documentation
use std::fmt::Display;

use crate::utils::deserialize_currency_code;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
pub struct Currency {
    pub is_blockchain: bool,
    pub is_stablecoin: bool,
    pub is_fiat: bool,
    pub name: String,
    #[serde(deserialize_with = "deserialize_currency_code")]
    pub code: CurrencyCode,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub url: Option<String>,
    pub decimals: u8,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(untagged)]
pub enum CurrencyCode {
    Crypto(CryptoCurrencyCode),
    Fiat(FiatCurrencyCode),
}

#[cfg(not(tarpaulin))]
impl Display for CurrencyCode {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            CurrencyCode::Crypto(code) => write!(f, "{code}"),
            CurrencyCode::Fiat(code) => write!(f, "{code}"),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "UPPERCASE")]
pub enum CryptoCurrencyCode {
    Usdt,
    Ton,
    Btc,
    Eth,
    Ltc,
    Bnb,
    Trx,
    Usdc,
    Doge,
    Send,
    Jet,
    #[serde(other)]
    Unknown,
}

#[cfg(not(tarpaulin))]
impl Display for CryptoCurrencyCode {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{self:?}")
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "UPPERCASE")]
pub enum FiatCurrencyCode {
    Usd,
    Eur,
    Rub,
    Byn,
    Uah,
    Gbp,
    Cny,
    Kgs,
    Kzt,
    Uzs,
    Gel,
    Try,
    Amd,
    Thb,
    Tjs,
    Inr,
    Brl,
    Idr,
    Azn,
    Aed,
    Pln,
    Ils,
    Lkr,
    #[serde(other)]
    Unknown,
}

#[cfg(not(tarpaulin))]
impl Display for FiatCurrencyCode {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{self:?}")
    }
}

#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
#[serde(rename_all = "lowercase")]
pub enum CurrencyType {
    Crypto,
    Fiat,
}

#[cfg(not(tarpaulin))]
impl Display for CurrencyType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{self:?}")
    }
}

impl From<CryptoCurrencyCode> for CurrencyCode {
    fn from(code: CryptoCurrencyCode) -> Self {
        CurrencyCode::Crypto(code)
    }
}

impl From<FiatCurrencyCode> for CurrencyCode {
    fn from(code: FiatCurrencyCode) -> Self {
        CurrencyCode::Fiat(code)
    }
}

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

    #[test]
    fn test_currency_type_serialization() {
        let crypto = CurrencyType::Crypto;
        let fiat = CurrencyType::Fiat;

        assert_eq!(serde_json::to_string(&crypto).unwrap(), "\"crypto\"");
        assert_eq!(serde_json::to_string(&fiat).unwrap(), "\"fiat\"");
    }

    #[test]
    fn test_crypto_currency_code_serialization() {
        let btc = CryptoCurrencyCode::Btc;
        let ton = CryptoCurrencyCode::Ton;

        assert_eq!(serde_json::to_string(&btc).unwrap(), "\"BTC\"");
        assert_eq!(serde_json::to_string(&ton).unwrap(), "\"TON\"");
    }

    #[test]
    fn test_fiat_currency_code_serialization() {
        let usd = FiatCurrencyCode::Usd;
        let eur = FiatCurrencyCode::Eur;

        assert_eq!(serde_json::to_string(&usd).unwrap(), "\"USD\"");
        assert_eq!(serde_json::to_string(&eur).unwrap(), "\"EUR\"");
    }

    #[test]
    fn test_currency_code_deserialization() {
        let crypto: CryptoCurrencyCode = serde_json::from_str("\"BTC\"").unwrap();
        let fiat: FiatCurrencyCode = serde_json::from_str("\"USD\"").unwrap();

        assert_eq!(crypto, CryptoCurrencyCode::Btc);
        assert_eq!(fiat, FiatCurrencyCode::Usd);

        assert_eq!(
            serde_json::from_str::<CryptoCurrencyCode>("\"btc\"").unwrap(),
            CryptoCurrencyCode::Unknown
        );
        assert_eq!(
            serde_json::from_str::<FiatCurrencyCode>("\"usd\"").unwrap(),
            FiatCurrencyCode::Unknown
        );
    }

    #[test]
    fn test_currency_code_conversion() {
        let crypto = CryptoCurrencyCode::Btc;
        let fiat = FiatCurrencyCode::Usd;

        let currency_code_crypto: CurrencyCode = crypto.into();
        let currency_code_fiat: CurrencyCode = fiat.into();

        assert!(matches!(
            currency_code_crypto,
            CurrencyCode::Crypto(CryptoCurrencyCode::Btc)
        ));
        assert!(matches!(currency_code_fiat, CurrencyCode::Fiat(FiatCurrencyCode::Usd)));
    }
}