use subms_treap::Treap;
enum Event {
Post(u32, u64),
Amend(u32, i64),
Cancel(u32),
}
const SEED: u64 = 0xB1D;
const TAPE: [Event; 14] = [
Event::Post(9998, 1_000),
Event::Post(10_000, 500),
Event::Post(9999, 250),
Event::Post(10_001, 100),
Event::Post(9997, 750),
Event::Post(10_002, 400),
Event::Post(9995, 300),
Event::Post(9993, 150),
Event::Post(9996, 600),
Event::Amend(10_000, 150),
Event::Amend(10_001, 800),
Event::Cancel(9997),
Event::Post(9994, 220),
Event::Amend(9993, -50),
];
fn main() {
let mut book = apply_tape();
report(&book);
sweep_the_touch(&mut book);
restore_from_snapshot(&book);
band_depth();
#[cfg(feature = "persistent")]
versioned_book();
#[cfg(feature = "merge-split")]
partition_ladder();
#[cfg(feature = "concurrent-reads")]
published_snapshot();
}
fn apply_tape() -> Treap<u32, u64> {
println!("== bid-side depth book ==");
let book = build_book();
println!(" applied {} events -> {} levels", TAPE.len(), book.len());
book
}
fn build_book() -> Treap<u32, u64> {
let mut book: Treap<u32, u64> = Treap::with_capacity(SEED, TAPE.len());
for event in &TAPE {
match event {
Event::Post(px, qty) => {
book.insert(*px, *qty);
}
Event::Amend(px, delta) => {
if let Some(qty) = book.get_mut(px) {
*qty = qty.saturating_add_signed(*delta);
}
}
Event::Cancel(px) => {
book.remove(px);
}
}
}
assert_eq!(book.len(), 9);
assert_eq!(
book.get(&10_000).copied(),
Some(650),
"amend applied in place"
);
assert!(!book.contains_key(&9997), "cancelled level is gone");
book
}
fn report(book: &Treap<u32, u64>) {
let (best_px, best_qty) = book.last().map(|(k, v)| (*k, *v)).expect("non-empty");
println!(
" best bid {best_px} x {best_qty} | height {} | {} levels",
book.height(),
book.len()
);
println!(" top 5, best first:");
for (px, qty) in book.iter_rev().take(5) {
println!(" {px} {qty:>5}");
}
let inside = book.predecessor(&best_px).map(|(k, _)| *k).unwrap();
println!(" next level down: {inside}");
assert_eq!(inside, 10_001);
let probe = 9_990u32;
println!(
" probe {probe}: floor {:?}, ceiling {:?}",
book.floor(&probe).map(|(k, _)| *k),
book.ceiling(&probe).map(|(k, _)| *k)
);
assert_eq!(book.floor(&probe), None);
assert_eq!(book.ceiling(&probe).map(|(k, _)| *k), Some(9993));
}
fn sweep_the_touch(book: &mut Treap<u32, u64>) {
let mut to_fill = 1_200u64;
let mut fills = Vec::new();
while to_fill > 0 {
let Some((px, qty)) = book.pop_last() else {
break;
};
let take = qty.min(to_fill);
to_fill -= take;
fills.push((px, take));
if qty > take {
book.insert(px, qty - take); }
}
println!(" sweep 1200 lots -> {fills:?}");
assert_eq!(fills, vec![(10_002, 400), (10_001, 800)]);
assert_eq!(book.len(), 8);
assert_eq!(
book.last().map(|(k, _)| *k),
Some(10_001),
"partial fill left the level"
);
}
fn restore_from_snapshot(book: &Treap<u32, u64>) {
let snapshot: Vec<(u32, u64)> = book.iter().map(|(k, v)| (*k, *v)).collect();
let restored = Treap::from_sorted(SEED, snapshot.clone()).expect("snapshot is sorted");
println!(
" restored {} levels from a sorted snapshot, height {}",
restored.len(),
restored.height()
);
let round_tripped: Vec<(u32, u64)> = restored.iter().map(|(k, v)| (*k, *v)).collect();
assert_eq!(round_tripped, snapshot);
let bad = Treap::from_sorted(SEED, [(2u32, 1u64), (1, 1)]);
assert!(bad.is_err(), "strictly-ascending precondition enforced");
}
fn band_depth() {
use subms_treap::RangeBound;
println!("\n== range-query: depth in a price band ==");
let book = build_book();
let (lo, hi) = (9_996u32, 10_000u32);
let band: Vec<(u32, u64)> = book
.range(RangeBound::Inclusive(&lo), RangeBound::Inclusive(&hi))
.map(|(k, v)| (*k, *v))
.collect();
let depth: u64 = band.iter().map(|(_, q)| *q).sum();
println!(" [{lo}, {hi}] -> {} levels, {depth} lots", band.len());
assert_eq!(
band.iter().map(|(k, _)| *k).collect::<Vec<_>>(),
vec![9_996, 9_998, 9_999, 10_000]
);
assert_eq!(depth, 2_500);
let inside: u64 = book
.range(RangeBound::Inclusive(&lo), RangeBound::Exclusive(&hi))
.map(|(_, q)| *q)
.sum();
println!(" same band, exclusive of {hi}: {inside} lots");
assert_eq!(inside, 1_850);
}
#[cfg(feature = "persistent")]
fn versioned_book() {
use subms_treap::PersistentTreap;
println!("\n== persistent: versioned book ==");
let open: PersistentTreap<u32, u64> = PersistentTreap::new(SEED);
let open = open
.insert(9_999, 250)
.insert(10_000, 500)
.insert(10_001, 100);
let after_fill = open.remove(&9_999);
println!(
" open: {} levels, depth@9999 {:?}",
open.len(),
open.get(&9_999).copied()
);
println!(
" after fill: {} levels, depth@9999 {:?}",
after_fill.len(),
after_fill.get(&9_999)
);
assert_eq!(open.get(&9_999).copied(), Some(250), "prior version intact");
assert_eq!(after_fill.get(&9_999), None);
assert_eq!((open.len(), after_fill.len()), (3, 2));
}
#[cfg(feature = "merge-split")]
fn partition_ladder() {
use subms_treap::SplittableTreap;
println!("\n== merge-split: partition at the touch ==");
let mut book: SplittableTreap<u32, u64> = SplittableTreap::new(SEED);
for (px, qty) in [
(9_996u32, 600u64),
(9_998, 1_000),
(9_999, 250),
(10_000, 650),
(10_001, 900),
(10_002, 400),
] {
book.insert(px, qty);
}
let (resting, marketable) = book.split(&10_000);
println!(
" below 10000: {} levels | 10000 and up: {} levels",
resting.len(),
marketable.len()
);
assert_eq!((resting.len(), marketable.len()), (3, 3));
assert_eq!(
marketable.collect_in_order().first().map(|(k, _)| **k),
Some(10_000)
);
let rejoined = SplittableTreap::merge(resting, marketable);
let keys: Vec<u32> = rejoined
.collect_in_order()
.into_iter()
.map(|(k, _)| *k)
.collect();
println!(" rejoined: {keys:?}");
assert_eq!(keys, vec![9_996, 9_998, 9_999, 10_000, 10_001, 10_002]);
}
#[cfg(feature = "concurrent-reads")]
fn published_snapshot() {
use std::thread;
use subms_treap::TreapSnapshot;
println!("\n== concurrent-reads: published book snapshot ==");
let mut book: Treap<u32, u64> = Treap::new(SEED);
for px in 9_990..10_010u32 {
book.insert(px, (px as u64) * 10);
}
let snap = TreapSnapshot::from_treap(&book);
let readers: Vec<_> = (0..4)
.map(|_| {
let s = snap.clone();
thread::spawn(move || s.range(&9_995, &10_004).count())
})
.collect();
book.insert(12_345, 1);
book.remove(&9_990);
for r in readers {
assert_eq!(
r.join().unwrap(),
10,
"reader sees the frozen 10-level band"
);
}
println!(" 4 readers each counted 10 levels in [9995, 10004]");
assert!(
snap.get(&12_345).is_none(),
"snapshot isolated from later writes"
);
assert_eq!(snap.len(), 20);
}