rinance_dtos 0.1.2

Rinance Dtos
Documentation
use serde::de::{self, MapAccess, Visitor};
use serde::{Deserialize, Deserializer, Serialize};
use std::fmt;

#[derive(Debug)]
pub enum Currency {
    USD,
    None,
}

#[derive(Debug)]
pub enum Type {
    PRIVATE,
    Misc,
    Right,
    Preference,
    MLP,
    RoyaltyTrst,
    CDI,
    TrackingStk,
    DutchCert,
    CommonStock,
    NVDR,
    OpenEndFund,
    Unit,
    SavingsShare,
    GDR,
    REIT,
    StapledSecurity,
    ClosedEndFund,
    SDR,
    ForeignSh,
    NYRegShrs,
    ETP,
    PUBLIC,
    LtdPart,
    EquityWRT,
    ADR,
    Receipt,
    None,
}

#[derive(Serialize, Debug)]
pub struct Symbol {
    pub currency: Currency,
    pub description: String,
    pub display_symbol: String,
    pub figi: String,
    pub isin: String,
    pub mic: String,
    pub share_class_figi: String,
    pub symbol: String,
    pub symbol2: String,
    pub typee: Type,
}

// AI generated deserialize since symbol contains 'type' and so on
impl<'de> Deserialize<'de> for Symbol {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        enum Field {
            Currency,
            Description,
            DisplaySymbol,
            Figi,
            Isin,
            Mic,
            ShareClassFigi,
            Symbol,
            Symbol2,
            Type,
        }

        impl<'de> Deserialize<'de> for Field {
            fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
            where
                D: Deserializer<'de>,
            {
                struct FieldVisitor;

                impl<'de> Visitor<'de> for FieldVisitor {
                    type Value = Field;

                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                        formatter.write_str("field identifier")
                    }

                    fn visit_str<E>(self, value: &str) -> Result<Field, E>
                    where
                        E: de::Error,
                    {
                        match value {
                            "currency" => Ok(Field::Currency),
                            "description" => Ok(Field::Description),
                            "displaySymbol" => Ok(Field::DisplaySymbol),
                            "figi" => Ok(Field::Figi),
                            "isin" => Ok(Field::Isin),
                            "mic" => Ok(Field::Mic),
                            "shareClassFIGI" => Ok(Field::ShareClassFigi),
                            "symbol" => Ok(Field::Symbol),
                            "symbol2" => Ok(Field::Symbol2),
                            "type" => Ok(Field::Type),
                            _ => Err(de::Error::unknown_field(value, FIELDS)),
                        }
                    }
                }

                deserializer.deserialize_identifier(FieldVisitor)
            }
        }

        struct SymbolVisitor;

        impl<'de> Visitor<'de> for SymbolVisitor {
            type Value = Symbol;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("struct Symbol")
            }

            fn visit_map<V>(self, mut map: V) -> Result<Symbol, V::Error>
            where
                V: MapAccess<'de>,
            {
                let mut currency = None;
                let mut description = None;
                let mut display_symbol = None;
                let mut figi = None;
                let mut isin = None;
                let mut mic = None;
                let mut share_class_figi = None;
                let mut symbol = None;
                let mut symbol2 = None;
                let mut typee = None;

                while let Some(key) = map.next_key()? {
                    match key {
                        Field::Currency => {
                            if currency.is_some() {
                                return Err(de::Error::duplicate_field("current"));
                            }

                            let string_value: &str = map.next_value()?;

                            let enum_value = match string_value.trim() {
                                "USD" => Currency::USD,
                                "" => Currency::None,
                                _ => {
                                    return Err(de::Error::custom(format!(
                                        "couldn't match {string_value} to a currency"
                                    )));
                                }
                            };

                            currency = Some(enum_value);
                        }
                        Field::Description => {
                            if description.is_some() {
                                return Err(de::Error::duplicate_field("description"));
                            }
                            description = Some(map.next_value()?);
                        }
                        Field::DisplaySymbol => {
                            if display_symbol.is_some() {
                                return Err(de::Error::duplicate_field("displaySymbol"));
                            }
                            display_symbol = Some(map.next_value()?);
                        }
                        Field::Figi => {
                            if figi.is_some() {
                                return Err(de::Error::duplicate_field("figi"));
                            }
                            figi = Some(map.next_value()?);
                        }
                        Field::Isin => {
                            if isin.is_some() {
                                return Err(de::Error::duplicate_field("isin"));
                            }
                            isin = Some(map.next_value()?);
                        }
                        Field::Mic => {
                            if mic.is_some() {
                                return Err(de::Error::duplicate_field("mic"));
                            }
                            mic = Some(map.next_value()?);
                        }
                        Field::ShareClassFigi => {
                            if share_class_figi.is_some() {
                                return Err(de::Error::duplicate_field("shareClassFIGI"));
                            }
                            share_class_figi = Some(map.next_value()?);
                        }
                        Field::Symbol => {
                            if symbol.is_some() {
                                return Err(de::Error::duplicate_field("symbol"));
                            }
                            symbol = Some(map.next_value()?);
                        }
                        Field::Symbol2 => {
                            if symbol2.is_some() {
                                return Err(de::Error::duplicate_field("symbol2"));
                            }
                            symbol2 = Some(map.next_value()?);
                        }
                        Field::Type => {
                            if typee.is_some() {
                                return Err(de::Error::duplicate_field("type"));
                            }
                            let string_value: &str = map.next_value()?;

                            let enum_value = match string_value.trim() {
                                "PRIVATE" => Type::PRIVATE,
                                "Misc." => Type::Misc,
                                "Right" => Type::Right,
                                "Preference" => Type::Preference,
                                "MLP" => Type::MLP,
                                "Royalty Trst" => Type::RoyaltyTrst,
                                "CDI" => Type::CDI,
                                "Tracking Stk" => Type::TrackingStk,
                                "Dutch Cert" => Type::DutchCert,
                                "Common Stock" => Type::CommonStock,
                                "NVDR" => Type::NVDR,
                                "Open-End Fund" => Type::OpenEndFund,
                                "Unit" => Type::Unit,
                                "Savings Share" => Type::SavingsShare,
                                "GDR" => Type::GDR,
                                "REIT" => Type::REIT,
                                "Stapled Security" => Type::StapledSecurity,
                                "Closed-End Fund" => Type::ClosedEndFund,
                                "SDR" => Type::SDR,
                                "Foreign Sh." => Type::ForeignSh,
                                "NY Reg Shrs" => Type::NYRegShrs,
                                "ETP" => Type::ETP,
                                "PUBLIC" => Type::PUBLIC,
                                "Ltd Part" => Type::LtdPart,
                                "Equity WRT" => Type::EquityWRT,
                                "ADR" => Type::ADR,
                                "Receipt" => Type::Receipt,
                                "" => Type::None,
                                _ => {
                                    return Err(de::Error::custom(format!(
                                        "couldn't match {string_value} to a type"
                                    )));
                                }
                            };

                            typee = Some(enum_value);
                        }
                    }
                }

                Ok(Symbol {
                    currency: currency.ok_or_else(|| de::Error::missing_field("current"))?,
                    description: description
                        .ok_or_else(|| de::Error::missing_field("description"))?,
                    display_symbol: display_symbol
                        .ok_or_else(|| de::Error::missing_field("displaySymbol"))?,
                    figi: figi.ok_or_else(|| de::Error::missing_field("figi"))?,
                    isin: isin.ok_or_else(|| de::Error::missing_field("isin"))?,
                    mic: mic.ok_or_else(|| de::Error::missing_field("mic"))?,
                    share_class_figi: share_class_figi
                        .ok_or_else(|| de::Error::missing_field("shareClassFIGI"))?,
                    symbol: symbol.ok_or_else(|| de::Error::missing_field("symbol"))?,
                    symbol2: symbol2.ok_or_else(|| de::Error::missing_field("symbol2"))?,
                    typee: typee.ok_or_else(|| de::Error::missing_field("type"))?,
                })
            }
        }

        const FIELDS: &[&str] = &[
            "current",
            "description",
            "displaySymbol",
            "figi",
            "isin",
            "mic",
            "shareClassFIGI",
            "symbol",
            "symbol2",
            "type",
        ];
        deserializer.deserialize_struct("Symbol", FIELDS, SymbolVisitor)
    }
}

impl Serialize for Currency {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        match self {
            Currency::USD => serializer.serialize_str("USD"),
            Currency::None => serializer.serialize_str(""),
        }
    }
}

impl Serialize for Type {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        let s = match self {
            Type::PRIVATE => "PRIVATE",
            Type::Misc => "Misc.",
            Type::Right => "Right",
            Type::Preference => "Preference",
            Type::MLP => "MLP",
            Type::RoyaltyTrst => "Royalty Trst",
            Type::CDI => "CDI",
            Type::TrackingStk => "Tracking Stk",
            Type::DutchCert => "Dutch Cert",
            Type::CommonStock => "Common Stock",
            Type::NVDR => "NVDR",
            Type::OpenEndFund => "Open-End Fund",
            Type::Unit => "Unit",
            Type::SavingsShare => "Savings Share",
            Type::GDR => "GDR",
            Type::REIT => "REIT",
            Type::StapledSecurity => "Stapled Security",
            Type::ClosedEndFund => "Closed-End Fund",
            Type::SDR => "SDR",
            Type::ForeignSh => "Foreign Sh.",
            Type::NYRegShrs => "NY Reg Shrs",
            Type::ETP => "ETP",
            Type::PUBLIC => "PUBLIC",
            Type::LtdPart => "Ltd Part",
            Type::EquityWRT => "Equity WRT",
            Type::ADR => "ADR",
            Type::Receipt => "Receipt",
            Type::None => "",
        };
        serializer.serialize_str(s)
    }
}