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,
}
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)
}
}