use super::{
events::{
BookEvent, BookEventEnvelope, CancelCause, CancelledOrderEntry, EventVec,
OrderCancellationCursor,
},
types::BookOrderInfo,
};
use crate::types::OrderId;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CancelledOrdersChunk {
pub cancelled_orders: Vec<CancelledOrderEntry>,
pub cursor_after: Option<OrderCancellationCursor>,
pub done: bool,
}
impl CancelledOrderEntry {
pub 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 OrderCancellationCursor {
pub fn from_order_info(order_id: OrderId, info: &BookOrderInfo) -> Self {
Self {
order_id,
account_id: info.account_id.clone(),
}
}
}
impl CancelledOrdersChunk {
pub fn into_event(self, cancel_cause: CancelCause, cause_detail: Option<String>) -> BookEvent {
BookEvent::OrderCancelled {
cancelled_orders: self.cancelled_orders,
cursor_after: if self.done { None } else { self.cursor_after },
is_final: self.done,
cancel_cause,
cause_detail,
}
}
}
pub 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 cursor_after = None;
let mut iter = iter.peekable();
while let Some((order_id, order)) = iter.next() {
let info = info_of(order);
cursor_after = Some(OrderCancellationCursor::from_order_info(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,
done,
};
}
}
CancelledOrdersChunk {
cancelled_orders,
cursor_after,
done: true,
}
}
pub fn push_cancel_chunk(
events: &mut EventVec,
mut emit: impl FnMut(BookEvent) -> BookEventEnvelope,
chunk: CancelledOrdersChunk,
cancel_cause: CancelCause,
cause_detail: Option<String>,
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(cancel_cause, cause_detail)));
}
if emit_completion && done {
events.push(emit(BookEvent::BatchProcessCompleted { cancel_cause }));
}
}