rustyfixml/
message.rs

1//! FIXML message types and field definitions.
2
3use crate::error::EncodeError;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7/// FIXML message types.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
9pub enum MessageType {
10    NewOrderSingle,
11    ExecutionReport,
12    MarketDataRequest,
13    Heartbeat,
14    Custom(u8),
15}
16
17/// FIXML field value types.
18#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
19pub enum FieldValue {
20    String(String),
21    Integer(i64),
22    Decimal(f64),
23    Boolean(bool),
24}
25
26/// FIXML message representation.
27#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
28pub struct FixmlMessage {
29    pub message_type: MessageType,
30    pub fields: HashMap<String, FieldValue>,
31}
32
33impl FixmlMessage {
34    pub fn new(message_type: MessageType) -> Self {
35        Self {
36            message_type,
37            fields: HashMap::new(),
38        }
39    }
40
41    pub fn new_order_single(symbol: String, price: f64, qty: f64, side: String) -> Self {
42        let mut message = Self::new(MessageType::NewOrderSingle);
43        message.set_field("Symbol", FieldValue::String(symbol));
44        message.set_field("Price", FieldValue::Decimal(price));
45        message.set_field("OrderQty", FieldValue::Decimal(qty));
46        message.set_field("Side", FieldValue::String(side));
47        message.set_field("OrdType", FieldValue::String("2".to_string())); // Limit
48        message
49    }
50
51    pub fn set_field(&mut self, name: &str, value: FieldValue) {
52        self.fields.insert(name.to_string(), value);
53    }
54
55    pub fn get_field(&self, name: &str) -> Option<&FieldValue> {
56        self.fields.get(name)
57    }
58
59    pub fn validate(&self) -> Result<(), EncodeError> {
60        if self.message_type == MessageType::NewOrderSingle {
61            self.require_field("Symbol")?;
62            self.require_field("Side")?;
63            self.require_field("OrderQty")?;
64            self.require_field("OrdType")?;
65        }
66        Ok(())
67    }
68
69    fn require_field(&self, name: &str) -> Result<(), EncodeError> {
70        if !self.fields.contains_key(name) {
71            return Err(EncodeError::MissingRequiredField {
72                field_name: name.to_string(),
73            });
74        }
75        Ok(())
76    }
77}