betex 0.35.0

Betfair / Prediction Market Exchange
Documentation
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 }));
    }
}