use crate::error::{Error, ErrorType};
use serde::de::{MapAccess, Visitor};
use serde::ser::SerializeMap;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
use std::fmt::Display;
use std::str::FromStr;
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum Urgency {
#[serde(rename = "super-passive")]
SuperPassive,
#[serde(rename = "passive")]
Passive,
#[serde(rename = "moderate")]
Moderate,
#[serde(rename = "aggressive")]
Aggressive,
#[serde(rename = "super-aggressive")]
SuperAggressive,
}
impl FromStr for Urgency {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"super-passive" => Ok(Urgency::SuperPassive),
"passive" => Ok(Urgency::Passive),
"moderate" => Ok(Urgency::Moderate),
"aggressive" => Ok(Urgency::Aggressive),
"super-aggressive" => Ok(Urgency::SuperAggressive),
other => Err(Error::new(
ErrorType::ParseError,
&format!("Invalid Urgency: {}", other),
)),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum Destination {
Arcx, Bats, Baty, Edga, Edgx, Eprl, Iexg, Memx, Xase, Xbos, Xcis, Xnms, Xnys, }
impl Display for Destination {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
Destination::Arcx => "arcx",
Destination::Bats => "bats",
Destination::Baty => "baty",
Destination::Edga => "edga",
Destination::Edgx => "edgx",
Destination::Eprl => "eprl",
Destination::Iexg => "iexg",
Destination::Memx => "memx",
Destination::Xase => "xase",
Destination::Xbos => "xbos",
Destination::Xcis => "xcis",
Destination::Xnms => "xnms",
Destination::Xnys => "xnys",
};
write!(f, "{}", s)
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Strategy {
SmartOrderRoute {
start_at: Option<i64>,
end_at: Option<i64>,
urgency: Option<Urgency>,
},
DirectMarketAccess {
destination: Destination
},
}
impl Default for Strategy {
fn default() -> Self {
Strategy::SmartOrderRoute {
start_at: None,
end_at: None,
urgency: Some(Urgency::Moderate),
}
}
}
impl Serialize for Strategy {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = serializer.serialize_map(None)?;
match self {
Strategy::SmartOrderRoute {
start_at,
end_at,
urgency, ..
} => {
map.serialize_entry("type", "sor")?;
if let Some(start_at) = start_at {
map.serialize_entry("start_at", start_at)?;
}
if let Some(end_at) = end_at {
map.serialize_entry("end_at", end_at)?;
}
if let Some(urgency) = urgency {
map.serialize_entry("urgency", urgency)?;
}
},
Strategy::DirectMarketAccess {
destination,
} => {
map.serialize_entry("type", "dma")?;
map.serialize_entry("destination", &destination.to_string())?;
}
}
map.end()
}
}
impl<'de> Deserialize<'de> for Strategy {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
enum Field {
Type,
StartAt,
EndAt,
Urgency,
Unknown,
Destination,
}
impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_identifier(FieldVisitor)
}
}
struct FieldVisitor;
impl<'de> Visitor<'de> for FieldVisitor {
type Value = Field;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a valid strategy field")
}
fn visit_str<E>(self, v: &str) -> Result<Field, E>
where
E: de::Error,
{
Ok(match v {
"type" => Field::Type,
"start_at" => Field::StartAt,
"end_at" => Field::EndAt,
"urgency" => Field::Urgency,
"destination" => Field::Destination,
_ => Field::Unknown,
})
}
}
struct StrategyVisitor;
impl<'de> Visitor<'de> for StrategyVisitor {
type Value = Strategy;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a valid strategy map")
}
fn visit_map<M>(self, mut map: M) -> Result<Strategy, M::Error>
where
M: MapAccess<'de>,
{
let mut strategy_type: Option<String> = None;
let mut start_at: Option<i64> = None;
let mut end_at: Option<i64> = None;
let mut urgency: Option<Urgency> = None;
let mut destination: Option<Destination> = None;
while let Some(key) = map.next_key::<Field>()? {
match key {
Field::Type => {
strategy_type = Some(map.next_value()?);
}
Field::StartAt => {
start_at = Some(map.next_value()?);
}
Field::EndAt => {
end_at = Some(map.next_value()?);
}
Field::Urgency => {
urgency = Some(map.next_value()?);
}
Field::Destination => {
destination = Some(map.next_value()?);
}
Field::Unknown => {
let _: de::IgnoredAny = map.next_value()?;
}
}
}
match strategy_type.as_deref() {
Some("sor") => Ok(Strategy::SmartOrderRoute {
start_at,
end_at,
urgency,
}),
Some("dma") => {
if let Some(dest) = destination {
Ok(Strategy::DirectMarketAccess { destination: dest })
} else {
Err(de::Error::missing_field("destination"))
}
}
Some(other) => Err(de::Error::custom(format!("unsupported strategy type: {}", other))),
None => Err(de::Error::missing_field("type")),
}
}
}
deserializer.deserialize_map(StrategyVisitor)
}
}