1use subms_treap::Treap;
21
22enum Event {
24 Post(u32, u64),
25 Amend(u32, i64),
26 Cancel(u32),
27}
28
29const SEED: u64 = 0xB1D;
30
31const TAPE: [Event; 14] = [
34 Event::Post(9998, 1_000),
35 Event::Post(10_000, 500),
36 Event::Post(9999, 250),
37 Event::Post(10_001, 100),
38 Event::Post(9997, 750),
39 Event::Post(10_002, 400),
40 Event::Post(9995, 300),
41 Event::Post(9993, 150),
42 Event::Post(9996, 600),
43 Event::Amend(10_000, 150),
44 Event::Amend(10_001, 800),
45 Event::Cancel(9997),
46 Event::Post(9994, 220),
47 Event::Amend(9993, -50),
48];
49
50fn main() {
51 let mut book = apply_tape();
52 report(&book);
53 sweep_the_touch(&mut book);
54 restore_from_snapshot(&book);
55
56 band_depth();
57
58 #[cfg(feature = "persistent")]
59 versioned_book();
60
61 #[cfg(feature = "merge-split")]
62 partition_ladder();
63
64 #[cfg(feature = "concurrent-reads")]
65 published_snapshot();
66}
67
68fn apply_tape() -> Treap<u32, u64> {
72 println!("== bid-side depth book ==");
73 let book = build_book();
74 println!(" applied {} events -> {} levels", TAPE.len(), book.len());
75 book
76}
77
78fn build_book() -> Treap<u32, u64> {
79 let mut book: Treap<u32, u64> = Treap::with_capacity(SEED, TAPE.len());
80 for event in &TAPE {
81 match event {
82 Event::Post(px, qty) => {
83 book.insert(*px, *qty);
84 }
85 Event::Amend(px, delta) => {
86 if let Some(qty) = book.get_mut(px) {
87 *qty = qty.saturating_add_signed(*delta);
88 }
89 }
90 Event::Cancel(px) => {
91 book.remove(px);
92 }
93 }
94 }
95 assert_eq!(book.len(), 9);
96 assert_eq!(
97 book.get(&10_000).copied(),
98 Some(650),
99 "amend applied in place"
100 );
101 assert!(!book.contains_key(&9997), "cancelled level is gone");
102 book
103}
104
105fn report(book: &Treap<u32, u64>) {
109 let (best_px, best_qty) = book.last().map(|(k, v)| (*k, *v)).expect("non-empty");
110 println!(
111 " best bid {best_px} x {best_qty} | height {} | {} levels",
112 book.height(),
113 book.len()
114 );
115
116 println!(" top 5, best first:");
117 for (px, qty) in book.iter_rev().take(5) {
118 println!(" {px} {qty:>5}");
119 }
120
121 let inside = book.predecessor(&best_px).map(|(k, _)| *k).unwrap();
122 println!(" next level down: {inside}");
123 assert_eq!(inside, 10_001);
124
125 let probe = 9_990u32;
128 println!(
129 " probe {probe}: floor {:?}, ceiling {:?}",
130 book.floor(&probe).map(|(k, _)| *k),
131 book.ceiling(&probe).map(|(k, _)| *k)
132 );
133 assert_eq!(book.floor(&probe), None);
134 assert_eq!(book.ceiling(&probe).map(|(k, _)| *k), Some(9993));
135}
136
137fn sweep_the_touch(book: &mut Treap<u32, u64>) {
141 let mut to_fill = 1_200u64;
142 let mut fills = Vec::new();
143 while to_fill > 0 {
144 let Some((px, qty)) = book.pop_last() else {
145 break;
146 };
147 let take = qty.min(to_fill);
148 to_fill -= take;
149 fills.push((px, take));
150 if qty > take {
151 book.insert(px, qty - take); }
153 }
154 println!(" sweep 1200 lots -> {fills:?}");
155 assert_eq!(fills, vec![(10_002, 400), (10_001, 800)]);
156 assert_eq!(book.len(), 8);
157 assert_eq!(
158 book.last().map(|(k, _)| *k),
159 Some(10_001),
160 "partial fill left the level"
161 );
162}
163
164fn restore_from_snapshot(book: &Treap<u32, u64>) {
167 let snapshot: Vec<(u32, u64)> = book.iter().map(|(k, v)| (*k, *v)).collect();
168 let restored = Treap::from_sorted(SEED, snapshot.clone()).expect("snapshot is sorted");
169 println!(
170 " restored {} levels from a sorted snapshot, height {}",
171 restored.len(),
172 restored.height()
173 );
174 let round_tripped: Vec<(u32, u64)> = restored.iter().map(|(k, v)| (*k, *v)).collect();
175 assert_eq!(round_tripped, snapshot);
176
177 let bad = Treap::from_sorted(SEED, [(2u32, 1u64), (1, 1)]);
179 assert!(bad.is_err(), "strictly-ascending precondition enforced");
180}
181
182fn band_depth() {
187 use subms_treap::RangeBound;
188 println!("\n== range-query: depth in a price band ==");
189 let book = build_book();
190 let (lo, hi) = (9_996u32, 10_000u32);
191 let band: Vec<(u32, u64)> = book
192 .range(RangeBound::Inclusive(&lo), RangeBound::Inclusive(&hi))
193 .map(|(k, v)| (*k, *v))
194 .collect();
195 let depth: u64 = band.iter().map(|(_, q)| *q).sum();
196 println!(" [{lo}, {hi}] -> {} levels, {depth} lots", band.len());
197 assert_eq!(
198 band.iter().map(|(k, _)| *k).collect::<Vec<_>>(),
199 vec![9_996, 9_998, 9_999, 10_000]
200 );
201 assert_eq!(depth, 2_500);
202
203 let inside: u64 = book
205 .range(RangeBound::Inclusive(&lo), RangeBound::Exclusive(&hi))
206 .map(|(_, q)| *q)
207 .sum();
208 println!(" same band, exclusive of {hi}: {inside} lots");
209 assert_eq!(inside, 1_850);
210}
211
212#[cfg(feature = "persistent")]
216fn versioned_book() {
217 use subms_treap::PersistentTreap;
218 println!("\n== persistent: versioned book ==");
219 let open: PersistentTreap<u32, u64> = PersistentTreap::new(SEED);
220 let open = open
221 .insert(9_999, 250)
222 .insert(10_000, 500)
223 .insert(10_001, 100);
224
225 let after_fill = open.remove(&9_999);
227 println!(
228 " open: {} levels, depth@9999 {:?}",
229 open.len(),
230 open.get(&9_999).copied()
231 );
232 println!(
233 " after fill: {} levels, depth@9999 {:?}",
234 after_fill.len(),
235 after_fill.get(&9_999)
236 );
237 assert_eq!(open.get(&9_999).copied(), Some(250), "prior version intact");
238 assert_eq!(after_fill.get(&9_999), None);
239 assert_eq!((open.len(), after_fill.len()), (3, 2));
240}
241
242#[cfg(feature = "merge-split")]
247fn partition_ladder() {
248 use subms_treap::SplittableTreap;
249 println!("\n== merge-split: partition at the touch ==");
250 let mut book: SplittableTreap<u32, u64> = SplittableTreap::new(SEED);
251 for (px, qty) in [
252 (9_996u32, 600u64),
253 (9_998, 1_000),
254 (9_999, 250),
255 (10_000, 650),
256 (10_001, 900),
257 (10_002, 400),
258 ] {
259 book.insert(px, qty);
260 }
261
262 let (resting, marketable) = book.split(&10_000);
265 println!(
266 " below 10000: {} levels | 10000 and up: {} levels",
267 resting.len(),
268 marketable.len()
269 );
270 assert_eq!((resting.len(), marketable.len()), (3, 3));
271 assert_eq!(
272 marketable.collect_in_order().first().map(|(k, _)| **k),
273 Some(10_000)
274 );
275
276 let rejoined = SplittableTreap::merge(resting, marketable);
277 let keys: Vec<u32> = rejoined
278 .collect_in_order()
279 .into_iter()
280 .map(|(k, _)| *k)
281 .collect();
282 println!(" rejoined: {keys:?}");
283 assert_eq!(keys, vec![9_996, 9_998, 9_999, 10_000, 10_001, 10_002]);
284}
285
286#[cfg(feature = "concurrent-reads")]
290fn published_snapshot() {
291 use std::thread;
292 use subms_treap::TreapSnapshot;
293 println!("\n== concurrent-reads: published book snapshot ==");
294 let mut book: Treap<u32, u64> = Treap::new(SEED);
295 for px in 9_990..10_010u32 {
296 book.insert(px, (px as u64) * 10);
297 }
298 let snap = TreapSnapshot::from_treap(&book);
299
300 let readers: Vec<_> = (0..4)
301 .map(|_| {
302 let s = snap.clone();
303 thread::spawn(move || s.range(&9_995, &10_004).count())
304 })
305 .collect();
306
307 book.insert(12_345, 1);
309 book.remove(&9_990);
310
311 for r in readers {
312 assert_eq!(
313 r.join().unwrap(),
314 10,
315 "reader sees the frozen 10-level band"
316 );
317 }
318 println!(" 4 readers each counted 10 levels in [9995, 10004]");
319 assert!(
320 snap.get(&12_345).is_none(),
321 "snapshot isolated from later writes"
322 );
323 assert_eq!(snap.len(), 20);
324}