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}