use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::{Error, Result};
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Serialize_repr, Deserialize_repr,
)]
#[repr(u8)]
pub enum NdaxMessageType {
Request = 0,
Reply = 1,
Subscribe = 2,
Event = 3,
Unsubscribe = 4,
Error = 5,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NdaxFrame {
pub m: u8,
pub i: u64,
pub n: String,
pub o: String,
}
impl NdaxFrame {
pub fn request(
id: u64,
name: &str,
payload: &impl Serialize,
) -> Result<Self> {
Ok(Self {
m: NdaxMessageType::Request as u8,
i: id,
n: name.to_string(),
o: serde_json::to_string(payload)?,
})
}
pub fn request_raw(id: u64, name: &str, payload_json: &str) -> Self {
Self {
m: NdaxMessageType::Request as u8,
i: id,
n: name.to_string(),
o: payload_json.to_string(),
}
}
pub fn subscribe(
id: u64,
name: &str,
payload: &impl Serialize,
) -> Result<Self> {
Ok(Self {
m: NdaxMessageType::Subscribe as u8,
i: id,
n: name.to_string(),
o: serde_json::to_string(payload)?,
})
}
pub fn parse_payload<T: DeserializeOwned>(&self) -> Result<T> {
serde_json::from_str(&self.o).map_err(Error::from)
}
pub fn message_type(&self) -> NdaxMessageType {
match self.m {
0 => NdaxMessageType::Request,
1 => NdaxMessageType::Reply,
2 => NdaxMessageType::Subscribe,
3 => NdaxMessageType::Event,
4 => NdaxMessageType::Unsubscribe,
_ => NdaxMessageType::Error,
}
}
pub fn is_reply(&self) -> bool { self.m == NdaxMessageType::Reply as u8 }
pub fn is_event(&self) -> bool { self.m == NdaxMessageType::Event as u8 }
pub fn is_error(&self) -> bool { self.m == NdaxMessageType::Error as u8 }
}
#[cfg(test)]
mod tests {
use serde::Deserialize;
use serde_json::json;
use super::*;
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct TestPayload {
value: i32,
name: String,
}
#[test]
fn test_frame_serialize_request() {
let payload = TestPayload {
value: 42,
name: "test".to_string(),
};
let frame = NdaxFrame::request(1, "TestFunc", &payload).unwrap();
let json = serde_json::to_value(&frame).unwrap();
assert_eq!(json["m"], 0);
assert_eq!(json["i"], 1);
assert_eq!(json["n"], "TestFunc");
}
#[test]
fn test_frame_deserialize_reply() {
let json_str = r#"{"m":1,"i":5,"n":"GetInstruments","o":"{\"value\":123,\"name\":\"test\"}"}"#;
let frame: NdaxFrame = serde_json::from_str(json_str).unwrap();
assert_eq!(frame.m, 1);
assert_eq!(frame.i, 5);
assert_eq!(frame.n, "GetInstruments");
assert!(frame.is_reply());
}
#[test]
fn test_frame_parse_payload() {
let inner = TestPayload {
value: 99,
name: "parsed".to_string(),
};
let frame = NdaxFrame {
m: 1,
i: 1,
n: "Test".to_string(),
o: serde_json::to_string(&inner).unwrap(),
};
let parsed: TestPayload = frame.parse_payload().unwrap();
assert_eq!(parsed, inner);
}
#[test]
fn test_message_type_values() {
assert_eq!(NdaxMessageType::Request as u8, 0);
assert_eq!(NdaxMessageType::Reply as u8, 1);
assert_eq!(NdaxMessageType::Subscribe as u8, 2);
assert_eq!(NdaxMessageType::Event as u8, 3);
assert_eq!(NdaxMessageType::Unsubscribe as u8, 4);
assert_eq!(NdaxMessageType::Error as u8, 5);
}
#[test]
fn test_message_type_serialization() {
let msg_type = NdaxMessageType::Reply;
let serialized = serde_json::to_string(&msg_type).unwrap();
assert_eq!(serialized, "1");
let deserialized: NdaxMessageType = serde_json::from_str("3").unwrap();
assert_eq!(deserialized, NdaxMessageType::Event);
}
#[test]
fn test_frame_helper_methods() {
let reply_frame = NdaxFrame {
m: 1,
i: 1,
n: "Test".to_string(),
o: "{}".to_string(),
};
assert!(reply_frame.is_reply());
assert!(!reply_frame.is_event());
assert!(!reply_frame.is_error());
assert_eq!(reply_frame.message_type(), NdaxMessageType::Reply);
let event_frame = NdaxFrame {
m: 3,
i: 0,
n: "Event".to_string(),
o: "{}".to_string(),
};
assert!(!event_frame.is_reply());
assert!(event_frame.is_event());
assert!(!event_frame.is_error());
assert_eq!(event_frame.message_type(), NdaxMessageType::Event);
let error_frame = NdaxFrame {
m: 5,
i: 1,
n: "Error".to_string(),
o: "{}".to_string(),
};
assert!(!error_frame.is_reply());
assert!(!error_frame.is_event());
assert!(error_frame.is_error());
assert_eq!(error_frame.message_type(), NdaxMessageType::Error);
}
#[test]
fn test_subscribe_frame() {
let payload = json!({"OMSId": 1, "InstrumentId": 1});
let frame = NdaxFrame::subscribe(10, "SubscribeLevel2", &payload).unwrap();
assert_eq!(frame.m, 2);
assert_eq!(frame.i, 10);
assert_eq!(frame.n, "SubscribeLevel2");
assert_eq!(frame.message_type(), NdaxMessageType::Subscribe);
}
}