use super::{
events::{
BookEvent, BookEventEnvelope, CancelledOrderEntry, EventVec, OrderCancellationCursor,
},
types::{BatchMode, BookOrderInfo},
};
use crate::types::OrderId;
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct CancelledOrdersChunk {
pub cancelled_orders: Vec<CancelledOrderEntry>,
pub cursor_after: Option<OrderCancellationCursor>,
pub done: bool,
}
impl CancelledOrderEntry {
pub(crate) fn from_order_info(order_id: OrderId, info: &BookOrderInfo) -> Self {
Self {
order_id,
account_id: info.account_id.clone(),
correlation_id: info.correlation_id.clone(),
}
}
}
impl CancelledOrdersChunk {
pub(crate) fn into_event(self, batch_mode: BatchMode, detail: Option<&str>) -> BookEvent {
BookEvent::OrderCancelledBatched {
cancelled_orders: self.cancelled_orders,
cursor_after: if self.done { None } else { self.cursor_after },
batch_mode,
detail: detail.map(str::to_owned),
}
}
}
pub(crate) fn collect_cancelled_orders_chunk<'a, T: 'a, I, P, F>(
iter: I,
max_orders: usize,
mut should_cancel: P,
info_of: F,
) -> CancelledOrdersChunk
where
I: Iterator<Item = (OrderId, &'a T)>,
P: FnMut(&T) -> bool,
F: Fn(&T) -> &BookOrderInfo,
{
debug_assert!(max_orders > 0);
let mut cancelled_orders = Vec::new();
let mut last_processed = None;
let mut iter = iter.peekable();
while let Some((order_id, order)) = iter.next() {
let info = info_of(order);
last_processed = Some((order_id, info));
if !should_cancel(order) {
continue;
}
cancelled_orders.push(CancelledOrderEntry::from_order_info(order_id, info));
if cancelled_orders.len() >= max_orders {
let done = iter.all(|(_, order)| !should_cancel(order));
return CancelledOrdersChunk {
cancelled_orders,
cursor_after: last_processed.map(|(order_id, info)| OrderCancellationCursor {
order_id,
account_id: info.account_id.clone(),
}),
done,
};
}
}
CancelledOrdersChunk {
cancelled_orders,
cursor_after: last_processed.map(|(order_id, info)| OrderCancellationCursor {
order_id,
account_id: info.account_id.clone(),
}),
done: true,
}
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn push_cancel_chunk(
events: &mut EventVec,
mut emit: impl FnMut(BookEvent) -> BookEventEnvelope,
chunk: CancelledOrdersChunk,
batch_mode: BatchMode,
detail: Option<&str>,
emit_empty_event: bool,
emit_completion: bool,
) {
let done = chunk.done;
if emit_empty_event || !chunk.cancelled_orders.is_empty() {
events.push(emit(chunk.into_event(batch_mode, detail)));
}
if emit_completion && done {
events.push(emit(BookEvent::BatchProcessCompleted { batch_mode }));
}
}