use std::sync::Mutex;
use nautilus_common::cache::fifo::{FifoCache, FifoCacheMap};
use nautilus_core::MUTEX_POISONED;
use nautilus_model::{
enums::{OrderSide, OrderType},
identifiers::{ClientOrderId, InstrumentId, StrategyId, VenueOrderId},
orders::{Order, OrderAny},
};
#[derive(Clone, Copy, Debug)]
pub(crate) struct OrderIdentity {
pub client_order_id: ClientOrderId,
pub strategy_id: StrategyId,
pub instrument_id: InstrumentId,
pub order_side: OrderSide,
pub order_type: OrderType,
}
impl OrderIdentity {
pub(crate) fn from_order(order: &OrderAny) -> Self {
Self {
client_order_id: order.client_order_id(),
strategy_id: order.strategy_id(),
instrument_id: order.instrument_id(),
order_side: order.order_side(),
order_type: order.order_type(),
}
}
}
#[derive(Debug, Default)]
pub(crate) struct OrderIdentityRegistry {
inner: Mutex<RegistryInner>,
}
#[derive(Debug, Default)]
struct RegistryInner {
identities: FifoCacheMap<VenueOrderId, OrderIdentity, 10_000>,
accepted: FifoCache<VenueOrderId, 10_000>,
}
impl OrderIdentityRegistry {
pub(crate) fn register_order_identity(
&self,
venue_order_id: VenueOrderId,
identity: OrderIdentity,
) {
self.inner
.lock()
.expect(MUTEX_POISONED)
.identities
.insert(venue_order_id, identity);
}
pub(crate) fn get(&self, venue_order_id: &VenueOrderId) -> Option<OrderIdentity> {
self.inner
.lock()
.expect(MUTEX_POISONED)
.identities
.get(venue_order_id)
.copied()
}
pub(crate) fn mark_accepted(&self, venue_order_id: VenueOrderId) -> bool {
let mut guard = self.inner.lock().expect(MUTEX_POISONED);
if guard.accepted.contains(&venue_order_id) {
false
} else {
guard.accepted.add(venue_order_id);
true
}
}
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use super::*;
fn test_identity() -> OrderIdentity {
OrderIdentity {
client_order_id: ClientOrderId::from("O-1"),
strategy_id: StrategyId::from("S-1"),
instrument_id: InstrumentId::from("TEST.POLYMARKET"),
order_side: OrderSide::Buy,
order_type: OrderType::Limit,
}
}
#[rstest]
fn test_register_and_get() {
let registry = OrderIdentityRegistry::default();
let vid = VenueOrderId::from("V-1");
assert!(registry.get(&vid).is_none());
registry.register_order_identity(vid, test_identity());
let identity = registry.get(&vid).expect("identity registered");
assert_eq!(identity.client_order_id, ClientOrderId::from("O-1"));
assert_eq!(identity.order_side, OrderSide::Buy);
}
#[rstest]
fn test_mark_accepted_is_idempotent() {
let registry = OrderIdentityRegistry::default();
let vid = VenueOrderId::from("V-1");
assert!(registry.mark_accepted(vid), "first mark is new");
assert!(!registry.mark_accepted(vid), "second mark is a no-op");
}
}