use crate::book::common::events::{BookEvent, BookEventEnvelope};
use crate::book::common::types::{BookMarketState, BookOrder, CloseProcessState};
use crate::types::OrderId;
pub const MIN_CLOSE_BATCH_EVENTS: u16 = 2;
pub const DEFAULT_CLOSE_BATCH_EVENTS: u16 = 4096;
pub fn close_start_reason(batch_max_events: u16) -> String {
format!("CLOSE_START:{batch_max_events}")
}
pub fn parse_close_start_batch_max_events(reason: &str) -> Option<u16> {
reason
.strip_prefix("CLOSE_START:")
.and_then(|s| s.parse::<u16>().ok())
}
#[inline]
pub fn is_live_order(o: &BookOrder) -> bool {
matches!(
o.info.state,
crate::book::common::types::BookOrderState::ExecutableUnmatched
| crate::book::common::types::BookOrderState::ExecutablePartiallyMatched
)
}
pub fn count_live_orders<'a>(orders: impl Iterator<Item = (OrderId, &'a BookOrder)>) -> u64 {
orders.filter(|(_, o)| is_live_order(o)).count() as u64
}
pub fn close_start_batch(
batch_max_events: u16,
mut state_change: impl FnMut(BookMarketState, &str, &mut Vec<BookEventEnvelope>),
emit: impl Fn(BookEvent) -> BookEventEnvelope,
mut cancel_chunk: impl FnMut(Option<OrderId>, usize) -> (Vec<OrderId>, Option<OrderId>, bool, u64),
) -> Vec<BookEventEnvelope> {
let cancel_budget = batch_max_events as usize;
let (cancelled_order_ids, cursor_after, done, _cancelled_count) =
cancel_chunk(None, cancel_budget);
let mut events = Vec::new();
if done {
state_change(BookMarketState::Closed, "CLOSE_DONE", &mut events);
events.push(emit(BookEvent::MarketOrdersSettled {
cursor_after: None, order_ids: cancelled_order_ids,
is_final: true,
}));
} else {
let reason = close_start_reason(batch_max_events);
state_change(BookMarketState::Closing, &reason, &mut events);
events.push(emit(BookEvent::MarketOrdersSettled {
cursor_after,
order_ids: cancelled_order_ids,
is_final: false,
}));
}
events
}
pub fn close_continue_batch(
proc_state: CloseProcessState,
mut state_change: impl FnMut(BookMarketState, &str, &mut Vec<BookEventEnvelope>),
emit: impl Fn(BookEvent) -> BookEventEnvelope,
mut cancel_chunk: impl FnMut(Option<OrderId>, usize) -> (Vec<OrderId>, Option<OrderId>, bool, u64),
) -> Vec<BookEventEnvelope> {
let mut events = Vec::new();
let cancel_budget = proc_state.batch_max_events as usize; let (cancelled_order_ids, cursor_after, done, _cancelled_count) =
cancel_chunk(proc_state.cursor_after, cancel_budget);
if done {
state_change(BookMarketState::Closed, "CLOSE_DONE", &mut events);
events.push(emit(BookEvent::MarketOrdersSettled {
cursor_after: None, order_ids: cancelled_order_ids,
is_final: true,
}));
} else {
events.push(emit(BookEvent::MarketOrdersSettled {
cursor_after,
order_ids: cancelled_order_ids,
is_final: false,
}));
}
events
}