use std::collections::VecDeque;
use crate::{OrderId, Price, Quantity};
#[derive(Clone, Debug)]
pub struct Level {
price: Price,
pub(crate) orders: VecDeque<OrderId>,
total_quantity: Quantity,
tombstone_count: usize,
}
impl Level {
pub fn new(price: Price) -> Self {
Self {
price,
orders: VecDeque::new(),
total_quantity: 0,
tombstone_count: 0,
}
}
#[inline]
pub fn price(&self) -> Price {
self.price
}
#[inline]
pub fn is_empty(&self) -> bool {
self.total_quantity == 0
}
#[inline]
pub fn order_count(&self) -> usize {
self.orders.len() - self.tombstone_count
}
#[inline]
pub fn total_quantity(&self) -> Quantity {
self.total_quantity
}
#[inline]
pub fn tombstone_count(&self) -> usize {
self.tombstone_count
}
pub fn front(&mut self) -> Option<OrderId> {
while let Some(&id) = self.orders.front() {
if id.0 == 0 {
self.orders.pop_front();
self.tombstone_count -= 1;
} else {
return Some(id);
}
}
None
}
pub fn push_back(&mut self, order_id: OrderId, quantity: Quantity) {
assert!(order_id.0 != 0, "OrderId(0) reserved for tombstones");
self.orders.push_back(order_id);
self.total_quantity = self.total_quantity.saturating_add(quantity);
}
pub fn pop_front(&mut self, quantity: Quantity) -> Option<OrderId> {
while let Some(id) = self.orders.pop_front() {
if id.0 == 0 {
self.tombstone_count -= 1;
continue;
}
self.total_quantity = self.total_quantity.saturating_sub(quantity);
return Some(id);
}
None
}
pub fn mark_tombstone(&mut self, index: usize, quantity: Quantity) {
if let Some(id_ref) = self.orders.get_mut(index) {
if id_ref.0 != 0 {
id_ref.0 = 0; self.total_quantity = self.total_quantity.saturating_sub(quantity);
self.tombstone_count += 1;
}
}
}
pub fn remove(&mut self, order_id: OrderId, quantity: Quantity) -> bool {
if let Some(pos) = self.orders.iter().position(|&id| id == order_id) {
self.orders.remove(pos);
self.total_quantity = self.total_quantity.saturating_sub(quantity);
true
} else {
false
}
}
pub fn compact(&mut self) {
if self.tombstone_count == 0 {
return;
}
self.orders.retain(|id| id.0 != 0);
self.tombstone_count = 0;
}
pub fn decrease_quantity(&mut self, amount: Quantity) {
self.total_quantity = self.total_quantity.saturating_sub(amount);
}
pub fn iter(&self) -> impl Iterator<Item = OrderId> + '_ {
self.orders.iter().copied().filter(|id| id.0 != 0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_level_is_empty() {
let mut level = Level::new(Price(100_00));
assert!(level.is_empty());
assert_eq!(level.order_count(), 0);
assert_eq!(level.total_quantity(), 0);
assert_eq!(level.front(), None);
assert_eq!(level.price(), Price(100_00));
}
#[test]
fn push_back_adds_orders() {
let mut level = Level::new(Price(100_00));
level.push_back(OrderId(1), 100);
level.push_back(OrderId(2), 200);
level.push_back(OrderId(3), 150);
assert!(!level.is_empty());
assert_eq!(level.order_count(), 3);
assert_eq!(level.total_quantity(), 450);
assert_eq!(level.front(), Some(OrderId(1)));
}
#[test]
fn pop_front_fifo_order() {
let mut level = Level::new(Price(100_00));
level.push_back(OrderId(1), 100);
level.push_back(OrderId(2), 200);
level.push_back(OrderId(3), 150);
assert_eq!(level.pop_front(100), Some(OrderId(1)));
assert_eq!(level.total_quantity(), 350);
assert_eq!(level.front(), Some(OrderId(2)));
assert_eq!(level.pop_front(200), Some(OrderId(2)));
assert_eq!(level.total_quantity(), 150);
assert_eq!(level.front(), Some(OrderId(3)));
assert_eq!(level.pop_front(150), Some(OrderId(3)));
assert_eq!(level.total_quantity(), 0);
assert!(level.is_empty());
assert_eq!(level.pop_front(0), None);
}
#[test]
fn remove_from_middle() {
let mut level = Level::new(Price(100_00));
level.push_back(OrderId(1), 100);
level.push_back(OrderId(2), 200);
level.push_back(OrderId(3), 150);
assert!(level.remove(OrderId(2), 200));
assert_eq!(level.order_count(), 2);
assert_eq!(level.total_quantity(), 250);
assert_eq!(level.pop_front(100), Some(OrderId(1)));
assert_eq!(level.pop_front(150), Some(OrderId(3)));
}
#[test]
fn remove_nonexistent_returns_false() {
let mut level = Level::new(Price(100_00));
level.push_back(OrderId(1), 100);
assert!(!level.remove(OrderId(999), 50));
assert_eq!(level.order_count(), 1);
assert_eq!(level.total_quantity(), 100);
}
#[test]
fn remove_from_front() {
let mut level = Level::new(Price(100_00));
level.push_back(OrderId(1), 100);
level.push_back(OrderId(2), 200);
assert!(level.remove(OrderId(1), 100));
assert_eq!(level.front(), Some(OrderId(2)));
}
#[test]
fn remove_from_back() {
let mut level = Level::new(Price(100_00));
level.push_back(OrderId(1), 100);
level.push_back(OrderId(2), 200);
assert!(level.remove(OrderId(2), 200));
assert_eq!(level.front(), Some(OrderId(1)));
assert_eq!(level.order_count(), 1);
}
#[test]
fn decrease_quantity_for_partial_fill() {
let mut level = Level::new(Price(100_00));
level.push_back(OrderId(1), 100);
level.push_back(OrderId(2), 200);
level.decrease_quantity(30);
assert_eq!(level.total_quantity(), 270);
assert_eq!(level.order_count(), 2); }
#[test]
fn iter_returns_fifo_order() {
let mut level = Level::new(Price(100_00));
level.push_back(OrderId(1), 100);
level.push_back(OrderId(2), 200);
level.push_back(OrderId(3), 150);
let ids: Vec<_> = level.iter().collect();
assert_eq!(ids, vec![OrderId(1), OrderId(2), OrderId(3)]);
}
#[test]
fn tombstone_marking() {
let mut level = Level::new(Price(100_00));
level.push_back(OrderId(1), 100);
level.push_back(OrderId(2), 200);
level.push_back(OrderId(3), 150);
level.mark_tombstone(1, 200);
assert_eq!(level.order_count(), 2);
assert_eq!(level.total_quantity(), 250);
assert_eq!(level.tombstone_count(), 1);
let ids: Vec<_> = level.iter().collect();
assert_eq!(ids, vec![OrderId(1), OrderId(3)]);
}
#[test]
fn tombstone_compaction() {
let mut level = Level::new(Price(100_00));
level.push_back(OrderId(1), 100);
level.push_back(OrderId(2), 200);
level.push_back(OrderId(3), 150);
level.mark_tombstone(0, 100);
level.mark_tombstone(2, 150);
assert_eq!(level.orders.len(), 3);
assert_eq!(level.tombstone_count(), 2);
level.compact();
assert_eq!(level.orders.len(), 1);
assert_eq!(level.tombstone_count(), 0);
assert_eq!(level.orders[0], OrderId(2));
}
#[test]
fn front_skips_tombstones() {
let mut level = Level::new(Price(100_00));
level.push_back(OrderId(1), 100);
level.push_back(OrderId(2), 200);
level.mark_tombstone(0, 100);
assert_eq!(level.front(), Some(OrderId(2)));
assert_eq!(level.orders.len(), 1);
assert_eq!(level.tombstone_count(), 0);
}
#[test]
fn quantity_saturates_on_underflow() {
let mut level = Level::new(Price(100_00));
level.push_back(OrderId(1), 100);
level.decrease_quantity(200);
assert_eq!(level.total_quantity(), 0);
level.push_back(OrderId(2), 50);
level.pop_front(100);
assert_eq!(level.total_quantity(), 0);
}
}