rusty_common/collections.rs
1//! Common collection type aliases for consistent usage across the codebase
2//!
3//! This module provides re-exports of performance-optimized collection types
4//! that should be used throughout the rusty trading system.
5//!
6//! ## Performance Benefits
7//!
8//! ### FxHashMap/FxHashSet
9//! - Uses FxHash (Firefox's fast hash) instead of SipHash
10//! - 2-4x faster for small keys (integers, short strings)
11//! - No cryptographic security (not needed for HFT)
12//! - Better cache locality
13//!
14//! ### SmallVec
15//! - Stack-allocated for small collections
16//! - Zero heap allocations for typical sizes
17//! - Seamless fallback to heap when needed
18//! - 8-51% performance improvement in benchmarks
19
20// Re-export FxHashMap and FxHashSet for better performance
21// MANDATORY: Always use these instead of std::collections::{HashMap, HashSet}
22pub use rustc_hash::{FxHashMap, FxHashSet};
23
24// Re-export SmallVec
25// MANDATORY: Use SmallVec instead of Vec for collections < 32 items
26pub use smallvec::SmallVec;
27
28// Common SmallVec type aliases for HFT use cases
29
30/// Small vector for order collections (typically < 16 orders)
31pub type SmallOrderVec<T> = SmallVec<[T; 16]>;
32
33/// Small vector for price levels (typically < 20 levels)
34pub type SmallPriceLevelVec<T> = SmallVec<[T; 20]>;
35
36/// Small vector for features/signals (typically < 32 features)
37pub type SmallFeatureVec<T> = SmallVec<[T; 32]>;
38
39/// Small vector for trade updates (typically < 8 trades)
40pub type SmallTradeVec<T> = SmallVec<[T; 8]>;
41
42/// Small vector for symbol lists (typically < 10 symbols)
43pub type SmallSymbolVec<T> = SmallVec<[T; 10]>;
44
45/// Small vector for risk rules (typically < 8 rules in HFT systems)
46pub type SmallRiskRuleVec<T> = SmallVec<[T; 8]>;
47
48/// Small vector for signals (typically < 8 signals per update)
49pub type SmallSignalVec<T> = SmallVec<[T; 8]>;
50
51/// Small vector for strategies (typically < 4 strategies per instrument)
52pub type SmallStrategyVec<T> = SmallVec<[T; 4]>;
53
54/// Small vector for executions (typically < 4 executions per order)
55pub type SmallExecutionVec<T> = SmallVec<[T; 4]>;
56
57/// Small vector for match info results (typically < 4 matches per operation)
58pub type SmallMatchVec<T> = SmallVec<[T; 4]>;
59
60// Common capacity constants for SmallVec usage
61/// Default capacity for execution-related SmallVecs
62pub const EXECUTION_CAPACITY: usize = 4;
63
64/// Default capacity for match-related SmallVecs
65pub const MATCH_CAPACITY: usize = 4;
66
67/// Default capacity for strategy-related SmallVecs
68pub const STRATEGY_CAPACITY: usize = 4;
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73 use smallvec::smallvec;
74
75 #[test]
76 fn test_smallordervec_from_vec_conversions() {
77 // Test data
78 let values = vec![1, 2, 3, 4, 5];
79
80 // Current pattern (inefficient - creates heap-allocated Vec first)
81 let vec1 = SmallOrderVec::from_vec(vec![1, 2, 3, 4, 5]);
82
83 // Better pattern 1: Use smallvec! macro
84 let vec2: SmallOrderVec<i32> = smallvec![1, 2, 3, 4, 5];
85
86 // Better pattern 2: Use from() with an existing Vec when you already have one
87 let existing_vec = vec![1, 2, 3, 4, 5];
88 let vec3: SmallOrderVec<i32> = SmallOrderVec::from(existing_vec);
89
90 // Better pattern 3: Use from_slice
91 let vec4 = SmallOrderVec::from_slice(&values);
92
93 // All should produce the same result
94 assert_eq!(vec1, vec2);
95 assert_eq!(vec1, vec3);
96 assert_eq!(vec1, vec4);
97
98 // Verify length and capacity
99 assert_eq!(vec1.len(), 5);
100 assert!(vec1.capacity() >= 5);
101 }
102
103 #[test]
104 fn test_smallordervec_empty_conversions() {
105 // Current pattern (inefficient)
106 let vec1 = SmallOrderVec::<i32>::from_vec(vec![]);
107
108 // Better pattern 1: Use new()
109 let vec2 = SmallOrderVec::<i32>::new();
110
111 // Better pattern 2: Use smallvec! macro
112 let vec3: SmallOrderVec<i32> = smallvec![];
113
114 // All should be empty
115 assert!(vec1.is_empty());
116 assert!(vec2.is_empty());
117 assert!(vec3.is_empty());
118
119 assert_eq!(vec1, vec2);
120 assert_eq!(vec1, vec3);
121 }
122
123 #[test]
124 fn test_smallordervec_single_element() {
125 // Current pattern (inefficient)
126 let vec1 = SmallOrderVec::from_vec(vec![42]);
127
128 // Better pattern: Use smallvec! macro
129 let vec2: SmallOrderVec<i32> = smallvec![42];
130
131 assert_eq!(vec1, vec2);
132 assert_eq!(vec1.len(), 1);
133 assert_eq!(vec1[0], 42);
134 }
135
136 #[test]
137 fn test_smallordervec_capacity() {
138 // SmallOrderVec should have inline capacity of 16
139 let vec = SmallOrderVec::<i32>::new();
140 assert!(vec.inline_size() >= 16);
141
142 // Adding up to 16 elements should not require heap allocation
143 let mut vec = SmallOrderVec::<i32>::new();
144 for i in 0..16 {
145 vec.push(i);
146 }
147
148 // Check that we're still using inline storage
149 assert!(!vec.spilled());
150
151 // Adding one more will spill to heap
152 vec.push(16);
153 assert!(vec.spilled());
154 }
155}