use std::fmt;
use serde::de::{Unexpected, Visitor};
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use std::fmt::{Display, Formatter};
const BUY: isize = 1;
const SELL: isize = -1;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Signal {
Sell = SELL,
Hold = 0,
Buy = BUY,
}
impl Into<i8> for Signal {
fn into(self) -> i8 {
match self {
Signal::Buy => BUY as i8,
Signal::Hold => 0,
Signal::Sell => SELL as i8,
}
}
}
impl From<i8> for Signal {
fn from(value: i8) -> Self {
match value as isize {
SELL => Signal::Sell,
0 => Signal::Hold,
BUY => Signal::Buy,
_ => panic!("Invalid signal value: {}", value),
}
}
}
impl Display for Signal {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Signal::Buy => write!(f, "BUY"),
Signal::Hold => write!(f, "HOLD"),
Signal::Sell => write!(f, "SELL"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Side {
Sell = SELL,
Buy = BUY,
}
impl Display for Side {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Side::Buy => write!(f, "BUY"),
Side::Sell => write!(f, "SELL"),
}
}
}
impl Serialize for Side {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = match *self {
Side::Buy => "BUY",
Side::Sell => "SELL",
};
serializer.serialize_str(s)
}
}
impl<'de> Deserialize<'de> for Side {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct SideVisitor;
impl<'de> Visitor<'de> for SideVisitor {
type Value = Side;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("a string representing a side (BUY or SELL)")
}
fn visit_str<E>(self, value: &str) -> Result<Side, E>
where
E: de::Error,
{
match value.to_uppercase().as_str() {
"BUY" => Ok(Side::Buy),
"SELL" => Ok(Side::Sell),
_ => Err(de::Error::invalid_value(Unexpected::Str(value), &self)),
}
}
}
deserializer.deserialize_str(SideVisitor)
}
}
impl Into<i8> for Side {
fn into(self) -> i8 {
match self {
Side::Buy => BUY as i8,
Side::Sell => SELL as i8,
}
}
}
impl TryFrom<Signal> for Side {
type Error = &'static str;
fn try_from(value: Signal) -> Result<Self, Self::Error> {
match value {
Signal::Buy => Ok(Side::Buy),
Signal::Sell => Ok(Side::Sell),
Signal::Hold => Err("Cannot convert Signal::Hold to Side"),
}
}
}
impl From<i8> for Side {
fn from(value: i8) -> Self {
match value as isize {
SELL => Side::Sell,
BUY => Side::Buy,
_ => panic!("Invalid side value: {}", value),
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_side_from_i8() {
assert_eq!(Side::from(1), Side::Buy);
assert_eq!(Side::from(-1), Side::Sell);
}
#[test]
#[should_panic]
fn test_side_from_i8_panic() {
let _ = Side::from(0);
}
#[test]
fn test_side_serialize() {
assert_eq!(serde_json::to_string(&Side::Buy).unwrap(), "\"buy\"");
assert_eq!(serde_json::to_string(&Side::Sell).unwrap(), "\"sell\"");
}
#[test]
fn test_side_deserialize() {
assert_eq!(serde_json::from_str::<Side>("\"buy\"").unwrap(), Side::Buy);
assert_eq!(
serde_json::from_str::<Side>("\"sell\"").unwrap(),
Side::Sell
);
}
}